nutools/runs

379 lines
14 KiB
Plaintext
Raw Normal View History

2013-08-27 15:14:44 +04:00
#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
2014-07-07 22:06:38 +04:00
source "$(dirname "$0")/lib/ulib/ulib" || exit 1
urequire DEFAULTS runs
2013-08-27 15:14:44 +04:00
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