224 lines
8.2 KiB
Python
224 lines
8.2 KiB
Python
# -*- coding: utf-8 mode: python -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
|
|
|
__all__ = (
|
|
'Wyapp',
|
|
'wyapp_matcher', 'wyappname_matcher',
|
|
)
|
|
|
|
import logging; log = logging.getLogger(__name__)
|
|
import os, sys
|
|
from os import path
|
|
|
|
from .utils import *
|
|
from .expr import *
|
|
from .objects import XT, fileP, pathP, mpathP, lowerP, Object, catalog
|
|
from .parser import Parser
|
|
from .base_module import withdomain, host_matcher, hostname_matcher
|
|
|
|
################################################################################
|
|
# Wyapp
|
|
|
|
def match_wyapp(qwyapp, object):
|
|
if withpath(qwyapp): # wyapp avec chemin
|
|
return qwyapp in object.get('wyapp', ())
|
|
else: # nom de wyapp
|
|
return qwyapp in object.get('wyappname', ())
|
|
def wyapp_matcher(qwyapp):
|
|
return lambda object: match_wyapp(qwyapp, object)
|
|
|
|
def match_wyappname(qwyapp, object):
|
|
qwyapp = path.basename(qwyapp)
|
|
return qwyapp in object.get('wyappname', ())
|
|
def wyappname_matcher(qwyapp):
|
|
return lambda object: match_wyappname(qwyapp, object)
|
|
|
|
class Wyapp(Object):
|
|
ATTRS = XT(Object,
|
|
values=pathP, wyapp=mpathP, wyappdir=pathP,
|
|
basedir=pathP, dirspec=fileP)
|
|
|
|
def _resolve(self, catalog):
|
|
if self.oid == '*': return
|
|
default = catalog.get(self.otype, '*', None, False)
|
|
|
|
wyapps = self.get('wyapp', [])
|
|
basedir = self.get('basedir', None)
|
|
if basedir is not None:
|
|
wyapps.extend(self.resolve_basedir(basedir, dirs=True))
|
|
dirspec = self.get('dirspec', None)
|
|
if dirspec is not None:
|
|
wyapps.extend(self.resolve_filespec(dirspec, dirs=True))
|
|
|
|
if wyapps:
|
|
# générer wyappdir et wyappname à partir de wyapp
|
|
wyappdirs = [path.dirname(wyapp) for wyapp in wyapps]
|
|
if wyappdirs: wyappdirs = self.wyappdir = ulistof(wyappdirs)
|
|
|
|
wyappnames = [path.basename(wyapp) for wyapp in wyapps]
|
|
if wyappnames: wyappnames = self.wyappname = ulistof(wyappnames)
|
|
|
|
else:
|
|
# générer wyapps à partir de wyappdir et wyappname
|
|
wyappdirs = self.get('wyappdir', ())
|
|
if not wyappdirs and default is not None:
|
|
wyappdirs = default.get('wyappdir', ())
|
|
if wyappdirs: wyappdirs = self.wyappdir = ulistof(wyappdirs)
|
|
|
|
wyappnames = self.get('wyappname', ())
|
|
if not wyappnames: wyappnames = [self.oid]
|
|
if wyappnames: wyappnames = self.wyappname = ulistof(wyappnames)
|
|
|
|
if wyappdirs:
|
|
wyapps = []
|
|
for wyappname in wyappnames:
|
|
found = []
|
|
for wyappdir in wyappdirs:
|
|
wyapp = path.join(wyappdir, wyappname)
|
|
if path.exists(wyapp):
|
|
found.append(wyapp)
|
|
break
|
|
if not found:
|
|
found = [path.join(wyappdirs[0], wyappname)]
|
|
wyapps.extend(found)
|
|
else:
|
|
wyapps = wyappnames
|
|
if wyapps: wyapps = self.wyapp = ulistof(wyapps)
|
|
|
|
if not self.values:
|
|
self.values = wyapps
|
|
|
|
################################################################################
|
|
# Actions
|
|
|
|
def query_rwyinst(*args):
|
|
"""afficher la commande pour déployer avec la commande $1 le wyapp $2 sur
|
|
l'hôte $3 dans le profil $4
|
|
|
|
$1 doit valoir 'rwyinst' ou être un chemin vers ce script
|
|
|
|
$2 peut être
|
|
* un nom de wyapp: tout les wyapps de ce nom sont sélectionnés
|
|
* un chemin complet: si un wyapp avec le chemin complet est trouvé, ne
|
|
sélectinner que celui-là, sinon faire comme si on n'avait spécifié que le
|
|
nom du wyapp
|
|
* non spécifié: tout les wyapps devant être déployé sur l'hôte sont
|
|
cherchés
|
|
|
|
$3 peut être
|
|
* un nom d'hôte: tous les hôtes de ce nom sont sélectionés
|
|
* un nom d'hôte pleinement qualifié: si le nom d'hôte pleinement qualifié
|
|
est trouvé, ne sélectionner que celui-là, sinon faire comme si on n'avait
|
|
spécifié que le nom d'hôte
|
|
* non spécifié: tous les hôtes vers lequel doit être déployé le wyapp sont
|
|
cherchés
|
|
|
|
$4 peut valoir
|
|
* 'NONE': seuls les déploiements sans profils définis sont sélectionnés.
|
|
c'est la valeur par défaut.
|
|
* 'ALL' ou '': ne pas tenir compte du profil lors de la sélection des
|
|
wyapps et des hôtes
|
|
* toute autre valeur, e.g prod ou test: seuls les déploiement de ce profil
|
|
sont sélectionnés
|
|
Il est possible de spécifier plusieurs profils en les séparant par des
|
|
virgules. Par exemple, 'prod,NONE' permet de sélectionner les déploiements
|
|
sans profil ou dans le profil 'prod'
|
|
|
|
le wyapp, ou l'hôte, ou les deux sont requis. le profil est facultatif.
|
|
|
|
Les valeurs $5..$* sont des définitions d'attributs utilisées pour mettre à
|
|
jour les faits trouvés. Ces définitions sont utilisés comme argument de
|
|
wyinst.
|
|
"""
|
|
rwyinst = args[0] if args[0:1] else None
|
|
if rwyinst is not None and (rwyinst == 'rwyinst' or rwyinst.endswith('/rwyinst')):
|
|
verb = 'rwyinst'
|
|
else:
|
|
raise ValueError("Le verbe est requis et doit valoir 'rwyinst'")
|
|
qwyapp = args[1:2] and args[1] or None
|
|
qhost = args[2:3] and args[2] or None
|
|
qprofile = args[3] if args[3:4] else 'NONE'
|
|
supplattrs = args[4:]
|
|
|
|
if not qwyapp and not qhost:
|
|
raise ValueError("Il faut spécifier wyapp et/ou host")
|
|
|
|
if not qwyapp:
|
|
wyapps = None
|
|
elif cwithpath(qwyapp):
|
|
qwyapp = path.abspath(qwyapp)
|
|
wyapps = catalog.find_objects('wyapp', expr=wyapp_matcher(qwyapp))
|
|
if not wyapps:
|
|
wyapps = catalog.find_objects('wyapp', expr=wyappname_matcher(qwyapp))
|
|
else:
|
|
wyapps = catalog.find_objects('wyapp', expr=wyappname_matcher(qwyapp))
|
|
|
|
if not qhost:
|
|
hosts = None
|
|
else:
|
|
if cwithpath(qhost):
|
|
qhost = path.basename(path.abspath(qhost))
|
|
if withdomain(qhost):
|
|
hosts = catalog.find_objects('host', expr=host_matcher(qhost))
|
|
if not hosts:
|
|
hosts = catalog.find_objects('host', expr=hostname_matcher(qhost))
|
|
else:
|
|
hosts = catalog.find_objects('host', expr=hostname_matcher(qhost))
|
|
|
|
if qprofile == '': qprofile = 'ALL'
|
|
qprofiles = flattenstr([qprofile])
|
|
if 'ALL' in qprofiles:
|
|
qprofile = None
|
|
else:
|
|
expr = []
|
|
for qprofile in qprofiles:
|
|
if qprofile == 'NONE':
|
|
qprofile = NONE(EXISTS('profile'))
|
|
else:
|
|
qprofile = dict(profile=qprofile)
|
|
expr.append(qprofile)
|
|
qprofile = ANY(*expr)
|
|
|
|
# wyapps et hosts sont spécifiés
|
|
if wyapps is not None and hosts is not None:
|
|
facts = catalog.find_facts(
|
|
verb=verb,
|
|
tsotype='wyapp', tsexpr=dict(oid=[wyapp.oid for wyapp in wyapps]),
|
|
ttotype='host', ttexpr=dict(oid=[host.oid for host in hosts]),
|
|
expr=qprofile,
|
|
)
|
|
|
|
# Seuls les wyapps sont spécifiés: chercher les hôtes
|
|
elif wyapps is not None:
|
|
facts = catalog.find_facts(
|
|
verb=verb,
|
|
tsotype='wyapp', tsexpr=dict(oid=[wyapp.oid for wyapp in wyapps]),
|
|
ttotype='host',
|
|
expr=qprofile,
|
|
)
|
|
|
|
# Seuls les hôtes sont spécifiés: chercher les wyapps
|
|
elif hosts is not None:
|
|
facts = catalog.find_facts(
|
|
verb=verb,
|
|
tsotype='wyapp',
|
|
ttotype='host', ttexpr=dict(oid=[host.oid for host in hosts]),
|
|
expr=qprofile,
|
|
)
|
|
|
|
# afficher la commande
|
|
if supplattrs: parser = Parser()
|
|
for fact, tsobjects, ttobjects in facts:
|
|
hs = flattenseq([host.host for host in ttobjects])
|
|
ws = flattenseq([wyapp.wyapp for wyapp in tsobjects])
|
|
if supplattrs: parser.parse_attrs(supplattrs, fact)
|
|
vars = []
|
|
for name, values in fact.attrs.items():
|
|
vars.append("%s=%s" % (name, qshell(':'.join(values))))
|
|
for w in ws:
|
|
# préférer si possible le chemin fourni par l'utilisateur
|
|
if withpath(qwyapp): w = qwyapp
|
|
hs = ':'.join(hs)
|
|
parts = [xwyinst, '--no-deploydb', '-h', qshell(hs), qshell(w), '--', '-y']
|
|
if vars: parts.append(' '.join(vars))
|
|
print ' '.join(parts)
|