un peu de nettoyage
This commit is contained in:
parent
5e0924aeb5
commit
be0ec1c3ab
39
TODO.md
39
TODO.md
|
@ -1,3 +1,42 @@
|
|||
# TODO
|
||||
|
||||
* 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à)
|
||||
|
||||
* mettre à jour l'algorithme pour la prise en compte du type de groupe.
|
||||
peut-être garder en mémoire la dernière commande ou le dernier type de
|
||||
commande.
|
||||
|
||||
* il faut distinguer: définitions par défaut globales, définitions par défaut
|
||||
pour le groupe, définition locale
|
||||
~~~
|
||||
host dh=dest-host.univ.run
|
||||
|
||||
group module defaults
|
||||
attr odef=value
|
||||
ruinst ldef=value
|
||||
ruinst -p PROFILE pldef=value
|
||||
|
||||
# group #1
|
||||
group module once
|
||||
module MyModule
|
||||
attr ovar=value
|
||||
ruinst ldef2=value
|
||||
ruinst -p PROFILE pldef2=value
|
||||
ruinst host=dh lvar=value
|
||||
|
||||
# group #2
|
||||
module OtherModule
|
||||
ruinst host=dh
|
||||
~~~
|
||||
dans l'exemple ci-dessus:
|
||||
* odef est un attribut global à tous les modules
|
||||
* ovar est spécifique à MyModule
|
||||
* ldef est un attribut global à tous les liens
|
||||
* pldef est un attribut global à tous les liens dans le profil PROFILE
|
||||
* ldef2 est attribut global à tous les liens du groupe #1
|
||||
* pldef2 est un attribut global à tous les liens du groupe #1 dans le profil PROFILE
|
||||
* lvar est spécifique au lien MyModule --> dh
|
||||
|
||||
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary
|
|
@ -9,20 +9,44 @@ 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
|
||||
|
||||
def isseq(t):
|
||||
return isinstance(t, list) or isinstance(t, tuple) or isinstance(t, set)
|
||||
|
||||
def flatten(src, unique=True, clean=True, sep=','):
|
||||
"""découper chaque élément du tableau src selon sep et les aplatir dans une
|
||||
seule liste.
|
||||
|
||||
Si unique==True, supprimer les doublons.
|
||||
Si clean==True, supprimer les valeurs vides et les espaces périphériques
|
||||
|
||||
e.g flatten(['a , b', 'c,']) --> ['a', 'b', 'c']
|
||||
|
||||
"""
|
||||
if not isseq(src): src = [src]
|
||||
dest = []
|
||||
for items in src:
|
||||
items = items.split(sep)
|
||||
if clean: items = filter(None, map(lambda item: item.strip(), items))
|
||||
if unique:
|
||||
for item in items:
|
||||
if item not in dest: dest.append(item)
|
||||
else:
|
||||
dest.extend(items)
|
||||
return dest
|
||||
|
||||
################################################################################
|
||||
# Base de données
|
||||
|
||||
class GenericObject(object):
|
||||
"""Un objet générique
|
||||
|
||||
Un objet a un identifiant (propriété id), une liste de valeurs (propriété
|
||||
values) et des attributs (propriété attrs)
|
||||
"""
|
||||
|
||||
_id = None
|
||||
_values = None
|
||||
_attrs = None
|
||||
|
@ -43,26 +67,45 @@ class GenericObject(object):
|
|||
def get_attrs(self): return self._attrs
|
||||
attrs = property(get_attrs)
|
||||
|
||||
def get_attr(self, name): return self._attrs.get(name, None)
|
||||
def get_attr(self, name):
|
||||
"""Obtenir la valeur d'un attribut ou None si l'attribut n'existe pas
|
||||
"""
|
||||
return self._attrs.get(name, None)
|
||||
def set_attr(self, name, value):
|
||||
"""Ajouter une valeur à la liste des valeurs d'un attribut si elle n'y est pas
|
||||
déjà.
|
||||
"""
|
||||
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):
|
||||
"""Recommencer à zéro la valeur d'un attribut
|
||||
"""
|
||||
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):
|
||||
"""Ajouter une valeur à la liste des valeurs d'un attribut
|
||||
"""
|
||||
if name not in self._attrs: self._attrs[name] = []
|
||||
self._attrs[name].append(value)
|
||||
def del_attr(self, name, value):
|
||||
"""Supprimer une valeur d'un attribut
|
||||
"""
|
||||
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'):
|
||||
"""Méthode générique pour modifier les valeurs d'un attribut
|
||||
|
||||
method peut valoir set, reset, add, del
|
||||
"""
|
||||
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 merge_attrs(self, other, method='set'):
|
||||
"""Fusionner dans cet objet les attributs d'un autre objet, avec la méthode
|
||||
spécifiée.
|
||||
"""
|
||||
for name, values in other.attrs.items():
|
||||
for value in values:
|
||||
self.modify_attr(name, value, method)
|
||||
|
@ -80,20 +123,30 @@ class GenericObject(object):
|
|||
else:
|
||||
print "%s %s=(%s)" % (indent, name, ', '.join(map(repr, values)))
|
||||
def dump(self, indent=''):
|
||||
"""Afficher l'identifiant, les valeurs et les attributs de cet objet
|
||||
"""
|
||||
self._dump_id(indent)
|
||||
self._dump_values(indent, 'values')
|
||||
self._dump_attrs(indent)
|
||||
|
||||
class HostObject(GenericObject):
|
||||
"""Un hôte
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def genid(host):
|
||||
"MY-Host42.self --> my_host42"
|
||||
"""Générer un identifiant à partir du nom d'hôte
|
||||
e.g. MY-Host42.tld --> 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"
|
||||
"""Générer un identifiant générique à partir d'un identifiant qualifié
|
||||
e.g. my_host42 --> my_host
|
||||
"""
|
||||
if re.match(r'\d+$', id): return id
|
||||
ib = re.sub(r'^(.*?)\d+$', r'\1', id)
|
||||
return ib
|
||||
|
@ -104,9 +157,14 @@ class HostObject(GenericObject):
|
|||
self._dump_attrs(indent)
|
||||
|
||||
class ModuleObject(GenericObject):
|
||||
"""Un module, uinst-allable
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def genid(module):
|
||||
"MY-Module --> MY_Module"
|
||||
"""Générér un identifiant à partir du nom du module
|
||||
e.g. MY-Module --> MY_Module
|
||||
"""
|
||||
module = re.sub(r'[^a-zA-Z0-9]', '_', module)
|
||||
return module
|
||||
|
||||
|
@ -116,9 +174,14 @@ class ModuleObject(GenericObject):
|
|||
self._dump_attrs(indent)
|
||||
|
||||
class WobundleObject(GenericObject):
|
||||
"""Un bundle Webobjects, woinst-allable
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def genid(wobundle):
|
||||
"MY-App.woa --> MY_App"
|
||||
"""Générér un identifiant à partir du nom du bundle
|
||||
e.g. MY-App.woa --> MY_App
|
||||
"""
|
||||
wobundle = re.sub(r'\.(woa|framework)$', '', wobundle)
|
||||
wobundle = re.sub(r'[^a-zA-Z0-9]', '_', wobundle)
|
||||
return wobundle
|
||||
|
@ -129,9 +192,14 @@ class WobundleObject(GenericObject):
|
|||
self._dump_attrs(indent)
|
||||
|
||||
class WebappObject(GenericObject):
|
||||
"""Une webapp, toinst-allable
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def genid(webapp):
|
||||
"MY-Webapp --> MY_Webapp"
|
||||
"""Générér un identifiant à partir du nom de la webapp
|
||||
e.g. MY-Webapp --> MY_Webapp
|
||||
"""
|
||||
webapp = re.sub(r'[^a-zA-Z0-9]', '_', webapp)
|
||||
return webapp
|
||||
|
||||
|
@ -141,6 +209,14 @@ class WebappObject(GenericObject):
|
|||
self._dump_attrs(indent)
|
||||
|
||||
class GenericLink(object):
|
||||
"""Un lien générique
|
||||
|
||||
Un lien est valide dans un profil (propriété profile), a un type d'objets de
|
||||
départ (propriété ftype), un type d'objet d'arrivée (propriété ttype), un
|
||||
ensemble d'objets de départ (propriété fos), un ensemble d'objets d'arrivée
|
||||
(propriété tos), et des attributs (propriété attrs).
|
||||
"""
|
||||
|
||||
_profile = None
|
||||
_ftype = None
|
||||
_fos = None
|
||||
|
@ -156,6 +232,9 @@ class GenericLink(object):
|
|||
self._attrs = {}
|
||||
|
||||
def is_defaults(self):
|
||||
"""Cet objet contient-il les attributs par défaut pour les liens provenant du
|
||||
type d'objet ftype
|
||||
"""
|
||||
fos = list(self._fos)
|
||||
return len(fos) == 1 and fos[0] is None
|
||||
|
||||
|
@ -180,46 +259,89 @@ class GenericLink(object):
|
|||
def get_attrs(self): return self._attrs
|
||||
attrs = property(get_attrs)
|
||||
|
||||
def get_attr(self, name): return self._attrs.get(name, None)
|
||||
def get_attr(self, name):
|
||||
"""Obtenir la valeur d'un attribut ou None si l'attribut n'existe pas
|
||||
"""
|
||||
return self._attrs.get(name, None)
|
||||
def set_attr(self, name, value):
|
||||
"""Ajouter une valeur à la liste des valeurs d'un attribut si elle n'y est pas
|
||||
déjà.
|
||||
"""
|
||||
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):
|
||||
"""Recommencer à zéro la valeur d'un attribut
|
||||
"""
|
||||
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):
|
||||
"""Ajouter une valeur à la liste des valeurs d'un attribut
|
||||
"""
|
||||
if name not in self._attrs: self._attrs[name] = []
|
||||
self._attrs[name].append(value)
|
||||
def del_attr(self, name, value):
|
||||
"""Supprimer une valeur d'un attribut
|
||||
"""
|
||||
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'):
|
||||
"""Méthode générique pour modifier les valeurs d'un attribut
|
||||
|
||||
method peut valoir set, reset, add, del
|
||||
"""
|
||||
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 merge_attrs(self, other, method='set'):
|
||||
"""Fusionner dans ce lien les attributs d'un autre lien, avec la méthode
|
||||
spécifiée.
|
||||
"""
|
||||
for name, values in other.attrs.items():
|
||||
for value in values:
|
||||
self.modify_attr(name, value, method)
|
||||
|
||||
def match_profiles(self, profiles):
|
||||
"""Tester si ce lien est dans l'un des profils spécifiés
|
||||
|
||||
Si profiles == None, alors l'utilisateur ne demande aucun profil en
|
||||
particulier. Dans ce cas, la réponse est OUI.
|
||||
|
||||
Si profiles == [], alors l'utilisateur demande tous les liens pour
|
||||
lesquels aucun profil n'est défini. Dans ce cas, la réponse est OUI si
|
||||
ce lien ne définit aucun profil.
|
||||
|
||||
Sinon, profiles est une liste des profils recherchés. Dans ce cas, la
|
||||
réponse n'est OUI que si le profil de ce lien fait partie des profils
|
||||
spécifiés.
|
||||
"""
|
||||
if profiles is None: return True
|
||||
if not isseq(profiles): profiles = [profiles]
|
||||
if profiles == []: return self._profile is None
|
||||
for profile in profiles:
|
||||
if profile == self._profile: return True
|
||||
return False
|
||||
def match_fos(self, fos, match='any'):
|
||||
"""Tester si ce lien a l'un des objets spécifiés dans ses objets de départ (avec
|
||||
match=='any' qui est la valeur par défaut)
|
||||
"""
|
||||
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'):
|
||||
"""Tester si ce lien a l'un des objets spécifiés dans ses objets d'arrivée (avec
|
||||
match=='any' qui est la valeur par défaut)
|
||||
"""
|
||||
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'):
|
||||
"""Tester si ce lien a un des attributs correspondant aux valeurs spécifiées
|
||||
(avec match=='any' qui est la valeur par défaut)
|
||||
"""
|
||||
for name, value in attrs.items():
|
||||
values = self._attrs.get(name, None)
|
||||
if values is not None:
|
||||
|
@ -243,6 +365,9 @@ class GenericLink(object):
|
|||
else:
|
||||
print "%s %s=(%s)" % (indent, name, ', '.join(map(repr, values)))
|
||||
def dump(self, indent=''):
|
||||
"""Afficher le profil, les objets de départ, les objets d'arrivée, et les
|
||||
attributs de ce lien
|
||||
"""
|
||||
print "%slink" % indent
|
||||
self._dump_profile(indent)
|
||||
self._dump_fos(indent)
|
||||
|
@ -250,6 +375,9 @@ class GenericLink(object):
|
|||
self._dump_attrs(indent)
|
||||
|
||||
class UinstLink(GenericLink):
|
||||
"""Un module déployé sur un hôte avec le type uinst:rsync
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(UinstLink, self).__init__('module', 'host')
|
||||
|
||||
|
@ -261,6 +389,9 @@ class UinstLink(GenericLink):
|
|||
self._dump_attrs(indent)
|
||||
|
||||
class RuinstLink(GenericLink):
|
||||
"""Un module déployé sur un hôte avec ruinst
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(RuinstLink, self).__init__('module', 'host')
|
||||
|
||||
|
@ -272,6 +403,9 @@ class RuinstLink(GenericLink):
|
|||
self._dump_attrs(indent)
|
||||
|
||||
class RwoinstBundleLink(GenericLink):
|
||||
"""Un bundle déployé sur un hôte avec rwoinst
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(RwoinstBundleLink, self).__init__('wobundle', 'host')
|
||||
|
||||
|
@ -283,6 +417,9 @@ class RwoinstBundleLink(GenericLink):
|
|||
self._dump_attrs(indent)
|
||||
|
||||
class RwoinstWebresLink(GenericLink):
|
||||
"""Les resources web d'un bundle déployées sur un hôte avec rwoinst
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(RwoinstWebresLink, self).__init__('wobundle', 'host')
|
||||
|
||||
|
@ -294,6 +431,9 @@ class RwoinstWebresLink(GenericLink):
|
|||
self._dump_attrs(indent)
|
||||
|
||||
class RtoinstLink(GenericLink):
|
||||
"""Une webapp déployée sur un hôte avec rtoinst
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(RtoinstLink, self).__init__('webapp', 'host')
|
||||
|
||||
|
@ -309,6 +449,9 @@ class UNDEF(object):
|
|||
UNDEF = UNDEF()
|
||||
|
||||
class Database(object):
|
||||
"""La base de données des objets et des liens
|
||||
"""
|
||||
|
||||
_default_profile = None
|
||||
_default_domain = None
|
||||
|
||||
|
@ -325,18 +468,38 @@ class Database(object):
|
|||
self._links_classes = {}
|
||||
|
||||
def has_default_profile(self):
|
||||
"""Vérifier si un profil par défaut a été spécifié
|
||||
"""
|
||||
return self._default_profile is not None
|
||||
def get_default_profile(self):
|
||||
"""Obtenir le profil par défaut, ou None si aucun profil par défaut n'a été
|
||||
défini
|
||||
"""
|
||||
return self._default_profile
|
||||
def set_default_profile(self, profile):
|
||||
"""Spécifier le profil par défaut
|
||||
|
||||
Si un lien est spécifié sans profil, il est réputé défini dans le
|
||||
profil par défaut.
|
||||
"""
|
||||
self._default_profile = profile or None
|
||||
default_profile = property(get_default_profile, set_default_profile)
|
||||
|
||||
def has_default_domain(self):
|
||||
"""Vérifier si un domaine par défaut a été spécifié
|
||||
"""
|
||||
return self._default_domain is not None
|
||||
def get_default_domain(self):
|
||||
"""Obtenir le domaine par défaut, ou None si aucun domaine par défaut n'a été
|
||||
défini
|
||||
"""
|
||||
return self._default_domain
|
||||
def set_default_domain(self, domain):
|
||||
"""Spécifier le domaine par défaut
|
||||
|
||||
Si un hôte est spécifié sans domaine, il est réputé défini avec le
|
||||
domaine par défaut.
|
||||
"""
|
||||
if domain is not None:
|
||||
#XXX si le domaine a été corrigé, l'indiquer en warning
|
||||
if domain.startswith('.'): domain = domain[1:]
|
||||
|
@ -345,26 +508,42 @@ class Database(object):
|
|||
default_domain = property(get_default_domain, set_default_domain)
|
||||
|
||||
def register_object(self, otype, oclass=None):
|
||||
"""Enregistrer un type d'objet et la classe utilisée pour l'instancier.
|
||||
|
||||
Par défaut, le classe utilisé est GenericObject.
|
||||
"""
|
||||
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_otypes(self):
|
||||
"""Obtenir la liste des types d'objets connus
|
||||
"""
|
||||
return self._objects_ids_otype.keys()
|
||||
known_otypes = property(get_known_otypes)
|
||||
def get_objects(self, otype):
|
||||
"""Obtenir tous les objets définis du type spécifié ou None si le type d'objets
|
||||
est invalide.
|
||||
"""
|
||||
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):
|
||||
"""Vérifier si l'objet avec l'identifiant spécifié est défini
|
||||
"""
|
||||
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):
|
||||
def get_object(self, otype, id, create=True):
|
||||
"""Obtenir l'objet avec l'identifiant spécifié, ou None si l'objet n'existe pas.
|
||||
|
||||
Si create==True, l'objet est créé s'il n'existe pas, et cette méthode ne
|
||||
retourne pas None.
|
||||
"""
|
||||
objects = self._objects_ids_otype.get(otype, None)
|
||||
if objects is None: return None
|
||||
object = objects.get(id, None)
|
||||
if object is None:
|
||||
if object is None and create:
|
||||
object_class = self._objects_classes.get(otype, None)
|
||||
if object_class is not None:
|
||||
object = object_class(id)
|
||||
|
@ -372,13 +551,24 @@ class Database(object):
|
|||
return object
|
||||
|
||||
def register_link(self, ltype, lclass):
|
||||
"""Enregister un type de lien et la classe utilisée pour l'instancier.
|
||||
|
||||
Il n'y a pas de classe par défaut, il faut absolument spécifier une
|
||||
classe valide.
|
||||
"""
|
||||
if not self._links_ltype.has_key(ltype):
|
||||
self._links_ltype[ltype] = []
|
||||
self._links_classes[ltype] = lclass
|
||||
def get_known_ltypes(self):
|
||||
"""Obtenir la liste des types de liens connus
|
||||
"""
|
||||
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):
|
||||
"""Obtenir les liens correspondant aux critères.
|
||||
|
||||
XXX compléter la doc
|
||||
"""
|
||||
links = self._links_ltype.get(ltype, None)
|
||||
if links is None: return None
|
||||
|
||||
|
@ -616,22 +806,24 @@ class Parser(object):
|
|||
if db is None: db = Database()
|
||||
self.db = db
|
||||
self.groups = {}
|
||||
self.commands = {}
|
||||
self.commands = {
|
||||
'default_profile': self.handle_default_profile,
|
||||
'default_domain': self.handle_default_domain,
|
||||
'group': self.handle_group,
|
||||
'attr': self.handle_attr,
|
||||
}
|
||||
self.__setup_hosts()
|
||||
self.__setup_uinst()
|
||||
self.__setup_woinst()
|
||||
self.__setup_toinst()
|
||||
self.__setup_query()
|
||||
|
||||
def parse(self, predicates):
|
||||
for p in predicates:
|
||||
cmd = p[0]
|
||||
args = p[1:]
|
||||
if cmd == 'default_profile': self.handle_default_profile(args)
|
||||
elif cmd == 'default_domain': self.handle_default_domain(args)
|
||||
elif cmd == 'group': self.handle_group(args)
|
||||
elif cmd == 'attr': self.handle_attr(args)
|
||||
elif cmd == 'host': self.handle_host(*p)
|
||||
elif cmd in self.commands: self.commands[cmd](*p)
|
||||
if cmd in self.commands: self.commands[cmd](*p)
|
||||
else: raise ValueError("%s: unknown command" % cmd)
|
||||
return self
|
||||
|
||||
def register_command(self, name, method):
|
||||
|
@ -647,18 +839,21 @@ class Parser(object):
|
|||
def add_group(self, otype, id):
|
||||
self.groups[otype]['current'].add(id)
|
||||
|
||||
def handle_group(self, args):
|
||||
"""group otype gtype
|
||||
def handle_group(self, cmd, *args):
|
||||
"""group otype [gtype]
|
||||
gtype peut valoir:
|
||||
- defaults: revenir à l'état initial, permettant de spécifier les
|
||||
attributs et liens pour tous les hôtes définis à partir de cette ligne
|
||||
- once: un nouveau groupe est défini à chaque nouvelle ligne 'group'
|
||||
- until: définir un groupe qui va jusqu'à la prochaine ligne 'group'
|
||||
- once: un nouveau groupe est défini à chaque nouvelle définition
|
||||
d'objet. en d'autres termes, ne font partie du groupe que les objets
|
||||
faisant partie d'une même définition. c'est la valeur par défaut
|
||||
- until: définir un groupe qui va jusqu'à la prochaine définition de
|
||||
groupe ou de lien.
|
||||
"""
|
||||
otype = args[0:1] and args[0] or 'host'
|
||||
if otype not in self.groups:
|
||||
raise ValueError('%s: invalid object type' % otype)
|
||||
gtype = args[1:2] and args[1] or 'until'
|
||||
gtype = args[1:2] and args[1] or 'once'
|
||||
self.groups[otype]['type'] = gtype
|
||||
if gtype == 'defaults':
|
||||
self.groups[otype]['current'] = set([None])
|
||||
|
@ -669,7 +864,7 @@ class Parser(object):
|
|||
self.attr_otype = otype
|
||||
|
||||
############################################################################
|
||||
def handle_attr(self, args):
|
||||
def handle_attr(self, cmd, *args):
|
||||
otype = self.attr_otype
|
||||
assert otype is not None, "attr_otype should not be None"
|
||||
for nv in args:
|
||||
|
@ -683,13 +878,13 @@ class Parser(object):
|
|||
self.db.get_object(otype, id).modify_attr(name, value, method)
|
||||
|
||||
############################################################################
|
||||
def handle_default_profile(self, args):
|
||||
def handle_default_profile(self, cmd, *args):
|
||||
if not args or not args[0]: profile = None
|
||||
else: profile = args[0]
|
||||
self.db.default_profile = profile
|
||||
|
||||
############################################################################
|
||||
def handle_default_domain(self, args):
|
||||
def handle_default_domain(self, cmd, *args):
|
||||
if not args or not args[0]: domain = None
|
||||
else: domain = args[0]
|
||||
self.db.default_domain = domain
|
||||
|
@ -699,7 +894,8 @@ class Parser(object):
|
|||
self.db.register_object('host', HostObject)
|
||||
self.db.get_object('host', None)
|
||||
self.groups['host'] = {}
|
||||
self.handle_group(['host', 'defaults'])
|
||||
self.handle_group('group', 'host', 'defaults')
|
||||
self.register_command('host', self.handle_host)
|
||||
def __fix_host(self, host):
|
||||
if host.endswith('.'):
|
||||
host = host[:-1]
|
||||
|
@ -779,7 +975,7 @@ class Parser(object):
|
|||
self.db.register_link('ruinst', RuinstLink)
|
||||
self.db.get_object('module', None)
|
||||
self.groups['module'] = {}
|
||||
self.handle_group(['module', 'defaults'])
|
||||
self.handle_group('group', 'module', 'defaults')
|
||||
self.register_command('module', self.handle_module)
|
||||
self.register_command('uinst', self.handle_xuinst)
|
||||
self.register_command('ruinst', self.handle_xuinst)
|
||||
|
@ -852,13 +1048,25 @@ class Parser(object):
|
|||
def handle_xuinst(self, ltype, *args):
|
||||
"""uinst -p profile attrs*
|
||||
ruinst -p profile attrs*
|
||||
|
||||
usage de l'option -p:
|
||||
pas d'option -p
|
||||
définir les liens dans le profil par défaut. équivalent à -p '' s'il
|
||||
n'y a pas de profil par défaut.
|
||||
-p ''
|
||||
définir les liens en ne les associant à aucun profil
|
||||
-p PROFILE,...
|
||||
définir les liens dans les profils spécifiés
|
||||
|
||||
"""
|
||||
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 ','
|
||||
|
||||
if o.profiles is None: profiles = [self.db.default_profile]
|
||||
else: profiles = flatten(o.profiles)
|
||||
if profiles == []: profiles = [None]
|
||||
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)
|
||||
|
@ -900,7 +1108,7 @@ class Parser(object):
|
|||
self.db.register_link('rwoinst-webres', RwoinstWebresLink)
|
||||
self.db.get_object('wobundle', None)
|
||||
self.groups['wobundle'] = {}
|
||||
self.handle_group(['wobundle', 'defaults'])
|
||||
self.handle_group('group', 'wobundle', 'defaults')
|
||||
self.register_command('wobundle', self.handle_wobundle)
|
||||
self.register_command('rwoinst', self.handle_rwoinst)
|
||||
def __fix_wobundle(self, wobundle):
|
||||
|
@ -980,9 +1188,11 @@ class Parser(object):
|
|||
AP.add_argument('stype', nargs=1)
|
||||
AP.add_argument('nvss', nargs=REMAINDER)
|
||||
o = AP.parse_args(args)
|
||||
|
||||
if o.profiles is None: profiles = [self.db.default_profile]
|
||||
else: profiles = flatten(o.profiles)
|
||||
if profiles == []: profiles = [None]
|
||||
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)
|
||||
|
@ -1023,7 +1233,7 @@ class Parser(object):
|
|||
self.db.register_link('rtoinst', RtoinstLink)
|
||||
self.db.get_object('webapp', None)
|
||||
self.groups['webapp'] = {}
|
||||
self.handle_group(['webapp', 'defaults'])
|
||||
self.handle_group('group', 'webapp', 'defaults')
|
||||
self.register_command('webapp', self.handle_webapp)
|
||||
self.register_command('rtoinst', self.handle_rtoinst)
|
||||
def __fix_webapp(self, webapp):
|
||||
|
@ -1099,8 +1309,10 @@ class Parser(object):
|
|||
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 ','
|
||||
|
||||
if o.profiles is None: profiles = [self.db.default_profile]
|
||||
else: profiles = flatten(o.profiles)
|
||||
if profiles == []: profiles = [None]
|
||||
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)
|
||||
|
@ -1135,6 +1347,15 @@ class Parser(object):
|
|||
for currentl in currentls:
|
||||
currentl.modify_attr(name, value, method)
|
||||
|
||||
############################################################################
|
||||
def __setup_query(self):
|
||||
self.register_command('query', self.handle_query)
|
||||
|
||||
def handle_query(self, cmd, *args):
|
||||
"""query config
|
||||
"""
|
||||
print "WARNING: query not implemented" #XXX
|
||||
|
||||
################################################################################
|
||||
# Programme principal
|
||||
|
||||
|
|
Loading…
Reference in New Issue