This commit is contained in:
Jephté Clain 2017-06-18 11:57:38 +04:00
parent f0de1213f6
commit e0b15350c1
1 changed files with 99 additions and 42 deletions

View File

@ -9,9 +9,19 @@ from glob import glob
USER_CONFDIR = '~/etc/deploy' USER_CONFDIR = '~/etc/deploy'
SYSTEM_CONFDIR = '/var/local/deploy' SYSTEM_CONFDIR = '/var/local/deploy'
################################################################################
# Diverses fonctions
def isseq(t):
return isinstance(t, list) or isinstance(t, tuple) or isinstance(t, set)
################################################################################ ################################################################################
# Base de données # Base de données
class UNDEFINED(object):
__repr__ = __string__ = lambda self: 'UNDEFINED'
UNDEFINED = UNDEFINED()
class GenericObject(object): class GenericObject(object):
_id = None _id = None
_values = None _values = None
@ -19,7 +29,7 @@ class GenericObject(object):
def __init__(self, id): def __init__(self, id):
self._id = id self._id = id
self._values = [] self._values = set()
self._attrs = {} self._attrs = {}
def get_id(self): return self._id def get_id(self): return self._id
@ -28,7 +38,7 @@ class GenericObject(object):
def get_values(self): return self._values def get_values(self): return self._values
values = property(get_values) values = property(get_values)
def add_value(self, value): def add_value(self, value):
if value not in self._values: self._values.append(value) self._values.add(value)
def get_attrs(self): return self._attrs def get_attrs(self): return self._attrs
attrs = property(get_attrs) attrs = property(get_attrs)
@ -133,16 +143,16 @@ class WebappObject(GenericObject):
class GenericLink(object): class GenericLink(object):
_profile = None _profile = None
_ftype = None _ftype = None
_froms = None _fos = None
_ttype = None _ttype = None
_tos = None _tos = None
_attrs = None _attrs = None
def __init__(self, ftype, ttype): def __init__(self, ftype, ttype):
self._ftype = ftype self._ftype = ftype
self._froms = [] self._fos = set()
self._ttype = ttype self._ttype = ttype
self._tos = [] self._tos = set()
self._attrs = {} self._attrs = {}
def get_profile(self): return self._profile def get_profile(self): return self._profile
@ -151,17 +161,17 @@ class GenericLink(object):
def get_ftype(self): return self._ftype def get_ftype(self): return self._ftype
ftype = property(get_ftype) ftype = property(get_ftype)
def get_froms(self): return self._froms def get_fos(self): return self._fos
froms = property(get_froms) fos = property(get_fos)
def add_from(self, fo): def add_fo(self, fo):
if fo not in self._froms: self._froms.append(fo) self._fos.add(fo)
def get_ttype(self): return self._ttype def get_ttype(self): return self._ttype
ttype = property(get_ttype) ttype = property(get_ttype)
def get_tos(self): return self._tos def get_tos(self): return self._tos
tos = property(get_tos) tos = property(get_tos)
def add_to(self, to): def add_to(self, to):
if to not in self._tos: self._tos.append(to) self._tos.add(to)
def get_attrs(self): return self._attrs def get_attrs(self): return self._attrs
attrs = property(get_attrs) attrs = property(get_attrs)
@ -190,11 +200,28 @@ class GenericLink(object):
for value in values: for value in values:
self.modify_attr(name, value, method) self.modify_attr(name, value, method)
def match_fos(self, fos, match='any'):
if not isseq(fos): fos = [fos]
for fo in fos:
if fo in self._fos: return True
return False
def match_tos(self, tos, match='any'):
if not isseq(tos): tos = [tos]
for to in tos:
if to in self._tos: return True
return False
def match_attrs(self, attrs, match='any'):
for name, value in attrs.items():
values = self._attrs.get(name, None)
if values is not None:
if value in values: return True
return False
def _dump_profile(self, indent): def _dump_profile(self, indent):
profile = self.profile or 'ALL' profile = self.profile or 'ALL'
print "%s profile: %s" % (indent, profile) print "%s profile: %s" % (indent, profile)
def _dump_froms(self, indent): def _dump_fos(self, indent):
print "%s from: %s" % (indent, ' '.join(self.froms)) print "%s from: %s" % (indent, ' '.join(self.fos))
def _dump_tos(self, indent): def _dump_tos(self, indent):
print "%s to: %s" % (indent, ' '.join(self.tos)) print "%s to: %s" % (indent, ' '.join(self.tos))
def _dump_attrs(self, indent): def _dump_attrs(self, indent):
@ -208,7 +235,7 @@ class GenericLink(object):
def dump(self, indent=''): def dump(self, indent=''):
print "%slink" % indent print "%slink" % indent
self._dump_profile(indent) self._dump_profile(indent)
self._dump_froms(indent) self._dump_fos(indent)
self._dump_tos(indent) self._dump_tos(indent)
self._dump_attrs(indent) self._dump_attrs(indent)
@ -219,17 +246,17 @@ class UinstLink(GenericLink):
def dump(self, indent=''): def dump(self, indent=''):
print "%suinst" % indent print "%suinst" % indent
self._dump_profile(indent) self._dump_profile(indent)
self._dump_froms(indent) self._dump_fos(indent)
self._dump_tos(indent) self._dump_tos(indent)
self._dump_attrs(indent) self._dump_attrs(indent)
class RuinstLink(GenericLink): class RuinstLink(GenericLink):
def __init__(self): def __init__(self):
super(UinstLink, self).__init__('module', 'host') super(RuinstLink, self).__init__('module', 'host')
def dump(self, indent=''): def dump(self, indent=''):
print "%suinst" % indent print "%suinst" % indent
self._dump_froms(indent) self._dump_fos(indent)
self._dump_tos(indent) self._dump_tos(indent)
self._dump_attrs(indent) self._dump_attrs(indent)
@ -244,7 +271,6 @@ class Database(object):
_links_classes = None _links_classes = None
def __init__(self): def __init__(self):
self._known_profiles = {}
self._objects = {} self._objects = {}
self._objects_classes = {} self._objects_classes = {}
self._links = {} self._links = {}
@ -297,17 +323,45 @@ class Database(object):
self._objects[otype][id] = object self._objects[otype][id] = object
return object return object
def register_link(self, ltype, lclass=None): def register_link(self, ltype, lclass):
if not self._links.has_key(ltype): if not self._links.has_key(ltype):
self._links[ltype] = {} self._links[ltype] = {}
if lclass is None: lclass = GenericLink
self._links_classes[ltype] = lclass self._links_classes[ltype] = lclass
def get_known_profiles(self, ltype): def get_known_profiles(self, ltype):
return self._links[ltype].keys() return self._links[ltype].keys()
def get_links(self, ltype, profile=None): def get_links(self, ltype, profile, fo=UNDEFINED, to=UNDEFINED, attrs=UNDEFINED, create=False):
links = self._links.get(ltype, None) if fo is UNDEFINED and to is UNDEFINED and attrs is UNDEFINED:
if links is None: return None raise ValueError("you must set either fo, to ou attrs")
return links.get(profile, None) plinks = self._links.get(ltype, None)
if plinks is None: return None
links = plinks.get(profile, None)
if links is None: links = plinks[profile] = []
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 found is None: found = []
found.append(link)
if found is not None: return found
if not create: return None
link = self._links_classes[ltype]()
if fo is not UNDEFINED:
if isseq(fo): fos = fo
else: fos = [fo]
for fo in fos:
link.add_fo(fo)
if to is not UNDEFINED:
if isseq(to): tos = to
else: tos = [to]
for to in tos:
link.add_to(to)
if attrs is not UNDEFINED:
for name, value in attrs.items():
link.set_attr(name, value)
links.append(link)
return [link]
################################################################################ ################################################################################
# Analyse des fichiers de configuration # Analyse des fichiers de configuration
@ -536,13 +590,13 @@ class Parser(object):
############################################################################ ############################################################################
def reset_group(self, otype): def reset_group(self, otype):
self.groups[otype]['current'] = {} self.groups[otype]['current'] = set()
def reset_group_maybe(self, otype): def reset_group_maybe(self, otype):
if self.groups[otype]['type'] in ('defaults', 'once'): if self.groups[otype]['type'] in ('defaults', 'once'):
self.reset_group(otype) self.reset_group(otype)
self.groups[otype]['type'] = 'once' self.groups[otype]['type'] = 'once'
def add_group(self, otype, id): def add_group(self, otype, id):
self.groups[otype]['current'][id] = True self.groups[otype]['current'].add(id)
def handle_group(self, args): def handle_group(self, args):
"""group otype gtype """group otype gtype
@ -558,9 +612,9 @@ class Parser(object):
gtype = args[1:2] and args[1] or 'until' gtype = args[1:2] and args[1] or 'until'
self.groups[otype]['type'] = gtype self.groups[otype]['type'] = gtype
if gtype == 'defaults': if gtype == 'defaults':
self.groups[otype]['current'] = {None: True} self.groups[otype]['current'] = set([None])
elif gtype in ('once', 'until'): elif gtype in ('once', 'until'):
self.groups[otype]['current'] = {} self.groups[otype]['current'] = set()
else: else:
raise ValueError('%s: invalid group type' % gtype) raise ValueError('%s: invalid group type' % gtype)
self.attr_otype = otype self.attr_otype = otype
@ -757,32 +811,35 @@ class Parser(object):
profiles = o.profiles or [None] profiles = o.profiles or [None]
for profile in profiles: for profile in profiles:
# préparer la mise à jour du groupe courant # préparer la mise à jour du groupe courant
currentls = self.db.get_link(ltype, profile, fo=self.groups['module']['current'], create=True) currentls = self.db.get_links(ltype, profile, fo=self.groups['module']['current'], create=True)
if profile is not None: if profile is not None:
globall = self.db.get_link(ltype, None, fo=None, create=True) globalls = self.db.get_links(ltype, None, fo=None, create=True)
for currentl in currentls: for currentl in currentls:
for globall in globalls:
currentl.merge_attrs(globall) currentl.merge_attrs(globall)
defaultl = self.db.get_link(ltype, profile, fo=None, create=True) defaultls = self.db.get_links(ltype, profile, fo=None, create=True)
for currentl in currentls: for currentl in currentls:
for defaultl in defaultls:
currentl.merge_attrs(defaultl) currentl.merge_attrs(defaultl)
defaultl = defaultls[0]
# traiter les liens # traiter les liens
for nvs in nvss: for nvs in args:
name, value = split_namev(nvs) name, value, type, method = split_namev(nvs)
if name == defaultl.ttype: if name == defaultl.ttype:
# définir des destinations du lien # définir des destinations du lien
values = split_nlist(nvs)[1] if value is not None:
for host in values: tos = split_nlist(nvs)[1]
for to in tos:
for currentl in currentls: for currentl in currentls:
currentl.add_to(host) currentl.add_to(to)
else: else:
# définir un attribut du lien # définir un attribut du lien
name, value, type, method = split_namev(nv) #name, value, type, method = split_namev(nv)
if value is None: if value is None:
method = 'set' method = 'set'
value = '1' value = '1'
elif type == 'path': elif type == 'path':
value = path.expanduser(value) value = path.expanduser(value)
for id in self.groups[otype]['current']:
for currentl in currentls: for currentl in currentls:
currentl.modify_attr(name, value, method) currentl.modify_attr(name, value, method)