text: #!/bin/bash
  [[ $DOKKU_TRACE ]] && set -x
  
  if [[ -z "$3"  ]]; then
    APP=$2
    DATABASE=$2
  else
    APP=$2
    DATABASE=$3
  fi
  
  OLDHOME=$HOME
  HOME="$DOKKU_ROOT/.mongodb"
  
  fail() {
  	echo "$@" 1>&2
  	exit 1
  }
  
  verify_min_args() {
  	local MIN_ARGS="$1"
  	[[ $# -le $((MIN_ARGS+1)) ]] && fail "Invalid number of arguments ($(($#-2)), expected $MIN_ARGS)."
  }
  
  check_exists() {
    if [[ ! -d "$DOKKU_ROOT/$APP" ]]; then
      fail "App must exist before creating mongodb storage for it"
    fi
  }
  
  check_app() {
    if [[ -z "$APP" ]]; then
      fail "You must specify an app name"
    fi
  }
  
  # checks whether a database exists
  check_db() {
    db=$(mongo $mongodb_public_ip:$mongodb_port --quiet -u admin -p"$admin_pass" --authenticationDatabase="admin" --eval "printjson(db.adminCommand('listDatabases'));" | grep name | cut -d \" -f 4 |grep -x $1)
  
    if [[ -z "$db" ]]; then
      fail "The database $1 doesn't exist"
    fi
  }
  
  check_container() {
    if [[ -z "$id" ]]; then
      fail "MongoDB container not started cannot continue. Start with dokku mongodb:start"
    fi
  }
  
  set_dokku_env() {
    env_var=$1
    env_val=$2
    ex -s -c "g/export ${env_var}=/d" -c "x" "$DOKKU_ROOT/$APP/ENV"
    echo "export ${env_var}=\"${env_val}\"" >> "$DOKKU_ROOT/$APP/ENV"
  }
  
  MONGODB_VERSION=""
  get_mongodb_version() {
    MONGODB_VERSION=$(docker run --rm jeffutter/mongodb mongod --version | egrep -o '[[:digit:]\.]*'|head -n1)
  }
  
  MONGODB_AUTH_SCHEMA_VERSION=""
  get_mongodb_auth_schema_version() {
    MONGODB_AUTH_SCHEMA_VERSION=$(mongo $mongodb_public_ip:$mongodb_port --quiet -u admin -p"$admin_pass" --authenticationDatabase="admin" --eval "db.adminCommand({getParameter: 1, authSchemaVersion: 1})['authSchemaVersion'];")
  }
  
  vercomp () {
    if [[ $1 == $2 ]]
    then
      return 0
    fi
    local IFS=.
    local i ver1=($1) ver2=($2)
    # fill empty fields in ver1 with zeros
    for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
    do
      ver1[i]=0
    done
    for ((i=0; i<${#ver1[@]}; i++))
    do
      if [[ -z ${ver2[i]} ]]
      then
        # fill empty fields in ver2 with zeros
        ver2[i]=0
      fi
      if ((10#${ver1[i]} > 10#${ver2[i]}))
      then
        return 1
      fi
      if ((10#${ver1[i]} < 10#${ver2[i]}))
      then
        return 2
      fi
    done
    return 0
  }
  
  get_mongodb_version
  vercomp "$MONGODB_VERSION" '2.5.9999999999999999'                                                                                                                                                   
  if [[ $? == 1 ]]; then
    # 2.6
    db_image="jeffutter/mongodb:latest"
  else
    # 2.4
    db_image="jeffutter/mongodb:2.4"
  fi
  
  admin_pass=$(cat "$DOKKU_ROOT/.mongodb/admin_pw")
  mongodb_database="${DATABASE//./_}-production"
  
  id=$(docker ps | grep "$db_image" |  awk '{print $1}')
  if [[ -n "$id" ]]; then
    mongodb_public_ip=$(docker port ${id} 27017 | awk '{split($0,a,":"); print a[1]}')
    mongodb_private_ip=$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' ${id})
    mongodb_port=$(docker port ${id} 27017 | awk '{split($0,a,":"); print a[2]}')
    if [[ $mongodb_public_ip = "0.0.0.0" ]]; then
      mongodb_public_ip=localhost
    fi
  fi
  
  case "$1" in
    mongodb:console)
      check_container
      mongo $mongodb_public_ip:$mongodb_port -u admin -p"$admin_pass" --authenticationDatabase="admin"
      ;;
    mongodb:create)
      check_container
      check_app
  
      mongodb_password=$(openssl rand -base64 32|base64)
  
      if [[ -z "$3"  ]]; then
        echo $mongodb_password > "$DOKKU_ROOT/.mongodb/pass_${APP}"
      else
        echo $mongodb_password > "$DOKKU_ROOT/.mongodb/pass_${APP}_${DATABASE}"
      fi
      
  
      mongodb_username=$APP
      
      get_mongodb_auth_schema_version
      vercomp "$MONGODB_AUTH_SCHEMA_VERSION" '2.9999999'
      if [[ $? == 1 ]]; then
        mongo $mongodb_public_ip:$mongodb_port/$mongodb_database --quiet -u admin -p"$admin_pass" --authenticationDatabase="admin" --eval "db.createUser({user: \"${mongodb_username}\", pwd: \"${mongodb_password}\", roles : [{ role : \"dbOwner\", db: \"${mongodb_database}\"}] })"
      else
        mongo $mongodb_public_ip:$mongodb_port/$mongodb_database --quiet -u admin -p"$admin_pass" --authenticationDatabase="admin" --eval "db.addUser(\"${mongodb_username}\", \"${mongodb_password}\")"
      fi
      ;;
    mongodb:delete)
      check_container
      check_app
  
      mongo $mongodb_public_ip:$mongodb_port/$mongodb_database --quiet -u admin -p"$admin_pass" --authenticationDatabase="admin" --eval "printjson(db.dropDatabase())"
  
      dokku config:unset "$APP" MONGODB_DATABASE \
        MONGODB_HOST \
        MONGODB_USERNAME \
        MONGODB_PASSWORD \
        MONGODB_PORT \
        MONGO_URL \
        MONGO_URI
      ;;
    mongodb:dump)
      verify_min_args 1 "$@"
      check_container
      check_db "$2"
  
      # set backup root dir
      if [[ -d "$4" ]]; then
        dumproot=$4
      else
        dumproot="$PWD"
      fi
  
      # echo "dump will save to $dumproot"
      # echo "dump run by $(whoami) user"
    
      logtime=$(date +%Y-%m-%d-%Hh%Mm%Ss)
      dumpdir="$dumproot/$2-$logtime"
  
      dumpfile="$dumpdir"
      mongodump -h $mongodb_public_ip:$mongodb_port -u admin -p"$admin_pass" -d"$2" --authenticationDatabase="admin" --out "$dumpdir" > /dev/null
      if [ $? -eq 0 ]; then
        # tar.gz dump
        if [[ $3 == "-tar" ]]; then 
          dumpfile="$dumpdir.tar.gz"
          tar -zcP -C "$dumpdir" -f "$dumpfile" "$2"
          rm -rf "$dumpdir"
        fi
        echo "Saved dump successfully to $dumpfile"
      # an error occured during the dump
      else 
        fail "An error occured while executing mongodump.
  Please check whether you have sufficient write privileges in $PWD"
      fi
      ;;
    mongodb:link)
      if [[ -d "$DOKKU_ROOT/$APP" ]]; then
        mongodb_internal_port=27017
        if [[ -z "$3"  ]]; then
          mongodb_password=$(cat "$DOKKU_ROOT/.mongodb/pass_${APP}")
        else
          mongodb_password=$(cat "$DOKKU_ROOT/.mongodb/pass_${APP}_${DATABASE}")
        fi
  
        mongodb_username=$APP
  
        dokku config:set-norestart "$APP" MONGODB_DATABASE="$mongodb_database" MONGODB_HOST="$mongodb_private_ip" MONGODB_PORT="$mongodb_internal_port" MONGODB_USERNAME="$mongodb_username" MONGODB_PASSWORD="$mongodb_password" MONGO_URL="mongodb://${mongodb_username}:${mongodb_password}@${mongodb_private_ip}:${mongodb_internal_port}/${mongodb_database}" MONGO_URI="mongodb://${mongodb_username}:${mongodb_password}@${mongodb_private_ip}:${mongodb_internal_port}/${mongodb_database}"
  
        echo
        echo "-----> $APP linked to $db_image container"
      fi
      ;;
    mongodb:list)
      check_container
      mongo $mongodb_public_ip:$mongodb_port --quiet -u admin -p"$admin_pass" --authenticationDatabase="admin" --eval "printjson(db.adminCommand('listDatabases'));" | grep name | cut -d \" -f 4 |grep -v admin | grep -v test
      ;;
    mongodb:logs)
      check_container
      docker logs dokku-mongodb | tail -n 100
      ;;
    mongodb:restore) 
      verify_min_args 2 "$@"
      check_container
  
      fileOrDir="${3%/}"
      # does file or folder exist?
      if [[ ! -d "$fileOrDir" && ! -f "$fileOrDir" ]]; then
        fail "$fileOrDir doesn't exist"
      fi
      
      if [[ $fileOrDir == *"tar.gz" ]]; then 
        randomstring=$(cat /dev/urandom | env LC_CTYPE=C tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)
        tempdir="/tmp/mongodump/$randomstring"
        mkdir -p "$tempdir"
        tar -xzvf $fileOrDir -C "$tempdir" > /dev/null
        fileOrDir="$tempdir/$2"
        if [[ ! -d "$fileOrDir" ]]; then
          fail "The .tar.gz-file didn't contain a database-dump for $2"
        fi
      fi
      output=$(mongorestore -h $mongodb_public_ip:$mongodb_port -u admin -p"$admin_pass" -d"$2" --authenticationDatabase="admin" --drop "$fileOrDir")  
      if [ $? -eq 0 ]; then
        echo "Successfully restored database $2 from $3"
      else
        fail "An error occured while executing mongorestore
  This is the output of the mongorestore-command:
  $output"
      fi
      # cleanup temp-dir
      if [ ! -z ${tempdir+x} ]; then
        rm -rf "$tempdir"
      fi
      ;;
    mongodb:start)
      if [[ "$id" != "" ]]; then
        echo "MongoDB container already running with ID: ${id}"
      else
        stopped_id=$(docker ps -a | grep "$db_image[[:space:]].\+[[:space:]]dokku-mongodb[[:space:]]*$" |  awk '{print $1}')
        if [[ "$stopped_id" != "" ]]; then
          docker start $stopped_id
        else
          docker run -p 27017 -v "$DOKKU_ROOT/.mongodb/data":/tmp/mongo --name="dokku-mongodb" -d "$db_image" /usr/bin/mongod --dbpath=/tmp/mongo --auth
        fi
      fi
      ;;
    mongodb:stop)
      check_container
      mongo $mongodb_public_ip:$mongodb_port/admin --quiet -u admin -p"$admin_pass" --authenticationDatabase="admin" --eval "db.shutdownServer()"
      ;;
    mongodb:status)
      if [[ "$id" != "" ]]; then
        echo "MongoDB container running with ID: ${id}"
      else
        echo "MongoDB container not running"
      fi
      ;;
    help)
      cat && cat<<EOF
      mongodb:console                 		    Launch an admin mongodb console
      mongodb:create <app> <database> 		    Create a Mongo database and optional params for app
      mongodb:delete <app> <database> 		    Delete specified Mongo database
      mongodb:dump <database> [-tar]	   	    Creates a binary export of the contents of a database (-tar tarball dump)
      mongodb:link <app> <database> 	            Set ENV variables for app if database exists
      mongodb:list                    		    List all databases
      mongodb:logs                    		    Show logs from MongoDB program
      mongodb:restore <database> <file-or dirname>    Restores the state of a database exported with mongodb:dump
      mongodb:start                   		    Start the MongoDB docker container if it isn't running
      mongodb:stop                    		    Stop the MongoDB docker container
      mongodb:status                  		    Shows status of MongoDB
  EOF
      ;;
  esac
  
  HOME=$OLDHOME
  