#!/bin/bash command=$1 config=$2 opt=$3 config_file=containers/"$config".yml cidfile=cids/"$config".cid cidbootstrap=cids/"$config"_boostrap.cid local_discourse=local_discourse image=samsaffron/discourse:0.2.0 docker_path=`which docker` docker_ip=`/sbin/ifconfig | \ grep -B1 "inet addr" | \ awk '{ if ( $1 == "inet" ) { print $2 } else if ( $2 == "Link" ) { printf "%s:" ,$1 } }' | \ grep docker0 | \ awk -F: '{ print $3 }';` usage () { echo "Usage: launcher COMMAND CONFIG [--skip-prereqs]" echo "Commands:" echo " start: Start/initialize a container" echo " stop: Stop a running container" echo " restart: Restart a container" echo " destroy: Stop and remove a container" echo " ssh: Start a bash shell in a running container" echo " logs: Docker logs for container" echo " bootstrap: Bootstrap a container for the config based on a template" echo " rebuild: Rebuild a container (destroy old, bootstrap, start new)" echo echo "Options:" echo " --skip-prereqs Don't check prerequisites" exit 1 } prereqs() { # 1. docker daemon running? test=`docker info >/dev/null` if [[ $? -ne 0 ]] ; then echo "Cannot connect to the docker daemon - verify it is running and you have access" exit 1 fi # 2. running aufs test=`docker info 2> /dev/null | grep 'Driver: aufs'` if [[ "$test" =~ "aufs" ]] ; then : ; else echo "Your Docker installation is not using aufs" echo "Device mapper and other experimental drivers are unstable" echo echo "Please ensure your kernel is running linux extras and aufs" echo "Please follow the installation guide for Docker here: http://docs.docker.io/en/latest/installation/ubuntulinux/" exit 1 fi # 3. running docker 0.10+ test=`docker --version | grep 0.10` if [[ "$test" =~ "0.10" ]] ; then : ; else echo "Your Docker installation is old, please upgrade to 0.10.0 or up" exit 1 fi # 4. able to attach stderr / out / tty test=`docker run -i --rm -a stdout -a stderr $image echo working` if [[ "$test" =~ "working" ]] ; then : ; else echo "Your Docker installation is not working correctly" echo echo "See: https://meta.discourse.org/t/docker-error-on-bootstrap/13657/18?u=sam" exit 1 fi } if [ "$opt" != "--skip-prereqs" ] ; then prereqs fi get_ssh_pub_key() { if tty -s ; then if [[ ! -e ~/.ssh/id_rsa.pub && ! -e ~/.ssh/id_dsa.pub ]] ; then echo You have no SSH key associated to this profile echo "(This will allow you ssh access into your container)" read -p "Generate SSH key at ~/.ssh/id_rsa.pub? (y/N) " -n 1 -r if [[ $REPLY =~ ^[Yy]$ ]] ; then echo echo Generating SSH key mkdir -p ~/.ssh && ssh-keygen -f ~/.ssh/id_rsa -t rsa -N '' else echo echo WARNING: You may not be able to log in to your container. echo fi fi fi ssh_pub_key="$(cat ~/.ssh/id_rsa.pub 2>/dev/null || cat ~/.ssh/id_dsa.pub)" } install_docker() { echo "Docker is not installed, make sure you are running on the 3.8 kernel" echo "The best supported Docker release is Ubuntu 12.04.03 for it run the following" echo echo "sudo apt-get update" echo "sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring" echo "sudo reboot" echo echo "sudo sh -c \"wget -qO- https://get.docker.io/gpg | apt-key add -\"" echo "sudo sh -c \"echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list\"" echo "sudo apt-get update" echo "sudo apt-get install lxc-docker" exit 1 } set_volumes() { volumes=`cat $config_file | docker run --rm -i -a stdout -a stdin $image ruby -e \ "require 'yaml'; puts YAML.load(STDIN.readlines.join)['volumes'].map{|v| '-v ' << v['volume']['host'] << ':' << v['volume']['guest'] << ' '}.join"` } set_template_info() { templates=`cat $config_file | docker run --rm -i -a stdin -a stdout $image ruby -e \ "require 'yaml'; puts YAML.load(STDIN.readlines.join)['templates']"` arrTemplates=(${templates// / }) config_data=$(cat $config_file) input="hack: true" for template in "${arrTemplates[@]}" do [ ! -z $template ] && { input="$input _FILE_SEPERATOR_ $(cat $template)" } done # we always want our config file last so it takes priority input="$input _FILE_SEPERATOR_ $config_data" read -r -d '' env_ruby << 'RUBY' require 'yaml' input=STDIN.readlines.join env = {} input.split('_FILE_SEPERATOR_').each do |yml| yml.strip! begin env.merge!(YAML.load(yml)['env'] || {}) rescue => e puts yml p e end end puts env.map{|k,v| "-e\n#{k}=#{v}" }.join("\n") RUBY raw=`exec echo "$input" | docker run --rm -i -a stdin -a stdout $image ruby -e "$env_ruby"` env=() while read i; do env[${#env[@]}]=$i done <<< "$raw" echo "Calculated ENV: ${env[@]}" } [ -z $docker_path ] && { install_docker } [ $# -lt 2 ] && { usage } if [ ! -e $config_file ] then echo "Config file was not found, ensure $config_file exists" exit 1 fi run_stop(){ if [ ! -e $cidfile ] then echo "No cid found" exit 1 else docker stop -t 10 `cat $cidfile` fi } run_start(){ if [ ! -e $cidfile ] then echo "No cid found, creating a new container" ports=`cat $config_file | docker run --rm -i -a stdout -a stdin $image ruby -e \ "require 'yaml'; puts YAML.load(STDIN.readlines.join)['expose'].map{|p| '-p ' << p.to_s << ' '}.join"` set_template_info set_volumes existing=`docker ps -a | awk '{ print $1, $(NF) }' | grep "$config$" | awk '{ print $1 }'` if [ ! -z $existing ] then echo "Found an existing container by its name, recovering cidfile, please rerun" echo $existing > $cidfile exit 1 fi docker run "${env[@]}" -h "`hostname`-$config" -e DOCKER_HOST_IP=$docker_ip --name $config -t --cidfile $cidfile $ports \ -d $volumes $local_discourse/$config /usr/bin/runsvdir -P /etc/service exit 0 else cid=`cat $cidfile` if [ -z $cid ] then echo "Detected empty cid file, deleting, please re-run" rm $cidfile exit 1 fi found=`docker ps -q -a --no-trunc | grep $cid` if [ -z $found ] then echo "Invalid cid file, deleting, please re-run" rm $cidfile exit 1 fi echo "cid found, ensuring container is started" docker start `cat $cidfile` exit 0 fi } run_bootstrap(){ get_ssh_pub_key # Is the image available? # If not, pull it here so the user is aware what's happening. docker history $image >/dev/null 2>&1 || docker pull $image set_template_info base_image=`cat $config_file | docker run --rm -i -a stdin -a stdout $image ruby -e \ "require 'yaml'; puts YAML.load(STDIN.readlines.join)['base_image']"` update_pups=`cat $config_file | docker run --rm -i -a stdin -a stdout $image ruby -e \ "require 'yaml'; puts YAML.load(STDIN.readlines.join)['update_pups']"` if [[ ! X"" = X"$base_image" ]]; then image=$base_image fi set_volumes rm -f $cidbootstrap run_command="cd /pups &&" if [[ ! "false" = $update_pups ]]; then run_command="$run_command git pull &&" fi run_command="$run_command /pups/bin/pups --stdin" echo $run_command env=("${env[@]}" "-e" "SSH_PUB_KEY=$ssh_pub_key") (exec echo "$input" | docker run "${env[@]}" -e DOCKER_HOST_IP=$docker_ip --cidfile $cidbootstrap -i -a stdin -a stdout -a stderr $volumes $image \ /bin/bash -c "$run_command") \ || (docker rm `cat $cidbootstrap` && rm $cidbootstrap) [ ! -e $cidbootstrap ] && echo "FAILED TO BOOTSTRAP" && exit 1 sleep 5 docker commit `cat $cidbootstrap` $local_discourse/$config || echo 'FAILED TO COMMIT' docker rm `cat $cidbootstrap` && rm $cidbootstrap } case "$command" in bootstrap) run_bootstrap echo "Successfully bootstrapped, to startup use ./launcher start $config" exit 0 ;; ssh) if [ ! -e $cidfile ] then echo "No cid found" exit 1 else cid="`cat $cidfile`" address="`docker port $cid 22`" split=(${address//:/ }) exec ssh -o StrictHostKeyChecking=no root@${split[0]} -p ${split[1]} fi ;; stop) run_stop exit 0 ;; logs) if [ ! -e $cidfile ] then echo "No cid found" exit 1 else docker logs `cat $cidfile` exit 0 fi ;; restart) run_stop run_start exit 0 ;; start) run_start exit 0 ;; rebuild) if [ -e $cidfile ] then echo "Stopping old container" docker stop -t 10 `cat $cidfile` fi run_bootstrap if [ -e $cidfile ] then docker rm `cat $cidfile` && rm $cidfile fi run_start exit 0 ;; destroy) if [ -e $cidfile ] then echo "destroying container $cidfile" docker stop -t 10 `cat $cidfile` docker rm `cat $cidfile` && rm $cidfile exit 0 else echo "nothing to destroy cidfile does not exist" exit 1 fi ;; esac usage