379 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			379 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/bin/bash
 | |
| # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
 | |
| source "$(dirname -- "$0")/lib/ulib/ulib" || exit 1
 | |
| urequire DEFAULTS woinst
 | |
| 
 | |
| function display_help() {
 | |
|     uecho "$scriptname: Déploiement distant avec woinst
 | |
| 
 | |
| USAGE
 | |
|     $scriptname [-H host] [-G tmproot] <archive|dir>... [-- 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
 | |
| 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
 |