#!/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.7 image=seafileltd/seafile:$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 logdbg() { if [[ $verbose == "true" ]]; then loginfo "[debug] $1" fi } loginfo() { 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 || { loginfo "Pulling Seafile server image $version, this may take a while." docker pull $image loginfo "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 loginfo "Now building the local docker image." docker build -f bootstrap/generated/Dockerfile -t local_seafile/server:latest . >/dev/null loginfo "Image built." } start() { existing=$(docker ps | awk '{ print $1, $(NF) }' | grep " seafile$" | awk '{ print $1 }' || true) if [[ $existing != "" ]]; then loginfo "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 loginfo "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 loginfo "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) logdbg "Your version: ${last_version}, latest version: ${version}" if [[ $last_major_version != "$current_major_version" ]]; then loginfo "******* Major upgrade detected *******" loginfo "You have $last_version, latest is $version" loginfo "Please run './launcher rebuild' to upgrade" exit 1 fi } check_upgrade() { loginfo "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 loginfo "********************************" loginfo "Major upgrade detected: You have $last_version, latest is $version" loginfo "********************************" # use_manual_upgrade=true if [[ $use_manual_upgrade == "true" ]]; then loginfo "Now you can run './launcher manual-upgrade' to do manual upgrade." exit 0 else loginfo "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 loginfo "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 loginfo "Launcher is up-to-date" elif [[ $LOCAL = "$BASE" ]]; then loginfo "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 loginfo "Your version of Launcher is ahead of origin" else loginfo "Launcher has diverged source, this is only expected in Dev mode" fi fi set_existing_container if [[ $existing != "" ]]; then loginfo "Stopping old container" ( set -x docker stop -t 10 seafile ) fi bootstrap loginfo "Rebuilt successfully." if [[ $existing != "" ]]; then loginfo "Removing old container" ( set -x docker rm seafile ) fi check_upgrade start loginfo "Your seafile server is now running." exit 0 } manual_upgrade() { _launch_for_upgrade loginfo "If you have manually upgraded the server, please update the version stamp by:" loginfo loginfo " echo $version | sudo tee $version_stamp_file" loginfo " sudo ./launcher start" loginfo } 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 "$@"