#!/bin/sh

# On first boot, copy scripts to a read-only dir
if [ ! -d vm-manager ]; then
  tar xzf vm-manager.tar.gz
fi

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

# Generate a unique dir as multiple containers can run in parallel
tmp_dir=$(mktemp -d -p /ce-client/ CE-XXXXXXXX)
mkdir ${tmp_dir}/input
mkdir ${tmp_dir}/output

# Set up the docker image cache, if needed
arch=$(uname -m)
mkdir -p scratch/$arch

echo "launching vm-manager"
cd vm-manager
node main.js --data-folder ${tmp_dir} --job-folder ../start/ --shared-folder ../ --proxy false > ../vm-manager.log 2>&1 &
cd ..

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

# Set args that will be passed to every container that is run
docker_args="--runtime=nvidia -e NVIDIA_VISIBLE_DEVICES=${NVIDIA_VISIBLE_DEVICES} -v ${tmp_dir}:/local"
# Check the start directory every "sleeptime" seconds
sleeptime=5
# The config file that contains runtime for the VM
config_file="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
  if [ -f completion_trigger_file ]; then
    echo "vm-manager exited"
    rm completion_trigger_file
    break
  fi

  sleep "$sleeptime"
  for file in start/*; do
    container=""
    url=""
    imagefile=""
    command=""
    name=""
    image_exists=""
    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 )
        imagefile=$( echo "$container" | sed -r 's/\:/\-/g' | sed -r 's/\//__/g' ).docker
        image_exists=$( test -f scratch/$arch/$imagefile && echo "true" || echo "" )
        if [ "$url" != "" ]; then
          # Use curl to determine if a file needs to be downloaded
          if [ "$image_exists" = "" ]; then
            echo "downloading $container from $url and loading into docker..."
            curl --silent -o "scratch/$arch/$imagefile" "$url"
            exists_now=$( test -f scratch/$arch/$imagefile && echo "true" || echo "" )
          else
            local_mod_time=$(date -r "scratch/$arch/$imagefile" +%s)
            remote_mod_time=$(date -D "%a, %d %b %Y %H:%M:%S %Z" -d "$(curl --silent -I $url | grep -i Last-Modified | sed -r 's/Last\-Modified: //gi')" +%s)
            time_diff=$(($remote_mod_time - $local_mod_time))
            if [ "$time_diff" -gt 0 ]; then
              echo "updating $container from $url and loading into docker..."
              curl --silent -o "scratch/$arch/$imagefile" "$url"
            else
              echo "$container is up-to-date; loading cached image into docker..."
            fi
          fi
          docker load < "scratch/$arch/$imagefile"
        else
          # Retrieve from dockerhub, if missing
          if [ "$image_exists" = "" ]; then
            echo "image not found locally"
            echo "pulling $container from dockerhub..."
            docker pull $container
            exists_now=$( docker images --quiet $container )
            if [ "$exists_now" != "" ]; 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 [ "$image_exists" != "" ] || [ "$exists_now" != "" ]; then
          name=${file##start\/}
          logname=$name
          name=$name$$
          # 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 --rm $docker_args --name='$name' $container \"$command\""
#            docker run --rm $docker_args --name=$name $container "$command" >> $logname.log 2>&1
#          else
            echo "launching image: docker run --rm $docker_args --name='$name' $container /bin/sh -c \"$command\""
            docker run --rm $docker_args --name=$name $container /bin/sh -c "$command" >> $logname.log 2>&1
            #echo "executing command: docker exec -it $name $command"
            #docker exec -it $name $command
#          fi
          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
