Package backend :: Module actions
[hide private]
[frames] | no frames]

Source Code for Module backend.actions

  1  import json 
  2  import os.path 
  3  import shutil 
  4  import time 
  5   
  6  from bunch import Bunch 
  7   
  8  from .createrepo import createrepo, createrepo_unsafe 
  9   
 10   
11 -class Action(object):
12 """ Object to send data back to fronted 13 14 :param multiprocessing.Queue events: collects events for logging 15 :param multiprocessing.Lock lock: Global lock for backend 16 :param backend.callback.FrontendCallback frontent_callback: 17 object to post data back to frontend 18 19 :param destdir: filepath with build results 20 21 :param dict action: dict-like object with action task 22 23 Expected **action** keys: 24 25 - action_type: main field determining what action to apply 26 # TODO: describe actions 27 28 """ 29
30 - def __init__(self, events, action, lock, 31 frontend_callback, destdir, 32 front_url, results_root_url):
33 super(Action, self).__init__() 34 self.frontend_callback = frontend_callback 35 self.destdir = destdir 36 self.data = action 37 self.events = events 38 self.lock = lock 39 self.front_url = front_url 40 self.results_root_url = results_root_url
41
42 - def __str__(self):
43 return "<Action: {}>".format(self.data)
44
45 - def add_event(self, what):
46 self.events.put({"when": time.time(), "who": "action", "what": what})
47 50
51 - def handle_createrepo(self, result):
52 self.add_event("Action create repo") 53 data = json.loads(self.data["data"]) 54 username = data["username"] 55 projectname = data["projectname"] 56 chroots = data["chroots"] 57 58 failure = False 59 for chroot in chroots: 60 self.add_event("Creating repo for: {}/{}/{}".format(username, projectname, chroot)) 61 62 path = os.path.join(self.destdir, username, projectname, chroot) 63 64 errcode, _, err = createrepo_unsafe(path=path, lock=self.lock) 65 if errcode != 0 or err.strip(): 66 self.add_event("Error making local repo: {0}".format(err)) 67 failure = True 68 69 if failure: 70 result.result = ActionResult.FAILURE 71 else: 72 result.result = ActionResult.SUCCESS
73
74 - def handle_rename(self, result):
75 self.add_event("Action rename") 76 old_path = os.path.normpath(os.path.join( 77 self.destdir, self.data["old_value"])) 78 new_path = os.path.normpath(os.path.join( 79 self.destdir, self.data["new_value"])) 80 81 if os.path.exists(old_path): 82 if not os.path.exists(new_path): 83 shutil.move(old_path, new_path) 84 result.result = ActionResult.SUCCESS 85 else: 86 result.message = "Destination directory already exist." 87 result.result = ActionResult.FAILURE 88 else: # nothing to do, that is success too 89 result.result = ActionResult.SUCCESS 90 result.job_ended_on = time.time()
91
93 self.add_event("Action delete copr") 94 project = self.data["old_value"] 95 path = os.path.normpath(self.destdir + '/' + project) 96 if os.path.exists(path): 97 self.add_event("Removing copr {0}".format(path)) 98 shutil.rmtree(path)
99
100 - def handle_delete_build(self):
101 self.add_event("Action delete build") 102 project = self.data["old_value"] 103 104 ext_data = json.loads(self.data["data"]) 105 username = ext_data["username"] 106 projectname = ext_data["projectname"] 107 chroots_requested = set(ext_data["chroots"]) 108 109 package_name = os.path.basename(ext_data["pkgs"]).replace(".src.rpm", "") 110 # TODO: replace with explicit pkg_name, send cleaned string into the action 111 if not package_name: 112 self.add_event("Bad package name {}, action data: {} ".format(package_name, ext_data)) 113 return 114 115 path = os.path.join(self.destdir, project) 116 117 self.add_event("Deleting package {0}".format(package_name)) 118 self.add_event("Copr path {0}".format(path)) 119 120 try: 121 chroot_list = set(os.listdir(path)) 122 except OSError: 123 # already deleted 124 chroot_list = set() 125 126 chroots_to_do = chroot_list.intersection(chroots_requested) 127 if not chroots_to_do: 128 self.add_event("Nothing to delete for delete action: package {}, {}" 129 .format(package_name, ext_data)) 130 return 131 132 for chroot in chroots_to_do: 133 self.add_event("In chroot {0}".format(chroot)) 134 altered = False 135 136 pkg_path = os.path.join(path, chroot, package_name) 137 if os.path.isdir(pkg_path): 138 self.add_event("Removing build {0}".format(pkg_path)) 139 shutil.rmtree(pkg_path) 140 altered = True 141 else: 142 self.add_event("Package {0} dir not found in chroot {1}".format(package_name, chroot)) 143 144 if altered: 145 self.add_event("Running createrepo") 146 147 result_base_url = "/".join( 148 [self.results_root_url, username, projectname, chroot]) 149 _, _, err = createrepo( 150 path=os.path.join(path, chroot), lock=self.lock, 151 front_url=self.front_url, base_url=result_base_url, 152 username=username, projectname=projectname 153 ) 154 if err.strip(): 155 self.add_event( 156 "Error making local repo: {0}".format(err)) 157 158 logs_to_remove = [ 159 os.path.join(path, chroot, template.format(self.data['object_id'])) 160 for template in ['build-{}.log', 'build-{}.rsync.log'] 161 ] 162 for log_path in logs_to_remove: 163 if os.path.isfile(log_path): 164 self.add_event("Removing log {0}".format(log_path)) 165 os.remove(log_path)
166
167 - def run(self):
168 """ Handle action (other then builds) - like rename or delete of project """ 169 result = Bunch() 170 result.id = self.data["id"] 171 172 action_type = self.data["action_type"] 173 174 if action_type == ActionType.DELETE: 175 if self.data["object_type"] == "copr": 176 self.handle_delete_copr_project() 177 elif self.data["object_type"] == "build": 178 self.handle_delete_build() 179 180 result.result = ActionResult.SUCCESS 181 182 elif action_type == ActionType.LEGAL_FLAG: 183 self.handle_legal_flag() 184 185 elif action_type == ActionType.RENAME: 186 self.handle_rename(result) 187 188 elif action_type == ActionType.CREATEREPO: 189 self.handle_createrepo(result) 190 191 if "result" in result: 192 if result.result == ActionResult.SUCCESS and \ 193 not getattr(result, "job_ended_on", None): 194 result.job_ended_on = time.time() 195 196 self.frontend_callback.update({"actions": [result]})
197 198
199 -class ActionType(object):
200 DELETE = 0 201 RENAME = 1 202 LEGAL_FLAG = 2 203 CREATEREPO = 3
204 205
206 -class ActionResult(object):
207 WAITING = 0 208 SUCCESS = 1 209 FAILURE = 2
210