From 5e0924aeb518eac2de9ea17d56417dbe1c03d0cf Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Sun, 18 Jun 2017 21:59:38 +0400 Subject: [PATCH] suite gestion des liens --- lib/ulib/support/deploydb.py | 231 ++++++++++++++++++++++++++++------- 1 file changed, 187 insertions(+), 44 deletions(-) diff --git a/lib/ulib/support/deploydb.py b/lib/ulib/support/deploydb.py index 3cf7064..67ecc85 100755 --- a/lib/ulib/support/deploydb.py +++ b/lib/ulib/support/deploydb.py @@ -9,6 +9,10 @@ from glob import glob USER_CONFDIR = '~/etc/deploy' SYSTEM_CONFDIR = '/var/local/deploy' +#XXX faire la différence entre "pas de profil défini" (=aucun profil) et +# "définition par défaut pour les profils" (si pas de définition plus précise +# pour un profil, prendre celle-là) + ################################################################################ # Diverses fonctions @@ -18,10 +22,6 @@ def isseq(t): ################################################################################ # Base de données -class UNDEFINED(object): - __repr__ = __string__ = lambda self: 'UNDEFINED' -UNDEFINED = UNDEFINED() - class GenericObject(object): _id = None _values = None @@ -155,8 +155,12 @@ class GenericLink(object): self._tos = set() self._attrs = {} + def is_defaults(self): + fos = list(self._fos) + return len(fos) == 1 and fos[0] is None + def get_profile(self): return self._profile - def set_profile(self): self._profile = profile + def set_profile(self, profile): self._profile = profile profile = property(get_profile, set_profile) def get_ftype(self): return self._ftype @@ -200,6 +204,11 @@ class GenericLink(object): for value in values: self.modify_attr(name, value, method) + def match_profiles(self, profiles): + if not isseq(profiles): profiles = [profiles] + for profile in profiles: + if profile == self._profile: return True + return False def match_fos(self, fos, match='any'): if not isseq(fos): fos = [fos] for fo in fos: @@ -221,7 +230,8 @@ class GenericLink(object): profile = self.profile or 'ALL' print "%s profile: %s" % (indent, profile) def _dump_fos(self, indent): - print "%s from: %s" % (indent, ' '.join(self.fos)) + fos = [fo or '(default)' for fo in self.fos] + print "%s from: %s" % (indent, ' '.join(fos)) def _dump_tos(self, indent): print "%s to: %s" % (indent, ' '.join(self.tos)) def _dump_attrs(self, indent): @@ -255,25 +265,63 @@ class RuinstLink(GenericLink): super(RuinstLink, self).__init__('module', 'host') def dump(self, indent=''): - print "%suinst" % indent + print "%sruinst" % indent + self._dump_profile(indent) self._dump_fos(indent) self._dump_tos(indent) self._dump_attrs(indent) +class RwoinstBundleLink(GenericLink): + def __init__(self): + super(RwoinstBundleLink, self).__init__('wobundle', 'host') + + def dump(self, indent=''): + print "%srwoinst bundle" % indent + self._dump_profile(indent) + self._dump_fos(indent) + self._dump_tos(indent) + self._dump_attrs(indent) + +class RwoinstWebresLink(GenericLink): + def __init__(self): + super(RwoinstWebresLink, self).__init__('wobundle', 'host') + + def dump(self, indent=''): + print "%srwoinst webres" % indent + self._dump_profile(indent) + self._dump_fos(indent) + self._dump_tos(indent) + self._dump_attrs(indent) + +class RtoinstLink(GenericLink): + def __init__(self): + super(RtoinstLink, self).__init__('webapp', 'host') + + def dump(self, indent=''): + print "%srtoinst" % indent + self._dump_profile(indent) + self._dump_fos(indent) + self._dump_tos(indent) + self._dump_attrs(indent) + +class UNDEF(object): + __repr__ = __string__ = lambda self: 'UNDEF' +UNDEF = UNDEF() + class Database(object): _default_profile = None _default_domain = None - _objects = None + _objects_ids_otype = None _objects_classes = None - _links = None + _links_ltype = None _links_classes = None def __init__(self): - self._objects = {} + self._objects_ids_otype = {} self._objects_classes = {} - self._links = {} + self._links_ltype = {} self._links_classes = {} def has_default_profile(self): @@ -297,67 +345,68 @@ class Database(object): default_domain = property(get_default_domain, set_default_domain) def register_object(self, otype, oclass=None): - if not self._objects.has_key(otype): - self._objects[otype] = {} + if not self._objects_ids_otype.has_key(otype): + self._objects_ids_otype[otype] = {} if oclass is None: oclass = GenericObject self._objects_classes[otype] = oclass - def get_known_objects(self): - return self._objects.keys() - known_objects = property(get_known_objects) + def get_known_otypes(self): + return self._objects_ids_otype.keys() + known_otypes = property(get_known_otypes) def get_objects(self, otype): - objects = self._objects.get(otype, None) + objects = self._objects_ids_otype.get(otype, None) if objects is None: return None return [objects[id] for id in objects if id is not None] def has_object(self, otype, id): - objects = self._objects.get(otype, None) + objects = self._objects_ids_otype.get(otype, None) if objects is None: return False return objects.has_key(id) def get_object(self, otype, id): - objects = self._objects.get(otype, None) + objects = self._objects_ids_otype.get(otype, None) if objects is None: return None object = objects.get(id, None) if object is None: object_class = self._objects_classes.get(otype, None) if object_class is not None: object = object_class(id) - self._objects[otype][id] = object + self._objects_ids_otype[otype][id] = object return object def register_link(self, ltype, lclass): - if not self._links.has_key(ltype): - self._links[ltype] = {} + if not self._links_ltype.has_key(ltype): + self._links_ltype[ltype] = [] self._links_classes[ltype] = lclass - def get_known_profiles(self, ltype): - return self._links[ltype].keys() - def get_links(self, ltype, profile, fo=UNDEFINED, to=UNDEFINED, attrs=UNDEFINED, create=False): - if fo is UNDEFINED and to is UNDEFINED and attrs is UNDEFINED: - raise ValueError("you must set either fo, to ou attrs") - plinks = self._links.get(ltype, None) - if plinks is None: return None - links = plinks.get(profile, None) - if links is None: links = plinks[profile] = [] + def get_known_ltypes(self): + return self._links_ltype.keys() + known_ltypes = property(get_known_ltypes) + def get_links(self, ltype, profile=UNDEF, fo=UNDEF, to=UNDEF, attrs=UNDEF, create=False): + links = self._links_ltype.get(ltype, None) + if links is None: return None found = None for link in links: - if (fo is UNDEFINED or link.match_fos(fo)) \ - and (to is UNDEFINED or link.match_tos(to)) \ - and (attrs is UNDEFINED or link.match_attrs(attrs)): + if (profile is UNDEF or link.match_profiles(profile)) \ + and (fo is UNDEF or link.match_fos(fo)) \ + and (to is UNDEF or link.match_tos(to)) \ + and (attrs is UNDEF or link.match_attrs(attrs)): if found is None: found = [] found.append(link) if found is not None: return found - if not create: return None + if not create: return [] + # ici, create==True + if profile is UNDEF: profile = None link = self._links_classes[ltype]() - if fo is not UNDEFINED: + link.profile = profile + if fo is not UNDEF: if isseq(fo): fos = fo else: fos = [fo] for fo in fos: link.add_fo(fo) - if to is not UNDEFINED: + if to is not UNDEF: if isseq(to): tos = to else: tos = [to] for to in tos: link.add_to(to) - if attrs is not UNDEFINED: + if attrs is not UNDEF: for name, value in attrs.items(): link.set_attr(name, value) links.append(link) @@ -809,6 +858,7 @@ class Parser(object): AP.add_argument('nvss', nargs=REMAINDER) o = AP.parse_args(args) profiles = o.profiles or [None] + #XXX spliter profiles sur ',' for profile in profiles: # préparer la mise à jour du groupe courant currentls = self.db.get_links(ltype, profile, fo=self.groups['module']['current'], create=True) @@ -823,7 +873,7 @@ class Parser(object): currentl.merge_attrs(defaultl) defaultl = defaultls[0] # traiter les liens - for nvs in args: + for nvs in o.nvss: name, value, type, method = split_namev(nvs) if name == defaultl.ttype: # définir des destinations du lien @@ -846,6 +896,8 @@ class Parser(object): ############################################################################ def __setup_woinst(self): self.db.register_object('wobundle', WobundleObject) + self.db.register_link('rwoinst-bundle', RwoinstBundleLink) + self.db.register_link('rwoinst-webres', RwoinstWebresLink) self.db.get_object('wobundle', None) self.groups['wobundle'] = {} self.handle_group(['wobundle', 'defaults']) @@ -919,12 +971,56 @@ class Parser(object): if valuep is not None: o.set_attr('path', valuep) self.add_group(otype, id) - def handle_rwoinst(self, cmd, *args): - pass + def handle_rwoinst(self, ltype, *args): + """rwoinst bundle -p profile attrs* + rwoinst webres -p profile attrs* + """ + AP = ArgumentParser() + AP.add_argument('-p', '--profile', action='append', dest='profiles') + AP.add_argument('stype', nargs=1) + AP.add_argument('nvss', nargs=REMAINDER) + o = AP.parse_args(args) + ltype = "%s-%s" % (ltype, o.stype[0]) + profiles = o.profiles or [None] + #XXX spliter profiles sur ',' + for profile in profiles: + # préparer la mise à jour du groupe courant + currentls = self.db.get_links(ltype, profile, fo=self.groups['wobundle']['current'], create=True) + if profile is not None: + globalls = self.db.get_links(ltype, None, fo=None, create=True) + for currentl in currentls: + for globall in globalls: + currentl.merge_attrs(globall) + defaultls = self.db.get_links(ltype, profile, fo=None, create=True) + for currentl in currentls: + for defaultl in defaultls: + currentl.merge_attrs(defaultl) + defaultl = defaultls[0] + # traiter les liens + for nvs in o.nvss: + name, value, type, method = split_namev(nvs) + if name == defaultl.ttype: + # définir des destinations du lien + if value is not None: + tos = split_nlist(nvs)[1] + for to in tos: + for currentl in currentls: + currentl.add_to(to) + else: + # définir un attribut du lien + #name, value, type, method = split_namev(nv) + if value is None: + method = 'set' + value = '1' + elif type == 'path': + value = path.expanduser(value) + for currentl in currentls: + currentl.modify_attr(name, value, method) ############################################################################ def __setup_toinst(self): self.db.register_object('webapp', WebappObject) + self.db.register_link('rtoinst', RtoinstLink) self.db.get_object('webapp', None) self.groups['webapp'] = {} self.handle_group(['webapp', 'defaults']) @@ -996,8 +1092,48 @@ class Parser(object): if valuep is not None: o.set_attr('path', valuep) self.add_group(otype, id) - def handle_rtoinst(self, cmd, *args): - pass + def handle_rtoinst(self, ltype, *args): + """rtoinst -p profile attrs* + """ + AP = ArgumentParser() + AP.add_argument('-p', '--profile', action='append', dest='profiles') + AP.add_argument('nvss', nargs=REMAINDER) + o = AP.parse_args(args) + profiles = o.profiles or [None] + #XXX spliter profiles sur ',' + for profile in profiles: + # préparer la mise à jour du groupe courant + currentls = self.db.get_links(ltype, profile, fo=self.groups['webapp']['current'], create=True) + if profile is not None: + globalls = self.db.get_links(ltype, None, fo=None, create=True) + for currentl in currentls: + for globall in globalls: + currentl.merge_attrs(globall) + defaultls = self.db.get_links(ltype, profile, fo=None, create=True) + for currentl in currentls: + for defaultl in defaultls: + currentl.merge_attrs(defaultl) + defaultl = defaultls[0] + # traiter les liens + for nvs in o.nvss: + name, value, type, method = split_namev(nvs) + if name == defaultl.ttype: + # définir des destinations du lien + if value is not None: + tos = split_nlist(nvs)[1] + for to in tos: + for currentl in currentls: + currentl.add_to(to) + else: + # définir un attribut du lien + #name, value, type, method = split_namev(nv) + if value is None: + method = 'set' + value = '1' + elif type == 'path': + value = path.expanduser(value) + for currentl in currentls: + currentl.modify_attr(name, value, method) ################################################################################ # Programme principal @@ -1027,7 +1163,7 @@ def run_qdd(o): print "=== predicates" for p in predicates: print ' '.join(map(repr, p)) - otypes = db.known_objects + otypes = db.known_otypes[:] otypes.remove('host') otypes.insert(0, 'host') for otype in otypes: @@ -1036,6 +1172,13 @@ def run_qdd(o): print "=== %s" % otype for o in objects: o.dump() + for ltype in db.known_ltypes: + links = db.get_links(ltype) + if links: + print "=== %s" % ltype + for link in links: + if link.is_defaults(): continue + link.dump(" ") elif o.action == 'query': parser = Parser(db).parse(lexer.get_predicates())