Bumps version to 1.3.9
[discourse_docker.git] / launcher
index 65c82713290f9789a19545c19354c4f5e32c3dee..c58d1db1f3f2749655b4db2e39700e367fe129dd 100755 (executable)
--- a/launcher
+++ b/launcher
@@ -1,8 +1,48 @@
 #!/bin/bash
 
 #!/bin/bash
 
+usage () {
+  echo "Usage: launcher COMMAND CONFIG [--skip-prereqs] [--docker-args STRING]"
+  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 "    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 "    cleanup:    Remove all containers that have stopped for > 24 hours"
+  echo
+  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
+}
+
 command=$1
 config=$2
 command=$1
 config=$2
-opt=$3
+user_args=""
+
+while [ ${#} -gt 0 ]; do
+  case "${1}" in
+  --debug)
+    DEBUG="1"
+    ;;
+  --skip-prereqs)
+    SKIP_PREREQS="1"
+    ;;
+  --skip-mac-address)
+    SKIP_MAC_ADDRESS="1"
+    ;;
+  --docker-args)
+    user_args="$2"
+    shift
+    ;;
+  esac
+
+  shift 1
+done
 
 # Docker doesn't like uppercase characters, spaces or special characters, catch it now before we build everything out and then find out
 re='[A-Z/ !@#$%^&*()+~`=]'
 
 # Docker doesn't like uppercase characters, spaces or special characters, catch it now before we build everything out and then find out
 re='[A-Z/ !@#$%^&*()+~`=]'
@@ -16,16 +56,17 @@ fi
 
 cd "$(dirname "$0")"
 
 
 cd "$(dirname "$0")"
 
-docker_min_version='1.6.0'
-docker_rec_version='1.6.0'
+docker_min_version='1.8.0'
+docker_rec_version='1.8.0'
+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
 
 config_file=containers/"$config".yml
 cidbootstrap=cids/"$config"_bootstrap.cid
 local_discourse=local_discourse
-image=discourse/discourse:1.0.17
+image=discourse/discourse:1.3.9
 docker_path=`which docker.io || which docker`
 docker_path=`which docker.io || which docker`
-template_path=samples/standalone_template.yml
-changelog=/tmp/changelog # used to test whether sed did anything
+git_path=`which git`
 
 if [ "${SUPERVISED}" = "true" ]; then
   restart_policy="--restart=no"
 
 if [ "${SUPERVISED}" = "true" ]; then
   restart_policy="--restart=no"
@@ -49,28 +90,6 @@ else
                   awk -F: '{ print $3 }';`
 fi
 
                   awk -F: '{ print $3 }';`
 fi
 
-
-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 "    enter:      Use nsenter to enter 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 "    memconfig:  Configure defaults based on available RAM"
-  echo "    cleanup:    Remove all containers that have stopped for > 24 hours"
-  echo
-  echo "Options:"
-  echo "    --skip-prereqs   Don't check prerequisites or resource requirements"
-  echo "    --docker-args    Extra arguments to pass when running docker"
-  exit 1
-}
-
 compare_version() {
     declare -a ver_a
     declare -a ver_b
 compare_version() {
     declare -a ver_a
     declare -a ver_b
@@ -92,13 +111,23 @@ compare_version() {
     return 1  # They are equal
 }
 
     return 1  # They are equal
 }
 
-prereqs() {
+
+install_docker() {
+  echo "Docker is not installed, you will need to install Docker in order to run Launcher"
+  echo "See https://docs.docker.com/installation/"
+  exit 1
+}
+
+check_prereqs() {
+
+  if [ -z $docker_path ]; then
+    install_docker
+  fi
 
   # 1. docker daemon running?
   # we send stderr to /dev/null cause we don't care about warnings,
   # it usually complains about swap which does not matter
   test=`$docker_path info 2> /dev/null`
 
   # 1. docker daemon running?
   # we send stderr to /dev/null cause we don't care about warnings,
   # it usually complains about swap which does not matter
   test=`$docker_path info 2> /dev/null`
-
   if [[ $? -ne 0 ]] ; then
     echo "Cannot connect to the docker daemon - verify it is running and you have access"
     exit 1
   if [[ $? -ne 0 ]] ; then
     echo "Cannot connect to the docker daemon - verify it is running and you have access"
     exit 1
@@ -110,8 +139,8 @@ prereqs() {
     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"
     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"
-    echo ""
-    echo "If you wish to continue anyway using your existing unsupported filesystem"
+    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."
     exit 1
   fi
     echo "read the source code of launcher and figure out how to bypass this."
     exit 1
   fi
@@ -120,15 +149,13 @@ prereqs() {
   test=($($docker_path --version))  # Get docker version string
   test=${test[2]//,/}  # Get version alone and strip comma if exists
 
   test=($($docker_path --version))  # Get docker version string
   test=${test[2]//,/}  # Get version alone and strip comma if exists
 
-  [[ "$test" =~ "0.12.0" ]] && echo "You are running a broken version of Docker, please upgrade ASAP. See: https://meta.discourse.org/t/the-installation-stopped-in-the-middle/16311/ for more details." && exit 1
-
-  # At least minimum version
+  # At least minimum docker version
   if compare_version "${docker_min_version}" "${test}"; then
     echo "ERROR: Docker version ${test} not supported, please upgrade to at least ${docker_min_version}, or recommended ${docker_rec_version}"
     exit 1
   fi
 
   if compare_version "${docker_min_version}" "${test}"; then
     echo "ERROR: Docker version ${test} not supported, please upgrade to at least ${docker_min_version}, or recommended ${docker_rec_version}"
     exit 1
   fi
 
-  # Recommend best version
+  # Recommend newer docker version
   if compare_version "${docker_rec_version}" "${test}"; then
     echo "WARNING: Docker version ${test} deprecated, recommend upgrade to ${docker_rec_version} or newer."
   fi
   if compare_version "${docker_rec_version}" "${test}"; then
     echo "WARNING: Docker version ${test} deprecated, recommend upgrade to ${docker_rec_version} or newer."
   fi
@@ -143,126 +170,39 @@ prereqs() {
     echo
     echo "Please be patient"
     echo
     echo
     echo "Please be patient"
     echo
-
   fi
 
   fi
 
-  # 5. able to attach stderr / out / tty
-  test=`$docker_path run $user_args -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"
+  # 5. running recommended git version
+  test=($($git_path --version))  # Get git version string
+  test=${test[2]//,/}  # Get version alone and strip comma if exists
+
+  # At least minimum version
+  if compare_version "${git_min_version}" "${test}"; then
+    echo "ERROR: Git version ${test} not supported, please upgrade to at least ${git_min_version}, or recommended ${git_rec_version}"
     exit 1
   fi
 
     exit 1
   fi
 
-}
-
-check_resources() {
-  # Memory
-  resources="ok"
-  avail_mem="$(LANG=C free -m | grep '^Mem:' | awk '{print $2}')"
-  if [ "$avail_mem" -lt 900 ]; then
-    resources="insufficient"
-    echo "WARNING: You do not appear to have sufficient memory to run Discourse."
-    echo
-    echo "Your system may not work properly, or future upgrades of Discourse may"
-    echo "not complete successfully."
-    echo
-    echo "See https://github.com/discourse/discourse/blob/master/docs/INSTALL-cloud.md#create-new-cloud-server"
-  elif [ "$avail_mem" -lt 1800 ]; then
-    total_swap="$(LANG=C free -m | grep ^Swap: | awk '{print $2}')"
-    if [ "$total_swap" -lt 1000 ]; then
-      resources="insufficient"
-      echo "WARNING: You must have at least 1GB of swap when running with less"
-      echo "than 2GB of RAM."
-      echo
-      echo "Your system may not work properly, or future upgrades of Discourse may"
-      echo "not complete successfully."
-      echo
-      echo "See https://github.com/discourse/discourse/blob/master/docs/INSTALL-cloud.md#set-up-swap-if-needed"
-    fi
+  # Recommend best version
+  if compare_version "${git_rec_version}" "${test}"; then
+    echo "WARNING: Git version ${test} deprecated, recommend upgrade to ${git_rec_version} or newer."
   fi
 
   fi
 
-  # Disk space
-  free_disk="$(df /var | tail -n 1 | awk '{print $4}')"
-  if [ "$free_disk" -lt 5000 ]; then
-    resources="insufficient"
-    echo "WARNING: You must have at least 5GB of *free* disk space to run Discourse."
-    echo
-    echo "Insufficient disk space may result in problems running your site, and may"
-    echo "not even allow Discourse installation to complete successfully."
+  # 6. able to attach stderr / out / tty
+  test=`$docker_path run $user_args -i --rm -a stdout -a stderr $image echo working`
+  if [[ "$test" =~ "working" ]] ; then : ; else
+    echo "Your Docker installation is not working correctly"
     echo
     echo
-    echo "Please free up some space, or expand your disk, before continuing."
+    echo "See: https://meta.discourse.org/t/docker-error-on-bootstrap/13657/18?u=sam"
     exit 1
   fi
 
     exit 1
   fi
 
-  if [ -t 0 ] && [ "$resources" != "ok" ]; then
-    echo
-    read -p "Press ENTER to continue, or Ctrl-C to exit and give your system more resources"
-  fi
-}
-
-check_ports() {
-  local valid=$(netstat -tln | awk '{print $4}' | grep ":${1}\$")
-
-  if [ -n "$valid" ]; then
-    echo "Launcher has detected that port ${1} is in use."
-    echo ""
-    echo "If you are trying to run Discourse simultaneously with another web server like Apache or nginx, you will need to bind to a different port."
-    echo "See https://meta.discourse.org/t/17247 for help."
-    echo "To continue anyway, re-run Launcher with --skip-prereqs"
-    exit 1
-  fi
 }
 
 }
 
-if [ "$opt" != "--skip-prereqs" ] ; then
-  prereqs
-fi
 
 
-if [ "$opt" == "--docker-args" ] ; then
-  user_args=$4
-else
-  user_args=""
+if [ -z "$SKIP_PREREQS" ] ; then
+  check_prereqs
 fi
 
 fi
 
-get_ssh_pub_key() {
-  local ${ssh_key_locations}
-  ssh_key_locations=(
-    ~/.ssh/id_ed25519.pub
-    ~/.ssh/id_ecdsa.pub
-    ~/.ssh/id_rsa.pub
-    ~/.ssh/id_dsa.pub
-    ~core/.ssh/authorized_keys
-  )
-
-  local $keyfile
-  for keyfile in "${ssh_key_locations[@]}"; do
-    if [[ -e ${keyfile} ]] ; then
-      ssh_pub_key="$(cat ${keyfile})"
-      return 0
-    fi
-  done
-
-  return 0
-}
-
-
-install_docker() {
-
-  echo "Docker is not installed, you will need to install Docker in order to run Discourse"
-  echo "Please visit https://docs.docker.com/installation/ for instructions on how to do this for your system"
-  echo
-  echo "If you are running Ubuntu Trusty or later, you can try the following:"
-  echo
-
-  echo "sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D"
-  echo "sudo sh -c \"echo deb https://apt.dockerproject.org/repo ubuntu-$(lsb_release -sc) main > /etc/apt/sources.list.d/docker.list\""
-  echo "sudo apt-get update"
-  echo "sudo apt-get install docker-engine"
-
-  exit 1
-}
-
 host_run() {
   read -r -d '' env_ruby << 'RUBY'
   require 'yaml'
 host_run() {
   read -r -d '' env_ruby << 'RUBY'
   require 'yaml'
@@ -304,11 +244,30 @@ set_links() {
         "require 'yaml'; puts YAML.load(STDIN.readlines.join)['links'].map{|l| '--link ' << l['link']['name'] << ':' << l['link']['alias'] << ' '}.join"`
 }
 
         "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']"`
 
       "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)
 
     arrTemplates=(${templates// / })
     config_data=$(cat $config_file)
@@ -360,14 +319,53 @@ RUBY
 
     if [ "$ok" -ne 1 ]; then
       echo "${env[@]}"
 
     if [ "$ok" -ne 1 ]; then
       echo "${env[@]}"
-      echo "YAML syntax error. Please check your /var/discourse/containers/*.yml config files."
+      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[@]}]=$i
+      fi
+    done <<< "$raw"
+
+    if [ "$ok" -ne 1 ]; then
+      echo "${labels[@]}"
+      echo "YAML syntax error. Please check your containers/*.yml config files."
       exit 1
     fi
 }
 
       exit 1
     fi
 }
 
-[ -z $docker_path ] && {
+if [ -z $docker_path ]; then
   install_docker
   install_docker
-}
+fi
 
 [ "$command" == "cleanup" ] && {
   echo
 
 [ "$command" == "cleanup" ] && {
   echo
@@ -392,33 +390,28 @@ RUBY
   exit 0
 }
 
   exit 0
 }
 
-[ $# -lt 2 ] && {
+if [ -z "$command" -a -z "$config" ]; then
   usage
   usage
-}
+fi
 
 
-if [[ ! -e $config_file &&  $command -ne "memconfig" ]]
-  then
+if [ ! "$command" == "setup" ]; then
+  if [[ ! -e $config_file ]]; then
     echo "Config file was not found, ensure $config_file exists"
     echo "Config file was not found, ensure $config_file exists"
-    echo ""
+    echo
     echo "Available configs ( `cd containers && ls -dm *.yml | tr -s '\n' ' ' | awk '{ gsub(/\.yml/, ""); print }'`)"
     exit 1
     echo "Available configs ( `cd containers && ls -dm *.yml | tr -s '\n' ' ' | awk '{ gsub(/\.yml/, ""); print }'`)"
     exit 1
+  fi
 fi
 
 docker_version=($($docker_path --version))
 docker_version=${test[2]//,/}
 fi
 
 docker_version=($($docker_path --version))
 docker_version=${test[2]//,/}
-
-if compare_version "1.2.0" "$docker_version"; then
-  echo "We recommend you upgrade docker, the version you are running has no restart policies, on reboot your container may not start up"
-  restart_policy=""
-else
-  restart_policy=${restart_policy:---restart=always}
-fi
+restart_policy=${restart_policy:---restart=always}
 
 set_existing_container(){
   existing=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
 }
 
 
 set_existing_container(){
   existing=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
 }
 
-run_stop(){
+run_stop() {
 
   set_existing_container
 
 
   set_existing_container
 
@@ -458,86 +451,14 @@ set_boot_command() {
   fi
 }
 
   fi
 }
 
-run_memconfig(){
-  if [ "$opt" != "--skip-prereqs" ] ; then
-    check_resources
-  fi
-  if [ -f $config_file ]
-  then
-    cp $config_file $config_file.bak
-    echo "Saving $config_file as $config_file.bak"
-  else
-    echo "Creating $config_file from $template_path"
-    if [ ! -f $template_path ]
-    then
-      echo "$template_path is missing. Exiting."
-      exit 1
-    fi
-    cp $template_path $config_file
-  fi
-
-  # get free mem
-  avail_mem="$(LANG=C free -m | grep '^Mem:' | awk '{print $2}')"
-  avail_gb=`expr $(($avail_mem / 950))`
-  avail_cores=`grep -c processor /proc/cpuinfo`
-  echo "Found $avail_mem (${avail_gb}GB), of memory and $avail_cores cores."
-
-  # set db_shared_buffers: "128MB" (1GB) or 256MB * GB
-  if [ "$avail_gb" -eq "1" ]
-  then
-    db_shared_buffers="128"
-  else
-    db_shared_buffers=`expr $avail_gb \* 256`
-  fi
-  echo -e "Setting db_shared_buffers to ${db_shared_buffers}GB\c"
-  sed -i -e "s/^  db_shared_buffers:.*/  db_shared_buffers: \"${db_shared_buffers}GB\"/w $changelog" $config_file
-  if [ -s $changelog ]
-  then
-    echo " successfully."
-    rm $changelog
-  else
-    echo -e ". . . oops!\n---> db_shared_buffers not found in $config_file. Retaining defaults."
-  fi
-
-  # set db_work_mem: "10MB" * GB?
-  db_work_mem=`expr $avail_gb \* 10`
-  echo -e "Setting db_work_mem to $db_work_mem MB\c"
-  sudo sed -i -e "s/^  db_work_mem:.*/  db_work_mem: \"${db_work_mem}MB\"/w $changelog" $config_file
-  if [ -s $changelog ]
-  then
-    echo " successfully."
-    rm $changelog
-  else
-    echo -e ". . . oops!\n---> db_work_mem not found in $config_file. Retaining defaults."
-  fi
-
-  # set UNICORN_WORKERS: 2*GB or 2*cores (the same on DO)
-  if [ "$avail_gb" -le "2" ]
-  then
-    unicorn_workers=`expr $avail_gb \* 2`
-  else
-    unicorn_workers=`expr $avail_cores \* 2`
-  fi
-
-  echo -e "Setting UNICORN_WORKERS to $unicorn_workers\c"
-  sed -i -e "s/^  UNICORN_WORKERS:.*/  UNICORN_WORKERS: ${unicorn_workers}/w $changelog" $config_file
-  if [ -s $changelog ]
-  then
-      echo " successfully."
-      rm $changelog
-  else
-    echo -e ". . . oops!\n---> UNICORN_WORKERS not found in $config_file. Retaining defaults.\n"
-  fi
-}
-
-run_start(){
+run_start() {
 
    existing=`$docker_path ps | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
    echo $existing
    if [ ! -z $existing ]
    then
      echo "Nothing to do, your container has already started!"
 
    existing=`$docker_path ps | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
    echo $existing
    if [ ! -z $existing ]
    then
      echo "Nothing to do, your container has already started!"
-     exit 1
+     exit 0
    fi
 
    existing=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
    fi
 
    existing=`$docker_path ps -a | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
@@ -552,19 +473,9 @@ run_start(){
    fi
 
    host_run
    fi
 
    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(' ')"`
 
 
-   IFS='-p ' read -a array <<< "$ports"
-   for element in "${array[@]}"
-   do
-     IFS=':' read -a args <<< "$element"
-     if [ "${#args[@]}" == "2" ]; then
-       check_ports "${args[0]}"
-     elif [ "${#args[@]}" == "3" ]; then
-       check_ports "${args[1]}"
-     fi
-   done
+   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_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']"`
@@ -598,53 +509,29 @@ run_start(){
      # we got to normalize so we only have allowed strings, this is more comprehensive but lets see how bash does first
      # hostname=`$docker_path run $user_args --rm $image ruby -e 'print ARGV[0].gsub(/[^a-zA-Z-]/, "-")' $hostname`
      # docker added more hostname rules
      # we got to normalize so we only have allowed strings, this is more comprehensive but lets see how bash does first
      # hostname=`$docker_path run $user_args --rm $image ruby -e 'print ARGV[0].gsub(/[^a-zA-Z-]/, "-")' $hostname`
      # docker added more hostname rules
-     hostname=${hostname/_/-}
+     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
 
      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 $user_args $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 \
+        $run_image $boot_command
 
    )
    exit 0
 
 }
 
 
    )
    exit 0
 
 }
 
-mail_config_check(){
- mail_config_verbose=0 # 1 prints mail config to stdout
- mail_config="ok"
-  for x in DISCOURSE_SMTP_ADDRESS DISCOURSE_SMTP_USER_NAME DISCOURSE_SMTP_PASSWORD \
-          DISCOURSE_SMTP_PORT DISCOURSE_SMTP_ENABLE_START_TLS
-  do
-    mail_var=`grep "^  $x:" $config_file`
-    result=$?
-    if (( result == 0 ))
-    then
-      if [ "$mail_config_verbose" -eq 1 ]; then
-         echo "$mail_var"
-      fi
-    else
-      echo "Warning: $x not configured."
-      mail_config="dubious"
-    fi
-  done
-  if [ -t 0 ] && [ "$mail_config" != "ok" ]; then
-    echo
-    read -p "Press ENTER to continue, or Ctrl-C to exit and fix your mail config."
-  fi
-}
-
-run_bootstrap(){
 
 
-  if [ "$opt" != "--skip-prereqs" ] ; then
-      check_resources
-  fi
-
-  mail_config_check  
+run_bootstrap() {
 
 
+  # I got no frigging clue what this does, ask Sam Saffron. It RUNS STUFF ON THE HOST I GUESS?
   host_run
 
   host_run
 
-  get_ssh_pub_key
-
   # Is the image available?
   # If not, pull it here so the user is aware what's happening.
   $docker_path history $image >/dev/null 2>&1 || $docker_path pull $image
   # Is the image available?
   # If not, pull it here so the user is aware what's happening.
   $docker_path history $image >/dev/null 2>&1 || $docker_path pull $image
@@ -674,13 +561,31 @@ run_bootstrap(){
 
   echo $run_command
 
 
   echo $run_command
 
-  env=("${env[@]}" "-e" "SSH_PUB_KEY=$ssh_pub_key")
-
+  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 \
   (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)
+    /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
 
 
   sleep 5
 
@@ -701,19 +606,6 @@ case "$command" in
       exec $docker_path exec -it $config /bin/bash --login
       ;;
 
       exec $docker_path exec -it $config /bin/bash --login
       ;;
 
-  ssh)
-       existing=`$docker_path ps | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
-
-       if [[ ! -z $existing ]]; then
-         address="`$docker_path port $config 22`"
-         split=(${address//:/ })
-         exec ssh -o StrictHostKeyChecking=no root@${split[0]} -p ${split[1]}
-       else
-         echo "$config is not running!"
-         exit 1
-       fi
-      ;;
-
   stop)
       run_stop
       exit 0
   stop)
       run_stop
       exit 0
@@ -736,14 +628,9 @@ case "$command" in
       exit 0
       ;;
 
       exit 0
       ;;
 
-  memconfig)
-      run_memconfig
-      exit 0
-      ;;
-
   rebuild)
       if [ "$(git symbolic-ref --short HEAD)" == "master" ]; then
   rebuild)
       if [ "$(git symbolic-ref --short HEAD)" == "master" ]; then
-        echo "Ensuring discourse docker is up to date"
+        echo "Ensuring launcher is up to date"
 
         git remote update
 
 
         git remote update
 
@@ -752,18 +639,23 @@ case "$command" in
         BASE=$(git merge-base @ @{u})
 
         if [ $LOCAL = $REMOTE ]; then
         BASE=$(git merge-base @ @{u})
 
         if [ $LOCAL = $REMOTE ]; then
-          echo "Discourse Docker is up-to-date"
+          echo "Launcher is up-to-date"
 
         elif [ $LOCAL = $BASE ]; then
 
         elif [ $LOCAL = $BASE ]; then
-          echo "Updating Discourse Docker"
+          echo "Updating Launcher"
           git pull || (echo 'failed to update' && exit 1)
           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
 
         elif [ $REMOTE = $BASE ]; then
-          echo "Your version of Discourse Docker is ahead of origin"
+          echo "Your version of Launcher is ahead of origin"
 
         else
 
         else
-          echo "Discourse Docker has diverged source, this is only expected in Dev mode"
+          echo "Launcher has diverged source, this is only expected in Dev mode"
         fi
 
       fi
         fi
 
       fi