def desired_status(self): """Get the desired status. Will download and compile status if necessary.""" if self._desired_status is None: services = context.machination_worker_elt.xpath("services/service") # TODO download from all services and merge. For now just # do the first one. # hurl = services[0].xpath('hierarchy/@id') service_id = services[0].get("id") l.lmsg('Connecting to service "{}"'.format(service_id)) # find the machination id for this service mid = context.get_id(service_id) wc = WebClient.from_service_id(service_id, "os_instance") # channel = wc.call("ProfChannel", 'os_instance') try: data = wc.call("GetAssertionList", "os_instance", mid) except: # couldn't dowload assertions - go with last desireed # status. Should already be canonicalized. l.wmsg("Failed to download assertions - using desired status from context.") self._desired_status = copy.deepcopy(context.desired_status.getroot()) else: # we do have some assertions - compile them # pprint.pprint(data) ac = AssertionCompiler(wc) self._desired_status, res = ac.compile(data) mc14n(self._desired_status) # Save as desired-status.xml with open(os.path.join(context.status_dir(), "desired-status.xml"), "w") as ds: ds.write(etree.tostring(self._desired_status, pretty_print=True).decode()) return self._desired_status
def load_previous_status(self): """Load previous_status.xml""" fname = os.path.join(context.status_dir(), "previous-status.xml") try: self._previous_status = etree.parse(fname).getroot() except IOError: # couldn't read file may be lack of permission or not exists # if not exists (first run?) we should make a new status if not os.path.isfile(fname): self._previous_status = E.status() else: raise mc14n(self._previous_status) return self._previous_status
def gather_status(self): """Invoke all workers' generate_status() and gather into one.""" l.lmsg("Gathering status from workers.") status = copy.deepcopy(self.load_previous_status()) # find all workers stelt = status.xpath("/status")[0] done = set() for welt in status.xpath("/status/worker"): # the following should create a worker object and store it # in self.workers worker = self.worker(welt.get("id")) if worker is not None: try: wstatus = worker.generate_status() except AttributeError: # No generate_status method: leave the previous # status element intact. This will, in effect, # cause the status to be tracked by do_update() # when it writes sucessful changes to # previous_status.xml pass stelt.remove(welt) try: stelt.append(wstatus) except Exception as e: stelt.append(welt) done.add(welt.get("id")) for welt in self.desired_status().xpath("/status/worker"): if welt.get("id") in done: continue worker = self.worker(welt.get("id")) if worker is not None: try: wstatus = worker.generate_status() except AttributeError: # No generate_status method and no previous status # element, create one # stelt.append(etree.Element('worker', id=welt.get('id'))) pass else: stelt.append(wstatus) mc14n(status) return status
def generate_status(self): """Generate worker status element. Part generated: Everything from desired status is just returned, apart from: - versionInstalled: auto-generated from installed packages """ # The current status of machination is just what desired # status says it is, apart from installedVersion. # Copy the __machination__ worker element as our starting point. w_elt = copy.deepcopy(context.get_worker_elt(self.name)) # Grab the installedVersion element. try: desiv = w_elt.xpath("installedVersion")[0] except IndexError: # No installedVersion, create an empty one for the rest of # the algorithm. desiv = etree.Element("installedVersion") else: w_elt.remove(desiv) # Find installedVersion information geniv = getattr(self, self.get_installed_func())() # Use geniv as a template to build new element. We do this so # that the installedVersion element's children are in the same # order. self.generated_iv = etree.Element("installedVersion") for desb in desiv.xpath("machinationFetcherBundle"): try: genb = geniv.xpath('machinationFetcherBundle[@id="{}"]'.format(desb.get("id")))[0] except IndexError: # No counterpart. pass else: # Found counterpart in geniv, add to generated_iv. self.generated_iv.append(genb) # Now add any elements left in geniv to generated_iv for genb in geniv: self.generated_iv.append(genb) w_elt.append(self.generated_iv) return xmltools.mc14n(w_elt)
from machination.xmltools import XMLCompare from machination.xmltools import generate_wus from machination.xmltools import mc14n import sys from lxml import etree import pprint left = mc14n(etree.parse(sys.argv[1])) right = mc14n(etree.parse(sys.argv[2])) # print(etree.tostring(left, pretty_print = True).decode()) # print(etree.tostring(right, pretty_print = True).decode()) deps = etree.fromstring("<status><deps/></status>")[0] comp = XMLCompare(left, right) wudeps = comp.wudeps(deps.iterchildren(tag=etree.Element)) pprint.pprint(comp.bystate) pprint.pprint(comp.actions()) pprint.pprint(comp.find_work()) wus, working = generate_wus(comp.find_work(), comp) for wu in wus: print(etree.tostring(wu, pretty_print=True).decode()) print(etree.tostring(working, pretty_print=True).decode())
def __init__(self, initial_status=None, desired_status=None): self.workers = {} mc14n(context.desired_status) self._initial_status = initial_status self._desired_status = desired_status self._previous_status = None