379 lines
14 KiB
Bash
Executable File
379 lines
14 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
|
|
|
|
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"
|
|
}
|
|
|
|
set_defaults runs
|
|
|
|
function runs_path_required() {
|
|
die "Vous devez définir $1 dans ~/etc/default/runs"
|
|
}
|
|
|
|
action=runs
|
|
create_verbose=
|
|
init_sysinfos=--NOT-SET--
|
|
list_verbose=
|
|
run_as_root=
|
|
rscripts=()
|
|
recipes=()
|
|
runshost=
|
|
runssysname=
|
|
runssysdist=
|
|
runssysver=
|
|
runsbits=
|
|
runsscriptspath=
|
|
runsmodulespath=
|
|
runshostspath=
|
|
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' \
|
|
--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= \
|
|
--runsmodulespath: runsmodulespath= \
|
|
--runshostspath: runshostspath= \
|
|
--runsexportdir: runsexportdir= \
|
|
--runsworkdir: runsworkdir= \
|
|
--runsvarsfile: runsvarsfile= \
|
|
-z RUNSRESET=1 \
|
|
@ args -- "$@" && set -- "${args[@]}" || die "$args"
|
|
|
|
[ -n "$runsscriptspath" ] && RUNSSCRIPTSPATH="$runsscriptspath"
|
|
[ -n "$runsmodulespath" ] && RUNSMODULESPATH="$runsmodulespath"
|
|
[ -n "$runshostspath" ] && RUNSHOSTSPATH="$runshostspath"
|
|
|
|
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
|
|
|
|
if ! is_root && [ -n "$run_as_root" ]; then
|
|
# reconstruire la ligne de commande
|
|
args=()
|
|
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
|
|
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?" N || die
|
|
fi
|
|
|
|
if [ "$action" == "init" ]; then
|
|
etitle "$runshost" runs_initdir "$runshost" "$create_verbose" "$init_sysinfos"
|
|
fi
|
|
|
|
################################################################################
|
|
elif [ "$action" == "create" ]; then
|
|
if [ -n "$runshost" ]; then
|
|
__runs_setpath
|
|
[ -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_required RUNSSCRIPTSPATH
|
|
[ -n "${RUNSMODULESDIRS[*]}" ] || runs_path_required RUNSMODULESPATH
|
|
[ -z "$runshost" -o -n "${RUNSHOSTSDIRS[*]}" ] || runs_path_required 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"
|
|
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
|
|
if [ -n "${rscripts[*]}" ]; then
|
|
# sans l'option -f, il faut définir RUNS*PATH
|
|
__runs_setpath
|
|
[ -n "${RUNSSCRIPTSDIRS[*]}" ] || runs_path_required RUNSSCRIPTSPATH
|
|
[ -n "${RUNSMODULESDIRS[*]}" ] || runs_path_required RUNSMODULESPATH
|
|
[ -z "$runshost" -o -n "${RUNSHOSTSDIRS[*]}" ] || runs_path_required RUNSHOSTSPATH
|
|
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
|