#!/bin/bash # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 source "$(dirname -- "$0")/lib/ulib/auto" || exit 1 urequire woinst function display_help() { uecho "$scriptname: Déploiement distant avec woinst USAGE $scriptname [-H host] [-G tmproot] ... [-- options de woinst] note: à cause d'une limitation de makeself, les options de toinst ne devraient pas contenir d'espaces ni de caractères spéciaux. L'échappement de ces caractères n'est pas garanti. OPTIONS -G, --tmproot TMPROOT Spécifier le répertoire temporaire sur l'hôte distant, comme par exemple /var/tmp. Cette option est utile pour les vservers, qui ont par défaut un /tmp minuscule de 16 Mo. -S, --ssh SSH Spécifier le programme à utiliser pour la connection par ssh. -h, --host hosts -h, --host @hostsfile Spécifier un ou plusieurs hôtes sur lequels faire le déploiement. Pour spécifier plusieurs hôtes, il est possible d'utiliser plusieurs fois l'option -h, ou spécifier en une seule fois plusieurs hôtes en les séparant par un espace ou le caractère ':', e.g. 'host1 host2' ou 'host1:host2'. Si la spécification contient les caractères { et }, l'expansion est effectuée, e.g -h 'root@{host1,host2}.univ.run' Par défaut, la connexion sur l'hôte distant se fait avec l'utilisateur root. Il est possible de spécifier un autre utilisateur avec la syntaxe user@host, e.g -h user@host La forme @hostsfile permet de lire la liste des hôtes depuis le fichier hostsfile, à raison d'un hôte par ligne. -w, -W, --whost host[:htdocs] Comme --host, mais pour le déploiement des resources web. Contrairement à --host, un seul hôte peut être spécifié par occurence de l'option, pour permettre de spécifier éventuellement le répertoire vers lequel copier les resources web. Ainsi, les deux commandes suivantes sont équivalentes: rwoinst -h host.tld -- -W HTDOCSDIR=HTDOCSBASE/wo rwoinst -w host.tld:HTDOCSBASE/wo Il est possible de spécifier en une seule invocation --host et --whost pour déployer l'application sur un hôte et les resources web sur un autre. --deploydb --nd, --no-deploydb Autoriser (respectivement interdire) l'utilisation de la configuration locale de déploiement pour identifier la source et/ou la destination s'ils ne sont pas spécifiés. Par défaut, la configuration locale de déploiement est utilisée. -p, --dp, --deploydb-profile PROFILENAME Spécifier un ou plusieurs profils séparés par des virgules pour le déploiement avec la configuration locale de déploiement. NONE est la valeur par défaut et signifie de ne sélectionner que les définitions sans profil. ALL signifie de ne pas tenir compte des profils dans les définitions. -A, --all-profiles -P, --prod -T, --test Raccourcis respectivement pour -pALL, -pprod et -ptest -c, --dc, --deploydb-config CONFNAME Cette option permet de spécifier un fichier de configuration ou le nom de la configuration locale de déploiement à utiliser pour effectuer la requête. Par défaut, utiliser le nom 'woinst.conf'" } __PARSED_HOSTS=() __PARSED_FILES=() function parse_hostsfile() { # Lire chacun des fichiers $* et initialiser __PARSED_HOSTS avec la liste # des hôtes mentionnés dans les fichiers. local inputfile basedir inputs input for inputfile in "$@"; do inputfile="$(abspath "$inputfile")" array_contains __PARSED_FILES "$inputfile" && { ewarn "$(ppath "$inputfile"): inclusion récursive" continue } array_add __PARSED_FILES "$inputfile" basedir="$(dirname "$inputfile")" array_from_lines inputs "$(<"$inputfile" filter_conf)" || { ewarn "$inputfile: fichier ingnoré" continue } for input in "${inputs[@]}"; do if [ "${input#@}" != "$input" ]; then # fichier inclus parse_hostsfile "$(abspath "${input#@}" "$basedir")" else array_addu __PARSED_HOSTS "$input" fi done done } function __expand_braces() { if [[ "$1" == *{* ]] && [[ "$1" == *}* ]]; then eval "echo $1" else echo "$1" fi } function __dot_is_localhost() { [ "$1" == "." ] && echo "localhost" || echo "$1"; } function fix_hosts() { # Si hosts contient des éléments multiple, comme a:b, séparer ces # éléments. i.e (a b:c) --> (a b c) # Supporter la syntaxe @hostsfile qui permet de charger la liste des hôtes # depuis un fichier. # Remplacer aussi les '.' par 'localhost' array_map hosts __expand_braces array_fix_paths hosts ":" array_fix_paths hosts " " local -a _hosts _tmphosts host for host in "${hosts[@]}"; do host="${host%/}" if [ "${host#@}" != "$host" ]; then __PARSED_HOSTS=() parse_hostsfile "${host#@}" array_fix_paths __PARSED_HOSTS array_extendu _hosts __PARSED_HOSTS else array_addu _hosts "$host" fi done array_copy hosts _hosts array_map hosts __dot_is_localhost } function deploy_to() { local archive="$1" host="$2" tmproot="$3" shift; shift; shift local r= if [ "$host" == "localhost" ]; then etitle "Sur l'hôte local" "$archive" ${tmproot:+--tmproot "$tmproot"} -- "$@" || r=1 eend else local user local archivename="$(basename "$archive")" splituserhost "$host" user host [ -n "$user" ] || user=root # sur l'hôte distant, ne rendre non interactif qu'à partir de -yy rinteraction=$__interaction [ $rinteraction -lt 2 ] && rinteraction=$(($rinteraction + 1)) etitle "Vers $user@$host" estep "Copie de l'archive" scp -S "$SSH" "$archive" "$user@$host:" || r=1 if [ -z "$r" ]; then estep "Lancement du script de déploiement" "$SSH" -qt "$user@$host" "\ __interaction=$rinteraction __estack=$(qval "$__estack") __tlevel=$(qval "$__tlevel") export __interaction __estack __tlevel ${UTOOLS_LANG:+UTOOLS_LANG='$UTOOLS_LANG'; export UTOOLS_LANG }$(qvals "./$archivename" ${tmproot:+--tmproot "$tmproot"} -- MYHOST="$host" "$@")" || r=1 fi eend fi return ${r:-0} } action=deploy tmproot= SSH= hosts=() whosts=() ddb_enable=1 ddb_profile=NONE ddb_conf=woinst.conf parse_opts "${PRETTYOPTS[@]}" \ --help '$exit_with display_help' \ -G:,--tmproot: tmproot= \ -S:,--ssh: SSH= \ -h:,-H:,--host: hosts \ -w:,-W:,--whost: whosts \ --deploydb ddb_enable=1 \ --nd,--no-deploydb ddb_enable= \ -p:,--dp:,--deploydb-profile ddb_profile= \ -A,--all-profiles ddb_profile=ALL \ -P,--prod ddb_profile=prod \ -T,--test ddb_profile=test \ -c:,--dc:,--deploydb-config ddb_conf= \ @ args -- "$@" && set -- "${args[@]}" || die "$args" : "${SSH:=ssh}" ## Bundle à déployer et hôtes sur lesquels faire le déploiement # quels informations avons-nous? array_isempty hosts && has_hosts= || has_hosts=1 if [ $# -eq 0 ] || [[ "$1" == -* ]] || [[ "$1" == *=* ]]; then # pas d'argument, ou c'est une option (qui fait donc partie des arguments de woinst) has_bundle= else bundle="$1" has_bundle=1 shift fi # configuration locale de déploiement ddb_enable= #XXX 05/04/2021 désactiver deploydb pour le moment if [ -n "$ddb_enable" ]; then # filtrer les options... elles seront ignorées si on passe finalement par # deploydb vars=() options=() for arg in "$@"; do if [[ "$arg" == *=* ]]; then array_add vars "$arg" else array_add options "$arg" fi done deploydb=( "$scriptdir/lib/nulib/deploydb" --missing-ok ${ddb_conf:+-c "$ddb_conf"} -m woinst --run -r woinst.query_rwoinst "$script" ) cmds=() myname="$(basename "$(pwd)")" if [ -n "$has_hosts" ]; then fix_hosts for host in "${hosts[@]}"; do array_from_lines tmpcmds "$("${deploydb[@]}" "$bundle" "$host" "$ddb_profile" "${vars[@]}")" array_extend cmds tmpcmds done elif [ -n "$has_bundle" ]; then array_from_lines tmpcmds "$("${deploydb[@]}" "$bundle" "" "$ddb_profile" "${vars[@]}")" array_extend cmds tmpcmds elif [[ "$myname" == *.woa ]] || [[ "$myname" == *.framework ]]; then read_value "Veuillez entrer le chemin du bundle à déployer" bundle . O has_bundle=1 array_from_lines tmpcmds "$("${deploydb[@]}" "$bundle" "" "$ddb_profile" "${vars[@]}")" array_extend cmds tmpcmds fi if [ ${#cmds[*]} -gt 0 ]; then [ ${#options[*]} -gt 0 ] && ewarn "Les options supplémentaires '${options[*]}' seront ignorées" if check_interaction -c; then if [ ${#cmds[*]} -eq 1 ]; then einfo "La commande suivante va être lancée:" eecho "\$ $script --no-deploydb \\" for cmd in "${cmds[0]}"; do eecho " ${cmd#$script --no-deploydb }" done else einfo "Les commandes suivantes seront lancées:" eecho "\$ $script --no-deploydb \\" for cmd in "${cmds[@]}"; do eecho " ... ${cmd#$script --no-deploydb }" done fi read -p "Confirmez ou attendez 4 secondes [On] " -t 4 r if [ $? -gt 128 ]; then echo # cosmetic elif [ $? -le 128 -a -n "$r" ]; then is_yes "$r" || die fi fi r=0 for cmd in "${cmds[@]}"; do einfo "$cmd" eval "$cmd" || r=1 done exit $r elif [ "$ddb_profile" != "ALL" ]; then ewarn "Aucune configuration locale de déploiement n'a été trouvée pour le profil $ddb_profile" fi fi if [ -z "$has_bundle" ]; then # pas d'argument, ou c'est une option (qui fait donc partie des arguments de woinst) read_value "Veuillez entrer le chemin du bundle à déployer" bundle "$bundle" O has_bundle=1 fi [ -n "$has_bundle" ] && set -- "$bundle" "$@" array_isempty hosts && read_value "Entrez une liste d'hôtes séparés par ':'" hosts "localhost" fix_hosts ## Création de l'archive etitle "Création du répertoire de travail" ac_set_tmpdir workdir bundles=() while [ -n "$1" ]; do if [ "$1" == "--" ]; then # début des options de woinst shift break elif [[ "$1" == -* ]] || [[ "$1" == *=* ]]; then # début des options de woinst break fi src="$1"; shift if [ -f "$src" ] && is_archive "$src"; then estep "$(ppath "$src")" cp_R "$src" "$workdir" || die elif [ -d "$src" ]; then src="$(abspath "$src")" setx srcname=basename -- "$src" case "$src" in *.woa|*.framework) ;; *) # support projet maven if [ ! -f "$src/pom.xml" ]; then : # non, pas un projet maven elif [ -d "$src/target/$srcname.woa" ]; then src="$src/target/$srcname.woa" elif [ -d "$src/target/$srcname.framework" ]; then src="$src/target/$srcname.framework" fi ;; esac if endswith "$src" .framework; then is_wofwkdir "$src" || die "Framework invalide: $(ppath "$src")" elif endswith "$src" .woa; then is_woappdir "$src" || die "Application invalide: $(ppath "$src")" else die "N'est pas un bundle valide: $(ppath "$src")" fi estep "$(ppath2 "$src")" cp_R "$src" "$workdir" || die else die "Fichier ou répertoire introuvable: $src" fi src="$(abspath "$src")" array_add bundles "$(basename "$src")" done estep "Copie de l'environnement de déploiement" mkdir "$workdir/lib" ulibsync "$workdir/lib" cp "$scriptdir/woinst.sh" "$workdir" chmod +x "$workdir/woinst.sh" eend etitle "Création de l'archive pour le déploiement" ac_set_tmpfile archive "$scriptdir/mkusfx" --bare --tmp-archive -o "$archive" "$workdir" -- ./woinst.sh --is-tmpdir "${bundles[@]}" || die eend ## Déploiement etitle "Déploiement des bundles" for host in "${hosts[@]}"; do deploy_to "$archive" "$host" "$tmproot" "$@" "${woinst_options[@]}" || die done eend if [ ${#whosts[*]} -gt 0 ]; then etitle "Déploiement des resources web" for hostdestdir in "${whosts[@]}"; do splitpair "$hostdestdir" host destdir deploy_to "$archive" "$host" "$tmproot" \ -y -W ${destdir:+HTDOCSDIR="$destdir"} "$@" "${woinst_options[@]}" || die done eend fi