implémenter la gestion des objets modules, wobundle, webapp

This commit is contained in:
Jephté Clain 2017-06-15 23:20:38 +04:00
parent ffe5f715c1
commit 02c5f91b78
1 changed files with 387 additions and 49 deletions

View File

@ -12,34 +12,23 @@ SYSTEM_CONFDIR = '/var/local/deploy'
################################################################################
# Base de données
class HostObject(object):
@staticmethod
def genid(host):
host = re.sub(r'\..*', '', host)
host = re.sub(r'[^a-zA-Z0-9]', '_', host)
host = host.lower()
return host
@staticmethod
def genib(id):
if re.match(r'\d+$', id): return id
ib = re.sub(r'^(.*?)\d+$', r'\1', id)
return ib
class GenericObject(object):
_id = None
_hosts = None
_values = None
_attrs = None
def __init__(self, id):
self._id = id
self._hosts = []
self._values = []
self._attrs = {}
def get_id(self): return self._id
id = property(get_id)
def get_hosts(self): return self._hosts
hosts = property(get_hosts)
def add_host(self, host):
if host not in self._hosts: self._hosts.append(host)
def get_values(self): return self._values
values = property(get_values)
def add_value(self, value):
if value not in self._values: self._values.append(value)
def get_attrs(self): return self._attrs
attrs = property(get_attrs)
@ -68,9 +57,11 @@ class HostObject(object):
for value in values:
self.modify_attr(name, value, method)
def dump(self, indent=''):
def _dump_id(self, indent):
print "%s%s" % (indent, self.id)
print "%s hosts: %s" % (indent, ' '.join(self.hosts))
def _dump_values(self, indent, name):
print "%s %s: %s" % (indent, name, ' '.join(self.values))
def _dump_attrs(self, indent):
if self.attrs:
print "%s attrs:" % indent
for name, values in self.attrs.items():
@ -78,6 +69,66 @@ class HostObject(object):
print "%s %s=%s" % (indent, name, repr(values[0]))
else:
print "%s %s=(%s)" % (indent, name, ', '.join(map(repr, values)))
def dump(self, indent=''):
self._dump_id(indent)
self._dump_attrs(indent)
class HostObject(GenericObject):
@staticmethod
def genid(host):
"MY-Host42.self --> my_host42"
host = re.sub(r'\..*', '', host)
host = re.sub(r'[^a-zA-Z0-9]', '_', host)
host = host.lower()
return host
@staticmethod
def genib(id):
"my_host42 --> my_host"
if re.match(r'\d+$', id): return id
ib = re.sub(r'^(.*?)\d+$', r'\1', id)
return ib
def dump(self, indent=''):
self._dump_id(indent)
self._dump_values(indent, 'hosts')
self._dump_attrs(indent)
class ModuleObject(GenericObject):
@staticmethod
def genid(module):
"MY-Module --> MY_Module"
module = re.sub(r'[^a-zA-Z0-9]', '_', module)
return module
def dump(self, indent=''):
self._dump_id(indent)
self._dump_values(indent, 'modules')
self._dump_attrs(indent)
class WobundleObject(GenericObject):
@staticmethod
def genid(wobundle):
"MY-App.woa --> MY_App"
wobundle = re.sub(r'\.(woa|framework)$', '', wobundle)
wobundle = re.sub(r'[^a-zA-Z0-9]', '_', wobundle)
return wobundle
def dump(self, indent=''):
self._dump_id(indent)
self._dump_values(indent, 'wobundles')
self._dump_attrs(indent)
class WebappObject(GenericObject):
@staticmethod
def genid(webapp):
"MY-Webapp --> MY_Webapp"
webapp = re.sub(r'[^a-zA-Z0-9]', '_', webapp)
return webapp
def dump(self, indent=''):
self._dump_id(indent)
self._dump_values(indent, 'webapps')
self._dump_attrs(indent)
class Database(object):
_known_profiles = None
@ -93,7 +144,7 @@ class Database(object):
self._objects_classes = {}
def get_known_profiles(self):
return self.known_profiles.keys()
return self._known_profiles.keys()
known_profiles = property(get_known_profiles)
def has_default_profile(self):
@ -117,10 +168,14 @@ class Database(object):
self._default_domain = domain or None
default_domain = property(get_default_domain, set_default_domain)
def register_object(self, otype, oclass):
def register_object(self, otype, oclass=None):
if not self._objects.has_key(otype):
self._objects[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_objects(self, otype):
objects = self._objects.get(otype, None)
if objects is None: return None
@ -289,7 +344,9 @@ class Lexer(object):
predicate.append(lexem)
return predicates
def split_scalar(arg):
RE_NAMETYPE = re.compile(r'(\S+):(\w+)$')
def split_namev(arg):
"spliter name[:type][method][=value]"
if '=' in arg:
name, value = arg.split('=', 1)
else:
@ -306,9 +363,24 @@ def split_scalar(arg):
method = 'del'
else:
method = 'set'
return name, method, value
mo = RE_NAMETYPE.match(name)
if mo is not None:
name, type = mo.groups()
else:
type = None
return name, value, type, method
def split_list(arg):
def split_nvalue(arg):
"spliter [name=]value"
if '=' in arg:
name, value = arg.split('=', 1)
else:
name = None
value = arg
return name, value
def split_nlist(arg):
"spliter [name=]values"
if '=' in arg:
name, values = arg.split('=', 1)
values = values.split(',')
@ -322,11 +394,17 @@ class Parser(object):
groups = None
attr_otype = None
commands = None
def __init__(self, db=None):
if db is None: db = Database()
self.db = db
self.groups = {}
self.commands = {}
self.__setup_hosts()
self.__setup_uinst()
self.__setup_woinst()
self.__setup_toinst()
def parse(self, predicates):
for p in predicates:
@ -337,8 +415,12 @@ class Parser(object):
elif cmd == 'group': self.handle_group(args)
elif cmd == 'attr': self.handle_attr(args)
elif cmd == 'host': self.handle_host(args)
elif cmd in self.commands: self.commands[cmd](*p)
return self
def register_command(self, name, method):
self.commands[name] = method
############################################################################
def reset_group(self, otype):
self.groups[otype]['current'] = {}
@ -368,16 +450,19 @@ class Parser(object):
self.groups[otype]['current'] = {}
else:
raise ValueError('%s: invalid group type' % gtype)
self.attr_otype = otype
############################################################################
def handle_attr(self, args):
otype = self.attr_otype
assert otype is not None, "attr_otype should not be None"
for nv in args:
name, method, value = split_scalar(nv)
name, value, type, method = split_namev(nv)
if value is None:
method = 'set'
value = '1'
elif type == 'path':
value = path.expanduser(value)
for id in self.groups[otype]['current']:
self.db.get_object(otype, id).modify_attr(name, value, method)
@ -399,7 +484,6 @@ class Parser(object):
self.db.get_object('host', None)
self.groups['host'] = {}
self.handle_group(['host', 'defaults'])
self.attr_otype = 'host'
def __fix_host(self, host):
if host.endswith('.'):
host = host[:-1]
@ -409,6 +493,8 @@ class Parser(object):
def handle_host(self, args):
"""host [id=]host,...
host -b [id=]basedir
host -d [id=]dirspec
"""
AP = ArgumentParser()
AP.add_argument('-b', '--basedir', action='append', dest='basedirs')
@ -418,23 +504,31 @@ class Parser(object):
# construire la liste des hôtes à traiter
nvss = []
if o.basedirs is not None:
for basedir in [path.expanduser(basedir) for basedir in o.basedirs]:
nvss.extend([path.abspath(path.join(basedir, name))
for pb in o.basedirs:
p, b = split_nvalue(pb)
if p is None: prefix = ''
else: prefix = p + '='
basedir = path.expanduser(b)
nvss.extend([prefix + path.abspath(path.join(basedir, name))
for name in os.listdir(basedir)
if path.isdir(path.join(basedir, name))])
if o.dirspecs is not None:
for dirspec in [path.expanduser(dirspec) for dirspec in o.dirspecs]:
nvss.extend([path.abspath(dir)
for pd in o.dirspecs:
p, d = split_nvalue(pd)
if p is None: prefix = ''
else: prefix = p + '='
dirspec = path.expanduser(d)
nvss.extend([prefix + path.abspath(dir)
for dir in glob(dirspec)
if path.isdir(dir)])
nvss.extend(o.nvss)
# préparer la mise à jour du groupe courant
self.reset_group_maybe('host')
self.attr_otype = 'host'
default_ho = self.db.get_object('host', None)
defaulto = self.db.get_object('host', None)
# traiter les hôtes
for nvs in nvss:
name, values = split_list(nvs)
name, values = split_nlist(nvs)
for host in values:
dir = None
if host:
@ -442,26 +536,263 @@ class Parser(object):
dir, host = path.split(path.abspath(path.expanduser(host)))
host = self.__fix_host(host)
if name:
ho = self.db.get_object('host', name)
if host: ho.add_host(host)
ho.copy_attrs(default_ho)
if dir is not None: ho.reset_attr('dir', dir)
o = self.db.get_object('host', name)
if host: o.add_value(host)
o.copy_attrs(defaulto)
if dir is not None: o.set_attr('dir', dir)
self.add_group('host', name)
else:
id = HostObject.genid(host)
ho = self.db.get_object('host', id)
ho.add_host(host)
ho.copy_attrs(default_ho)
if dir is not None: ho.reset_attr('dir', dir)
o = self.db.get_object('host', id)
o.add_value(host)
o.copy_attrs(defaulto)
if dir is not None: o.set_attr('dir', dir)
self.add_group('host', id)
ib = HostObject.genib(id)
ho = self.db.get_object('host', ib)
ho.add_host(host)
ho.copy_attrs(default_ho)
if dir is not None: ho.reset_attr('dir', dir)
o = self.db.get_object('host', ib)
o.add_value(host)
o.copy_attrs(defaulto)
if dir is not None: o.set_attr('dir', dir)
self.add_group('host', ib)
############################################################################
def __setup_uinst(self):
self.db.register_object('module', ModuleObject)
self.db.get_object('module', None)
self.groups['module'] = {}
self.handle_group(['module', 'defaults'])
self.register_command('module', self.handle_module)
self.register_command('uinst', self.handle_xuinst)
self.register_command('ruinst', self.handle_xuinst)
def __fix_module(self, module):
return module
def handle_module(self, cmd, *args):
"""module [id=]path/to/module
module -b [id=]basedir
module -d [id=]dirspec
"""
AP = ArgumentParser()
AP.add_argument('-b', '--basedir', action='append', dest='basedirs')
AP.add_argument('-d', '--dirspec', action='append', dest='dirspecs')
AP.add_argument('nvss', nargs=REMAINDER)
o = AP.parse_args(args)
# construire la liste des modules à traiter
nvss = []
if o.basedirs is not None:
for pb in o.basedirs:
p, b = split_nvalue(pb)
if p is None: prefix = ''
else: prefix = p + '='
basedir = path.expanduser(b)
nvss.extend([prefix + path.abspath(path.join(basedir, name))
for name in os.listdir(basedir)
if path.isdir(path.join(basedir, name))])
if o.dirspecs is not None:
for pd in o.dirspecs:
p, d = split_nvalue(pd)
if p is None: prefix = ''
else: prefix = p + '='
dirspec = path.expanduser(d)
nvss.extend([prefix + path.abspath(dir)
for dir in glob(dirspec)
if path.isdir(dir)])
nvss.extend(o.nvss)
# préparer la mise à jour du groupe courant
self.reset_group_maybe('module')
self.attr_otype = 'module'
defaulto = self.db.get_object('module', None)
# traiter les modules
for nvs in nvss:
name, values = split_nlist(nvs)
for module in values:
dir = None
modulep = None
if module:
if '/' in module:
dir, module = path.split(path.abspath(path.expanduser(module)))
module = self.__fix_module(module)
if dir is not None:
modulep = path.join(dir, module)
if name:
o = self.db.get_object('module', name)
if module: o.add_value(module)
o.copy_attrs(defaulto)
if dir is not None: o.set_attr('dir', dir)
if modulep is not None: o.set_attr('path', modulep)
self.add_group('module', name)
else:
id = ModuleObject.genid(module)
o = self.db.get_object('module', id)
if module: o.add_value(module)
o.copy_attrs(defaulto)
if dir is not None: o.set_attr('dir', dir)
if modulep is not None: o.set_attr('path', modulep)
self.add_group('module', id)
def handle_xuinst(self, cmd, *args):
pass
############################################################################
def __setup_woinst(self):
self.db.register_object('wobundle', WobundleObject)
self.db.get_object('wobundle', None)
self.groups['wobundle'] = {}
self.handle_group(['wobundle', 'defaults'])
self.register_command('wobundle', self.handle_wobundle)
self.register_command('rwoinst', self.handle_rwoinst)
def __fix_wobundle(self, wobundle):
if path.splitext(wobundle)[1] not in ('.woa', '.framework'):
wobundle = wobundle + '.woa'
return wobundle
def handle_wobundle(self, cmd, *args):
"""wobundle [id=]path/to/wobundle
wobundle -b [id=]basedir
wobundle -d [id=]dirspec
"""
AP = ArgumentParser()
AP.add_argument('-b', '--basedir', action='append', dest='basedirs')
AP.add_argument('-d', '--dirspec', action='append', dest='dirspecs')
AP.add_argument('nvss', nargs=REMAINDER)
o = AP.parse_args(args)
# construire la liste des wobundles à traiter
nvss = []
if o.basedirs is not None:
for pb in o.basedirs:
p, b = split_nvalue(pb)
if p is None: prefix = ''
else: prefix = p + '='
basedir = path.expanduser(b)
nvss.extend([prefix + path.abspath(path.join(basedir, name))
for name in os.listdir(basedir)
if path.isdir(path.join(basedir, name)) and path.splitext(name)[1] in ('.woa', '.framework')])
if o.dirspecs is not None:
for pd in o.dirspecs:
p, d = split_nvalue(pd)
if p is None: prefix = ''
else: prefix = p + '='
dirspec = path.expanduser(d)
nvss.extend([prefix + path.abspath(dir)
for dir in glob(dirspec)
if path.isdir(dir) and path.splitext(dir)[1] in ('.woa', '.framework')])
nvss.extend(o.nvss)
# préparer la mise à jour du groupe courant
self.reset_group_maybe('wobundle')
self.attr_otype = 'wobundle'
defaulto = self.db.get_object('wobundle', None)
# traiter les wobundles
for nvs in nvss:
name, values = split_nlist(nvs)
for wobundle in values:
dir = None
wobundlep = None
if wobundle:
if '/' in wobundle:
dir, wobundle = path.split(path.abspath(path.expanduser(wobundle)))
wobundle = self.__fix_wobundle(wobundle)
if dir is not None:
wobundlep = path.join(dir, wobundle)
if name:
o = self.db.get_object('wobundle', name)
if wobundle: o.add_value(wobundle)
o.copy_attrs(defaulto)
if dir is not None: o.set_attr('dir', dir)
if wobundlep is not None: o.set_attr('path', wobundlep)
self.add_group('wobundle', name)
else:
id = WobundleObject.genid(wobundle)
o = self.db.get_object('wobundle', id)
if wobundle: o.add_value(wobundle)
o.copy_attrs(defaulto)
if dir is not None: o.set_attr('dir', dir)
if wobundlep is not None: o.set_attr('path', wobundlep)
self.add_group('wobundle', id)
def handle_rwoinst(self, cmd, *args):
pass
############################################################################
def __setup_toinst(self):
self.db.register_object('webapp', WebappObject)
self.db.get_object('webapp', None)
self.groups['webapp'] = {}
self.handle_group(['webapp', 'defaults'])
self.register_command('webapp', self.handle_webapp)
self.register_command('rtoinst', self.handle_rtoinst)
def __fix_webapp(self, webapp):
return webapp
def handle_webapp(self, cmd, *args):
"""webapp [id=]path/to/webapp
webapp -b [id=]basedir
webapp -d [id=]dirspec
"""
AP = ArgumentParser()
AP.add_argument('-b', '--basedir', action='append', dest='basedirs')
AP.add_argument('-d', '--dirspec', action='append', dest='dirspecs')
AP.add_argument('nvss', nargs=REMAINDER)
o = AP.parse_args(args)
# construire la liste des webapps à traiter
nvss = []
if o.basedirs is not None:
for pb in o.basedirs:
p, b = split_nvalue(pb)
if p is None: prefix = ''
else: prefix = p + '='
basedir = path.expanduser(b)
nvss.extend([prefix + path.abspath(path.join(basedir, name))
for name in os.listdir(basedir)
if path.isdir(path.join(basedir, name))])
if o.dirspecs is not None:
for pd in o.dirspecs:
p, d = split_nvalue(pd)
if p is None: prefix = ''
else: prefix = p + '='
dirspec = path.expanduser(d)
nvss.extend([prefix + path.abspath(dir)
for dir in glob(dirspec)
if path.isdir(dir)])
nvss.extend(o.nvss)
# préparer la mise à jour du groupe courant
self.reset_group_maybe('webapp')
self.attr_otype = 'webapp'
defaulto = self.db.get_object('webapp', None)
# traiter les webapps
for nvs in nvss:
name, values = split_nlist(nvs)
for webapp in values:
dir = None
webappp = None
if webapp:
if '/' in webapp:
dir, webapp = path.split(path.abspath(path.expanduser(webapp)))
webapp = self.__fix_webapp(webapp)
if dir is not None:
webappp = path.join(dir, webapp)
if name:
o = self.db.get_object('webapp', name)
if webapp: o.add_value(webapp)
o.copy_attrs(defaulto)
if dir is not None: o.set_attr('dir', dir)
if webappp is not None: o.set_attr('path', webappp)
self.add_group('webapp', name)
else:
id = WebappObject.genid(webapp)
o = self.db.get_object('webapp', id)
if webapp: o.add_value(webapp)
o.copy_attrs(defaulto)
if dir is not None: o.set_attr('dir', dir)
if webappp is not None: o.set_attr('path', webappp)
self.add_group('webapp', id)
def handle_rtoinst(self, cmd, *args):
pass
################################################################################
# Programme principal
def run_qdd(o):
# fichier de configuration
confname = o.confname or 'deploy'
@ -487,9 +818,16 @@ def run_qdd(o):
print "=== predicates"
for p in predicates:
print ' '.join(map(repr, p))
print "=== hosts"
for ho in db.get_objects('host'):
ho.dump()
otypes = db.known_objects
otypes.remove('host')
otypes.insert(0, 'host')
for otype in otypes:
objects = db.get_objects(otype)
if objects:
print "=== %s" % otype
for o in objects:
o.dump()
elif o.action == 'query':
parser = Parser(db).parse(lexer.get_predicates())