Don't set db_work_mem
[discourse_docker.git] / launcher
index ba32b4b85bee3efed4bf07d5f9d23562d3d9784a..1f3561f1a4e1de3ceef91fdbfe9125cadad56119 100755 (executable)
--- a/launcher
+++ b/launcher
@@ -8,7 +8,7 @@ opt=$3
 re='[A-Z/ !@#$%^&*()+~`=]'
 if [[ $config =~ $re ]];
   then
-    echo 
+    echo
     echo "ERROR: Config name must not contain upper case characters, spaces or special characters. Correct config name and rerun $0."
     echo
     exit 1
@@ -16,14 +16,16 @@ fi
 
 cd "$(dirname "$0")"
 
-docker_min_version='1.2.0'
-docker_rec_version='1.2.0'
+docker_min_version='1.6.0'
+docker_rec_version='1.6.0'
 
 config_file=containers/"$config".yml
 cidbootstrap=cids/"$config"_bootstrap.cid
 local_discourse=local_discourse
-image=discourse/discourse:1.0.14
+image=discourse/discourse:1.0.17
 docker_path=`which docker.io || which docker`
+template_path=samples/standalone_template.yml
+changelog=/tmp/changelog # used to test whether sed did anything
 
 if [ "${SUPERVISED}" = "true" ]; then
   restart_policy="--restart=no"
@@ -60,10 +62,11 @@ usage () {
   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"
+  echo "    --skip-prereqs   Don't check prerequisites or resource requirements"
   echo "    --docker-args    Extra arguments to pass when running docker"
   exit 1
 }
@@ -199,6 +202,19 @@ check_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
@@ -381,7 +397,7 @@ RUBY
   usage
 }
 
-if [ ! -e $config_file ]
+if [[ ! -e $config_file &&  $command -ne "memconfig" ]]
   then
     echo "Config file was not found, ensure $config_file exists"
     echo ""
@@ -420,6 +436,90 @@ run_stop(){
   fi
 }
 
+set_run_image() {
+  run_image=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
+    "require 'yaml'; puts YAML.load(STDIN.readlines.join)['run_image']"`
+
+  if [ -z "$run_image" ]; then
+    run_image="$local_discourse/$config"
+  fi
+}
+
+set_boot_command() {
+  boot_command=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
+    "require 'yaml'; puts YAML.load(STDIN.readlines.join)['boot_command']"`
+
+  if [ -z "$boot_command" ]; then
+
+    no_boot_command=`cat $config_file | $docker_path run $user_args --rm -i -a stdin -a stdout $image ruby -e \
+      "require 'yaml'; puts YAML.load(STDIN.readlines.join)['no_boot_command']"`
+
+    if [ -z "$no_boot_command" ]; then
+      boot_command="/sbin/boot"
+    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 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(){
 
    existing=`$docker_path ps | awk '{ print $1, $(NF) }' | grep " $config$" | awk '{ print $1 }'`
@@ -443,7 +543,18 @@ run_start(){
 
    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.to_s << ' '}.join"`
+          "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
 
    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']"`
@@ -451,13 +562,37 @@ run_start(){
    set_template_info
    set_volumes
    set_links
+   set_run_image
+   set_boot_command
+
+   # get hostname and settings from container configuration
+   for envar in "${env[@]}"
+   do
+     if [[ $envar == DOCKER_USE_HOSTNAME* ]] || [[ $envar == DISCOURSE_HOSTNAME* ]]
+     then
+       # use as environment variable
+       eval $envar
+     fi
+   done
 
    (
-     hostname=`hostname`
+     hostname=`hostname -s`
+     # overwrite hostname
+     if [ "$DOCKER_USE_HOSTNAME" = "true" ]
+     then
+       hostname=$DISCOURSE_HOSTNAME
+     else
+       hostname=$hostname-$config
+     fi
+
+     # 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/_/-}
+
      set -x
-     $docker_path run $user_args $links $attach_on_run $restart_policy "${env[@]}" -h "$hostname-$config" \
-        -e DOCKER_HOST_IP=$docker_ip --name $config -t $ports $volumes $docker_args $local_discourse/$config \
-        /sbin/boot
+     $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
 
    )
    exit 0
@@ -466,7 +601,9 @@ run_start(){
 
 run_bootstrap(){
 
-  check_resources
+  if [ "$opt" != "--skip-prereqs" ] ; then
+    check_resources
+  fi
 
   host_run
 
@@ -515,6 +652,8 @@ run_bootstrap(){
   $docker_path rm `cat $cidbootstrap` && rm $cidbootstrap
 }
 
+
+
 case "$command" in
   bootstrap)
       run_bootstrap
@@ -523,7 +662,7 @@ case "$command" in
       ;;
 
   enter)
-      exec $docker_path exec -it $config /bin/bash
+      exec $docker_path exec -it $config /bin/bash --login
       ;;
 
   ssh)
@@ -561,6 +700,11 @@ case "$command" in
       exit 0
       ;;
 
+  memconfig)
+      run_memconfig
+      exit 0
+      ;;
+
   rebuild)
       if [ "$(git symbolic-ref --short HEAD)" == "master" ]; then
         echo "Ensuring discourse docker is up to date"