# -*- 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)