détacher la base de données du parser
This commit is contained in:
parent
5a3504e141
commit
ffe5f715c1
|
@ -9,6 +9,141 @@ from glob import glob
|
|||
USER_CONFDIR = '~/etc/deploy'
|
||||
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
|
||||
|
||||
_id = None
|
||||
_hosts = None
|
||||
_attrs = None
|
||||
|
||||
def __init__(self, id):
|
||||
self._id = id
|
||||
self._hosts = []
|
||||
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_attrs(self): return self._attrs
|
||||
attrs = property(get_attrs)
|
||||
|
||||
def get_attr(self, name): return self._attrs.get(name, None)
|
||||
def set_attr(self, name, value):
|
||||
if name not in self._attrs: self._attrs[name] = []
|
||||
if value not in self._attrs[name]: self._attrs[name].append(value)
|
||||
def reset_attr(self, name, value=None):
|
||||
if name in self._attrs: del self._attrs[name]
|
||||
if value is not None: self.set_attr(name, value)
|
||||
def add_attr(self, name, value):
|
||||
if name not in self._attrs: self._attrs[name] = []
|
||||
self._attrs[name].append(value)
|
||||
def del_attr(self, name, value):
|
||||
if name not in self._attrs: return
|
||||
self._attrs[name].remove(value)
|
||||
if not self._attrs[name]: del self._attrs[name]
|
||||
def modify_attr(self, name, value, method='set'):
|
||||
if method == 'set': self.set_attr(name, value)
|
||||
elif method == 'reset': self.reset_attr(name, value)
|
||||
elif method == 'add': self.add_attr(name, value)
|
||||
elif method == 'del': self.del_attr(name, value)
|
||||
def copy_attrs(self, other, method='set'):
|
||||
for name, values in other.attrs.items():
|
||||
for value in values:
|
||||
self.modify_attr(name, value, method)
|
||||
|
||||
def dump(self, indent=''):
|
||||
print "%s%s" % (indent, self.id)
|
||||
print "%s hosts: %s" % (indent, ' '.join(self.hosts))
|
||||
if self.attrs:
|
||||
print "%s attrs:" % indent
|
||||
for name, values in self.attrs.items():
|
||||
if len(values) == 1:
|
||||
print "%s %s=%s" % (indent, name, repr(values[0]))
|
||||
else:
|
||||
print "%s %s=(%s)" % (indent, name, ', '.join(map(repr, values)))
|
||||
|
||||
class Database(object):
|
||||
_known_profiles = None
|
||||
_default_profile = None
|
||||
_default_domain = None
|
||||
|
||||
_objects = None
|
||||
_objects_classes = None
|
||||
|
||||
def __init__(self):
|
||||
self._known_profiles = {}
|
||||
self._objects = {}
|
||||
self._objects_classes = {}
|
||||
|
||||
def get_known_profiles(self):
|
||||
return self.known_profiles.keys()
|
||||
known_profiles = property(get_known_profiles)
|
||||
|
||||
def has_default_profile(self):
|
||||
return self._default_profile is not None
|
||||
def get_default_profile(self):
|
||||
return self._default_profile
|
||||
def set_default_profile(self, profile):
|
||||
if profile: self._known_profiles[profile] = True
|
||||
self._default_profile = profile or None
|
||||
default_profile = property(get_default_profile, set_default_profile)
|
||||
|
||||
def has_default_domain(self):
|
||||
return self._default_domain is not None
|
||||
def get_default_domain(self):
|
||||
return self._default_domain
|
||||
def set_default_domain(self, domain):
|
||||
if domain is not None:
|
||||
#XXX si le domaine a été corrigé, l'indiquer en warning
|
||||
if domain.startswith('.'): domain = domain[1:]
|
||||
if domain.endswith('.'): domain = domain[:-1]
|
||||
self._default_domain = domain or None
|
||||
default_domain = property(get_default_domain, set_default_domain)
|
||||
|
||||
def register_object(self, otype, oclass):
|
||||
if not self._objects.has_key(otype):
|
||||
self._objects[otype] = {}
|
||||
self._objects_classes[otype] = oclass
|
||||
def get_objects(self, otype):
|
||||
objects = self._objects.get(otype, None)
|
||||
if objects is None: return None
|
||||
return [objects[id] for id in objects if id is not None]
|
||||
objects = property(get_objects)
|
||||
def has_object(self, otype, id):
|
||||
objects = self._objects.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)
|
||||
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
|
||||
return object
|
||||
|
||||
################################################################################
|
||||
# Analyse des fichiers de configuration
|
||||
|
||||
class EOL(object):
|
||||
__repr__ = __string__ = lambda self: 'EOL'
|
||||
EOL = EOL()
|
||||
|
@ -154,47 +289,6 @@ class Lexer(object):
|
|||
predicate.append(lexem)
|
||||
return predicates
|
||||
|
||||
class HostObject(object):
|
||||
id = None
|
||||
dir = None
|
||||
hosts = None
|
||||
attrs = None
|
||||
|
||||
def __init__(self, id):
|
||||
self.id = id
|
||||
self.hosts = []
|
||||
self.attrs = {}
|
||||
def get_id(self): return self.id
|
||||
def get_dir(self): return self.dir
|
||||
def set_dir(self, dir): self.dir = dir
|
||||
def get_hosts(self): return self.hosts
|
||||
def add_host(self, host):
|
||||
if host not in self.hosts: self.hosts.append(host)
|
||||
def get_attrs(self): return self.attrs
|
||||
def get_attr(self, name): return self.attrs.get(name, None)
|
||||
def set_attr(self, name, value):
|
||||
if name not in self.attrs: self.attrs[name] = []
|
||||
if value not in self.attrs[name]: self.attrs[name].append(value)
|
||||
def reset_attr(self, name, value=None):
|
||||
if name in self.attrs: del self.attrs[name]
|
||||
if value is not None: self.set_attr(name, value)
|
||||
def add_attr(self, name, value):
|
||||
if name not in self.attrs: self.attrs[name] = []
|
||||
self.attrs[name].append(value)
|
||||
def del_attr(self, name, value):
|
||||
if name not in self.attrs: return
|
||||
self.attrs[name].remove(value)
|
||||
if not self.attrs[name]: del self.attrs[name]
|
||||
def modify_attr(self, name, value, method='set'):
|
||||
if method == 'set': self.set_attr(name, value)
|
||||
elif method == 'reset': self.reset_attr(name, value)
|
||||
elif method == 'add': self.add_attr(name, value)
|
||||
elif method == 'del': self.del_attr(name, value)
|
||||
def copy_attrs(self, other, method='set'):
|
||||
for name, values in other.attrs.items():
|
||||
for value in values:
|
||||
self.modify_attr(name, value, method)
|
||||
|
||||
def split_scalar(arg):
|
||||
if '=' in arg:
|
||||
name, value = arg.split('=', 1)
|
||||
|
@ -224,27 +318,18 @@ def split_list(arg):
|
|||
return name, values
|
||||
|
||||
class Parser(object):
|
||||
lexer = None
|
||||
predicates = None
|
||||
|
||||
known_profiles = None
|
||||
default_profile = None
|
||||
default_domain = None
|
||||
|
||||
objects = None
|
||||
db = None
|
||||
groups = None
|
||||
attr_otype = None
|
||||
|
||||
def __init__(self, lexer, parse=True):
|
||||
self.lexer = lexer
|
||||
self.objects = {}
|
||||
def __init__(self, db=None):
|
||||
if db is None: db = Database()
|
||||
self.db = db
|
||||
self.groups = {}
|
||||
self.__setup_hosts()
|
||||
if parse: self.parse()
|
||||
|
||||
def parse(self):
|
||||
self.predicates = self.lexer.get_predicates()
|
||||
for p in self.predicates:
|
||||
def parse(self, predicates):
|
||||
for p in predicates:
|
||||
cmd = p[0]
|
||||
args = p[1:]
|
||||
if cmd == 'default_profile': self.handle_default_profile(args)
|
||||
|
@ -252,10 +337,7 @@ class Parser(object):
|
|||
elif cmd == 'group': self.handle_group(args)
|
||||
elif cmd == 'attr': self.handle_attr(args)
|
||||
elif cmd == 'host': self.handle_host(args)
|
||||
|
||||
def get_objects(self, otype):
|
||||
objects = self.objects[otype]
|
||||
return [objects[id] for id in objects if id is not None]
|
||||
return self
|
||||
|
||||
############################################################################
|
||||
def reset_group(self, otype):
|
||||
|
@ -297,54 +379,33 @@ class Parser(object):
|
|||
method = 'set'
|
||||
value = '1'
|
||||
for id in self.groups[otype]['current']:
|
||||
self.objects[otype][id].modify_attr(name, value, method)
|
||||
self.db.get_object(otype, id).modify_attr(name, value, method)
|
||||
|
||||
############################################################################
|
||||
def handle_default_profile(self, args):
|
||||
if not args or not args[0]:
|
||||
profile = None
|
||||
else:
|
||||
profile = args[0]
|
||||
if self.known_profiles is None: self.known_profiles = {}
|
||||
self.known_profiles[profile] = True
|
||||
self.default_profile = profile
|
||||
if not args or not args[0]: profile = None
|
||||
else: profile = args[0]
|
||||
self.db.default_profile = profile
|
||||
|
||||
############################################################################
|
||||
def handle_default_domain(self, args):
|
||||
if not args or not args[0]:
|
||||
domain = None
|
||||
else:
|
||||
domain = args[0]
|
||||
self.default_domain = domain
|
||||
if not args or not args[0]: domain = None
|
||||
else: domain = args[0]
|
||||
self.db.default_domain = domain
|
||||
|
||||
############################################################################
|
||||
def __setup_hosts(self):
|
||||
self.objects['host'] = {}
|
||||
self.__host_object(None)
|
||||
self.db.register_object('host', HostObject)
|
||||
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]
|
||||
elif '.' not in host and self.default_domain:
|
||||
host = '%s.%s' % (host, self.default_domain)
|
||||
elif '.' not in host and self.db.has_default_domain():
|
||||
host = '%s.%s' % (host, self.db.default_domain)
|
||||
return host
|
||||
def __hostid(self, host):
|
||||
host = re.sub(r'\..*', '', host)
|
||||
host = re.sub(r'[^a-zA-Z0-9]', '_', host)
|
||||
host = host.lower()
|
||||
return host
|
||||
def __hostib(self, id):
|
||||
if re.match(r'\d+$', id): return id
|
||||
ib = re.sub(r'^(.*?)\d+$', r'\1', id)
|
||||
return ib
|
||||
def __host_object(self, id):
|
||||
ho = self.objects['host'].get(id, None)
|
||||
if ho is None:
|
||||
ho = HostObject(id)
|
||||
self.objects['host'][id] = ho
|
||||
return ho
|
||||
|
||||
def handle_host(self, args):
|
||||
"""host [id=]host,...
|
||||
|
@ -370,7 +431,7 @@ class Parser(object):
|
|||
# préparer la mise à jour du groupe courant
|
||||
self.reset_group_maybe('host')
|
||||
self.attr_otype = 'host'
|
||||
default_ho = self.__host_object(None)
|
||||
default_ho = self.db.get_object('host', None)
|
||||
# traiter les hôtes
|
||||
for nvs in nvss:
|
||||
name, values = split_list(nvs)
|
||||
|
@ -381,20 +442,21 @@ class Parser(object):
|
|||
dir, host = path.split(path.abspath(path.expanduser(host)))
|
||||
host = self.__fix_host(host)
|
||||
if name:
|
||||
ho = self.__host_object(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)
|
||||
self.add_group('host', name)
|
||||
else:
|
||||
id = self.__hostid(host)
|
||||
ho = self.__host_object(id)
|
||||
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)
|
||||
self.add_group('host', id)
|
||||
ib = self.__hostib(id)
|
||||
ho = self.__host_object(ib)
|
||||
|
||||
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)
|
||||
|
@ -415,24 +477,21 @@ def run_qdd(o):
|
|||
if path.exists(user_conf): conf = user_conf
|
||||
elif path.exists(system_conf): conf = system_conf
|
||||
lexer = Lexer(conf)
|
||||
db = Database()
|
||||
|
||||
if o.action == 'nop':
|
||||
pass
|
||||
elif o.action == 'dump': #XXX
|
||||
parser = Parser(lexer)
|
||||
predicates = lexer.get_predicates()
|
||||
parser = Parser(db).parse(predicates)
|
||||
print "=== predicates"
|
||||
for p in parser.predicates:
|
||||
for p in predicates:
|
||||
print ' '.join(map(repr, p))
|
||||
print "=== hosts"
|
||||
for ho in parser.get_objects('host'):
|
||||
id, dir, hosts = ho.get_id(), ho.get_dir(), ho.get_hosts()
|
||||
attrs = ho.get_attrs()
|
||||
print id
|
||||
if dir: print " dir=%s" % dir
|
||||
print " hosts=%r" % hosts
|
||||
if attrs: print " attrs=%r" % attrs
|
||||
for ho in db.get_objects('host'):
|
||||
ho.dump()
|
||||
elif o.action == 'query':
|
||||
parser = Parser(lexer)
|
||||
parser = Parser(db).parse(lexer.get_predicates())
|
||||
|
||||
if __name__ == '__main__':
|
||||
from argparse import ArgumentParser, HelpFormatter
|
||||
|
|
Loading…
Reference in New Issue