déploiement d'application webpyapp
This commit is contained in:
parent
1c3c07f8b2
commit
7356c1da73
|
@ -0,0 +1,312 @@
|
|||
#!/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
|
||||
|
||||
function display_help() {
|
||||
uecho "$scriptname: Déploiement distant avec wyinst
|
||||
|
||||
USAGE
|
||||
$scriptname [-h host] [-G tmproot] <archive|dir> [-- options de wyinst]
|
||||
|
||||
note: à cause d'une limitation de makeself, les options de wyinst 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.
|
||||
--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 'wyinst.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
|
||||
}
|
||||
|
||||
action=deploy
|
||||
tmproot=
|
||||
SSH=
|
||||
hosts=()
|
||||
ddb_enable=1
|
||||
ddb_profile=NONE
|
||||
ddb_conf=wyinst.conf
|
||||
parse_opts "${PRETTYOPTS[@]}" \
|
||||
--help '$exit_with display_help' \
|
||||
-G:,--tmproot: tmproot= \
|
||||
-S:,--ssh: SSH= \
|
||||
-h:,-H:,--host: hosts \
|
||||
--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}"
|
||||
|
||||
## wyapp à 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" == -* ]]; then
|
||||
# pas d'argument, ou c'est une option (qui fait donc partie des arguments de wyinst)
|
||||
has_wyapp=
|
||||
else
|
||||
wyapp="$1"
|
||||
has_wyapp=1
|
||||
shift
|
||||
fi
|
||||
|
||||
# configuration locale de déploiement
|
||||
if [ -n "$ddb_enable" ]; then
|
||||
deploydb=(
|
||||
"$scriptdir/lib/nulib/deploydb"
|
||||
--missing-ok
|
||||
${ddb_conf:+-c "$ddb_conf"}
|
||||
-m wyinst
|
||||
--run -r wyinst.query_rwyinst "$script"
|
||||
)
|
||||
cmds=()
|
||||
if [ -n "$has_hosts" ]; then
|
||||
fix_hosts
|
||||
for host in "${hosts[@]}"; do
|
||||
array_from_lines tmpcmds "$("${deploydb[@]}" "$wyapp" "$host" "$ddb_profile")"
|
||||
array_extend cmds tmpcmds
|
||||
done
|
||||
elif [ -n "$has_wyapp" ]; then
|
||||
array_from_lines tmpcmds "$("${deploydb[@]}" "$wyapp" "" "$ddb_profile")"
|
||||
array_extend cmds tmpcmds
|
||||
else
|
||||
read_value "Entrez le répertoire à déployer" wyapp . O
|
||||
has_wyapp=1
|
||||
array_from_lines tmpcmds "$("${deploydb[@]}" "$wyapp" "" "$ddb_profile")"
|
||||
array_extend cmds tmpcmds
|
||||
fi
|
||||
if [ ${#cmds[*]} -gt 0 ]; then
|
||||
[ $# -gt 0 ] && ewarn "Les options supplémentaires '$*' 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
|
||||
|
||||
## Répertoires à déployer et hôtes sur lesquels faire le déploiement
|
||||
|
||||
if [ -z "$has_wyapp" ]; then
|
||||
# pas d'argument, ou c'est une option (qui fait donc partie des arguments de wyinst)
|
||||
read_value "Entrez le répertoire à déployer" wyapp . O
|
||||
has_wyapp=1
|
||||
fi
|
||||
[ -n "$has_wyapp" ] && set -- "$wyapp" "$@"
|
||||
|
||||
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
|
||||
wyapps=()
|
||||
while [ $# -gt 0 ]; do
|
||||
if [ "$1" == "--" ]; then
|
||||
# début des options de wyinst
|
||||
shift
|
||||
break
|
||||
elif [[ "$1" == -* ]]; then
|
||||
# début des options de wyinst
|
||||
break
|
||||
fi
|
||||
|
||||
osrc="$1"; shift
|
||||
setx src=abspath "$osrc"
|
||||
setx srcname=basename -- "$src"
|
||||
if [ -f "$src" ] && is_archive "$src"; then
|
||||
setx waname=get_archive_appname "$src"
|
||||
estep "$(ppath "$src") --> $waname"
|
||||
wadir="$workdir/$waname"
|
||||
mkdir "$wadir"
|
||||
extract_archive "$src" "$wadir" || die
|
||||
src="$wadir"
|
||||
elif [ -d "$src" ]; then
|
||||
estep "$(ppath2 "$src")"
|
||||
cpdirnovcs "$src" "$workdir/$srcname" || die
|
||||
elif [ -e "$src" ]; then
|
||||
die "$osrc: fichier invalide"
|
||||
else
|
||||
die "$osrc: fichier ou répertoire introuvable"
|
||||
fi
|
||||
|
||||
array_add wyapps "$srcname"
|
||||
done
|
||||
|
||||
estep "Copie de l'environnement de déploiement"
|
||||
mkdir "$workdir/lib"
|
||||
ulibsync "$workdir/lib"
|
||||
cp "$scriptdir/wyinst" "$workdir"
|
||||
chmod +x "$workdir/wyinst"
|
||||
|
||||
eend
|
||||
|
||||
ac_set_tmpfile archive
|
||||
archivename="$(basename "$archive")"
|
||||
|
||||
etitle "Création de l'archive pour le déploiement"
|
||||
"$scriptdir/mkusfx" --bare --tmp-archive -o "$archive" "$workdir" -- ./wyinst || die
|
||||
eend
|
||||
|
||||
## Déploiement
|
||||
|
||||
# sur l'hôte distant, ne rendre non interactif qu'à partir de -yy
|
||||
rinteraction=$__interaction
|
||||
[ $rinteraction -lt 2 ] && rinteraction=$(($rinteraction + 1))
|
||||
|
||||
for host in "${hosts[@]}"; do
|
||||
if [ "$host" == "localhost" ]; then
|
||||
etitle "Déploiement sur l'hôte local"
|
||||
"$archive" ${tmproot:+--tmproot "$tmproot"} -- "${wyapps[@]}" "$@"
|
||||
eend
|
||||
else
|
||||
splituserhost "$host" user host
|
||||
[ -n "$user" ] || user=root
|
||||
|
||||
etitle -s "Déploiement sur $user@$host"
|
||||
|
||||
estep "Copie de l'archive"
|
||||
scp -S "$SSH" "$archive" "$user@$host:" || die
|
||||
|
||||
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"} -- "${wyapps[@]}" "$@")"
|
||||
|
||||
eend
|
||||
fi
|
||||
done
|
|
@ -0,0 +1,198 @@
|
|||
#!/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 debian service conf
|
||||
|
||||
function display_help() {
|
||||
uecho "$scriptname: installer une webpyapp et le service associé
|
||||
|
||||
USAGE
|
||||
$scriptname [options] [APPDIR]
|
||||
|
||||
OPTIONS
|
||||
-c, --config CONFIG
|
||||
Spécifier un fichier de configuration à utiliser pour installer le
|
||||
service. Par défaut, prendre APPDIR/config/server.conf
|
||||
-n, --name NAME
|
||||
Spécifier le nom du service
|
||||
--port PORT
|
||||
Spécifier le port sur lequel doit écouter le serveur
|
||||
-p, --profile PROFILE
|
||||
Spécifier le profil avec lequel l'application doit tourner
|
||||
-P, --prod-profile
|
||||
-T, --test-profile
|
||||
Raccourcis pour -pprod et -ptest respectivement
|
||||
-u, --owner USER[:GROUP]
|
||||
Spécifier l'utilisateur qui doit faire tourner le serveur. La valeur par
|
||||
défaut est $DEFAULT_OWNER
|
||||
-d, --destdir DESTDIR
|
||||
Spécifier le répertoire d'installation. Par défaut, l'installation se
|
||||
fait dans le répertoire $DEFAULT_DESTDIR
|
||||
-s, --start
|
||||
Activer et démarrer le service après installation
|
||||
-k, --no-restart
|
||||
Ne pas redémarrer le service s'il était déjà en train de tourner"
|
||||
}
|
||||
|
||||
DEFAULT_DESTDIR=/opt
|
||||
DEFAULT_OWNER=root
|
||||
DEFAULT_PYTHON=python2.7
|
||||
|
||||
serverconf=
|
||||
name=
|
||||
port=
|
||||
profile=
|
||||
owner=
|
||||
mode=u=rwX,go=rX
|
||||
destdir=
|
||||
overwrite_config=
|
||||
enable=
|
||||
start=
|
||||
norestart=
|
||||
args=(
|
||||
--help '$exit_with display_help'
|
||||
-c:,--config: serverconf=
|
||||
-n:,--name: name=
|
||||
--port: port=
|
||||
-p:,--profile: profile=
|
||||
-P,--prod-profile profile=prod
|
||||
-T,--test-profile profile=test
|
||||
-u:,--owner: owner=
|
||||
-d:,--destdir: destdir=
|
||||
--overwrite-config overwrite_config=1
|
||||
-s,--start '$enable=1; start=1'
|
||||
-k,--no-restart norestart=1
|
||||
)
|
||||
parse_args "$@"; set -- "${args[@]}"
|
||||
|
||||
appdir="${1:-.}"; shift
|
||||
[ -d "$appdir" ] || die "$appdir: répertoire inexistant"
|
||||
[ -d "$appdir/config" -a -d "$appdir/python" ] || die "$appdir: ne semble pas être une webpyapp"
|
||||
setx appdir=abspath "$appdir"
|
||||
|
||||
[ -n "$serverconf" ] || serverconf="$appdir/config/server.conf"
|
||||
[ -f "$serverconf" ] || die "$(ppath "$serverconf"): impossible de trouver le fichier de configuration"
|
||||
NAME=
|
||||
PORT=
|
||||
PROFILE=
|
||||
OWNER=
|
||||
VIRTUAL_ENV=
|
||||
PYTHON=
|
||||
source "$serverconf"
|
||||
|
||||
[ -n "$name" ] || name="$NAME"
|
||||
[ -n "$name" ] || setx name=basename "$appdir"
|
||||
[ -n "$port" ] || port="$PORT"
|
||||
[ -n "$profile" ] || profile="$PROFILE"
|
||||
[ -n "$owner" ] || owner="$OWNER"
|
||||
[ -n "$destdir" ] || destdir="$DEFAULT_DESTDIR"
|
||||
run_as_root -c "$serverconf" -n "$name" ${port:+--port "$port"} \
|
||||
${profile:+-p "$profile"} \
|
||||
${owner:+-u "$owner"} \
|
||||
-d "$destdir" ${overwrite_config:+--overwrite-config} \
|
||||
${start:+-s} ${norestart:+-k} \
|
||||
"$appdir" "$@"
|
||||
|
||||
: "${PYTHON:=$DEFAULT_PYTHON}"
|
||||
if [ -n "$VIRTUAL_ENV" ]; then
|
||||
etitle "Environnement virtuel"
|
||||
packages=(python-virtualenv)
|
||||
if ! pkg_check "${packages[@]}"; then
|
||||
estep "Installation ${packages[*]}"
|
||||
pkg_install "${packages[@]}" || die
|
||||
fi
|
||||
if [ ! -d "$VIRTUAL_ENV" ]; then
|
||||
estep "Installation dans $VIRTUAL_ENV"
|
||||
virtualenv -p "$PYTHON" "$VIRTUAL_ENV" || die
|
||||
fi
|
||||
eend
|
||||
fi
|
||||
[ -n "$VIRTUAL_ENV" ] && PYTHON="$VIRTUAL_ENV/bin/python"
|
||||
|
||||
restart=
|
||||
if [ -z "$norestart" ]; then
|
||||
if service "$name" check; then
|
||||
estep "Arrêt du service"
|
||||
service "$name" stop
|
||||
start=1
|
||||
restart=1
|
||||
fi
|
||||
fi
|
||||
|
||||
etitle "Copie des fichiers"
|
||||
destdir="$destdir/$name"
|
||||
mkdir -p "$destdir" || die
|
||||
rsync -a --delete-after \
|
||||
--exclude /config/ --exclude /nulib --exclude /.devel \
|
||||
-f "P /var/**" \
|
||||
"$appdir/" "$destdir"
|
||||
eend
|
||||
|
||||
etitle "Vérification de la configuration"
|
||||
estep "Dans $destdir/config:"
|
||||
array_from_lines configs "$(list_files "$appdir/config")"
|
||||
for config in "${configs[@]}"; do
|
||||
if [ -n "$overwrite_config" -o ! -f "$destdir/config/$config" ]; then
|
||||
estepi "$config: copie initiale"
|
||||
mkdir -p "$destdir/config"
|
||||
if [ "$config" == server.conf ]; then
|
||||
# pour ce cas particulier, prendre le fichier $serverconf
|
||||
cp "$serverconf" "$destdir/config/$config"
|
||||
estep "Mise à jour de la configuration"
|
||||
conf_enable "$destdir/config/$config" \
|
||||
NAME="$name" ${port:+PORT="$port"} \
|
||||
${profile:+PROFILE="$profile"} \
|
||||
${owner:+OWNER="$owner"}
|
||||
else
|
||||
cp "$appdir/config/$config" "$destdir/config/$config"
|
||||
fi
|
||||
else
|
||||
estepw "$config: refus d'écraser la configuration existante"
|
||||
fi
|
||||
done
|
||||
eend
|
||||
|
||||
[ -n "$owner" ] || owner="$DEFAULT_OWNER"
|
||||
splitpair "$owner" user group
|
||||
sdowner="User=$user"
|
||||
[ -n "$group" ] && sdowner="$sdowner\\
|
||||
Group=$group"
|
||||
|
||||
etitle "Compilation des classes"
|
||||
"$PYTHON" -m compileall "$destdir/config"
|
||||
"$PYTHON" -m compileall "$destdir/python"
|
||||
eend
|
||||
|
||||
etitle "Correction des permissions"
|
||||
chown -R "$user:$group" "$destdir"
|
||||
chmod -R "$mode" "$destdir"
|
||||
eend
|
||||
|
||||
etitle "Configuration du service"
|
||||
estep "Vérification du fichier unit"
|
||||
if [ -d /etc/systemd/system ]; then
|
||||
service="/etc/systemd/system/$name.service"
|
||||
ac_set_tmpfile tmpfile
|
||||
sed "\
|
||||
s|@@destdir@@|$destdir|g
|
||||
/^User=@@owner@@\$/c\\
|
||||
$sdowner
|
||||
s|@@name@@|$name|g" "$destdir/support/server.service" >"$tmpfile"
|
||||
if testupdated "$tmpfile" "$service"; then
|
||||
estep "$service"
|
||||
cat "$tmpfile" >"$service"
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
ac_clean "$tmpfile"
|
||||
fi
|
||||
if [ -n "$enable" ]; then
|
||||
estep "Activation du service"
|
||||
service_enable "$name"
|
||||
fi
|
||||
if [ -n "$start" ]; then
|
||||
if [ -n "$restart" ]; then estep "Redémarrage du service"
|
||||
else estep "Démarrage du service"
|
||||
fi
|
||||
service "$name" start
|
||||
fi
|
||||
eend
|
Loading…
Reference in New Issue