echo " stop: Stop a running container"
echo " restart: Restart a container"
echo " destroy: Stop and remove a container"
- echo " enter: Use nsenter to get a shell into a container"
+ echo " enter: Open a shell to run commands inside the container"
echo " logs: View the Docker logs for a container"
echo " bootstrap: Bootstrap a container for the config based on a template"
echo " rebuild: Rebuild a container (destroy old, bootstrap, start new)"
echo "Options:"
echo " --skip-prereqs Don't check launcher prerequisites"
echo " --docker-args Extra arguments to pass when running docker"
+ echo " --skip-mac-address Don't assign a mac address"
exit 1
}
while [ ${#} -gt 0 ]; do
case "${1}" in
-
+ --debug)
+ DEBUG="1"
+ ;;
--skip-prereqs)
- SKIP_PREREQ="1"
+ SKIP_PREREQS="1"
+ ;;
+ --skip-mac-address)
+ SKIP_MAC_ADDRESS="1"
;;
--docker-args)
user_args="$2"
cd "$(dirname "$0")"
-docker_min_version='1.6.0'
-docker_rec_version='1.6.0'
+docker_min_version='17.03.1'
+docker_rec_version='17.06.2'
git_min_version='1.8.0'
git_rec_version='1.8.0'
config_file=containers/"$config".yml
cidbootstrap=cids/"$config"_bootstrap.cid
local_discourse=local_discourse
-image=discourse/discourse:1.0.17
+image=discourse/base:2.0.20171204
docker_path=`which docker.io || which docker`
git_path=`which git`
awk -F: '{ print $3 }';`
fi
+# From https://stackoverflow.com/a/44660519/702738
compare_version() {
- declare -a ver_a
- declare -a ver_b
- IFS=. read -a ver_a <<< "$1"
- IFS=. read -a ver_b <<< "$2"
-
- while [[ -n $ver_a ]]; do
- if (( ver_a > ver_b )); then
- return 0
- elif (( ver_b > ver_a )); then
+ if [[ $1 == $2 ]]; then
+ return 1
+ fi
+ local IFS=.
+ local i a=(${1%%[^0-9.]*}) b=(${2%%[^0-9.]*})
+ local arem=${1#${1%%[^0-9.]*}} brem=${2#${2%%[^0-9.]*}}
+ for ((i=0; i<${#a[@]} || i<${#b[@]}; i++)); do
+ if ((10#${a[i]:-0} < 10#${b[i]:-0})); then
return 1
- else
- unset ver_a[0]
- ver_a=("${ver_a[@]}")
- unset ver_b[0]
- ver_b=("${ver_b[@]}")
+ elif ((10#${a[i]:-0} > 10#${b[i]:-0})); then
+ return 0
fi
done
- return 1 # They are equal
+ if [ "$arem" '<' "$brem" ]; then
+ return 1
+ elif [ "$arem" '>' "$brem" ]; then
+ return 0
+ fi
+ return 1
}
install_docker() {
echo "Docker is not installed, you will need to install Docker in order to run Launcher"
- echo "Please visit https://docs.docker.com/installation/ for instructions on how to do this for your system"
- echo
- echo "If you are running a recent Ubuntu Server, try the following:"
- echo "sudo apt-get install docker-engine"
+ echo "See https://docs.docker.com/installation/"
exit 1
}
exit 1
fi
- # 2. running aufs or btrfs
- test=`$docker_path info 2> /dev/null | grep 'Driver: '`
- if [[ "$test" =~ [aufs|btrfs|zfs|overlay] ]] ; then : ; else
- echo "Your Docker installation is not using a supported filesystem if we were to proceed you may have a broken install."
- echo "aufs is the recommended filesystem you should be using (zfs/btrfs and overlay may work as well)"
- echo "You can tell what filesystem you are using by running \"docker info\" and looking at the driver"
+ # 2. running an approved storage driver?
+ if ! $docker_path info 2> /dev/null | egrep -q '^Storage Driver: (aufs|btrfs|zfs|overlay|overlay2)$'; then
+ echo "Your Docker installation is not using a supported storage driver. If we were to proceed you may have a broken install."
+ echo "aufs is the recommended storage driver, although zfs/btrfs/overlay and overlay2 may work as well."
+ echo "Other storage drivers are known to be problematic."
+ echo "You can tell what filesystem you are using by running \"docker info\" and looking at the 'Storage Driver' line."
echo
- echo "If you wish to continue anyway using your existing unsupported filesystem, "
- echo "read the source code of launcher and figure out how to bypass this."
+ echo "If you wish to continue anyway using your existing unsupported storage driver,"
+ echo "read the source code of launcher and figure out how to bypass this check."
exit 1
fi
exit 1
fi
+ # 7. enough space for the bootstrap on docker folder
+ folder=`$docker_path info --format '{{.DockerRootDir}}'`
+ safe_folder=${folder:-/var/lib/docker}
+ test=$(($(stat -f --format="%a*%S" $safe_folder)/1024**3 < 5))
+ if [[ $test -ne 0 ]] ; then
+ echo "You have less than 5GB of free space on the disk where $safe_folder is located. You will need more space to continue"
+ df -h $safe_folder
+ echo
+ read -p "Would you like to attempt to recover space by cleaning docker images and containers in the system?(y/N)" -n 1 -r
+ echo
+ if [[ $REPLY =~ ^[Yy]$ ]]
+ then
+ docker system prune
+ echo "If the cleanup was successful, you may try again now"
+ fi
+ exit 1
+ fi
}
-if [ -z "$SKIP_PREREQS" ] ; then
+if [ -z "$SKIP_PREREQS" ] && [ "$command" != "cleanup" ]; then
check_prereqs
fi
"require 'yaml'; puts YAML.load(STDIN.readlines.join)['links'].map{|l| '--link ' << l['link']['name'] << ':' << l['link']['alias'] << ' '}.join"`
}
-set_template_info() {
-
- templates=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
+find_templates() {
+ local templates=`cat $1 | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
"require 'yaml'; puts YAML.load(STDIN.readlines.join)['templates']"`
+ local arrTemplates=${templates// / }
+
+ if [ ! -z "$templates" ]; then
+ for template in "${arrTemplates[@]}"
+ do
+ local nested_templates=$(find_templates $template)
+
+ if [ ! -z "$nested_templates" ]; then
+ templates="$templates $nested_templates"
+ fi
+ done
+
+ echo $templates
+ else
+ echo ""
+ fi
+}
+
+set_template_info() {
+ templates=$(find_templates $config_file)
+
arrTemplates=(${templates// / })
config_data=$(cat $config_file)
echo "YAML syntax error. Please check your containers/*.yml config files."
exit 1
fi
+
+ read -r -d '' labels_ruby << 'RUBY'
+ require 'yaml'
+
+ input=STDIN.readlines.join
+ # default to UTF-8 for the dbs sake
+ labels = {}
+ input.split('_FILE_SEPERATOR_').each do |yml|
+ yml.strip!
+ begin
+ labels.merge!(YAML.load(yml)['labels'] || {})
+ rescue Psych::SyntaxError => e
+ puts e
+ puts "*ERROR."
+ rescue => e
+ puts yml
+ p e
+ end
+ end
+ puts labels.map{|k,v| "-l\n#{k}=#{v}" }.join("\n")
+RUBY
+
+ raw=`exec echo "$input" | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e "$labels_ruby"`
+
+ labels=()
+ ok=1
+ while read i; do
+ if [ "$i" == "*ERROR." ]; then
+ ok=0
+ elif [ -n "$i" ]; then
+ labels[${#labels[@]}]=$(echo $i | sed s/{{config}}/${config}/g)
+ fi
+ done <<< "$raw"
+
+ if [ "$ok" -ne 1 ]; then
+ echo "${labels[@]}"
+ echo "YAML syntax error. Please check your containers/*.yml config files."
+ exit 1
+ fi
}
if [ -z $docker_path ]; then
host_run
+ ports=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
+ "require 'yaml'; puts YAML.load(STDIN.readlines.join)['expose'].map{|p| \"-p #{p}\"}.join(' ')"`
+
docker_args=`cat $config_file | $docker_path run $user_args --rm -i -a stdout -a stdin $image ruby -e \
"require 'yaml'; puts YAML.load(STDIN.readlines.join)['docker_args']"`
# docker added more hostname rules
hostname=${hostname//_/-}
+
+ if [ -z "$SKIP_MAC_ADDRESS" ] ; then
+ mac_address="--mac-address $($docker_path run $user_args -i --rm -a stdout -a stderr $image /bin/sh -c "echo $hostname | md5sum | sed 's/^\(..\)\(..\)\(..\)\(..\)\(..\).*$/02:\1:\2:\3:\4:\5/'")"
+ fi
+
set -x
- $docker_path run $user_args $links $attach_on_run $restart_policy "${env[@]}" -h "$hostname" \
- -e DOCKER_HOST_IP=$docker_ip --name $config -t $ports $volumes $docker_args $run_image $boot_command
+ $docker_path run $links $attach_on_run $restart_policy "${env[@]}" "${labels[@]}" -h "$hostname" \
+ -e DOCKER_HOST_IP="$docker_ip" --name $config -t $ports $volumes $mac_address $docker_args $user_args \
+ $run_image $boot_command
)
exit 0
echo $run_command
- (exec echo "$input" | $docker_path run $user_args $links "${env[@]}" -e DOCKER_HOST_IP=$docker_ip --cidfile $cidbootstrap -i -a stdin -a stdout -a stderr $volumes $image \
- /bin/bash -c "$run_command") \
- || ($docker_path rm `cat $cidbootstrap` && rm $cidbootstrap)
+ unset ERR
+ (exec echo "$input" | $docker_path run $user_args $links "${env[@]}" -e DOCKER_HOST_IP="$docker_ip" --cidfile $cidbootstrap -i -a stdin -a stdout -a stderr $volumes $image \
+ /bin/bash -c "$run_command") || ERR=$?
+
+ unset FAILED
+ # magic exit code that indicates a retry
+ if [[ "$ERR" == 77 ]]; then
+ $docker_path rm `cat $cidbootstrap`
+ rm $cidbootstrap
+ exit 77
+ elif [[ "$ERR" > 0 ]]; then
+ FAILED=TRUE
+ fi
+
+ if [[ $FAILED = "TRUE" ]]; then
+ if [[ ! -z "$DEBUG" ]]; then
+ $docker_path commit `cat $cidbootstrap` $local_discourse/$config-debug || echo 'FAILED TO COMMIT'
+ echo "** DEBUG ** Maintaining image for diagnostics $local_discourse/$config-debug"
+ fi
- [ ! -e $cidbootstrap ] && echo "** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one" && exit 1
+ $docker_path rm `cat $cidbootstrap`
+ rm $cidbootstrap
+ echo "** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one"
+ exit 1
+ fi
sleep 5
elif [ $LOCAL = $BASE ]; then
echo "Updating Launcher"
git pull || (echo 'failed to update' && exit 1)
- exec /bin/bash $0 $@
+
+ 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
echo "Your version of Launcher is ahead of origin"