Mercurial > sat_docs
view docker/libervia_cont.sh @ 129:bcfe5f20d6e8
screenshot (0.7): renamed ticket screenshot after typo
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 05 Jul 2018 14:10:30 +0200 |
parents | 37e100fd30ef |
children |
line wrap: on
line source
#!/bin/sh # Libervia container manager # Copyright (C) 2014-2016 Jérôme Poisson (goffi@goffi.org) # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. VERSION="0.3.0" APP_NAME="Libervia" ACCOUNT="salutatoi" # environment variables that can be used for configuration: # SAT_CONT_TLS_DIR for TLS certificates directory # SAT_CONT_DOMAIN for the host name # SAT_CONT_BACKUP_DIR is the directory where tar.gz backup will be written # SAT_CONT_DK_EXTRA is used for extra options (used with all containers but sat_data) # SAT_CONT_PORT_<port> is used to specify port when -p is used, <port> must be an exposed port CONTAINERS="prosody sat_pubsub salut sat libervia" TEST_CONT="libervia" # container used to test status MAINT_CONT="debian:jessie" # container used for maintenance DK_DETACH="-d" DK_TERM="-ti" VOLUME_NAME="data" VOLUME_CONT="$ACCOUNT/$VOLUME_NAME" VOLUME_ALIAS="sat_data" DK_VOLUME="--volumes-from $VOLUME_ALIAS" PUBLIC=0 PROSODY_PORTS="5222 5269 5280 5281" PORT_5222_NAME="XMPP client to server" PORT_5269_NAME="XMPP server to server" PORT_5280_NAME="HTTP Upload" PORT_5281_NAME="HTTP Upload (HTTPS)" SAT_PORTS="10143 10125" PORT_10143_NAME="IMAP server" PORT_10125_NAME="SMTP server" LIBERVIA_PORTS="8080 8443" PORT_8080_NAME="HTTP" PORT_8443_NAME="HTTPS" NO_PORT="No public port" DOCKER_EXE="docker" USAGE="Usage: $0 [start|stop|restart|status|update|backup|restore|ports|config|stats] [ARGS...]" HELP_SITE="https://wiki.goffi.org/wiki/Docker/en" HELP_MUC="sat@chat.jabberfr.org" CONT_CERT_DIR="/usr/share/sat/certificates" DEFAULT_TMP_DIR="/tmp/tmp_sat_docker" eprintf() { >&2 printf "$@" } get_dyn_var() { # get dynamicly variable based on given name name=$1 var_type=$2 name_upp=$(echo "$name" | tr '[:lower:]' '[:upper:]') case $var_type in ports) eval echo "\$${name_upp}_PORTS";; port_name) eval echo "\$PORT_${name_upp}_NAME";; esac } list_ports() { # list used ports in currently running containers for cont in $CONTAINERS; do # we get variable name with uppercase container name # some magic to get the ports ports=$(get_dyn_var $cont ports) [ -n "$ports" ] && printf "== $cont ==\n\n" for port in $ports; do # some magic to get port human readable name port_name=$(get_dyn_var $port port_name) real_port=$(docker port $cont $port 2>&1) if [ $? -ne 0 ]; then real_port=$NO_PORT fi # we now show the ports with nice alignment desc="port $port ($port_name):" nb_tabs=$((5-${#desc}/8)) printf "$desc" for i in $(seq $nb_tabs); do printf "\t" done printf "$real_port\n" done [ -n "$ports" ] && printf '\n' done } public_ports_arg() { # create Docker arg to have public ports corresponding to container ports if [ $PUBLIC -ne 1 ]; then return fi cont=$1 ports=$(get_dyn_var $cont ports) ARG="" for port in $ports; do host_port=$(eval echo "\$SAT_CONT_PORT_${port}") if [ -z "$host_port" ]; then host_port=$port fi if [ "$host_port" != 0 ]; then ARG="$ARG -p $host_port:$port" fi done echo $ARG } download_missing() { # download images wich are not present locally for cont in $CONTAINERS $VOLUME_NAME; do image="$ACCOUNT/$cont" docker inspect $image:latest > /dev/null 2>&1 if [ $? -ne 0 ]; then printf "$image is not present locally, downloading it\n" docker pull $image:latest if [ $? -eq 0 ]; then printf "\nDownload of latest $image finished\n\n" else eprintf "\nError while downloading $image, please check your connection and logs\n" return 1 fi fi done } check_docker() { which $DOCKER_EXE > /dev/null 2>&1 if [ $? -ne 0 ]; then printf "Docker is not installed or not accessible, please install it.\nYou can check $HELP_SITE for instructions\n" return 1 fi } check_docker_version() { # check if current docker version is greater than or equal to the requested one wanted_major=$1 wanted_minor=$2 wanted_rev=$3 raw=$(docker --version | grep -o '\([0-9]\+\)\.[0-9]\+\.[0-9]\+') docker_major=$(echo "$raw" | cut -d . -f 1) docker_minor=$(echo "$raw" | cut -d . -f 2) docker_rev=$(echo "$raw" | cut -d . -f 3) for name in major minor rev; do docker_val=$(eval echo \$docker_$name) wanted_val=$(eval echo \$wanted_$name) if [ $docker_val -gt $wanted_val ]; then return 0 fi if [ $docker_val -lt $wanted_val ]; then return 1 fi done # wanted version and docker version are the same return 0 } parse_run_args() { # manage arguments for run command while [ $# -gt 0 ]; do case "$1" in -h|--help) cat << OPT_END options available for the run command: -h, --help display this help message -p, --public publish using true ports -d DOMAIN, --domain DOMAIN use DOMAIN as domain name OPT_END exit 0 ;; -d|--domain) shift if [ $# -eq 0 ]; then printf "no domain given, --domain must be followed by a domain\n" exit 1 fi SAT_CONT_DOMAIN="$1" shift ;; -p|--public) shift PUBLIC=1 ;; *) printf "Invalid argument, please check \"$0 run --help\"\n" exit 1 ;; esac done } check_docker || exit 1 if [ $# -ge 1 ];then case $1 in start) CMD=START;; stop) CMD=STOP;; restart) CMD=RESTART;; status) CMD=STATUS;; update) CMD=UPDATE;; backup) CMD=BACKUP;; restore) CMD=RESTORE;; ports) CMD=PORTS;; config) CMD=CONFIG;; stats) CMD=STATS;; -v|--version) printf "$VERSION\n"; exit 0;; -h|--help) printf "$USAGE\n\nYou can check $HELP_SITE for instructions, or go to $HELP_MUC XMPP MUC room for help\n"; exit 0;; *) echo $USAGE exit 1 esac shift else CMD=START fi case $CMD in START) parse_run_args "$@" download_missing || exit 1 printf "Running data container... " # we use -d even if data container doesn't stay in background to get id of the container docker_id=$(docker run -d --name $VOLUME_ALIAS $VOLUME_CONT 2>&1) if [ $? -eq 0 ]; then printf "OK ($docker_id)\n" else echo $docker_id | grep Conflict > /dev/null 2>&1 if [ $? -eq 0 ]; then printf "A data container already exists ($VOLUME_ALIAS), use \"docker ps -a\" to see it\n" else eprintf "Error, please check data volume\nerror message: $docker_id\n" exit 1 fi fi printf "\nRunning Libervia\n\n" # we first check if we need to mount TLS directory if [ -n "$SAT_CONT_TLS_DIR" ]; then printf "$SAT_CONT_TLS_DIR will be used for TLS certificate\n" DK_TLS="--volume=$SAT_CONT_TLS_DIR:$CONT_CERT_DIR" fi for CONT in $CONTAINERS; do case $CONT in prosody) OPTS="$DK_DETACH $DK_TERM $DK_VOLUME $DK_TLS $(public_ports_arg $CONT) --name prosody" if [ -n "$SAT_CONT_DOMAIN" ]; then OPTS="-e DOMAIN=$SAT_CONT_DOMAIN $OPTS" fi ;; sat_pubsub) OPTS="$DK_DETACH $DK_TERM $DK_VOLUME --name sat_pubsub --link=prosody:prosody";; salut) OPTS="$DK_DETACH $DK_TERM $DK_VOLUME --name salut --link=prosody:prosody";; sat) OPTS="$DK_DETACH $DK_TERM $DK_VOLUME -P $(public_ports_arg $CONT) --name sat --link=prosody:prosody";; libervia) OPTS="$DK_DETACH $DK_TERM $DK_VOLUME --volumes-from sat $DK_TLS -P $(public_ports_arg $CONT) --name libervia --link=sat:sat";; *) eprintf "Unkown container $CONT\n"; exit 1 esac printf "Launching $CONT... " docker_id=$(docker run $OPTS $SAT_CONT_DK_EXTRA $ACCOUNT/$CONT 2>&1) if [ $? -eq 0 ]; then printf "OK ($docker_id)\n" else eprintf "Error, please check container or ask help on XMPP MUC sat@chat.jabberfr.org\nerror message: $docker_id\n" eprintf "Abandon\n" exit 1 fi done printf '\nLibervia is launched and should be reachable in a couple of seconds.\nYou can check logs with "docker logs -f libervia" (or any other container name).\n' printf "An \"admin\" account has been created, you can check its password on $VOLUME_ALIAS container, in file /home/sat/ADMIN_PWD. Config can be tuned on this container.\n" printf 'Below are the ports used to connect, you can go with your browser to Libervia HTTP(S) port.\n\n' list_ports ;; STOP) printf "stopping Libervia\n" REVERSED="" for CONT in $CONTAINERS; do REVERSED="$CONT $REVERSED" done; for CONT in $REVERSED; do printf "\nStopping container $CONT" docker stop $CONT > /dev/null 2>&1 || eprintf "... Error while stopping $CONT\n" printf "\rDeleting container $CONT" docker rm -v $CONT > /dev/null 2>&1 || eprintf "... Error while removing $CONT\n" done printf "\n" ;; RESTART) printf "restarting containers...\n" "$0" stop && "$0" start "$@" ;; STATUS) docker inspect $TEST_CONT > /dev/null 2>&1 if [ $? -eq 0 ]; then printf "$APP_NAME is running" # we test the presence of "starting on xxxx" (where xxxx is one of the exposed ports) # this is not really reliable as ports can be changed in configuration # but in most case it should work OK PORTS_REGEX=$(get_dyn_var $TEST_CONT ports | sed 's/ /\\|/') docker logs $TEST_CONT | grep "starting on \($PORTS_REGEX\)" > /dev/null 2>&1 if [ $? -ne 0 ]; then printf " but no server is started\n" exit 2 fi printf "\n" exit 0 else printf "$APP_NAME is not running\n" exit 1 fi ;; UPDATE) printf "updating images...\n" errors=0 for CONT in $CONTAINERS data; do printf "\n*** updating $CONT ***\n" docker pull $ACCOUNT/$CONT:latest if [ $? -ne 0 ]; then eprintf "\nError while updating $ACCOUNT/$CONT\n" errors=1 fi done if [ $errors -eq 0 ]; then printf "\n\nImages are up-to-date\n" else eprintf "\n\nSome errors happened while updating images\n" exit 1 fi ;; BACKUP) case $# in 0) SAT_CONT_BACKUP_DIR="$(pwd)";; 1) SAT_CONT_BACKUP_DIR="$1";; *) printf "syntaxe is $0 backup [backup_dir_absolute_path]\n[backup_dir_absolute_path] default to current working dir\n" exit 1 ;; esac SAT_CONT_BACKUP_DIR=$(echo $SAT_CONT_BACKUP_DIR | sed 's%^\/*\|\/*$%\/%g') # we want to be sure that path starts and finishes with "/" filename="sat_data_backup_$(date '+%Y-%m-%d_%H:%M:%S').tar.gz" printf "backing up data container to ${SAT_CONT_BACKUP_DIR}${filename}\n\n" docker run --rm $DK_VOLUME -v "$SAT_CONT_BACKUP_DIR:/backup" $MAINT_CONT tar zcvf "/backup/$filename" -C / -h volumes if [ $? -eq 0 ]; then printf "\nBackup finished and available at ${SAT_CONT_BACKUP_DIR}${filename}\n" else eprintf "\nBackup Error !\n" exit 1 fi ;; RESTORE) if [ $# -ne 1 ]; then printf "syntaxe is $0 restore <backup_file.tar.gz>\n" exit 1 fi docker run --name $VOLUME_ALIAS $VOLUME_CONT > /dev/null 2>&1 if [ $? -ne 0 ]; then eprintf "Can't create $VOLUME_ALIAS container.\n\ If you have an existing one, please remove it with \"docker rm -v $VOLUME_ALIAS\" (/!\\ it will remove *ALL* your data)\n\n\ Hint: you can also rename your current data container with \"docker rename $VOLUME_ALIAS new_container_name\"\n" exit 1 fi printf "restoring $1 to $VOLUME_ALIAS container\n\n" HOST_BACKUP_DIR=$(dirname "$1") HOST_BACKUP_NAME=$(basename "$1") if [ $HOST_BACKUP_DIR = "." ]; then # workaround for a Docker bug (container crash if "." is used) HOST_BACKUP_DIR=$(pwd) fi docker run --rm $DK_VOLUME -v "$HOST_BACKUP_DIR:/backup" $MAINT_CONT tar zxvf "/backup/$HOST_BACKUP_NAME" -C / -h volumes if [ $? -eq 0 ]; then printf "\nRestore finished\n" else eprintf "\nRestore Error !\n" exit 1 fi ;; PORTS) list_ports ;; CONFIG) case $# in 0) CONF="libervia";; 1) CONF="$1";; *) CONF="";; esac case $CONF in libervia) CONT_CONF_FILE="/home/sat/.config/sat/sat.conf" ;; prosody) CONT_CONF_FILE="/etc/prosody/prosody_sat_cfg/prosody.cfg.lua" ;; *) printf "\nPlease enter type of configuration to edit (libervia, prosody)\n" exit 1 ;; esac HOST_CONF_FILE=$(basename $CONT_CONF_FILE) printf "\ngetting configuration for $CONF\n" # we copy config file to a temporary dit # then edit with $EDITOR and put it back TMP_DIR=$(mktemp -d 2>/dev/null) if [ $? -ne 0 ]; then TMP_DIR="$DEFAULT_TMP_DIR" mkdir -p "$TMP_DIR" fi docker cp "$VOLUME_ALIAS:$CONT_CONF_FILE" "$TMP_DIR/" "$EDITOR" "$TMP_DIR/$HOST_CONF_FILE" if [ $? -eq 0 -a -s "$TMP_DIR/$HOST_CONF_FILE" ]; then printf "updating configuration\n" check_docker_version 1 8 0 if [ $? -eq 0 ]; then docker cp "$TMP_DIR/$HOST_CONF_FILE" "$VOLUME_ALIAS:$CONT_CONF_FILE" else eprintf "Old Docker version detected, using workaround, please update!\n" docker run --rm $DK_VOLUME -v "$TMP_DIR:/tmp_config" $MAINT_CONT /bin/cp -f "/tmp_config/$HOST_CONF_FILE" "$CONT_CONF_FILE" fi # "docker cp" copy file on container as root, if an option is available later to change this behaviour, # the following operation could be removed printf "ownership fix..." docker run --rm $DK_VOLUME $MAINT_CONT /bin/chown 1000:1000 "$CONT_CONF_FILE" printf "done\n" fi rm -rf "$TMP_DIR" ;; STATS) if [ -n "$1" -a "$1" != "--no-stream" ]; then printf "usage: $0 stats [--no-stream]\n" exit 1 fi docker stats $1 $CONTAINERS ;; *) eprintf "Error: unknown command !" exit 2 esac