nutools/dk

1699 lines
59 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/auto" || exit 1
urequire pff
function display_help() {
uecho "$scriptname: outil pour faciliter l'utilisation de docker
USAGE
$scriptname CMDs...
COMMANDES
b|build [SERVICE]
Construire les images
p|push
p|push [SERVICES...]
La première syntaxe est utilisable avec un projet docker. Elle permet de
pousser l'image qui a été construite avec build vers le serveur
La deuxième syntaxe est utilisée avec un projet docker-compose. Elle
permet de pousser les images correspondant aux services qui ont été
construit vers le serveur.
s|start [SERVICE]
Démarrer le(s) service(s)
k|stop [SERVICE]
Arrêter le(s) service(s)
1|up
Créer l'environnement, démarrer les services et suivre les logs de façon
interactive.
Vaguement équivalent à -- start -- logs
l|logs [SERVICE]
Afficher les logs
0|down
Arrêter les services et supprimer l'environnement
r|run SERVICE [COMMAND]
Démarrer le service en mode interactif avec la commande spécifiée
Les options suivantes sont supportées, mais il faut les spécifier avant
SERVICE:
* pour docker et docker-compose: --volume
* uniquement pour docker-compose: --detach, -e, --label, --no-deps,
--service-ports, --use-aliases
Par défaut, --rm est activé; utiliser --no-rm pour ne pas supprimer le
container après utilisation.
x|exec SERVICE COMMAND
Lancer une commande dans le container correspondant au service spécifié,
qui doit être en fonctionnement
d|brd
Construire les images (comme avec build), démarrer les services et
suivre les logs de façon interactive (comme avec up). Dès que l'on
arrête l'affichage des logs avec Ctrl+C, arrêter les services et
supprimer l'environnement (comme avec down)
Vaguement équivalent à -- build -- start [args] -- logs
suivi de -- down
bs
Construire les images (comme avec build) puis démarrer les services
(comme avec start)
Equivalent à -- build -- start [args]
br SERVICE [COMMAND]
Construire les images (comme avec build) puis démarrer le service avec
la commande spécifiée (comme avec run)
Equivalent à -- build -- run [args]
y|deploy [args...]
(Re)déployer un stack. Cette commande ne fonctionne qu'en mode swarm.
Implique --stack
by|bd [args...]
Equivalent à --stack -- build -- deploy args...
Utilisable notamment en développement
bp [args...]
Equivalent à --stack -- build -- push args...
bpy|bpd [args...]
Equivalent à --stack -- build -- push -- deploy args...
service COMMAND SERVICE [args...]
Frontend pour 'docker service COMMAND args... SERVICE'
Cette commande ne fonctionne qu'en mode swarm. Il n'est pas nécessaire
de préfixer le nom du service avec le nom du stack, pour être cohérent
avec les autres commandes
IMPORTANT: notez que les arguments sont placés avant le nom du service.
Celà signifie qu'on ne peut spécifier que des options à la commande.
Penser aussi à protéger ces options de l'analyse eg.
$scriptname -- service logs web -f
Pour des cas d'utilisation plus complexe, il faut lancer directement
docker service
u|update SERVICE [args...]
Mettre à jour un service, équivalent à 'service update SERVICE'
scale SERVICE=REPLICAS [args...]
Mettre à jour le nom de réplicas d'un service, équivalent à la commande
'service scale SERVICE=REPLICAS'
ip|show-ip [SERVICE]
Afficher l'adresse IP interne du service
systemd|systemd-unit
Générer une unité systemd qui démarre les services. A priori, ce n'est
nécessaire que si aucune politique de redémarrage n'a été définie.
ps [filter|name=value]
Afficher les containers en cours d'exécution
Le filtre est une expression régulière de type awk qui est mise en
correspondace avec les noms de l'image et de la tâche.
Il est aussi possible d'utiliser un filtre docker de la forme name=value
- ancestor=(<image-name>[:tag]|<image-id>| <image@digest>)
containers created from an image or a descendant.
- before=(<container-name>|<container-id>)
- expose=(<port>[/<proto>]|<startport-endport>/[<proto>])
- exited=<int> an exit code of <int>
- health=(starting|healthy|unhealthy|none)
- id=<ID> a container's ID
- is-task=(true|false)
- label=<key> or label=<key>=<value>
- name=<string> a container's name
- network=(<network-id>|<network-name>)
- publish=(<port>[/<proto>]|<startport-endport>/[<proto>])
- since=(<container-name>|<container-id>)
- status=(created|restarting|removing|running|paused|exited)
- volume=(<volume name>|<mount point destination>)
ls [filter|name=value]
Lister les images actuellement présentes
Le filtre est une expression régulière de type awk qui est mise en
correspondance avec le nom de l'image. Un suffixe :tag permet de ne
sélectionner que les images correspondant au filtre qui ont le tag
spécifié.
Il est aussi possible d'utiliser un filtre docker de la forme name=value
- dangling=(true|false) - find unused images
- label=<key> or label=<key>=<value>
- before=(<image-name>[:tag]|<image-id>| <image@digest>)
- since=(<image-name>[:tag]|<image-id>| <image@digest>)
- reference=(pattern of an image reference)
pull filter
Mettre à jour une ou plusieurs images
Le filtre est une expression régulière de type awk qui est mise en
correspondance avec le nom de l'image. Un suffixe :tag permet de ne
sélectionner que les images correspondant au filtre qui ont le tag
spécifié.
rm filter
Supprimer une ou plusieurs images
Le filtre est une expression régulière de type awk qui est mise en
correspondance avec le nom de l'image. Un suffixe :tag permet de ne
sélectionner que les images correspondant au filtre qui ont le tag
spécifié.
X|prune
Supprimer les containers et les images inutilisées
composer|ci|cu|cs [args...]
Frontend pour lancer composer à l'intérieur d'un container. Les
commandes 'ci', 'cu' et 'cs' sont respectivement des alias pour
'composer install', 'composer update' et 'composer shell'
Le répertoire \$HOME est monté à l'intérieur du container et le script
composer.phar du projet est utilisé le cas échéant.
L'image utilisée pour lancer composer est indiquée par la variable
d'environnement COMPOSER_IMAGE et vaut par défaut:
$DEFAULT_COMPOSER_IMAGE
Cette image doit disposer de la commande 'su-exec' afin de pouvoir
lancer la commande avec l'utilisateur courant.
La commande shell est une extension qui lance un shell bash au lieu de
lancer la commande composer, ce qui permet de faire des opérations plus
complexes si le besoin s'en fait sentir.
OPTIONS générales
(ces options sont communes à toutes les commandes)
-d, --chdir PROJDIR
Spécifier le répertoire du projet
-c, --config CONFIG[.yml]
Spécifier le fichier de configuration à utiliser. le fichier de profil
CONFIG.PROFILE.yml est chargé aussi s'il existe.
NB: il n'est pas nécessaire d'ajouter l'extension .yml au nom, cela
permet de faciliter l'utilisation avec l'auto-complétion quand il existe
des fichiers de profil
Si cette option n'est pas spécifiée, docker-compose.yml est utilisé par
défaut (ou avec l'option --stack docker-stack.yml s'il existe)
-p, --profile PROFILE
-P, --prod
-T, --test
Spécifier le profil
-m, --set-machine MACHINE
Choisir l'environnement docker-machine spécifié avant de lancer les
commandes. Utiliser -u pour desélectionner la machine en cours, e.g -m-u
-n, --fake
Ne pas lancer les commandes, simplement les afficher
-h, --host HOST
Spécifier l'hôte pour la commande systemd-unit
OPTIONS build
(ces options ne sont valides que pour les commandes build, brd, bs, bd, bpd)
--stack
Indiquer que le build est fait pour un déploiement avec deploy.
S'il existe un fichier docker-stack.yml, il est utilisé de préférence à
la place de docker-compose.yml. De même, les fichiers de profil de la
forme docker-stack.PROFILE.yml sont utilisés de préférence aux fichiers
docker-compose.PROFILE.yml
Cette option n'est nécessaire qu'avec build puisque les commandes
deploy, bd, bpd et update impliquent --stack
-j, --no-cache
Ne pas utiliser le cache lors du build
-g, --ug, --no-update-apps
ne pas mettre à jour les dépôts dépendants. ces dépôts sont définis dans
le fichier update-apps.conf qui a le format suivant:
DEFAULT_ORIGIN=
DEFAULT_BRANCH=
DEFAULT_DEVEL_SRCDIR=
APPS=() # liste d'applications à mettre à jour
app_URL= # url du dépôt
app_DEVEL_SRCDIR= # répertoire source en mode devel
app_DEST= # répertoire dans lequel faire le checkout
app_PROFILE_ORIGIN= # origine spécifique au profil 'PROFILE'
app_PROFILE_BRANCH= # branche spécifique au profil 'PROFILE'
app_ORIGIN= # ou... origine par défaut de la branche
app_BRANCH= # ou... branche par défaut
app_TYPE= # type de projet (composer par défaut)
app_AFTER_UPDATE=() # liste de commandes à lancer après le checkout
-u, --uu, --update-apps-only
Ne faire que la mise à jour depuis les dépôts dépendants.
-w, --ww, --update-apps-devel
Faire la mise à jour en mode devel: le projet ainsi que ses fichiers des
répertoires vendor/lib et vendor/ur sont synchronisés via rsync depuis
\$DEFAULT_DEVEL_SRCDIR qui vaut par défaut \$HOME/wop/php
--uo, --update-apps-origin ORIGIN
Spécifier l'origine par défaut pour update-apps
--ub, --update-apps-branch BRANCH
Spécifier la branche par défaut pour update-apps
OPTIONS deploy
-l, --without-registry-auth
Ne pas transporter les informations d'autorisation aux agents swarm
(c'est à dire ne pas utiliser l'option --with-registry-auth)
VARIABLES de update-apps.conf
DEVEL_SRCDIR
répertoire source pour le mode devel. attention, il s'agit du répertoire
du projet, alors que DEFAULT_DEVEL_SRCDIR est le répertoire de base par
défaut des projets
ORIGIN
vaut 'origin' par défaut
BRANCH
vaut 'develop' par défaut
TYPE
vaut 'composer' par défaut si le fichier composer.json existe à la
racine du projet. sinon vaut 'inconnu' par défaut
AFTER_UPDATE
Cette variable est une liste de commandes à lancer après la maj du dépôt
- si le chemin est absolu ou relatif, lancer la commande telle quelle
- s'il n'y a pas de chemin, alors ce doit être le nom d'une fonction
existante auquel on enlève le préfixe update_apps_func_
Au moment où la commande est lancée, le répertoire courant est celui du
projet. Les variables suivantes sont disponibles:
URL= # url du dépôt
DEVEL_SRCDIR= # répertoire source en mode devel
DEST= # répertoire dans lequel faire le checkout
ORIGIN= # ou... origine par défaut de la branche
BRANCH= # ou... branche par défaut
TYPE= # type de projet (composer par défaut)
COMPOSER_ACTION
vaut 'install' par défaut. Indique ce qu'il faut faire pour un projet de
type 'composer' après avoir lancé les commandes de AFTER_UPDATE. Les
directives supporées sont 'install', 'update' et 'none'
FONCTIONS de update-apps.conf
sqlmig [DESTDIR [SRCDIR [NOFIX]]]
Copier les définitions des bases de données au format sqlmig de
SRCDIR/config/sqlmig vers DESTDIR/config/mariadb/sqlmig
Si SRCDIR ne se termine pas par '/config/sqlmig' ou si DESTDIR ne se
termine pas par '/config/mariadb/sqlmig', rajouter ces suffixes
automatiquement, sauf si une valeur NOFIX est spécifiée.
pff [MAPS [PFFDIR]]
Si PFFDIR est un projet pff, mettre à jour le profil pff en fonction du
profil de déploiement.
MAPS détermine le mapping entre profil de déploiement (prod, test,
devel) et le profil pff. Il s'agit d'une liste de valeurs séparées par
des virgules de la forme DEST[:SRC]
- Une valeur de la forme 'DEST:SRC' fait correspondre le profil de
déploiement SRC au profil pff 'DEST'
- Une valeur de la forme 'DEST' force le choix du profil pff DEST quel
que soit le profil de déploiement
- La valeur par défaut si aucun profil de déploiement ne correspond est
de forcer le premier profil défini"
}
function echo_lines() { local IFS=$'\n'; echo "$*"; }
function get_version() {
local GIT_DIR; unset GIT_DIR
if git rev-parse --git-dir >/dev/null 2>&1; then
local head commit tag
commit="$(git rev-list --tags --max-count=1 2>/dev/null)"
if [ -n "$commit" ]; then
tag="$(git describe --tags "$commit" 2>/dev/null)"
if [ -n "$tag" ]; then
head="$(git rev-parse HEAD)"
if [ "$commit" != "$head" ]; then
echo "$tag-develop"
else
echo "$tag"
fi
return
fi
fi
elif [ -f VERSION.txt ]; then
cat VERSION.txt
fi
echo develop
}
function docker_add_build_arg() {
eval "replace_build_args+=(--build-arg $1=\"$2\"); $1=\"$2\""
}
function docker_parse_build_args() {
cat "$1" |
grep -v '^#' |
grep -v '^$' |
sed -r 's/([^=]+)=(.*)/replace_build_args+=(--build-arg \1="\2"); \1="\2"/'
}
function docker_parse_env_args() {
[ -f .build.env ] && eval "$(docker_parse_build_args .build.env)"
[ -f build.env ] && eval "$(docker_parse_build_args build.env)"
[ -n "$PROFILE" -a -f ".build.$PROFILE.env" ] && eval "$(docker_parse_build_args ".build.$PROFILE.env")"
}
function docker_set_env_args() {
[ -f .build.env ] && source ./.build.env
[ -f build.env ] && source ./build.env
[ -n "$PROFILE" -a -f ".build.$PROFILE.env" ] && source "./.build.$PROFILE.env"
}
function docker_set_run_args() {
replace_run_args+=(--env-file "$1")
source "$1"
}
function docker_check_name() {
[ -n "$NAME" ] || die "Vous devez définir NAME dans .build.env"
if [ "$1" == set_container_name ]; then
project_name="$NAME"
container_name="${project_name//[^a-zA-Z0-9_-]/}"
[ -n "$PROFILE" ] && container_name="${container_name}_$PROFILE"
fi
}
function compose_set_project_name() {
local PROJECT_NAME= PROJECT_NAME_REMOVE_SUFFIX=.service PROJECT_NAME_ADD_PROFILE=
[ -f .compose.env ] && source ./.compose.env
[ -n "$PROJECT_NAME" ] || PROJECT_NAME="$(basename -- "$(pwd)")"
PROJECT_NAME="${PROJECT_NAME%$PROJECT_NAME_REMOVE_SUFFIX}"
if [ -n "$PROFILE" ]; then
[ -n "$COMPOSE_PROJECT_NAME" ] || COMPOSE_PROJECT_NAME="$PROJECT_NAME${PROJECT_NAME_ADD_PROFILE:+_${PROFILE}}"
else
[ -n "$COMPOSE_PROJECT_NAME" ] || COMPOSE_PROJECT_NAME="$PROJECT_NAME"
fi
export COMPOSE_PROJECT_NAME
if [ "$1" == set_container_name ]; then
project_name="$PROJECT_NAME"
container_name="${project_name//[^a-zA-Z0-9_-]/}"
[ -n "$PROFILE" -a -n "$PROJECT_NAME_ADD_PROFILE" ] && container_name="${container_name}_$PROFILE"
fi
}
function compose_set_env_args() {
if [ -n "$CONFIG" ]; then
# autocomplétion friendly
[ ! -f "$CONFIG" -a -f "${CONFIG}yml" ] && CONFIG="${CONFIG}yml"
[ ! -f "$CONFIG" -a -f "$CONFIG.yml" ] && CONFIG="$CONFIG.yml"
##
replace_env_args+=(-f "$CONFIG")
if [ -n "$PROFILE" -a -f "${CONFIG%.yml}.$PROFILE.yml" ]; then
replace_env_args+=(-f "${CONFIG%.yml}.$PROFILE.yml")
fi
else
if [ -n "$USE_STACK" -a -f docker-stack.yml ]; then
replace_env_args+=(-f docker-stack.yml)
else
replace_env_args+=(-f docker-compose.yml)
fi
if [ -n "$USE_STACK" -a -f docker-stack.override.yml ]; then
replace_env_args+=(-f docker-stack.override.yml)
elif [ -f docker-compose.override.yml ]; then
replace_env_args+=(-f docker-compose.override.yml)
fi
if [ -n "$PROFILE" ]; then
if [ -n "$USE_STACK" -a -f "docker-stack.$PROFILE.yml" ]; then
replace_env_args+=(-f "docker-stack.$PROFILE.yml")
elif [ -f "docker-compose.$PROFILE.yml" ]; then
replace_env_args+=(-f "docker-compose.$PROFILE.yml")
fi
fi
fi
compose_set_project_name "$@"
}
function docker_set_deploy_args() {
if [ -n "$CONFIG" ]; then
# autocomplétion friendly
[ ! -f "$CONFIG" -a -f "${CONFIG}yml" ] && CONFIG="${CONFIG}yml"
[ ! -f "$CONFIG" -a -f "$CONFIG.yml" ] && CONFIG="$CONFIG.yml"
##
replace_deploy_args+=(-c "$CONFIG")
if [ -n "$PROFILE" -a -f "${CONFIG%.yml}.$PROFILE.yml" ]; then
replace_deploy_args+=(-c "${CONFIG%.yml}.$PROFILE.yml")
fi
else
if [ -n "$USE_STACK" -a -f docker-stack.yml ]; then
replace_deploy_args+=(-c docker-stack.yml)
else
replace_deploy_args+=(-c docker-compose.yml)
fi
if [ -n "$USE_STACK" -a -f docker-stack.override.yml ]; then
replace_deploy_args+=(-c docker-stack.override.yml)
elif [ -f docker-compose.override.yml ]; then
replace_deploy_args+=(-c docker-compose.override.yml)
fi
if [ -n "$PROFILE" ]; then
if [ -n "$USE_STACK" -a -f "docker-stack.$PROFILE.yml" ]; then
replace_deploy_args+=(-c "docker-stack.$PROFILE.yml")
elif [ -f "docker-compose.$PROFILE.yml" ]; then
replace_deploy_args+=(-c "docker-compose.$PROFILE.yml")
fi
fi
fi
compose_set_project_name "$@"
}
function host_run() {
# lancer le script $2..@ sur l'hôte $1
# si $1 n'est pas défini ou est le nom de l'hôte local ou vaut 'localhost',
# lancer le script en local avec les droits root
# sinon, si docker-machine existe, l'hôte doit correspondre à la machine active
# sinon, lancer inconditionnellement le script sur l'hôte distant
local host="$1" script="$2"; shift; shift
if [ -n "$host" -a "$host" != localhost ]; then
if check_hostname "$host"; then
estep "Lancement de $script localement"
runscript_as_root "$script" "$@"
elif progexists docker-machine; then
if [ "${host%%.*}" == "$DOCKER_MACHINE_NAME" ]; then
estep "Copie du script vers root@$host"
scp "$script" "root@$host:/tmp/tmp-dk-service-script" || die
estep "Lancement du script à distance"
local -a args; args=(/tmp/tmp-dk-service-script "$@")
ssh -qt "root@$host" "$(qvals "${args[@]}"); rm -f /tmp/tmp-dk-service-script"
else
ewarn "La machine active ($DOCKER_MACHINE_NAME) n'est pas la destination ($host)"
fi
else
estep "Copie du script vers root@$host"
scp "$script" "root@$host:/tmp/tmp-dk-service-script" || die
estep "Lancement du script à distance"
local -a args; args=(/tmp/tmp-dk-service-script "$@")
ssh -qt "root@$host" "$(qvals "${args[@]}"); rm -f /tmp/tmp-dk-service-script"
fi
else
estep "Lancement de $script localement"
runscript_as_root "$script" "$@"
fi
}
function local_run() {
# lancer le script $2..@ sur l'hôte $1 uniquement si c'est l'hôte courant
local host="$1" script="$2"; shift; shift
if [ -n "$host" ]; then
if ! check_hostname "$host"; then
eerror "Cette commande doit obligatoirement être lancée depuis l'hôte $host"
return 1
fi
fi
estep "Lancement de $script localement"
runscript_as_root "$script" "$@"
}
BUILD_UPDATE_APPS=
BUILD_BUILD=
UPDATE_APPS_ORIGIN=
UPDATE_APPS_BRANCH=
function build_set_options() {
BUILD_BUILD=
BUILD_UPDATE_APPS=
BUILD_UPDATE_DEVEL=
[[ "$1" == *b* ]] && BUILD_BUILD=1
[[ "$1" == *u* ]] && BUILD_UPDATE_APPS=1
[[ "$1" == *w* ]] && BUILD_UPDATE_DEVEL=1
UPDATE_APPS_ORIGIN="$2"
UPDATE_APPS_BRANCH="$3"
}
function update_apps_func_sqlmig() {
local destdir="$1" srcdir="$2" nofix="$3"
[ -n "$destdir" ] || destdir=db
[ -n "$srcdir" ] || srcdir="$DEST"
if [ -z "$nofix" ]; then
[ "${destdir%/config/mariadb/sqlmig}" != "$destdir" ] || destdir="$destdir/config/mariadb/sqlmig"
[ "${srcdir%/config/sqlmig}" != "$srcdir" ] || srcdir="$srcdir/config/sqlmig"
fi
if [ ! -d "$srcdir" ]; then
eerror "$srcdir: répertoire introuvable"
return 1
fi
local -a sqlmigs; local sqlmig name
array_lsall sqlmigs "$srcdir"
mkdir -p "$destdir" || return 1
for sqlmig in "${sqlmigs[@]}"; do
if [ -d "$sqlmig" ]; then
setx name=basename -- "$sqlmig"
rsync -av --delete-after "$sqlmig/" "$destdir/$name"
else
rsync -av "$sqlmig" "$destdir"
fi
done
return 0
}
function update_apps_func_pff() {
local maps="$1" pffdir="${2:-$DEST}"
[ -f "$pffdir/$PFF_CONF" ] || return 0
source "$pffdir/$PFF_CONF"
pff_autofix "$pffdir"
local map src dest
array_split maps "$maps" ,
for map in "${maps[@]}"; do
if [ -z "$map" ]; then
continue
elif [[ "$map" == *:* ]]; then
# mapping de profil
splitpair "$map" dest src
if [ "$src" == "$PROFILE" ]; then
if array_contains PROFILES "$dest"; then
estep "Sélection du profil pff $dest"
pff_select_profile "$dest" "$pffdir"
return 0
fi
eerror "$dest: profil invalide, il a été ignoré"
fi
else
# forcer le profil
dest="$map"
if array_contains PROFILES "$dest"; then
estep "Sélection du profil pff $dest"
pff_select_profile "$dest" "$pffdir"
return 0
fi
eerror "$dest: profil invalide, il a été ignoré"
fi
done
# sélectionner le premier profil
setx dest=pff_get_first_profile "$pffdir"
if [ -n "$dest" ]; then
estep "Sélection du profil pff $dest"
pff_select_profile "$dest" "$pffdir"
fi
}
function build_update_apps() {
[ -n "$BUILD_UPDATE_APPS" ] || return 0
[ -f update-apps.conf ] || return 0
# charger le fichier de configuration
local DEFAULT_ORIGIN DEFAULT_BRANCH APPS
DEFAULT_ORIGIN="$UPDATE_APPS_ORIGIN"
[ -z "$DEFAULT_ORIGIN" ] && DEFAULT_ORIGIN=origin
DEFAULT_BRANCH="$UPDATE_APPS_BRANCH"
#XXX à terme, on déploiera la branche master en prod
[ -z "$DEFAULT_BRANCH" -a "$PROFILE" == prod ] && DEFAULT_BRANCH=develop #master
[ -z "$DEFAULT_BRANCH" ] && DEFAULT_BRANCH=develop
DEFAULT_DEVEL_SRCDIR="$HOME/wop/php"
DEFAULT_COMPOSER_ACTION=install
APPS=()
[ -f update-apps.conf ] && source ./update-apps.conf
[ ${#APPS[*]} -gt 0 ] || return 0
local PRODUCTION DEVELOPMENT
case "$PROFILE" in
prod) PRODUCTION=1; DEVELOPMENT=;;
test) PRODUCTION=1; DEVELOPMENT=1;;
devel) PRODUCTION=; DEVELOPMENT=;;
esac
etitle "Mise à jour des dépendances"
local app var URL DEVEL_SRCDIR DEST ORIGIN BRANCH TYPE after_update after_updates composer_action
for app in "${APPS[@]}"; do
etitle "$app"
var="${app//-/_}"
URL="${var}_URL"; URL="${!URL}"
[ -n "$URL" ] || {
ewarn "$app: vous devez définir l'url"
eend; return 1
}
DEVEL_SRCDIR="${var}_DEVEL_SRCDIR"; DEVEL_SRCDIR="${!DEVEL_SRCDIR}"
[ -n "$DEVEL_SRCDIR" ] || DEVEL_SRCDIR="$DEFAULT_DEVEL_SRCDIR/${URL##*/}"
DEST="${var}_DEST"; DEST="${!DEST}"
[ -n "$DEST" ] || DEST="$app/b"
mkdir -p "$DEST" || { eend; return 1; }
ORIGIN="${var}_${PROFILE}_ORIGIN"; ORIGIN="${!ORIGIN}"
[ -n "$ORIGIN" ] || { ORIGIN="${var}_ORIGIN"; ORIGIN="${!ORIGIN}"; }
[ -n "$ORIGIN" ] || ORIGIN="$DEFAULT_ORIGIN"
BRANCH="${var}_${PROFILE}_BRANCH"; BRANCH="${!BRANCH}"
[ -n "$BRANCH" ] || { BRANCH="${var}_BRANCH"; BRANCH="${!BRANCH}"; }
[ -n "$BRANCH" ] || BRANCH="$DEFAULT_BRANCH"
# calculer le type maintenant, on en a besoin pour le mode devel
TYPE="${var}_TYPE"; TYPE="${!TYPE}"
DEST="$DEST/$app"
if [ -n "$BUILD_UPDATE_DEVEL" ]; then
# synchronisation en mode devel
local -a rsync_opts; rsync_opts=(-a --delete --exclude .git/ --delete-excluded)
estep "Synchro $DEVEL_SRCDIR --> $DEST"
rsync "${rsync_opts[@]}" "$DEVEL_SRCDIR/" "$DEST" || { eend; return 1; }
if [ -z "$TYPE" ]; then
# possible de détecter le type quand on a le projet
# en cas de maj ici, mettre à jour aussi le code ci-dessous
if [ -f "$DEST/composer.json" ]; then TYPE=composer
else TYPE=inconnu
fi
fi
if [ "$TYPE" == composer ]; then
# Synchronisation des dépendances
local -a depdirs; local depdir pname
setx -a depdirs=ls -d "$DEST/vendor/"{lib,ur}/* 2>/dev/null
for depdir in "${depdirs[@]}"; do
[ -L "$depdir" ] && rm "$depdir"
pname="${depdir#$DEST/vendor/}"; pname="${pname/\//-}"
estep "Synchro $DEFAULT_DEVEL_SRCDIR/$pname --> $depdir"
rsync "${rsync_opts[@]}" --exclude /vendor/ "$DEFAULT_DEVEL_SRCDIR/$pname/" "$depdir"
done
fi
else
if [ -d "$DEST" -a -d "$DEST/.git" ]; then
# mise à jour
estep "Maj dépôt $URL:$BRANCH --> $DEST"
setx cwd=pwd
cd "$DEST"
git fetch --all -p -f || { eend; return 1; }
git reset --hard "$ORIGIN/$BRANCH" || { eend; return 1; }
cd "$cwd"
else
# reliquat mode devel?
[ -d "$DEST" ] && rm -rf "$DEST"
# clonage initial
estep "Clonage $URL:$BRANCH --> $DEST"
git clone -o "$ORIGIN" -b "$BRANCH" "$URL" "$DEST" || { eend; return 1; }
fi
if [ -z "$TYPE" ]; then
# possible de détecter le type quand on a le projet
# en cas de maj ici, mettre à jour aussi le code ci-dessus
if [ -f "$DEST/composer.json" ]; then TYPE=composer
else TYPE=inconnu
fi
fi
fi
after_updates="${var}_AFTER_UPDATE"
if is_defined "$after_updates"; then
after_updates="$after_updates[@]"; after_updates=("${!after_updates}")
elif [ "$TYPE" == composer ]; then
after_updates=(sqlmig)
else
after_updates=()
fi
estep "Type de dépôt: $TYPE"
if [ "$TYPE" == composer ]; then
composer_action="${var}_${PROFILE}_COMPOSER_ACTION"; composer_action="${!composer_action}"
[ -n "$composer_action" ] || { composer_action="${var}_COMPOSER_ACTION"; composer_action="${!composer_action}"; }
[ -n "$composer_action" ] || composer_action="$DEFAULT_COMPOSER_ACTION"
composer=/usr/bin/composer
[ -x "$DEST/composer.phar" ] && composer="$DEST/composer.phar"
if [ -z "$BUILD_UPDATE_DEVEL" ]; then
case "${composer_action:-install}" in
i|install) composer_action=install;;
u|update) composer_action=update;;
none|nop) composer_action=;;
*) ewarn "$composer_action: action invalide"; composer_action=;;
esac
if [ -n "$composer_action" ]; then
estep "Installation des dépendances composer"
"$composer" -d"$DEST" "$composer_action" ${PRODUCTION:+--no-dev -o} || { eend; return 1; }
fi
fi
fi
for after_update in "${after_updates[@]}"; do
if [ "${after_update#/}" != "$after_update" ]; then
# commande absolue, la lancer telle quelle
etitle "$after_update"
eval "$after_update" || { eend; eend; return 1; }
eend
elif [ "${after_update#./}" != "$after_update" ]; then
# commande relative, la lancer telle quelle
etitle "$after_update"
eval "$after_update" || { eend; eend; return 1; }
eend
else
# c'est une fonction update_apps_func_*
etitle "$after_update"
eval "update_apps_func_$after_update" || { eend; eend; return 1; }
eend
fi
done
eend
done
eend
}
function initialize_build_env() {
CTXDIR=.
NAME=
TAGS=(latest)
VERSION=
DIST=
}
function default_update_build_env() {
if [ -n "$DIST" ]; then
[ -n "$VERSION" ] && VERSION="$VERSION-"
VERSION="$VERSION$DIST"
TAGS+=("$DIST")
fi
[ -n "$VERSION" ] || docker_add_build_arg VERSION "$(get_version)"
[ -n "$VERSION" ] && TAGS+=("$VERSION")
}
function update_build_env() { default_update_build_env; }
function default_compose_build() {
${FAKE:+qvals} docker-compose \
"${replace_env_args[@]}" "${env_args[@]}" \
build \
${NO_CACHE:+--no-cache} \
"${replace_build_args[@]}" "${build_args[@]}" \
"$@"
}
function default_docker_build() {
local tag
for tag in "${TAGS[@]}"; do
replace_build_args+=(-t "$NAME:$tag")
done
${FAKE:+qvals} docker build \
${NO_CACHE:+--no-cache} \
"${replace_env_args[@]}" "${env_args[@]}" \
"${replace_build_args[@]}" "${build_args[@]}" \
"$@" "$CTXDIR"
}
function compose_build() {
[ -n "$BUILD_BUILD" ] || return 0
default_compose_build "$@"
}
function docker_build() {
[ -n "$BUILD_BUILD" ] || return 0
default_docker_build "$@"
}
function auto_build() {
local -a replace_env_args env_args
local -a replace_build_args build_args
initialize_build_env
if [ -f docker-compose.yml ]; then
compose_set_env_args
update_build_env
build_update_apps || return 1
compose_build "$@"
else
docker_parse_env_args
docker_check_name
docker_add_build_arg build_date "$(date +%y%m%d)"
update_build_env
build_update_apps || return 1
docker_build "$@"
fi
}
function default_compose_push() {
${FAKE:+qvals} docker-compose \
"${replace_env_args[@]}" "${env_args[@]}" \
push \
"$@"
}
function default_docker_push() {
${FAKE:+qvals} docker push \
"${replace_env_args[@]}" "${env_args[@]}" \
"$@"
}
function compose_push() {
default_compose_push "$@"
}
function docker_push() {
local tag
for tag in "${TAGS[@]}"; do
default_docker_push "$NAME:$tag" "$@"
done
}
function auto_push() {
local -a replace_env_args env_args
local -a replace_build_args build_args
initialize_build_env
if [ -f docker-compose.yml ]; then
compose_set_env_args
update_build_env
compose_push "$@"
else
docker_parse_env_args
docker_check_name
update_build_env
docker_push "$@"
fi
}
function default_compose_up() {
${FAKE:+qvals} docker-compose \
"${replace_env_args[@]}" "${env_args[@]}" \
up "${replace_run_args[@]}" "${run_args[@]}" \
"${replace_user_args[@]}" "${user_args[@]}" "$@"
}
function default_docker_up() {
${FAKE:+qvals} docker run \
"${replace_env_args[@]}" "${env_args[@]}" \
"${replace_run_args[@]}" "${run_args[@]}" \
"$NAME" \
"${replace_user_args[@]}" "${user_args[@]}" "$@"
}
function compose_up() { default_compose_up "$@"; }
function docker_up() { default_docker_up "$@"; }
function auto_up() {
local -a replace_env_args env_args
local -a replace_run_args run_args
local -a replace_user_args user_args
local project_name container_name
if [ -f docker-compose.yml ]; then
compose_set_env_args
replace_run_args=(-d)
compose_up "$@"
else
docker_set_env_args
docker_check_name set_container_name
replace_run_args=(-d --name "$container_name")
docker_up "$@"
fi
}
function default_compose_stop() {
${FAKE:+qvals} docker-compose \
"${replace_env_args[@]}" "${env_args[@]}" \
stop "${replace_stop_args[@]}" "${stop_args[@]}" \
"$@"
}
function default_docker_stop() {
${FAKE:+qvals} docker container stop \
"${replace_stop_args[@]}" "${stop_args[@]}" \
"$container_name" "$@"
}
function compose_stop() { default_compose_stop "$@"; }
function docker_stop() { default_docker_stop "$@"; }
function auto_stop() {
local -a replace_env_args env_args
local -a replace_stop_args stop_args
local project_name container_name
if [ -f docker-compose.yml ]; then
compose_set_env_args
compose_stop "$@"
else
docker_set_env_args
docker_check_name set_container_name
docker_stop "$@"
fi
}
function default_compose_logs() {
${FAKE:+qvals} docker-compose \
"${replace_env_args[@]}" "${env_args[@]}" \
logs "${replace_logs_args[@]}" "${logs_args[@]}" \
"$@"
}
function default_docker_logs() {
${FAKE:+qvals} docker logs \
"${replace_logs_args[@]}" "${logs_args[@]}" \
"$container_name" "$@"
}
function compose_logs() { default_compose_logs "$@"; }
function docker_logs() { default_docker_logs "$@"; }
function auto_logs() {
local -a replace_env_args env_args
local -a replace_logs_args logs_args
local project_name container_name
if [ -f docker-compose.yml ]; then
compose_set_env_args
replace_logs_args=(-f)
compose_logs "$@"
else
docker_set_env_args
docker_check_name set_container_name
replace_logs_args=(-f)
docker_logs "$@"
fi
}
function default_compose_down() {
${FAKE:+qvals} docker-compose \
"${replace_env_args[@]}" "${env_args[@]}" \
down "${replace_down_args[@]}" "${down_args[@]}" \
"$@"
}
function default_docker_down() {
estep "stop"
${FAKE:+qvals} docker container stop \
"${replace_down_args[@]}" "${down_args[@]}" \
"$container_name" "$@"
estep "rm"
${FAKE:+qvals} docker container rm \
"${replace_rm_args[@]}" "${rm_args[@]}" \
"$container_name"
}
function compose_down() { default_compose_down "$@"; }
function docker_down() { default_docker_down "$@"; }
function auto_down() {
local -a replace_env_args env_args
local -a replace_down_args down_args
local -a replace_rm_args rm_args
local project_name container_name
if [ -f docker-compose.yml ]; then
compose_set_env_args
compose_down "$@"
else
docker_set_env_args
docker_check_name set_container_name
docker_down "$@"
fi
}
function default_compose_run() {
${FAKE:+qvals} docker-compose \
"${replace_env_args[@]}" "${env_args[@]}" \
run "${replace_run_args[@]}" "${run_args[@]}" \
"${replace_user_args[@]}" "${user_args[@]}" "$@"
}
function default_docker_run() {
${FAKE:+qvals} docker run \
"${replace_env_args[@]}" "${env_args[@]}" \
"${replace_run_args[@]}" "${run_args[@]}" \
"$NAME" \
"${replace_user_args[@]}" "${user_args[@]}" "$@"
}
function compose_run() { default_compose_run "$@"; }
function docker_run() { default_docker_run "$@"; }
function auto_run() {
eval "$(utools_local parse_opts)"
local detach no_deps rm=1 service_ports use_aliases volume
local -a envs labels
args=(
+
-d,--detach detach=1
-e: '$add@ envs -e; add@ envs'
-l:,--label: '$add@ labels -l; add@ labels'
--no-deps no_deps=1
--no-rm rm=
--rm rm=1
--service-ports service_ports=1
--use-aliases use_aliases=1
-v:,--volume: volume=
@ args -- "$@"
)
parse_opts "${args[@]}" && set -- "${args[@]}" || { eerror "$args"; return 1; }
local -a replace_env_args env_args
local -a replace_run_args run_args
local -a replace_user_args user_args
local project_name container_name
if [ -f docker-compose.yml ]; then
compose_set_env_args
replace_run_args=(
${detach:+-d}
"${envs[@]}" "${labels[@]}"
${no_deps:+--no-deps}
${rm:+--rm}
${service_ports:+--service-ports}
${use_aliases:+--use-aliases}
${volume:+-v "$volume"}
)
compose_run "$@"
else
docker_set_env_args
docker_check_name set_container_name
replace_run_args=(
--name "$container_name"
${rm:+--rm}
${volume:+-v "$volume"}
)
docker_run "$@"
fi
}
function default_compose_exec() {
${FAKE:+qvals} docker-compose \
"${replace_env_args[@]}" "${env_args[@]}" \
exec "${replace_exec_args[@]}" "${exec_args[@]}" \
"$@"
}
function default_docker_exec() {
${FAKE:+qvals} docker container exec \
"${replace_exec_args[@]}" "${exec_args[@]}" \
"$container_name" "$@"
}
function compose_exec() { default_compose_exec "$@"; }
function docker_exec() { default_docker_exec "$@"; }
function auto_exec() {
local -a replace_env_args env_args
local -a replace_exec_args exec_args
local project_name container_name
if [ -f docker-compose.yml ]; then
compose_set_env_args
compose_exec "$@"
else
docker_set_env_args
docker_check_name set_container_name
docker_exec "$@"
fi
}
function default_docker_deploy() {
${FAKE:+qvals} docker \
stack deploy \
"${replace_deploy_args[@]}" "${deploy_args[@]}" \
"$container_name" "$@"
}
function docker_deploy() { default_docker_deploy "$@"; }
function auto_deploy() {
local -a replace_env_args env_args
local -a replace_deploy_args deploy_args
local project_name container_name
if [ -f docker-compose.yml -o -f docker-stack.yml ]; then
docker_set_deploy_args set_container_name
[ -n "$WITH_REGISTRY_AUTH" ] && replace_deploy_args+=(--with-registry-auth)
docker_deploy "$@"
else
die "Impossible de trouver ni docker-compose.yml ni docker-stack.yml"
fi
}
function default_docker_service() {
${FAKE:+qvals} docker service "$@"
}
function docker_service() { default_docker_service "$@"; }
function auto_service() {
if [ -f docker-compose.yml -o -f docker-stack.yml ]; then
local command="$1"; shift
[ -n "$command" ] || {
eerror "Vous devez spécifier la commande"
return 1
}
local -a command_args
[ "$command" == update -a -n "$WITH_REGISTRY_AUTH" ] && command_args+=(--with-registry-auth)
case "$command" in
ls) # ces commandes n'ont pas besoin du nom de service
docker_service "$command" "$@"
;;
*) # ces commandes ont besoin du nom du service
local service="$1"; shift
[ -n "$service" ] || {
eerror "Vous devez spécifier le nom du service"
return 1
}
local -a replace_env_args env_args
local -a replace_deploy_args deploy_args
local project_name container_name
docker_set_deploy_args set_container_name
service="${container_name}_${service#${container_name}_}"
docker_service "$command" "${command_args[@]}" "$@" "$service"
;;
esac
else
die "Impossible de trouver ni docker-compose.yml ni docker-stack.yml"
fi
}
function default_compose_show_ip() {
local -a cmd cids; local cid
cmd=(
docker-compose
"${replace_env_args[@]}" "${env_args[@]}"
ps -q "${replace_show_ip_args[@]}" "${show_ip_args[@]}"
"$@"
)
if [ -n "$FAKE" ]; then
echo "docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \"\$($(qvals "${cmd[@]}"))\""
else
setx -a cids="${cmd[@]}" 2>/dev/null
for cid in "${cids[@]}"; do
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$cid"
done
fi
}
function default_docker_show_ip() {
${FAKE:+qvals} docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \
"${replace_show_ip_args[@]}" "${show_ip_args[@]}" \
"$container_name" "$@"
}
function compose_show_ip() { default_compose_show_ip "$@"; }
function docker_show_ip() { default_docker_show_ip "$@"; }
function auto_show_ip() {
local -a replace_env_args env_args
local -a replace_show_ip_args show_ip_args
local project_name container_name
if [ -f docker-compose.yml ]; then
compose_set_env_args
compose_show_ip "$@"
else
docker_set_env_args
docker_check_name set_container_name
docker_show_ip "$@"
fi
}
function default_compose_systemd_unit() {
local docker_compose="$(which docker-compose 2>/dev/null)"
if [ -z "$docker_compose" ]; then
if [ -x /usr/bin/docker-compose ]; then
docker_compose=/usr/bin/docker-compose
elif [ -x /usr/local/bin/docker-compose ]; then
docker_compose=/usr/local/bin/docker-compose
else
die "Impossible de trouver docker-compose"
fi
fi
setx startcmd=qvals "$docker_compose" \
"${replace_env_args[@]}" "${env_args[@]}" \
up "${replace_run_args[@]}" "${run_args[@]}" \
"${replace_user_args[@]}" "${user_args[@]}" "$@"
setx stopcmd=qvals "$docker_compose" down
}
function default_docker_systemd_unit() {
local docker="$(which docker 2>/dev/null)"
if [ -z "$docker" ]; then
if [ -x /usr/bin/docker ]; then
docker=/usr/bin/docker
elif [ -x /usr/local/bin/docker ]; then
docker=/usr/local/bin/docker
else
die "Impossible de trouver docker"
fi
fi
setx startcmd=qvals "$docker" run \
"${replace_env_args[@]}" "${env_args[@]}" \
"${replace_run_args[@]}" "${run_args[@]}" \
"$NAME" \
"${replace_user_args[@]}" "${user_args[@]}" "$@"
setx stopcmd=qvals "$docker" stop "$container_name"
}
function compose_systemd_unit() { default_compose_systemd_unit "$@"; }
function docker_systemd_unit() { default_docker_systemd_unit "$@"; }
function auto_systemd_unit() {
local -a replace_env_args env_args
local -a replace_run_args run_args
local -a replace_user_args user_args
local project_name container_name startcmd stopcmd
local tmpscript; ac_set_tmpfile tmpscript
estep "Génération de l'unité systemd"
export COMPOSE_PROJECT_NAME=
if [ -f docker-compose.yml ]; then
compose_set_env_args set_container_name
replace_run_args=(-d --no-color)
compose_systemd_unit "$@"
if [ -z "$HOST" -a -f .env ]; then
source ./.env
if [ -n "$PROFILE" ]; then
HOST="${PROFILE^^}_HOST"; HOST="${!HOST}"
fi
fi
else
docker_set_env_args
docker_check_name set_container_name
replace_run_args=(-d --name "$container_name")
docker_systemd_unit "$@"
fi
[ -n "$COMPOSE_PROJECT_NAME" ] || COMPOSE_PROJECT_NAME="$project_name"
chmod 755 "$tmpscript"
cat >"$tmpscript" <<EOF
#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
cat >/etc/systemd/system/$container_name.service <<EOD
[Unit]
Description=$project_name stack ($PROFILE)
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=$(pwd)
Environment=$(qval "COMPOSE_PROJECT_NAME=$COMPOSE_PROJECT_NAME")
ExecStart=$startcmd
ExecStop=$stopcmd
TimeoutStopSec=300
[Install]
WantedBy=multi-user.target
EOD
systemctl daemon-reload
systemctl enable $container_name.service
EOF
estep "Installation de l'unité systemd"
local_run "$HOST" "$tmpscript"
}
function auto_composer() {
local -a replace_env_args env_args
if [ -f docker-compose.yml ]; then compose_set_env_args
else docker_set_env_args
fi
local user group projdir
local actualcmd args
setx user=id -un; setx user=getent passwd "$user"
setx group=id -gn; setx group=getent group "$group"
setx projdir=pwd
case "$1" in
shell|bash)
shift
actualcmd='eval "su-exec \"$user\" bash $args"'
;;
*)
actualcmd='eval "su-exec \"$user\" \"$composer\" $args"'
;;
esac
setx args=qvals "$@"
local -a cmd
cmd=(
docker run -it --rm
-e user="$user"
-e group="$group"
-e home="$HOME"
-e projdir="$projdir"
-e args="$args"
-v "$HOME:$HOME"
)
if [ "${projdir#$HOME/}" == "$projdir" ]; then
# si le répertoire de projet ne se trouve pas dans $HOME, le monter aussi
cmd+=(-v "$projdir:$projdir")
fi
cmd+=(
"${COMPOSER_IMAGE:-$DEFAULT_COMPOSER_IMAGE}"
bash -c '
echo "$user" >>/etc/passwd; user="${user%%:*}"
echo "$group" >>/etc/group; group="${group%%:*}"
cd "$projdir"
if [ -x composer.phar ]; then composer=./composer.phar
elif [ -x /usr/bin/composer ]; then composer=/usr/bin/composer
else
echo "ERROR: unable to find composer"
exit 1
fi
'"$actualcmd"
)
"${cmd[@]}"
}
################################################################################
DEFAULT_PROFILE=devel
DEFAULT_COMPOSER_IMAGE=docker.univ-reunion.fr/image/utils-icmycas-php-apache:d9
PROFILE=
DM_PROFILES=()
set_defaults dk
export PROFILE
chdir=
CONFIG=
DM_SET_MACHINE=
USE_STACK=
FAKE=
NO_CACHE=
HOST=
WITH_REGISTRY_AUTH=1
update_apps_mode=ub
update_apps_devel=
update_apps_origin=
update_apps_branch=
args=(
--help '$exit_with display_help'
-d:,--chdir: chdir=
-c:,--config: CONFIG=
-p:,--profile: PROFILE=
-P,--prod PROFILE=prod
-T,--test PROFILE=test
-m:,--set-machine: DM_SET_MACHINE=
--stack USE_STACK=1
-n,--fake FAKE=1
-j,--no-cache NO_CACHE=1
-h:,--host: HOST=
-g,--ug,--no-update-apps update_apps_mode=b
-u,--uu,--update-apps-only update_apps_mode=u
-w,--uw,--update-apps-devel update_apps_devel=1
--uo:,--update-apps-origin: update_apps_origin=
--ub:,--update-apps-branch: update_apps_branch=
-l,--without-registry-auth WITH_REGISTRY_AUTH=
)
parse_args "$@"; set -- "${args[@]}"
progexists docker-machine && DM_AVAILABLE=1 || DM_AVAILABLE=
if [ -n "$DM_SET_MACHINE" ]; then
[ -n "$DM_AVAILABLE" ] || die "docker-machine n'est pas disponible"
[ "$DM_SET_MACHINE" == - ] && DM_SET_MACHINE=-u
setx dm_env=docker-machine env "$DM_SET_MACHINE" || die
eval "$dm_env"
fi
if [ -n "$DM_AVAILABLE" ]; then
for dm_profile in "${DM_PROFILES[@]}"; do
splitpair "$dm_profile" dm profile
if [ "$dm" == "$DOCKER_MACHINE_NAME" ]; then
DEFAULT_PROFILE="$profile"
break
fi
done
fi
# construire par défaut
[ $# -eq 0 ] && set -- build
[ -n "$PROFILE" ] || PROFILE="$DEFAULT_PROFILE"
[ -n "$chdir" ] && { cd "$chdir" || die; }
update_apps_mode="${update_apps_mode}${update_apps_devel:+w}"
[ -f .dk.scripts.sh ] && source ./.dk.scripts.sh
[ -f dk.scripts.sh ] && source ./dk.scripts.sh
while [ $# -gt 0 ]; do
[ "$1" == -- ] && { shift; continue; }
cmd="$1"; shift
case "$cmd" in
b|build)
build_set_options "$update_apps_mode" "$update_apps_origin" "$update_apps_branch"
[ -f .build.scripts.sh ] && source ./.build.scripts.sh
[ -f build.scripts.sh ] && source ./build.scripts.sh
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_build "${args[@]}" || die
;;
p|push)
[ -f .build.scripts.sh ] && source ./.build.scripts.sh
[ -f build.scripts.sh ] && source ./build.scripts.sh
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_push "${args[@]}" || die
;;
s|start)
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_up "${args[@]}" || die
;;
k|stop)
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_stop "${args[@]}" || die
;;
1|up)
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_up "${args[@]}" && auto_logs || die
;;
l|logs)
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_logs "${args[@]}" || die
;;
0|down)
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_down "${args[@]}" || die
;;
r|run)
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_run "${args[@]}" || die
;;
x|exec)
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_exec "${args[@]}" || die
;;
d|brd)
do_auto_down=1
function auto_down_trap() {
[ -n "$do_auto_down" ] && auto_down
}
trap auto_down_trap 1 3 15 EXIT
build_set_options "$update_apps_mode" "$update_apps_origin" "$update_apps_branch"
[ -f .build.scripts.sh ] && source ./.build.scripts.sh
[ -f build.scripts.sh ] && source ./build.scripts.sh
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
if auto_build; then
auto_up "${args[@]}" && auto_logs || die
else
do_auto_down=
fi
;;
bs)
build_set_options "$update_apps_mode" "$update_apps_origin" "$update_apps_branch"
[ -f .build.scripts.sh ] && source ./.build.scripts.sh
[ -f build.scripts.sh ] && source ./build.scripts.sh
USE_STACK=1
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_build && auto_up "${args[@]}"
;;
br)
build_set_options "$update_apps_mode" "$update_apps_origin" "$update_apps_branch"
[ -f .build.scripts.sh ] && source ./.build.scripts.sh
[ -f build.scripts.sh ] && source ./build.scripts.sh
USE_STACK=1
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_build && auto_run "${args[@]}"
;;
y|deploy)
USE_STACK=1
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_deploy "${args[@]}" || die
;;
by|bd)
build_set_options "$update_apps_mode" "$update_apps_origin" "$update_apps_branch"
[ -f .build.scripts.sh ] && source ./.build.scripts.sh
[ -f build.scripts.sh ] && source ./build.scripts.sh
USE_STACK=1
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_build && auto_deploy "${args[@]}"
;;
bp)
build_set_options "$update_apps_mode" "$update_apps_origin" "$update_apps_branch"
[ -f .build.scripts.sh ] && source ./.build.scripts.sh
[ -f build.scripts.sh ] && source ./build.scripts.sh
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_build && auto_push "${args[@]}"
;;
bpy|bpd)
build_set_options "$update_apps_mode" "$update_apps_origin" "$update_apps_branch"
[ -f .build.scripts.sh ] && source ./.build.scripts.sh
[ -f build.scripts.sh ] && source ./build.scripts.sh
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_build && auto_push && auto_deploy "${args[@]}"
;;
service)
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_service "${args[@]}" || die
;;
u|update)
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_service update "${args[@]}" || die
;;
scale)
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_service scale "${args[@]}" || die
;;
ip|show-ip)
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_show_ip "${args[@]}" || die
;;
systemd-unit|systemd)
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_systemd_unit "${args[@]}" || die
;;
ps)
pscmd=(
docker container ps -a
--format "table {{.ID}}\t{{.Image}}\t{{.Names}}\t{{.Status}}\t{{.RunningFor}}\t{{.Ports}}"
)
filtercmd=(cat)
awkscript='
NR == 1 { print; next }
($2 ~ filter || $3 ~ filter) { print }
'
if [ $# -eq 0 ]; then
# pas de filtre
:
elif [ "$1" == -- ]; then
# fin de la commande
shift
elif [[ "$1" == *=* ]]; then
# filtre docker
pscmd+=(--filter "$1")
shift
else
# expression régulière
filtercmd=(awk -v filter="$1" "$awkscript")
shift
fi
set -o pipefail
"${pscmd[@]}" | "${filtercmd[@]}" || die
;;
ls)
lscmd=(docker image ls)
filtercmd=(cat)
awkscript='
BEGIN {
if (split(filter, parts, /:/) > 1) {
filter = parts[1]
tag = parts[2]
} else {
tag = ""
}
}
NR == 1 { print; next }
(filter == "" || $1 ~ filter) && (tag == "" || $2 ~ tag) { print }
'
if [ $# -eq 0 ]; then
# pas de filtre
:
elif [ "$1" == -- ]; then
# fin de la commande
shift
elif [[ "$1" == *=* ]]; then
# filtre docker
lscmd+=(--filter "$1")
shift
else
# expression régulière
filtercmd=(awk -v filter="$1" "$awkscript")
shift
fi
set -o pipefail
"${lscmd[@]}" | "${filtercmd[@]}" || die
;;
pull)
lscmd=(docker image ls)
filtercmd=(awk 'NR == 1 { print; next } $2 !~ /</ { print }')
awkscript='
BEGIN {
if (split(filter, parts, /:/) > 1) {
filter = parts[1]
tag = parts[2]
} else {
tag = ""
}
}
NR == 1 { print; next }
(filter == "" || $1 ~ filter) && (tag == "" || $2 ~ tag) && $2 !~ /</ { print }
'
if [ $# -eq 0 -o "$1" == -- ]; then
# pas de filtre
ewarn "pull: Vous devez spécifier l'image à mettre à jour"
continue
elif [[ "$1" == *=* ]]; then
# filtre docker
lscmd+=(--filter "$1")
shift
else
# expression régulière
filtercmd=(awk -v filter="$1" "$awkscript")
shift
fi
all="$("${lscmd[@]}" | "${filtercmd[@]}")"
setx -a images awk 'NR == 1 { next } { print $1 ":" $2 }' <<<"$all"
if [ ${#images[*]} -gt 0 ]; then
echo "$all"
ask_yesno "Etes-vous sûr de vouloir mettre à jour ces images?" O || die
for image in "${images[@]}"; do
docker pull "$image" || die
done
fi
;;
rm)
lscmd=(docker image ls)
filtercmd=(cat)
awkscript='
BEGIN {
if (split(filter, parts, /:/) > 1) {
filter = parts[1]
tag = parts[2]
} else {
tag = ""
}
}
NR == 1 { print; next }
(filter == "" || $1 ~ filter) && (tag == "" || $2 ~ tag) { print }
'
if [ $# -eq 0 -o "$1" == -- ]; then
# pas de filtre
ewarn "rm: Vous devez spécifier l'image à supprimer"
continue
elif [[ "$1" == *=* ]]; then
# filtre docker
lscmd+=(--filter "$1")
shift
else
# expression régulière
filtercmd=(awk -v filter="$1" "$awkscript")
shift
fi
all="$("${lscmd[@]}" | "${filtercmd[@]}")"
setx -a images awk 'NR == 1 { next } { print $3 }' <<<"$all"
if [ ${#images[*]} -gt 0 ]; then
echo "$all"
ask_yesno "Etes-vous sûr de vouloir supprimer ces images?" || die
docker image rm "${images[@]}" || die
fi
;;
X|prune)
docker container prune -f || die
docker image prune -f || die
;;
composer|c|ci|cu|cs)
build_set_options "$update_apps_mode" "$update_apps_origin" "$update_apps_branch"
[ -f .build.scripts.sh ] && source ./.build.scripts.sh
[ -f build.scripts.sh ] && source ./build.scripts.sh
args=()
if [ "$cmd" == ci ]; then args+=(install)
elif [ "$cmd" == cu ]; then args+=(update)
elif [ "$cmd" == cs ]; then args+=(shell)
fi
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
auto_composer "${args[@]}"
;;
*) die "$cmd: commande inconnue";;
esac
done