#!/bin/bash usage () { echo "Usage: launcher COMMAND [--skip-prereqs] [--docker-args STRING]" echo "Commands:" echo " start: Start/initialize the container" echo " stop: Stop a running container" echo " restart: Restart the container" echo " destroy: Stop and remove the container" echo " enter: Open a shell to run commands inside the container" echo " logs: View the Docker container logs" echo " bootstrap: Bootstrap the container based on a template" echo " rebuild: Rebuild the container (destroy old, bootstrap, start new)" echo echo "Options:" echo " --skip-prereqs Don't check launcher prerequisites" echo " --docker-args Extra arguments to pass when running docker" exit 1 } set -e set -o pipefail version=6.0.5 image=seafileorg/server:$version local_image=local_seafile/server:latest dockerdir=$(cd "$(dirname $0)"; pwd -P) sharedir=$dockerdir/shared installdir=/opt/seafile/seafile-server-$version bootstrap_conf=$dockerdir/bootstrap/bootstrap.conf version_stamp_file=$sharedir/seafile/seafile-data/current_version cd $dockerdir dlog() { if [[ $verbose == "true" ]]; then show_progress "[debug] $1" fi } show_progress() { if [[ -t 1 ]]; then >&2 printf "[$(date +'%Y-%m-%d %H:%M:%S')] \033[32m%s\033[m\n" "$1" else >&2 echo "[$(date +'%Y-%m-%d %H:%M:%S')] " "$1" fi } install_docker() { echo "---------------------------------------------------------------------------------" echo "Docker is not installed, you will need to install Docker in order to run Launcher" echo "See https://docs.docker.com/installation/" echo "---------------------------------------------------------------------------------" exit 1 } err_and_quit () { if [[ -t 1 ]]; then >&2 printf "\n\n\033[33mError: %s\033[m\n\n" "$1" else >&2 echo "$1" fi exit 1 } init_shared() { mkdir -p $sharedir/{seafile,db} mkdir -p $sharedir/logs/{seafile,var-log} mkdir -p $sharedir/logs/var-log/nginx touch $sharedir/logs/var-log/syslog local bash_history=$sharedir/.bash_history if [[ ! -e $bash_history ]]; then touch $bash_history fi } set_envs() { envs="" if [[ $verbose == "true" ]]; then envs="$envs -e SEAFILE_DOCKER_VERBOSE=true" fi } set_ports() { ports=$(docker run $user_args --rm -it \ -v ${dockerdir}/scripts:/scripts \ -v ${dockerdir}/bootstrap:/bootstrap:ro \ $image \ /scripts/bootstrap.py --parse-ports) } set_bootstrap_volumes() { local mounts init_shared mounts=( $sharedir:/shared $sharedir/logs/var-log:/var/log $sharedir/db:/var/lib/mysql $dockerdir/bootstrap:/bootstrap $dockerdir/scripts:/scripts:ro $dockerdir/templates:/templates:ro $dockerdir/scripts/tmp/check_init_admin.py:$installdir/check_init_admin.py:ro $sharedir/.bash_history:/root/.bash_history ) volumes="" local m for m in ${mounts[*]}; do volumes="$volumes -v $m" done } set_volumes() { local mounts init_shared mounts=( $sharedir:/shared $sharedir/logs/var-log:/var/log $sharedir/db:/var/lib/mysql $sharedir/.bash_history:/root/.bash_history ) volumes="" local m for m in ${mounts[*]}; do volumes="$volumes -v $m" done } set_existing_container() { existing=$(docker ps -a | awk '{ print $1, $(NF) }' | grep " seafile$" | awk '{ print $1 }' || true) } bootstrap() { if [[ ! -e $bootstrap_conf ]]; then err_and_quit "The file $bootstrap_conf doesn't exist. Have you run seafile-server-setup?" fi docker history $image >/dev/null 2>&1 || { show_progress "Pulling Seafile server image $version, this may take a while." docker pull $image show_progress "Seafile server image $version pulled. Now bootstrapping the server ..." } # First initialize seafile server and letsencrypt set_envs set_bootstrap_volumes set_ports docker run $user_args --rm -it --name seafile-bootstrap -e SEAFILE_BOOTSRAP=1 $envs $volumes $ports $image /sbin/my_init $quiet -- /scripts/bootstrap.py show_progress "Now building the local docker image." docker build -f bootstrap/generated/Dockerfile -t local_seafile/server:latest . >/dev/null show_progress "Image built." } start() { existing=$(docker ps | awk '{ print $1, $(NF) }' | grep " seafile$" | awk '{ print $1 }' || true) if [[ $existing != "" ]]; then show_progress "Nothing to do, your container has already started!" exit 0 fi check_version_match chmod 0700 $dockerdir/bootstrap $sharedir/seafile/conf set_existing_container if [[ $existing != "" ]]; then show_progress "starting up existing container" ( set -x docker start seafile ) exit 0 fi set_envs set_volumes set_ports local restart_policy attach_on_run if [[ "${SUPERVISED}" = "true" ]]; then restart_policy="--restart=no" attach_on_run="-a stdout -a stderr" else attach_on_run="-d" fi show_progress "Starting up new seafile server container" ( set -x docker run $user_args $attach_on_run $restart_policy --name seafile -h seafile $envs $volumes $ports $local_image ) } ensure_container_running() { set_existing_container if [[ $existing == "" ]]; then err_and_quit "seafile was not started !" fi } stop() { ensure_container_running ( set -x docker stop -t 10 seafile ) } enter() { ensure_container_running ( set -x docker exec -it seafile /bin/bash ) } restart() { stop start } check_prereqs() { if [[ $SKIP_PREREQS == "true" ]]; then return 0 fi # check docker if ! which docker >/dev/null; then install_docker fi # TODO: check git version } logs() { ensure_container_running ( set -x docker logs --tail=20 -f seafile ) } destroy() { ( set -x docker stop -t 10 seafile || true docker rm seafile ) } get_major_version() { echo $1| awk -F . '{printf "%s.%s", $1, $2}' } check_version_match() { local last_version last_major_version current_major_version last_version=$(cat $version_stamp_file) last_major_version=$(get_major_version $last_version) current_major_version=$(get_major_version $version) dlog "Your version: ${last_version}, latest version: ${version}" if [[ $last_major_version != "$current_major_version" ]]; then show_progress "******* Major upgrade detected *******" show_progress "You have $last_version, latest is $version" show_progress "Please run './launcher rebuild' to upgrade" exit 1 fi } check_upgrade() { show_progress "Checking if there is major version upgrade" local last_version last_major_version current_major_version last_version=$(cat $version_stamp_file) last_major_version=$(get_major_version $last_version) current_major_version=$(get_major_version $version) if [[ $last_major_version == "$current_major_version" ]]; then return else show_progress "********************************" show_progress "Major upgrade detected: You have $last_version, latest is $version" show_progress "********************************" # use_manual_upgrade=true if [[ $use_manual_upgrade == "true" ]]; then show_progress "Now you can run './launcher manual-upgrade' to do manual upgrade." exit 0 else show_progress "Going to launch the docker container for manual upgrade" _launch_for_upgrade --auto fi fi } _launch_for_upgrade() { local cmd if [[ $1 == "--auto" ]]; then cmd="/scripts/upgrade.py" else cmd="/bin/bash" fi set_envs set_volumes ( set -x docker run $user_args \ -it --rm --name seafile-upgrade -h seafile \ $envs $volumes $local_image \ /sbin/my_init $quiet -- $cmd ) } rebuild() { if [[ "$(git symbolic-ref --short HEAD)" == "master" ]]; then show_progress "Ensuring launcher is up to date" git remote update LOCAL=$(git rev-parse @) REMOTE=$(git rev-parse "@{u}") BASE=$(git merge-base @ "@{u}") if [[ $LOCAL = "$REMOTE" ]]; then show_progress "Launcher is up-to-date" elif [[ $LOCAL = "$BASE" ]]; then show_progress "Updating Launcher" git pull || (echo 'failed to update' && exit 1) for (( i=${#BASH_ARGV[@]}-1,j=0; i>=0,j<${#BASH_ARGV[@]}; i--,j++ )) do args[$j]=${BASH_ARGV[$i]} done exec /bin/bash $0 "${args[@]}" # $@ is empty, because of shift at the beginning. Use BASH_ARGV instead. elif [[ $REMOTE = "$BASE" ]]; then show_progress "Your version of Launcher is ahead of origin" else show_progress "Launcher has diverged source, this is only expected in Dev mode" fi fi set_existing_container if [[ $existing != "" ]]; then show_progress "Stopping old container" ( set -x docker stop -t 10 seafile ) fi bootstrap show_progress "Rebuilt successfully." if [[ $existing != "" ]]; then show_progress "Removing old container" ( set -x docker rm seafile ) fi check_upgrade start show_progress "Your seafile server is now running." exit 0 } manual_upgrade() { _launch_for_upgrade } main() { local action while [[ $# -gt 0 ]] do case "$1" in bootstrap|start|stop|restart|enter|destroy|logs|rebuild|manual-upgrade) action=${1//-/_} ; shift 1 ;; -h|--help) ( usage ; exit 1) ; shift 1 ;; -v|--verbose) verbose=true ; shift 1 ;; --skip-prereqs) SKIP_PREREQS=true ; shift 1 ;; --docker-args) user_args=$2 ; shift 2 ;; --manual-upgrade) use_manual_upgrade=true ; shift 1 ;; *) err_and_quit "Argument error. Please see help." ;; esac done # By default we suppress the verbose logs like "Running # /etc/my_init.d/99_mysql_setup.sh". Use "./launcher -v " to enable # printing of these verbose logs. quiet="--quiet" if [[ $verbose == "true" ]]; then quiet="" fi "$action" } check_prereqs main "$@"