#!/bin/sh

# Routing for network access without networking
#iptables -t nat -A OUTPUT -d 127.0.1.1/32 -p udp -m udp --dport 53 -j REDIRECT --to-ports 5353
#iptables -t nat -A PREROUTING --src 0/0 -p tcp --dport 80 -j DNAT --to-destination 127.0.0.1:3646
#iptables -t nat -A PREROUTING --src 0/0 -p tcp --dport 443 -j DNAT --to-destination 127.0.0.1:3647
#iptables -t nat -A POSTROUTING -j MASQUERADE

cd /root

# Set system DNS server for docker pull support
echo 'nameserver 172.17.0.1' > /etc/resolv.conf

mkdir -p scratch/vm/ca/certs
mkdir -p scratch/vm/ca/newcerts
mkdir -p scratch/vm/ca/private

cp shared/openssl.cnf scratch/vm/ca

# Set up the local CA for certificate management
cd scratch/vm/ca
if [ ! -f certs/ca.cert.pem ]; then
  openssl genrsa -out private/ca.key.pem 4096
  chmod 444 private/ca.key.pem
  openssl req -config openssl.cnf -key private/ca.key.pem -new -x509 -days 365 -sha256 -extensions v3_ca -out certs/ca.cert.pem -subj "/CN=*.charityengine.com/O=Proxy/C=US/ST=Massachusetts"
  chmod 444 certs/ca.cert.pem
fi
cp certs/ca.cert.pem /usr/local/share/ca-certificates/
ln -s /usr/local/share/ca-certificates/ca.cert.pem /etc/ssl/certs/
cd /etc/ssl/certs
ln -s ca.cert.pem `openssl x509 -noout -hash -in /usr/local/share/ca-certificates/ca.cert.pem`.0
cp ca-certificates.crt ca-certificates.crt.backup
cat /usr/local/share/ca-certificates/ca.cert.pem >> ca-certificates.crt

cd /root

# Restart the docker daemon... no containers should be running yet!
echo "restarting docker service"
/etc/init.d/docker stop

# Slow down docker pull commands to prevent timeouts
cat > /var/lib/boot2docker/profile << EOL
EXTRA_ARGS="--max-concurrent-downloads 1"
EOL

/etc/init.d/docker start

sleep 5

# On first boot, copy scripts to a read-only dir
if [ ! -d scripts ]; then
  mkdir scripts
  cp -r shared/main.js shared/proxy.js shared/node_modules scripts
fi

if [ ! -d start ]; then
  mkdir start
fi

if [ ! -d /local ]; then
  mkdir /local
  chown 1001 /local
fi

# Load cached docker images to minimize future downloads
arch=$(uname -m)
mkdir -p scratch/$arch
for file in scratch/$arch/*.docker; do
  echo "loading cached docker image $file"
  docker load < $file
done

echo "launching primary node container"

if [ "$(docker ps -aq -f status=exited -f name=primary)" ]; then
  # Remove the primary container if it already exists
  docker rm primary
fi
docker load < scratch/$arch/node-12-alpine.docker
docker run -td -p 172.17.0.1:53:53/udp -p 172.17.0.1:80:3646 -p 172.17.0.1:443:3647 -v /root/scratch:/root/scratch -v /root/shared:/root/shared -v /root/scripts:/root/scripts:ro -v /local:/local -v /root/start:/root/start --name='primary' node:12-alpine
docker exec -d primary sh -c 'cd /root/scripts; node main.js > /root/shared/main.js.log 2>&1'

#
# Monitor the "start" directory for new containers to run
#

# Set args that will be passed to every container that is run
docker_args="--dns=172.17.0.1 -v /etc/ssl/certs:/etc/ssl/certs:ro -v /usr/local/share/ca-certificates:/usr/local/share/ca-certificates:ro -v /local:/local"
# Check the start directory every "sleeptime" seconds
sleeptime=5
# The config file that contains runtime for the VM
config_file="shared/state.default.json"

# Attempt to read from config the total time (seconds) to continue looping
runtime=$(sed -nE 's/.*"timeLimit":([0-9]*).*/\1/p' $config_file)
if [ "$runtime" = "" ]; then
  runtime=7200
fi

timeout=$((runtime/sleeptime))
echo "ready - checking start directory every $sleeptime seconds for new jobs"
while [ $timeout -gt 0 ]
do
  sleep "$sleeptime"
  for file in start/*; do
    container=""
    url=""
    imagefile=""
    command=""
    name=""
    exists_already=""
    exists_now=""
    [ -e $file ] || continue
    echo "new start file found: $file"
    while read -r line || [ -n "$line" ]; do
      if [ "$container" = "" ]; then
        container=$( echo "$line" | cut -d " " -f 1 )
        url=$( echo "$line" | cut -s -d " " -f 2 )
        exists_already=$( docker images --quiet $container )
        imagefile=$( echo "$container" | sed -r 's/\:/\-/g' | sed -r 's/\//__/g' ).docker
        if [ "$url" != "" ]; then
          # Use curl to determine if a file needs to be downloaded
          if [ "$exists_already" = "" ]; then
            echo "downloading $container from $url and loading into docker..."
          else
            echo "updating $container from $url and loading into docker..."
          fi
          curl -k -L -o "scratch/$arch/$imagefile" -z "scratch/$arch/$imagefile" "$url"
          container=$( docker load < "scratch/$arch/$imagefile" | cut -d " " -f 3 )
          exists_now=$( docker images --quiet $container )
        else
          # Retrieve from dockerhub, if missing
          if [ "$exists_already" = "" ]; then
            echo "image not found locally"
            echo "pulling $container from dockerhub..."
            docker pull $container
            exists_now=$( docker images --quiet $container )
            if [ "$exists_now" != "" ] && [ ! -f "scratch/$arch/$imagefile" ]; then
              echo "adding $container to persistent local docker image cache"
              docker save -o "scratch/$arch/$imagefile" "$container"
              #tar -czf scratch/vm/docker-cache.tar.gz -C /var/lib/docker .
            else
              echo "failed to load $container!"
            fi
          fi
        fi
      elif [ "$command" = "" ]; then
        command="$line"
      fi
    done < "$file"
    if [ "$container" != "" ]; then
      if [ "$command" != "" ]; then
        if [ "$exists_already" != "" ] || [ "$exists_now" != "" ]; then
          name=${file##start\/}
          # Check for an Entrypoint; if not found, use /bin/sh to launch the
          # command in the container
          if tar --wildcards -Ox "*.json" -f "scratch/$arch/$imagefile" | grep -q ENTRYPOINT || \
             tar --wildcards -Ox "*.json" -f "scratch/$arch/$imagefile" | grep -q CMD; then
            echo "launching image: docker run -it $docker_args --name='$name' $container \"$command\""
            docker run -it $docker_args --name=$name $container "$command" >> shared/$name.log 2>&1
          else
            echo "launching image: docker run -it $docker_args --name='$name' $container /bin/sh -c \"$command\""
            docker run -it $docker_args --name=$name $container /bin/sh -c "$command" >> shared/$name.log 2>&1
            #echo "executing command: docker exec -it $name $command"
            #docker exec -it $name $command
          fi
          docker rm $name
          rm "$file"
        else
          echo "no container found to run; retrying $file"
        fi
      else
        echo "could not parse command; aborting $file"
        rm "$file"
      fi
    else
      echo "could not parse container name; aborting $file"
      rm "$file"
    fi
  done
  timeout=$((timeout-1))
done
