#!/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 get-profile Afficher le profil courant 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=([:tag]|| ) containers created from an image or a descendant. - before=(|) - expose=([/]|/[]) - exited= an exit code of - health=(starting|healthy|unhealthy|none) - id= a container's ID - is-task=(true|false) - label= or label== - name= a container's name - network=(|) - publish=([/]|/[]) - since=(|) - status=(created|restarting|removing|running|paused|exited) - volume=(|) 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= or label== - before=([:tag]|| ) - since=([:tag]|| ) - 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|cr|cs [args...] Frontend pour lancer composer à l'intérieur d'un container. Les commandes 'ci', 'cu', 'cr', 'cs' sont des alias pour 'composer install', 'composer update', 'composer rshell' et 'composer shell' respectivement S'il existe un fichier .composer.conf dans le répertoire du projet, il est sourcé. Ce fichier définit des variables qui indiquent comment la commande composer est lancée. Les variables suivantes peuvent être définies: * COMPOSER_PHP -- Version de PHP en dessous de laquelle COMPOSER_IMAGE est utilisé. En d'autres termes, c'est la version minimum de PHP nécessaire pour faire tourner composer. L'idée est que si la version de PHP installée est suffisante, il n'est pas nécessaire de passer par une image docker. Cette valeur doit être spécifiée avec le format de PHP_VERSION_ID i.e 70300 pour PHP 7.3 Spécifier 'any' ou 'force' pour forcer l'utilisation de l'image docker * COMPOSER_PHP_MAX -- Version de PHP à partir de laquelle COMPOSER_IMAGE est utilisée. En d'autres termes, c'est la version maximum de PHP, à partir de laquelle il faut passer par une image docker. L'idée est que si la version de PHP installée est trop récente, ça peut poser problème avec le calcul des dépendances. Cette valeur doit être spécifiée avec le format de PHP_VERSION_ID i.e 70300 pour PHP 7.3 Si la valeur n'est pas spécifiée ou vaut 'none', elle est ignorée. * COMPOSER_IMAGE -- Image utilisée pour lancer composer. La valeur par défaut est: $DEFAULT_COMPOSER_IMAGE Spécifier 'none' pour lancer directement composer sans passer par une image docker. L'image spécifiée doit disposer de la commande 'su-exec' afin de pouvoir lancer la commande avec l'utilisateur courant. Le répertoire \$HOME est monté à l'intérieur du container et le script composer.phar du projet est utilisé le cas échéant. * COMPOSER_MACHINE -- Nom de la docker machine sur laquelle se connecter pour lancer l'image docker. La valeur par défaut est -u, ce qui force l'utilisation de l'instance docker locale. * COMPOSER_CMD -- Chemin vers l'exécutable composer. Par défaut, utiliser composer.phar s'il existe dans le répertoire du projet. Sinon utiliser /usr/bin/composer * COMPOSER_SETUP -- Liste de commandes à lancer pour configurer le container. Dans ce cas, un container ayant pour base \$COMPOSER_IMAGE et nommé d'après le nom du projet est préparé et les commandes spécifiées y sont lancées. Ce container est réutilisé à chaque fois. Ce paramétrage est utilisé pour par exemple installer certains packages nécessaire au projet. La commande 'rshell' 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. NB: le shell est lancé avec l'utilisateur root. La commande alternative 'shell' lance le shell avec le compte utilisateur. Pour faciliter l'utilisation dans un script, les premiers arguments peuvent être utilisés pour redéfinir les variables COMPOSER_*, e.g $scriptname composer COMPOSER_IMAGE=none install 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 -f, --force Forcer l'opération (là où cela a du sens) -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_DEVEL_SRCDIR= DEFAULT_ORIGIN= DEFAULT_BRANCH= DEFAULT_COMPOSER_ACTION= PROFILE_CLEAN= # fonction de nettoyage spécifique au profil CLEAN= # ou... fonction de nettoyage par défaut APPS=() # applications à mettre à jour par défaut PROFILE_APPS=() # ou... spécifique au profil 'PROFILE' 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_ORIGIN= # ou... origine par défaut de la branche app_PROFILE_BRANCH= # branche spécifique au profil 'PROFILE' app_BRANCH= # ou... branche par défaut app_TYPE= # type de projet (composer|none) app_AFTER_UPDATE=() # liste de commandes à lancer après le checkout app_COMPOSER_ACTION= # action projet composer (install|update|none) -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 'none' 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= # origine de la branche BRANCH= # branche sélectionnée dans le dépôt TYPE= # type de projet (composer|none) 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 supporté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 - Pour simplifier l'écriture des mappings, les aliases suivants sont reconnus:"' PTD est remplacé par prod:prod,test:test,devel:devel PT " " " prod:prod,test:test '"Si aucun profil de déploiement ne correspond, le comportement par défaut est de forcer le premier profil défini dans le projet pff" } 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/([^=]+)=(.*)/\1=\2; replace_build_args+=(--build-arg \1="$\1")/' } 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 __maps_replace() { if [ "${maps#$1,}" != "$maps" ]; then maps="$2,${maps#$1,}" elif [ "${maps%,$1}" != "$maps" ]; then maps="${maps%,$1},$2" elif [ "${maps/,$1,/}" != "$maps" ]; then maps="${maps/,$1,/,$2,}" elif [ "$maps" == "$1" ]; then maps="$2" fi } function update_apps_func_pff() { local maps="$1" pffdir="${2:-$DEST}" [ -f "$pffdir/$PFF_CONF" ] || return 0 # aliases __maps_replace PTD prod:prod,test:test,devel:devel __maps_replace PT prod:prod,test:test 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=() CLEAN= [ -f update-apps.conf ] && source ./update-apps.conf local apps # liste des applications spécifique au profil apps="${PROFILE}_APPS[@]"; apps=("${!apps}") [ ${#apps[*]} -gt 0 ] && APPS=("${apps[@]}") [ ${#APPS[*]} -gt 0 ] || return 0 local PRODUCTION DEVELOPMENT case "$PROFILE" in prod) PRODUCTION=1; DEVELOPMENT=;; test) PRODUCTION=1; DEVELOPMENT=1;; devel) PRODUCTION=; DEVELOPMENT=;; esac local clean clean="${PROFILE}_CLEAN"; clean="${!clean}" [ -n "$clean" ] && CLEAN="$clean" if [ -n "$CLEAN" ]; then etitle "Nettoyage" "$CLEAN" eend fi 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=none 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=none 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" 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 setx cwd=pwd cd "$DEST" estep "Installation des dépendances composer" auto_composer "$composer_action" ${PRODUCTION:+--no-dev -o} || { eend; return 1; } cd "$cwd" 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" </etc/systemd/system/$container_name.service < $version)? 0: 1); ' -- "$COMPOSER_PHP_MAX" && use_image=1 fi if [ -n "$use_image" ]; then : # ok, on a déjà décidé qu'il faut utiliser une image elif [ -z "$COMPOSER_PHP" ]; then # pas de version minimum, tester simplement la valeur de COMPOSER_IMAGE [ "$COMPOSER_IMAGE" != none ] && use_image=1 elif [ "$COMPOSER_PHP" == force -o "$COMPOSER_PHP" == any ]; then use_image=1 else # Vérifier la version de PHP php -r ' $version = $argv[1]; if (strpos($version, ".") !== false) { $version = explode(".", $version); $version = $version[0] * 10000 + $version[1] * 100 + (isset($version[2])? $version[2]: 0); } exit((PHP_VERSION_ID < $version)? 0: 1); ' -- "$COMPOSER_PHP" && use_image=1 fi if [ -n "$use_image" ]; then [ "$COMPOSER_IMAGE" != none ] || die "Vous devez spécifier l'image à utiliser pour composer" local PREVIOUS_DOCKER_MACHINE_NAME="$DOCKER_MACHINE_NAME" if [ -n "$COMPOSER_MACHINE" -a "$DOCKER_MACHINE_NAME" != "$COMPOSER_MACHINE" ]; then local -x DOCKER_TLS_VERIFY= DOCKER_HOST= DOCKER_CERT_PATH= DOCKER_MACHINE_NAME= if [ "$COMPOSER_MACHINE" != -u ]; then local env setx env=docker-machine env "$COMPOSER_MACHINE" 2>/dev/null || { eerror "$COMPOSER_MACHINE: une erreur s'est produite lors de la sélection du noeud avec docker-machine" return 1 } eval "$env" fi fi docker_composer "$@" else local_composer "$@" fi } ################################################################################ # support limité docker / podman if progexists docker; then DOCKER=docker elif progexists podman; then DOCKER=podman else DOCKER=docker fi DEFAULT_PROFILE=devel # pour le moment ne pas lancer composer dans un container par défaut DEFAULT_COMPOSER_IMAGE=none #docker.univ-reunion.fr/image/apache-php-myiccas-utils:d9 PROFILE= DM_PROFILES=() set_defaults dk export PROFILE chdir= CONFIG= DM_SET_MACHINE= USE_STACK= FAKE= FORCE= 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 -f,--force FORCE=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 get-profile|get_profile|profile) echo "$PROFILE" exit 0 ;; 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 !~ / 1) { filter = parts[1] tag = parts[2] } else { tag = "" } } NR == 1 { print; next } (filter == "" || $1 ~ filter) && (tag == "" || $2 ~ tag) && $2 !~ / 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 ${FORCE:+--force} "${images[@]}" || die fi ;; X|prune) "$DOCKER" container prune -f || die "$DOCKER" image prune -f || die ;; composer|c|ci|cu|cr|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" == cr ]; then args+=(rshell) elif [ "$cmd" == cs ]; then args+=(shell) fi while [ $# -gt 0 -a "$1" != -- ]; do args+=("$1"); shift done auto_composer "${args[@]}" ;; *) # transmettre directement à docker pour les autres commandes exec "$DOCKER" "$cmd" "$@" esac done