407 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			407 lines
		
	
	
		
			15 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 runs runsmod
 | |
| 
 | |
| function display_help() {
 | |
|     uecho "$scriptname: Lancer un script avec le protocole runs
 | |
| 
 | |
| USAGE
 | |
|     $scriptname [options] rscriptname name=value...
 | |
|     $scriptname [options] @recipe name=value...
 | |
|     $scriptname [options] -f rscript name=value...
 | |
|     $scriptname [options] -r recipe name=value...
 | |
| 
 | |
| OPTIONS
 | |
| Configuration
 | |
|     --init
 | |
|     --verify
 | |
|         Vérifier le nom d'hôte et créer si nécessaire le répertoire d'hôte
 | |
|         correspondant à l'hôte courant ou à l'hôte spécifié avec l'option -h
 | |
|         Avec --verify, la création du répertoire d'hôte n'est pas effectuée.
 | |
|     --sysinfos DATA
 | |
|         Avec l'option --init, initialiser le fichier sysinfos.conf avec DATA, si
 | |
|         le fichier n'a pas déjà été provisionné. Sans cette option, un fichier
 | |
|         vide avec des commentaires est créé à la place.
 | |
|     --create RSCRIPT
 | |
|         Créer un modèle de script avec le nom donné.
 | |
|         Avec l'option -h, le script est créé dans le répertoire d'hôte
 | |
|         correspondant à l'hôte spécifié
 | |
| 
 | |
| Gestion des scripts
 | |
|     -s  Forcer l'exécution du script avec l'utilisateur root si ce n'est pas
 | |
|         déjà le cas
 | |
|     -f RSCRIPT
 | |
|         Lancer le script individuel spécifié au lieu de chercher dans les
 | |
|         répertoires de \$RUNSSCRIPTSPATH
 | |
|     -r RECIPE
 | |
|         Lancer les scripts spécifiés dans le fichier de recettes individuel
 | |
|         spécifié.
 | |
|     -h HOSTNAME[.DOMAIN]
 | |
|         Spécifier que les scripts sont destinés à être lancés sur l'hôte
 | |
|         spécifié. Les scripts sont alors aussi cherchés dans les répertoires
 | |
|         {\$RUNSHOSTSPATH}/\$hostname.\$domain (par défaut) et
 | |
|         {\$RUNSHOSTSPATH}/\$domain/\$hostname (le cas échéant)
 | |
|         L'option --host est équivalente, sauf que son argument est facultatif et
 | |
|         que sa valeur par défaut est l'hôte courant, soit $MYHOST
 | |
|     --list
 | |
|         Afficher la liste des scripts qui sont disponibles. Avec l'option -h,
 | |
|         inclure aussi les scripts spécifiques à cet hôte.
 | |
|         Avec cette option, les arguments supplémentaires agissent comme des
 | |
|         filtres (regexp utilisée avec l'opérateur == de la commande [[). Les
 | |
|         noms des scripts doivent valider au moins un filtre.
 | |
|     --info
 | |
|         Afficher la la description du script et la valeur de chaque variable
 | |
|         définies
 | |
|     --desc-only
 | |
|         Afficher seulement la description du script
 | |
|     -z  Forcer la réinstallation des scripts qui se basent sur shouldrun/setdone"
 | |
| }
 | |
| 
 | |
| function runs_path_required() {
 | |
|     die "Vous devez définir $1 dans ~/etc/default/runs"
 | |
| }
 | |
| function runs_path_undefined() {
 | |
|     ewarn "La variable $1 n'est pas définie dans ~/etc/default/runs"
 | |
| }
 | |
| 
 | |
| runs_before_parse_args
 | |
| 
 | |
| auto_runsmod=1
 | |
| action=runs
 | |
| create_verbose=
 | |
| init_sysinfos=--NOT-SET--
 | |
| list_verbose=
 | |
| run_as_root=
 | |
| rscripts=()
 | |
| recipes=()
 | |
| runshost=
 | |
| runssysname=
 | |
| runssysdist=
 | |
| runssysver=
 | |
| runsbits=
 | |
| runsscriptspath=
 | |
| runsscriptsdirs=()
 | |
| runsmodulespath=
 | |
| runsmodulesdirs=()
 | |
| runshostspath=
 | |
| runshostsdirs=()
 | |
| runsexportdir= # répertoire dans lequel exporter les fichiers
 | |
| runsworkdir= # si runsexportdir n'est pas spécifié, répertoire de travail
 | |
| runsvarsfile= # fichier contenant des définitions à charger
 | |
| runs_init "$scriptdir"
 | |
| parse_opts "${PRETTYOPTS[@]}" \
 | |
|     --help '$exit_with display_help' \
 | |
|     --no-auto-runsmod auto_runsmod= \
 | |
|     --i '$action=init;create_verbose=false' \
 | |
|     --init '$action=init;create_verbose=true' \
 | |
|     --verify action=verify \
 | |
|     --sysinfos: init_sysinfos= \
 | |
|     -c,--c '$action=create;create_verbose=false' \
 | |
|     --create '$action=create;create_verbose=true' \
 | |
|     -l,--l '$action=list;list_verbose=false' \
 | |
|     --list '$action=list;list_verbose=true' \
 | |
|     --desc-only '$action=runs;RUNSACTION=runs_action_desc' \
 | |
|     -d,--dump,-i,--info '$action=runs;RUNSACTION=runs_action_dump' \
 | |
|     --export '$action=runs;RUNSACTION=runs_action_export' \
 | |
|     -s run_as_root \
 | |
|     -f: rscripts \
 | |
|     -r: recipes \
 | |
|     -h:,-H: runshost= \
 | |
|     --host:: '$set@ runshost "$MYHOST"' \
 | |
|     --sysname: runssysname= \
 | |
|     --sysdist: runssysdist= \
 | |
|     --sysver: runssysver= \
 | |
|     --bits: runsbits= \
 | |
|     --runsscriptspath: runsscriptspath= \
 | |
|     --runsscriptsdir: runsscriptsdirs \
 | |
|     --runsmodulespath: runsmodulespath= \
 | |
|     --runsmodulesdir: runsmodulesdirs \
 | |
|     --runshostspath: runshostspath= \
 | |
|     --runshostsdir: runshostsdirs \
 | |
|     --runsexportdir: runsexportdir= \
 | |
|     --runsworkdir: runsworkdir= \
 | |
|     --runsvarsfile: runsvarsfile= \
 | |
|     -z RUNSRESET=1 \
 | |
|     @ args -- "$@" && set -- "${args[@]}" || die "$args"
 | |
| 
 | |
| runs_after_parse_args
 | |
| 
 | |
| if [ "$action" == runs \
 | |
|     -o "$action" == init -o "$action" == verify \
 | |
|     -o \( -n "$runshost" -a \( "$action" == create -o "$action" == list \) \) ]; then
 | |
|     # configurer le nom d'hôté ici, parce qu'avec l'option -s, le fichier de
 | |
|     # configuration ~/etc/default/runs ne sera plus disponible
 | |
|     runs_initdomains
 | |
|     runs_inithost "$runshost"
 | |
|     host="$RUNSHOST"
 | |
|     splithost "$host" hostname domain
 | |
|     if [ -z "$domain" ]; then
 | |
|         host="$(runs_find_host "$host")"
 | |
|         splithost "$host" hostname domain
 | |
|     fi
 | |
|     [ -n "$domain" ] || host="$(runs_add_domain "$host")"
 | |
|     if [ "$host" != "$RUNSHOST" ]; then
 | |
|         enote "Le nom d'hôte '$RUNSHOST' a été automatiquement corrigé en '$host'"
 | |
|         if ask_yesno "Acceptez-vous cette modification?" O; then
 | |
|             RUNSHOST="$host"
 | |
|             runshost="$host" # pour l'option -s
 | |
|         fi
 | |
|     fi
 | |
| fi
 | |
| 
 | |
| [ -n "$auto_runsmod" ] && runsmod_autoconf
 | |
| 
 | |
| if ! is_root && [ -n "$run_as_root" ]; then
 | |
|     # reconstruire la ligne de commande
 | |
|     args=(--no-auto-runsmod)
 | |
|     if [ "$action" == "init" ]; then
 | |
|         args=("${args[@]}" --init)
 | |
|     elif [ "$action" == "verify" ]; then
 | |
|         args=("${args[@]}" --verify)
 | |
|     elif [ "$action" == "create" ]; then
 | |
|         is_yes "$create_verbose" &&
 | |
|         args=("${args[@]}" --create) ||
 | |
|         args=("${args[@]}" -c)
 | |
|     elif [ "$action" == "runs" ]; then
 | |
|         if [ "$RUNSACTION" == "runs_action_run" ]; then
 | |
|             :
 | |
|         elif [ "$RUNSACTION" == "runs_action_desc" ]; then
 | |
|             args=("${args[@]}" --desc-only)
 | |
|         elif [ "$RUNSACTION" == "runs_action_dump" ]; then
 | |
|             args=("${args[@]}" --dump)
 | |
|         else
 | |
|             ewarn "RUNSACTION inconnu: $RUNSACTION"
 | |
|         fi
 | |
|     else
 | |
|         ewarn "action inconnue: $action"
 | |
|     fi
 | |
|     for rscript in "${rscripts[@]}"; do
 | |
|         args=("${args[@]}" -f "$rscript")
 | |
|     done
 | |
|     for recipe in "${recipes[@]}"; do
 | |
|         args=("${args[@]}" -r "$recipe")
 | |
|     done
 | |
|     args=("${args[@]}" ${runshost:+-h "$runshost"}
 | |
|         ${runssysname:+--sysname "$runssysname"} ${runssysdist:+--sysdist "$runssysdist"} ${runssysver:+--sysver "$runssysver"} ${runsbits:+--bits "$runsbits"}
 | |
|         ${RUNSSCRIPTSPATH:+--runsscriptspath "$RUNSSCRIPTSPATH"}
 | |
|         ${RUNSMODULESPATH:+--runsmodulespath "$RUNSMODULESPATH"}
 | |
|         ${RUNSHOSTSPATH:+--runshostspath "$RUNSHOSTSPATH"}
 | |
|         ${runsexportdir:+--runsexportdir "$runsexportdir"} ${runsworkdir:+--runsworkdir "$runsworkdir"}
 | |
|         ${runsvarsfile:+--runsvarsfile "$runsvarsfile"}
 | |
|         ${RUNSRESET:+-z})
 | |
|     # puis relancer le script en root
 | |
|     run_as root "${args[@]}" -- "$@"
 | |
| fi
 | |
| 
 | |
| # si on donne un chemin relatif à '.' ou '..' ou un chemin absolu, forcer -f
 | |
| if [ -z "${rscripts[*]}" -a -z "${recipes[*]}" -a -n "$1" ]; then
 | |
|     if withpath "$1"; then
 | |
|         rscripts=("$1")
 | |
|         shift
 | |
|     fi
 | |
| fi
 | |
| 
 | |
| ################################################################################
 | |
| if [ "$action" == "init" -o "$action" == "verify" ]; then
 | |
|     if [ "$init_sysinfos" == "--NOT-SET--" ]; then
 | |
|         init_sysinfos=
 | |
|     elif [ -z "$init_sysinfos" ]; then
 | |
|         # Valeur par défaut de sysinfos pour l'hôte courant
 | |
|         init_sysinfos="\
 | |
| sysname=(${MYSYSNAME[*]})
 | |
| sysdist=(${MYSYSDIST[*]})
 | |
| sysver=(${MYSYSVER[*]})
 | |
| bits=$MYBITS"
 | |
|     fi
 | |
| 
 | |
|     __runs_setpath
 | |
|     [ -n "${RUNSHOSTSDIRS[*]}" ] || runs_path_required RUNSHOSTSPATH
 | |
|     runshost="${runshost:-$RUNSHOST}"
 | |
| 
 | |
|     resolv_ips __runs_ips "$runshost"
 | |
|     if [ -z "${__runs_ips[*]}" ]; then
 | |
|         check_interaction -c && eerror "$runshost ne semble pas être une adresse valide."
 | |
|         ask_yesno "Voulez-vous réellement utiliser cette adresse, bien qu'elle n'existe pas dans le DNS?" C || die
 | |
|     fi
 | |
| 
 | |
|     if [ "$action" == "init" ]; then
 | |
|         etitle "$runshost" runs_initdir "$runshost" "$create_verbose" "$init_sysinfos"
 | |
|     fi
 | |
| 
 | |
| ################################################################################
 | |
| elif [ "$action" == "create" ]; then
 | |
|     __runs_setpath
 | |
|     if [ -n "$runshost" ]; then
 | |
|         [ -n "${RUNSHOSTSDIRS[*]}" ] || runs_path_required RUNSHOSTSPATH
 | |
|         etitle "$runshost" runs_initdir "$runshost" "$create_verbose"
 | |
|     fi
 | |
| 
 | |
|     # générer les scripts spécifié
 | |
|     overwrite=no
 | |
|     error=
 | |
|     new_rscripts=()
 | |
|     for rscript in "$@"; do
 | |
|         etitle "$(ppath "$rscript")" runs_create_rscript "$rscript" "$runshost" "$create_verbose" "$overwrite" || error=1
 | |
|     done
 | |
| 
 | |
|     # Puis éditer les fichiers nouvellement créés
 | |
|     if [ -z "$error" -a -n "${new_rscripts[*]}" ]; then
 | |
|         etitle "Edition des fichiers"
 | |
|         if ask_yesno "Voulez-vous éditer le script nouvellement créé?" O; then
 | |
|             "${EDITOR:-vi}" "${new_rscripts[@]}"
 | |
|         fi
 | |
|         eend
 | |
|     fi
 | |
| 
 | |
| ################################################################################
 | |
| elif [ "$action" == "list" ]; then
 | |
|     function find_items() {
 | |
|         # Trouver tous les scripts runs et les répertoire uinstallable à partir
 | |
|         # du répertoire $2, et mettre les chemins dans le tableau $1
 | |
|         local dest="$1"
 | |
|         local runsdir="$2"
 | |
|         # $3 est un préfixe à enlever des chemins, pour qu'ils soient exprimés
 | |
|         # relativement à un chemin qui vaut $2 par défaut
 | |
|         local prefix="${3:-$runsdir/}"
 | |
|         local items item
 | |
| 
 | |
|         [ -d "$runsdir" ] || return
 | |
|         array_lsall items "$runsdir"
 | |
|         for item in "${items[@]}"; do
 | |
|             if __runs_is_runsscript "$item"; then
 | |
|                 array_add "$dest" "${item#$prefix}"
 | |
|             elif [ -d "$item" ]; then
 | |
|                 find_items "$dest" "$item" "$prefix"
 | |
|             fi
 | |
|         done
 | |
|     }
 | |
| 
 | |
|     __runs_setpath
 | |
|     [ -n "${RUNSSCRIPTSDIRS[*]}" ] || runs_path_undefined RUNSSCRIPTSPATH
 | |
|     [ -n "${RUNSMODULESDIRS[*]}" ] || runs_path_undefined RUNSMODULESPATH
 | |
|     [ -z "$runshost" -o -n "${RUNSHOSTSDIRS[*]}" ] || runs_path_undefined RUNSHOSTSPATH
 | |
| 
 | |
|     splithost "$runshost" hostname domain
 | |
| 
 | |
|     # chercher tous les scripts runs et les répertoires uinstallables
 | |
|     rscriptpaths=()
 | |
|     if [ -n "$runshost" ]; then
 | |
|         for runsdir in "${RUNSHOSTSDIRS[@]}"; do
 | |
|             find_items rscriptpaths "$runsdir/$runshost/runs"
 | |
|             find_items rscriptpaths "$runsdir/$domain/$hostname/runs"
 | |
|             find_items rscriptpaths "$runsdir/$runshost"
 | |
|             find_items rscriptpaths "$runsdir/$domain/$hostname"
 | |
|         done
 | |
|     fi
 | |
|     for runsdir in "${RUNSSCRIPTSDIRS[@]}" "${RUNSMODULESDIRS[@]}"; do
 | |
|         find_items rscriptpaths "$runsdir"
 | |
|     done
 | |
| 
 | |
|     # les trier en enlevant les doublons, recalculer le nom canonique
 | |
|     # RUNSSCRIPT, puis les afficher
 | |
|     array_from_lines rscriptpaths "$(array_to_lines rscriptpaths | sort -u)"
 | |
|     for rscriptpath in "${rscriptpaths[@]}"; do
 | |
|         runs_find_scriptfile "$rscriptpath" "$runshost" || continue
 | |
|         if [ -n "$*" ]; then
 | |
|             # filtrer
 | |
|             match=
 | |
|             for filter in "$@"; do
 | |
|                 [[ "$filter" == *\** ]] || filter="$filter*"
 | |
|                 eval "[[ \"\$rscriptpath\" == $filter ]] && match=1"
 | |
|             done
 | |
|             [ -n "$match" ] || continue
 | |
|         fi
 | |
|         if is_yes "$list_verbose"; then
 | |
|             echo "$rscriptpath $RUNSSCRIPT"
 | |
|         else
 | |
|             echo "$rscriptpath"
 | |
|         fi
 | |
|     done
 | |
| 
 | |
| ################################################################################
 | |
| elif [ "$action" == "runs" ]; then
 | |
|     __runs_setpath
 | |
|     if [ -z "${rscripts[*]}" -a -z "${recipes[*]}" ]; then
 | |
|         # sans les options -f et -r, prendre par défaut le répertoire courant
 | |
|         # comme répertoire de script, de module et d'hôtes
 | |
|         refix=
 | |
|         [ -n "${RUNSSCRIPTSDIRS[*]}" ] || {
 | |
|             runs_path_undefined RUNSSCRIPTSPATH
 | |
|             setx RUNSSCRIPTSPATH=pwd
 | |
|             refix=1
 | |
|         }
 | |
|         [ -n "${RUNSMODULESDIRS[*]}" ] || {
 | |
|             runs_path_undefined RUNSMODULESPATH
 | |
|             setx RUNSMODULESPATH=pwd
 | |
|             refix=1
 | |
|         }
 | |
|         [ -z "$runshost" -o -n "${RUNSHOSTSDIRS[*]}" ] || {
 | |
|             runs_path_undefined RUNSHOSTSPATH
 | |
|             setx RUNSHOSTSPATH=pwd
 | |
|             refix=1
 | |
|         }
 | |
|         [ -n "$refix" ] && __runs_setpath
 | |
|     fi
 | |
| 
 | |
|     # initialisation
 | |
|     [ -f "$runsvarsfile" ] && source "$runsvarsfile"
 | |
|     runs_initsysinfos "$runssysname" "$runssysdist" "$runssysver" "$runsbits"
 | |
|     runs_initworkdir "$runsexportdir" "$runsworkdir" "$scriptdir"
 | |
| 
 | |
|     if [ -n "${rscripts[*]}" ]; then
 | |
|         # scripts individuels
 | |
|         for rscript in "${rscripts[@]}"; do
 | |
|             etitle "$(ppath "$rscript")" \
 | |
|                 runs_rscript "$rscript" "$@" || die "Arrêt du déploiement"
 | |
|         done
 | |
| 
 | |
|     elif [ -n "${recipes[*]}" ]; then
 | |
|         # fichiers de recette
 | |
|         for recipe in "${recipes[@]}"; do
 | |
|             [ -f "$recipe" ] || die "$recipe: fichier introuvable"
 | |
|             etitle "$(ppath "$recipe")" \
 | |
|                 runs_recipe "$recipe" "$@" || die "Arrêt du déploiement"
 | |
|         done
 | |
| 
 | |
|     else
 | |
|         # suite de scripts et/ou de recettes séparés par --
 | |
|         # note: si on spécifie plusieurs scripts séparés par --, il faut le
 | |
|         # faire de cette manière:
 | |
|         #     runs -- script1 ... -- script2 ... -- @recipe ...
 | |
|         # le premier -- est important, il permet de ne pas traiter les arguments
 | |
|         # suivants, et donc de ne pas fusionner les valeurs script1 avec script2
 | |
|         while [ -n "$1" ]; do
 | |
|             if [ "$1" == -- ]; then
 | |
|                 shift
 | |
|                 continue
 | |
|             elif [ "${1#@}" != "$1" ]; then
 | |
|                 # recette à chercher dans RUNSSCRIPTSPATH
 | |
|                 # prendre les arguments jusqu'à --
 | |
|                 recipe="${1#@}"; shift
 | |
|                 args=()
 | |
|                 while [ -n "$1" -a "$1" != "--" ]; do
 | |
|                     args=("${args[@]}" "$1")
 | |
|                     shift
 | |
|                 done
 | |
|                 etitle "@$recipe" \
 | |
|                     runs_recipepath "$recipe" "${args[@]}" || die "Arrêt du déploiement"
 | |
|                 shift
 | |
|             else
 | |
|                 # script à chercher dans RUNSSCRIPTSPATH
 | |
|                 # prendre les arguments jusqu'à --
 | |
|                 args=()
 | |
|                 while [ -n "$1" -a "$1" != "--" ]; do
 | |
|                     args=("${args[@]}" "$1")
 | |
|                     shift
 | |
|                 done
 | |
|                 etitle "${args[0]}" \
 | |
|                     runs_rscriptpath "${args[@]}" || die "Arrêt du déploiement"
 | |
|             fi
 | |
|         done
 | |
|     fi
 | |
| 
 | |
|     # traitement après déploiement
 | |
|     runs_after_export
 | |
| fi
 |