#!/bin/bash
#
# Runs a temporary docker container 
# using optional docker run options specifed as $CIU_DOCKER_RUNOPTS
# the image specifed as $CIU_DOCKER_IMAGE (required)
# bind-mounting the ~ directory unless it's / or /root
# bind-mounting the directories optionally specified $CIU_DOCKER_BINDMOUNTS_RO in mode :ro
# bind-mounting the directories optionally specified $CIU_DOCKER_BINDMOUNTS_RW in mode :ro
# using $CIU_DOCKER_WORKDIR (default: current directory) as work dir
# with -u to current user or specified $CIU_DOCKER_USER (and HOME set accordingly)
# and /etc/passwd bind-mounted ro unless $CIU_DOCKER_USER is root
# executing whatever was specified as $*
#
# ci-utils' config files and anything optionally specified as CIU_DOCKER_ENVFILES
# are passed via --env-file= in this order:
#   /usr/lib/ci-utils/ci-utils.defaults.conf
#   /etc/ci-utils/ci-utils.conf (if it exists)
#   ~/.ci-utils/ci-utils.conf (if it exists)
#   anything optionally specified as CIU_DOCKER_ENVFILES
#
# if SSH_AUTH_SOCK is set and exists then
#   ${SSH_AUTH_SOCK} is added to the bind mounts in mode :ro
#   -e SSH_AUTH_SOCK=${SSH_AUTH_SOCK} is added to the options
#   if /etc/ssh/ssh_known_hosts exists it's added to bind mounts in mode :ro
#
# for more complex demands use a script within a bindmounted directory!

export CIU_PWD=$(pwd)

if [ -z "${CIU_DOCKER_IMAGE}" ] ; then
  echo "ERROR: No docker image specifed as \$CIU_DOCKER_IMAGE"
  exit 1
fi

. /usr/lib/ci-utils/source_conf.sh

# make sure we didn't get chdired elsewhere
cd ${CIU_PWD}

export CIU_FULL_DOCKEROPTS=""
# disabled again, some CIs might reuse containers as a means of optimization:
# CIU_FULL_DOCKEROPTS="${CIU_FULL_DOCKEROPTS} --rm"

for CIU_CONFFILE in \
  /usr/lib/ci-utils/ci-utils.defaults.conf \
  /etc/ci-utils/ci-utils.conf \
  ~/.ci-utils/ci-utils.conf \
  ${CIU_DOCKER_ENVFILES}
do
  if [ -e "${CIU_CONFFILE}" ] ; then
    CIU_FULL_DOCKEROPTS="${CIU_FULL_DOCKEROPTS} --env-file=${CIU_CONFFILE}"
  fi
done

if [ -n "${CIU_DOCKER_ENVFILES}" ] ; then
  test ${CIU_VERBOSITY} -gt 0 && echo "INFO: Adding your environment files from \$CIU_DOCKER_ENVFILES, '${CIU_DOCKER_ENVFILES}'"
  for CIU_ENVFILE in ${CIU_DOCKER_ENVFILES} ; do
    CIU_FULL_DOCKEROPTS="${CIU_FULL_DOCKEROPTS} --env-file=${CIU_ENVFILE}"
  done
fi

#CIU_FULL_DOCKEROPTS="${CIU_FULL_DOCKEROPTS} -v=${CIU_PWD}:${CIU_PWD}:rw -w ${CIU_DOCKER_WORKDIR:-${CIU_PWD}}"
CIU_FULL_DOCKEROPTS="${CIU_FULL_DOCKEROPTS} -w ${CIU_DOCKER_WORKDIR:-${CIU_PWD}}"
if [ -n "${SSH_AUTH_SOCK}" ] ; then
  if [ -e "${SSH_AUTH_SOCK}" ] ; then 
    test ${CIU_VERBOSITY} -gt 0 && echo "INFO: Adding SSH_AUTH_SOCK=${SSH_AUTH_SOCK} as environment variable and readonly bind-mount ..."
    CIU_FULL_DOCKEROPTS="${CIU_FULL_DOCKEROPTS} -v=${SSH_AUTH_SOCK}:${SSH_AUTH_SOCK}:ro -e SSH_AUTH_SOCK=${SSH_AUTH_SOCK}"
    if [ -e "/etc/ssh/ssh_known_hosts" ] ; then 
      test ${CIU_VERBOSITY} -gt 0 && echo "INFO: Adding /etc/ssh/ssh_known_hosts as readonly bind-mount too ..."
      CIU_FULL_DOCKEROPTS="${CIU_FULL_DOCKEROPTS} -v=/etc/ssh/ssh_known_hosts:/etc/ssh/ssh_known_hosts:ro"
    else
      test ${CIU_VERBOSITY} -gt 1 && echo "INFO: No /etc/ssh/ssh_known_hosts found, not adding it as readonly bind-mount."
    fi
  else
    echo "WARNING: \$SSH_AUTH_SOCK set to '${SSH_AUTH_SOCK}' but does not exist, not adding anything there."
  fi
else
  test ${CIU_VERBOSITY} -gt 1 && echo "INFO: \$SSH_AUTH_SOCK not set, not thinking about adding anything there."
fi

if [ -n "${CIU_DOCKER_BINDMOUNTS_RO}" ] ; then
  test ${CIU_VERBOSITY} -gt 0 && echo "INFO: Picking up read-only bind mounts specified as \$CIU_DOCKER_BINDMOUNTS_RO ..."
  for CIU_BINDMOUNT in ${CIU_DOCKER_BINDMOUNTS_RO} ; do
    test ${CIU_VERBOSITY} -gt 0 && echo "INFO: Picking up read-only bind mount ${CIU_BINDMOUNT} ..."
    CIU_FULL_DOCKEROPTS="${CIU_FULL_DOCKEROPTS} -v=${CIU_BINDMOUNT}:${CIU_BINDMOUNT}:ro"
  done
else
  test ${CIU_VERBOSITY} -gt 2 && echo "DEBUG: No read-only bind mounts to add specified as \$CIU_DOCKER_BINDMOUNTS_RO"
fi

if [ -n "${CIU_DOCKER_BINDMOUNTS_RW}" ] ; then
  test ${CIU_VERBOSITY} -gt 0 && echo "INFO: Picking up read-write bind mounts specified as \$CIU_DOCKER_BINDMOUNTS_RW ..."
  for CIU_BINDMOUNT in ${CIU_DOCKER_BINDMOUNTS_RW} ; do
    test ${CIU_VERBOSITY} -gt 0 && echo "INFO: Picking up read-write bind mount ${CIU_BINDMOUNT} ..."
    CIU_FULL_DOCKEROPTS="${CIU_FULL_DOCKEROPTS} -v=${CIU_BINDMOUNT}:${CIU_BINDMOUNT}:rw"
  done
else
  test ${CIU_VERBOSITY} -gt 2 && echo "DEBUG: No read-write bind mounts to add specified as \$CIU_DOCKER_BINDMOUNTS_RW"
fi

export CIU_DOCKER_USER
if [ -z "${CIU_DOCKER_USER}" ] ; then
  test ${CIU_VERBOSITY} -gt 0 && echo "INFO: No user specified as \$CIU_DOCKER_USER, defaulting to myself ..."
  CIU_DOCKER_USER=$(whoami)
  test ${CIU_VERBOSITY} -gt 1 && echo "INFO: Computed \$CIU_DOCKER_USER to '${CIU_DOCKER_USER}'"
else
  test ${CIU_VERBOSITY} -gt 0 && echo "INFO: Using \$CIU_DOCKER_USER, '${CIU_DOCKER_USER}'"
fi
if [ -z "${CIU_DOCKER_USER}" ] ; then
  echo -n "ERROR: Failed to auto-set \$CIU_DOCKER_USER ..."
  exit 10
fi
# always for now, but keeping old if-ed indentation, we might need it in the end
  test ${CIU_VERBOSITY} -gt 0 && echo "INFO: Collecting id and home of specified \$CIU_DOCKER_USER, ${CIU_DOCKER_USER} ..."
  CIU_DOCKER_USER_UID=$(id -u ${CIU_DOCKER_USER})
  if [ -z "${CIU_DOCKER_USER_UID}" ] ; then
    echo "ERROR: Failed to detect id of specified \$CIU_DOCKER_USER, ${CIU_DOCKER_USER}"
    exit 11
  fi
  test ${CIU_VERBOSITY} -gt 1 && echo "INFO: Detected id of specified \$CIU_DOCKER_USER, ${CIU_DOCKER_USER} to be ${CIU_DOCKER_USER_UID} ..."
  CIU_DOCKER_USER_HOME=$(getent passwd ${CIU_DOCKER_USER} |cut -f6 -d':')
  if [ -z "${CIU_DOCKER_USER_HOME}" ] ; then
    echo "ERROR: Failed to detect home dir of specified \$CIU_DOCKER_USER, ${CIU_DOCKER_USER}"
    exit 12
  fi
  if [ "${CIU_DOCKER_USER_HOME}" = "/" ] ; then
    echo "ERROR: Refusing to work with user home '/'"
    exit 13
  fi
  test ${CIU_VERBOSITY} -gt 1 && echo "INFO: Detected homedir of specified \$CIU_DOCKER_USER, ${CIU_DOCKER_USER} to be ${CIU_DOCKER_USER_HOME} ..."
  if [ ! -d "${CIU_DOCKER_USER_HOME}" ] ; then
    echo "ERROR: Detect home dir of specified \$CIU_DOCKER_USER, ${CIU_DOCKER_USER}, to be '${CIU_DOCKER_USER_HOME}' but it does not exist"
    exit 14
  fi
  CIU_FULL_DOCKEROPTS="${CIU_FULL_DOCKEROPTS} -u ${CIU_DOCKER_USER_UID} -e HOME=${CIU_DOCKER_USER_HOME}"
  if [ "${CIU_DOCKER_USER}" = "root" ] ; then
    test ${CIU_VERBOSITY} -gt 0 && echo "INFO: With \$CIU_DOCKER_USER set to root not passing through /etc/passwd as read-only bindmount"
  else
    test ${CIU_VERBOSITY} -gt 0 && echo "INFO: With \$CIU_DOCKER_USER not root also adding /etc/passwd as read-only bindmount and  ${CIU_DOCKER_USER_HOME} to read-write mounts ..."
    CIU_FULL_DOCKEROPTS="${CIU_FULL_DOCKEROPTS} -v=/etc/passwd:/etc/passwd:ro -v=${CIU_DOCKER_USER_HOME}:${CIU_DOCKER_USER_HOME}:rw"
  fi
#fi

if [ -n "${CIU_DOCKER_RUNOPTS}" ] ; then
  test ${CIU_VERBOSITY} -gt 0 && echo "INFO: Adding your docker options from \$CIU_DOCKER_RUNOPTS, '${CIU_DOCKER_RUNOPTS}'"
  CIU_FULL_DOCKEROPTS="${CIU_FULL_DOCKEROPTS} ${CIU_DOCKER_RUNOPTS}"
else
  test ${CIU_VERBOSITY} -gt 2 && echo "DEBUG: No docker run options specified as \$CIU_DOCKER_RUNOPTS to add"
fi

test ${CIU_VERBOSITY} -gt 2 && echo "DEBUG: Final full docker run options are: '${CIU_FULL_DOCKEROPTS}'"

test ${CIU_VERBOSITY} -gt 2 && echo "DEBUG: set |grep VERBO ..." && set |grep VERBO && echo "---"

test ${CIU_VERBOSITY} -gt 0 && echo "INFO: Calling   docker run ${CIU_FULL_DOCKEROPTS} ${CIU_DOCKER_IMAGE} $*   ..."
docker run ${CIU_FULL_DOCKEROPTS} ${CIU_DOCKER_IMAGE} $*

RC=$?

echo ""

if [ "$RC" = "0" ] ; then
  test ${CIU_VERBOSITY} -gt 0 && echo "GOOD: Got good exit code 0 from   docker run ${CIU_FULL_DOCKEROPTS} ${CIU_DOCKER_IMAGE} $*"
  exit 0
fi

echo "ERROR: Got and forwarding bad exit code ${RC} from   docker run ${CIU_FULL_DOCKEROPTS} ${CIU_DOCKER_IMAGE} $*"
exit $RC

