Trees | Indices | Help |
---|
|
1 import json 2 import time 3 4 from sqlalchemy import and_, or_ 5 from sqlalchemy.exc import IntegrityError 6 7 from copr_common.enums import ActionTypeEnum, BackendResultEnum 8 from coprs import db 9 from coprs import models 10 from coprs import helpers 11 from coprs import exceptions 12 from .helpers import get_graph_parameters15 16 @classmethod44218 """ 19 Return single action identified by `action_id` 20 """ 21 22 query = models.Action.query.filter(models.Action.id == action_id) 23 return query24 25 @classmethod27 query = models.Action.query 28 if action_type is not None: 29 query = query.filter(models.Action.action_type == 30 int(action_type)) 31 if result is not None: 32 query = query.filter(models.Action.result == 33 int(result)) 34 35 return query36 37 @classmethod39 """ 40 Return actions that aren't finished 41 """ 42 43 query = (models.Action.query 44 .filter(models.Action.result == 45 BackendResultEnum("waiting")) 46 .filter(models.Action.action_type != 47 ActionTypeEnum("legal-flag")) 48 .order_by(models.Action.created_on.asc())) 49 50 return query51 52 @classmethod54 """ 55 Return actions matching passed `ids` 56 """ 57 58 return models.Action.query.filter(models.Action.id.in_(ids))59 60 @classmethod62 """ 63 Update `action` object with `upd_dict` data 64 65 Updates result, message and ended_on parameters. 66 """ 67 68 for attr in ["result", "message"]: 69 value = upd_dict.get(attr, None) 70 if value: 71 setattr(action, attr, value) 72 73 if upd_dict.get('result', None) in [BackendResultEnum("success"), 74 BackendResultEnum("failure")]: 75 action.ended_on = time.time() 76 db.session.add(action) 77 return action78 79 @classmethod81 possible_dirnames = [copr_dir.name for copr_dir in copr.dirs] 82 if not dirnames: 83 # by default we createrepo for all of them 84 dirnames = possible_dirnames 85 else: 86 missing = set(dirnames) - set(possible_dirnames) 87 if missing: 88 raise exceptions.NotFoundException( 89 "Can't createrepo for {} dirnames in {} project".format( 90 missing, copr.full_name)) 91 data_dict = { 92 "ownername": copr.owner_name, 93 "projectname": copr.name, 94 "project_dirnames": dirnames, 95 "chroots": [chroot.name for chroot in copr.active_chroots], 96 } 97 action = models.Action( 98 action_type=ActionTypeEnum("createrepo"), 99 object_type="repository", 100 object_id=0, 101 data=json.dumps(data_dict), 102 created_on=int(time.time()), 103 ) 104 db.session.add(action) 105 return action106 107 @classmethod109 data_dict = { 110 "ownername": copr.owner_name, 111 "project_dirnames": [copr_dir.name for copr_dir in copr.dirs], 112 } 113 action = models.Action(action_type=ActionTypeEnum("delete"), 114 object_type="copr", 115 object_id=copr.id, 116 data=json.dumps(data_dict), 117 created_on=int(time.time())) 118 db.session.add(action) 119 return action120 121 @classmethod123 """ 124 Creates a dictionary of chroot builddirs for build delete action 125 :type build: models.build 126 """ 127 chroot_builddirs = {} 128 129 # plan to remove sub-dir in srpm-builds/ directory 130 if build.result_dir: 131 chroot_builddirs['srpm-builds'] = [build.result_dir] 132 133 # and all chroot sub-dirs 134 for build_chroot in build.build_chroots: 135 if not build_chroot.result_dir: 136 # when we cancel build when the src.rpm (e.g. SCM method) is not 137 # yet generated 138 continue 139 chroot_builddirs[build_chroot.name] = [build_chroot.result_dir] 140 141 return chroot_builddirs142 143 @classmethod145 """ 146 Creates data needed for build delete action 147 :type build: models.build 148 """ 149 return { 150 "ownername": build.copr.owner_name, 151 "projectname": build.copr_name, 152 "project_dirname": 153 build.copr_dirname if build.copr_dir else build.copr_name, 154 "chroot_builddirs": cls.get_chroot_builddirs(build) 155 }156 157 @classmethod159 """ 160 Schedules build delete action 161 :type build: models.Build 162 """ 163 action = models.Action( 164 action_type=ActionTypeEnum("delete"), 165 object_type="build", 166 object_id=build.id, 167 data=json.dumps(cls.get_build_delete_data(build)), 168 created_on=int(time.time()) 169 ) 170 db.session.add(action) 171 return action172 173 @classmethod175 """ 176 Schedules builds delete action for builds belonging to the same project 177 :type build: list of models.Build 178 """ 179 project_dirnames = {} 180 data = {'project_dirnames': project_dirnames} 181 182 build_ids = [] 183 for build in builds: 184 build_delete_data = cls.get_build_delete_data(build) 185 build_ids.append(build.id) 186 187 # inherit some params from the first build 188 for param in ['ownername', 'projectname']: 189 new = build_delete_data[param] 190 if param in data and data[param] != new: 191 # this shouldn't happen 192 raise exceptions.BadRequest("Can not delete builds " 193 "from more projects") 194 data[param] = new 195 196 dirname = build_delete_data['project_dirname'] 197 if not dirname in project_dirnames: 198 project_dirnames[dirname] = {} 199 200 project_dirname = project_dirnames[dirname] 201 for chroot, subdirs in build_delete_data['chroot_builddirs'].items(): 202 if chroot not in project_dirname: 203 project_dirname[chroot] = subdirs 204 else: 205 project_dirname[chroot].extend(subdirs) 206 207 data['build_ids'] = build_ids 208 209 # not object_id here, we are working with multiple IDs 210 action = models.Action( 211 action_type=ActionTypeEnum("delete"), 212 object_type="builds", 213 data=json.dumps(data), 214 created_on=int(time.time()) 215 ) 216 db.session.add(action) 217 return action218 219 @classmethod221 """ 222 Schedule build cancel. The build is marked as canceled immediately, but 223 to not waste the resources we propagate this information to Backend 224 which may deallocate the builder resources. 225 226 :type build: models.Build 227 """ 228 if build.canceled: 229 return 230 db.session.add(models.CancelRequest(what=str(build.id))) 231 for chroot in build.build_chroots: 232 db.session.add(models.CancelRequest(what=chroot.task_id))233 234 @classmethod236 """ Schedules update comps.xml action 237 238 :type copr_chroot: models.CoprChroot 239 """ 240 241 url_path = helpers.copr_url("coprs_ns.chroot_view_comps", chroot.copr, chrootname=chroot.name) 242 data_dict = { 243 "ownername": chroot.copr.owner_name, 244 "projectname": chroot.copr.name, 245 "chroot": chroot.name, 246 "comps_present": chroot.comps_zlib is not None, 247 "url_path": url_path, 248 } 249 250 action = models.Action( 251 action_type=ActionTypeEnum("update_comps"), 252 object_type="copr_chroot", 253 data=json.dumps(data_dict), 254 created_on=int(time.time()) 255 ) 256 db.session.add(action) 257 return action258 259 @classmethod261 """ 262 :type copr: models.Copr 263 """ 264 265 data_dict = { 266 "ownername": copr.owner_name, 267 "projectname": copr.name, 268 } 269 270 action = models.Action( 271 action_type=ActionTypeEnum("gen_gpg_key"), 272 object_type="copr", 273 data=json.dumps(data_dict), 274 created_on=int(time.time()), 275 ) 276 db.session.add(action) 277 return action278 279 @classmethod281 action = models.Action( 282 action_type=ActionTypeEnum("rawhide_to_release"), 283 object_type="None", 284 data=json.dumps(data), 285 created_on=int(time.time()), 286 ) 287 db.session.add(action) 288 return action289 290 @classmethod292 """ 293 :type src: models.Copr 294 :type dst: models.Copr 295 :type builds_map: dict where keys are forked builds IDs and values are IDs from the original builds. 296 """ 297 298 action = models.Action( 299 action_type=ActionTypeEnum("fork"), 300 object_type="copr", 301 old_value="{0}".format(src.full_name), 302 new_value="{0}".format(dst.full_name), 303 data=json.dumps({"user": dst.owner_name, "copr": dst.name, "builds_map": builds_map}), 304 created_on=int(time.time()), 305 ) 306 db.session.add(action) 307 return action308 309 @classmethod311 """ 312 :type copr: models.Copr 313 :type modulemd: str content of module yaml file 314 """ 315 316 mock_chroots = set.intersection(*[set(b.chroots) for b in module.builds]) 317 data = { 318 "chroots": [ch.name for ch in mock_chroots], 319 "builds": [b.id for b in module.builds], 320 } 321 322 action = models.Action( 323 action_type=ActionTypeEnum("build_module"), 324 object_type="module", 325 object_id=module.id, 326 old_value="", 327 new_value="", 328 data=json.dumps(data), 329 created_on=int(time.time()), 330 ) 331 db.session.add(action) 332 return action333 334 @classmethod336 """ 337 Schedules deletion of a chroot directory from project 338 Useful to remove outdated chroots 339 :type build: models.CoprChroot 340 """ 341 data_dict = { 342 "ownername": copr_chroot.copr.owner_name, 343 "projectname": copr_chroot.copr.name, 344 "chrootname": copr_chroot.name, 345 } 346 347 action = models.Action( 348 action_type=ActionTypeEnum("delete"), 349 object_type="chroot", 350 object_id=None, 351 data=json.dumps(data_dict), 352 created_on=int(time.time()) 353 ) 354 db.session.add(action) 355 return action356 357 @classmethod359 result = models.ActionsStatistics.query\ 360 .filter(models.ActionsStatistics.stat_type == type)\ 361 .filter(models.ActionsStatistics.time == time).first() 362 if result: 363 return 364 365 try: 366 cached_data = models.ActionsStatistics( 367 time = time, 368 stat_type = type, 369 waiting = waiting, 370 success = success, 371 failed = failure 372 ) 373 db.session.add(cached_data) 374 db.session.commit() # @FIXME We should not commit here 375 except IntegrityError: # other process already calculated the graph data and cached it 376 db.session.rollback()377 378 @classmethod380 if actionType == 0: 381 # used for getting data for "processed" line of action graphs 382 result = models.Action.query\ 383 .filter(and_( 384 models.Action.created_on <= end, 385 or_( 386 models.Action.ended_on > start, 387 models.Action.ended_on == None 388 )))\ 389 .count() 390 return result 391 392 else: 393 # used to getting data for "successed and failure" line of action graphs 394 result = models.Action.query\ 395 .filter(models.Action.ended_on <= end)\ 396 .filter(models.Action.ended_on > start)\ 397 .filter(models.Action.result == actionType)\ 398 .count() 399 return result400 401 @classmethod403 data = { 404 "waiting": [], 405 "success": [], 406 "failure": [], 407 } 408 result = models.ActionsStatistics.query\ 409 .filter(models.ActionsStatistics.stat_type == params["type"])\ 410 .filter(models.ActionsStatistics.time >= params["start"])\ 411 .filter(models.ActionsStatistics.time <= params["end"])\ 412 .order_by(models.ActionsStatistics.time) 413 for row in result: 414 data["waiting"].append(row.waiting) 415 data["success"].append(row.success) 416 data["failure"].append(row.failed) 417 418 return data419 420 @classmethod422 data = [["processed"], ["success"], ["failure"], ["time"] ] 423 params = get_graph_parameters(type) 424 cached_data = cls.get_cached_action_data(params) 425 for actionType in ["waiting", "success", "failure"]: 426 data[BackendResultEnum(actionType)].extend(cached_data[actionType]) 427 for i in range(len(data[0]) - 1, params["steps"]): 428 step_start = params["start"] + i * params["step"] 429 step_end = step_start + params["step"] 430 waiting = cls.get_actions_bucket(step_start, step_end, BackendResultEnum("waiting")) 431 success = cls.get_actions_bucket(step_start, step_end, BackendResultEnum("success")) 432 failure = cls.get_actions_bucket(step_start, step_end, BackendResultEnum("failure")) 433 data[0].append(waiting) 434 data[1].append(success) 435 data[2].append(failure) 436 cls.cache_action_graph_data(type, time=step_start, waiting=waiting, success=success, failure=failure) 437 438 for i in range(params["start"], params["end"], params["step"]): 439 data[3].append(time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime(i))) 440 441 return data
Trees | Indices | Help |
---|
Generated by Epydoc 3.0.1 | http://epydoc.sourceforge.net |