#!/bin/bash

#set -x
LOGDIR=/srv/obs/service/log/
LOGFILE=$LOGDIR/`basename $0`.log

function printlog {
  printf "%s %s %7s %s\n" `date +"%Y-%m-%d %H:%M:%S"` "[$$]" "$@" >> $LOGFILE
}

function create_dir {
  DIR=$1
  if [ ! -d $DIR ];then
    printlog "Creating directory '$DIR'"
    mkdir -p $DIR || exit 1
  else
    printlog "Directory '$DIR' already exists"
  fi
}

function cleanup_container {
  printlog "Starting cleanup $1"
  [ -d "$MOUNTDIR/$INNERSRCDIR" ] && rmdir --ignore-fail-on-non-empty "$MOUNTDIR/$INNERSRCDIR"
  [ -d "$MOUNTDIR/$INNEROUTDIR" ] && rmdir --ignore-fail-on-non-empty "$MOUNTDIR/$INNEROUTDIR"
  rm -f "$MOUNTDIR/${INNERSCRIPT}.command" 2> /dev/null
  rm -f "$MOUNTDIR/$INNERSCRIPT" 2> /dev/null
  rmdir --ignore-fail-on-non-empty "$MOUNTDIR$INNERSCRIPTDIR" 2> /dev/null
  rmdir --ignore-fail-on-non-empty "$MOUNTDIR" 2> /dev/null
  
  if [ "$1" == "timeout" ];then
    podman rm $CONTAINER_ROOT_OPT --force --volumes $CONTAINER_ID
  else
    podman inspect $CONTAINER_ROOT_OPT $CONTAINER_ID > /dev/null 2>&1 && podman rm $CONTAINER_ROOT_OPT --force --volumes $CONTAINER_ID
  fi

  printlog "Finished cleanup"
}

export USER=`getent passwd $UID|cut -f1 -d:`
export HOME=`eval echo ~$USER`

#FSDIR="/opt/obs/SourceServiceSystem"
CONTAINER_IMAGE=`obs_admin --query-config container_image`
CONTAINER_CUSTOM_OPT=`obs_admin --query-config container_custom_opt`
CONTAINERS_ROOT=`obs_admin --query-config containers_root`
SERVICES_DIR=`obs_admin --query-config servicetempdir`
OBS_SERVICE_BUNDLE_GEMS_MIRROR_URL=`obs_admin --query-config gems_mirror`
OBS_SERVICE_USER=`obs_admin --query-config obs_service_user`
OBS_SERVICE_PASS=`obs_admin --query-config obs_service_pass`
OBS_SERVICE_NETWORK=`obs_admin --query-config obs_service_network`
# Fallback to bridge for legacy setup w/o docker user-defined networks
[ -z "$OBS_SERVICE_NETWORK" ] && OBS_SERVICE_NETWORK="bridge"
SCM_COMMAND=0
WITH_NET=0
COMMAND="$1"

if [[ ! $CONTAINER_IMAGE ]];then
  CONTAINER_IMAGE=localhost/obs-source-service:latest
fi

if [[ ! $CONTAINERS_ROOT ]];then
  CONTAINERS_ROOT="/srv/obs/service/containers"
fi

printlog "$0 called:"
printlog "$@"

create_dir "$LOGDIR"

shift
case "$COMMAND" in
  */download_url|*/download_src_package|*/update_source|*/download_files|*/generator_pom|*/snapcraft|*/kiwi_import|*/appimage|*/node_modules|*/cargo_vendor|*/go_modules)
    WITH_NET="1"
    ;;
  */bundle_gems)
    GEMINABOX=`obs_admin --query-config geminabox_container`
    if  [ -n "$GEMINABOX" ];then
      if [ "$OBS_SERVICE_NETWORK" == "bridge";then
        LINK="--link $GEMINABOX:$GEMINABOX"
      fi
    else
      # use default bridge if no proxy service like geminabox is required
      OBS_SERVICE_NETWORK=bridge
    fi
    WITH_NET="1"
    ;;
  */tar_scm|*/obs_scm|*/obs_scm_bridge|*/download_assets)
    SCM_COMMAND=1
    WITH_NET="1"
  ;;
esac

while [ $# -gt 0 ]; do
  case $1 in
    --scm)
      PARAM_SCM=$2
    ;;
    --scm=*)
      PARAM_SCM=$1
      PARAM_SCM=${PARAM_SCM#--scm=}
    ;;
    --url)
      PARAM_URL=$2
    ;;
    --url=*)
      PARAM_URL=$1
      PARAM_URL=${PARAM_URL#--url=}
    ;;
  esac
  if [ "$1" == "--outdir" ] ; then
     shift
     OUTDIR="$1"
  else
     COMMAND="$COMMAND '${1//\'/_}'"
     shift
     COMMAND="$COMMAND '${1//\'/_}'"
  fi
  shift
done

if [ -z "$OUTDIR" ] ; then
  echo "ERROR: no outdir given"
  exit 1
fi

MOUNTDIR=`dirname $OUTDIR`
RETURN="0"
create_dir "$MOUNTDIR"

# set -x
INNERBASEDIR=`mktemp -u /var/cache/obs/XXXXXXXXXXXX`
CONTAINER_ID=src-service-`basename $INNERBASEDIR`
INNEROUTDIR="$INNERBASEDIR/out"
OUTEROUTDIR="$MOUNTDIR/out"
INNERSRCDIR="$INNERBASEDIR/src"
OUTERSRCDIR="$MOUNTDIR/src"
INNERSCRIPTDIR="$INNERBASEDIR/scripts"
INNERSCRIPT="$INNERSCRIPTDIR/inner.sh"

OUTERHOMEDIR="$MOUNTDIR/home"
INNERHOMEDIR="$INNERBASEDIR/home"

create_dir "$OUTEROUTDIR"
create_dir "$OUTERSRCDIR"
create_dir "$MOUNTDIR$INNERSCRIPTDIR"
create_dir "$OUTERHOMEDIR"

# Create inner.sh which is just a wrapper for
# su nobody -s inner.sh.command

printlog "Creating INNERSCRIPT '$MOUNTDIR/$INNERSCRIPT'"
echo "#!/bin/bash"                                                                          > "$MOUNTDIR/$INNERSCRIPT"
echo "export OBS_SERVICE_APIURL=\"$OBS_SERVICE_APIURL\""                                   >> "$MOUNTDIR/$INNERSCRIPT"
echo "export OBS_SERVICE_BUNDLE_GEMS_MIRROR_URL=\"$OBS_SERVICE_BUNDLE_GEMS_MIRROR_URL\""   >> "$MOUNTDIR/$INNERSCRIPT"
echo "export OBS_SERVICE_DAEMON=\"$OBS_SERVICE_DAEMON\""                                   >> "$MOUNTDIR/$INNERSCRIPT"
echo "export OBS_SERVICE_USER=\"$OBS_SERVICE_USER\""                                       >> "$MOUNTDIR/$INNERSCRIPT"
echo "export OBS_SERVICE_PASS=\"$OBS_SERVICE_PASS\""                                       >> "$MOUNTDIR/$INNERSCRIPT"
echo "cd $INNERSRCDIR"                                                                     >> "$MOUNTDIR/$INNERSCRIPT"
echo -n "${INNERSCRIPT}.command"                                                           >> "$MOUNTDIR/$INNERSCRIPT"

# Create inner.sh.command
# dirname /srv/obs/service/11875/out/
printlog "Creating INNERSCRIPT.command '$MOUNTDIR/${INNERSCRIPT}.command'"
echo "#!/bin/bash"               			>  "$MOUNTDIR/${INNERSCRIPT}.command"
#echo "set -x" 						>> "$MOUNTDIR/${INNERSCRIPT}.command"
echo "echo Running ${COMMAND[@]} --outdir $INNEROUTDIR" >> "$MOUNTDIR/${INNERSCRIPT}.command"

if [ "$WITH_NET" != "1" ] ; then
  printlog "Using docker without network"
  CONTAINER_OPTS_NET="--net=none"
else
  printlog "Using docker with network"
fi

CONTAINER_VOLUMES="-v $OUTEROUTDIR:$INNEROUTDIR -v $OUTERSRCDIR:$INNERSRCDIR -v $OUTERHOMEDIR:$INNERHOMEDIR -v $MOUNTDIR$INNERSCRIPTDIR:$INNERSCRIPTDIR:ro"
JAILED=""

if [ $SCM_COMMAND -eq 1 ];then
  URL_HASH=`echo ${PARAM_URL%\?*}|sha256sum|cut -f1 -d\ `
  OUTERSCMCACHE="$SERVICES_DIR/scm-cache/$URL_HASH"
  INNERSCMCACHE="$INNERBASEDIR/scm-cache"
  create_dir "$OUTERSCMCACHE"

  CONTAINER_VOLUMES="$CONTAINER_VOLUMES -v $OUTERSCMCACHE:$INNERSCMCACHE"
  echo "export CACHEDIRECTORY='$INNERSCMCACHE'" 	>> "$MOUNTDIR/${INNERSCRIPT}.command"
fi
FULL_COMMAND="${COMMAND[@]} --outdir $INNEROUTDIR"
printlog "FULL_COMMAND: '$FULL_COMMAND'"
echo "export HOME='$INNERHOMEDIR'" 			>> "$MOUNTDIR/${INNERSCRIPT}.command"
echo "$FULL_COMMAND" 					>> "$MOUNTDIR/${INNERSCRIPT}.command"


chmod 0755 "$MOUNTDIR/$INNERSCRIPT"
chmod 0755 "$MOUNTDIR/${INNERSCRIPT}.command"

# useful for debugging purposes
if [[ $DEBUG_CONTAINER ]];then
	DEBUG_OPTIONS="-it"
	INNERSCRIPT=/bin/bash
fi

if [ -n "$CONTAINERS_ROOT" ];then
  CONTAINER_ROOT_OPT="--root $CONTAINERS_ROOT --storage-opt overlay.mount_program=/usr/bin/fuse-overlayfs"
fi

# force cleanup of container on timeout (SIGTERM)
trap "cleanup_container timeout" 15

# run jailed process
CONTAINER_RUN_CMD="podman run $CONTAINER_ROOT_OPT --userns keep-id $CONTAINER_OPTS_NET $LINK --rm --name $CONTAINER_ID $CONTAINER_CUSTOM_OPT $CONTAINER_VOLUMES $DEBUG_OPTIONS $CONTAINER_IMAGE $INNERSCRIPT"
printlog "CONTAINER_RUN_CMD: '$CONTAINER_RUN_CMD'"
CMD_OUT=$(${CONTAINER_RUN_CMD} 2>&1)
RET_ERR=$?
if [ $RET_ERR -eq 0 ]; then
  # move out the result
  if [ 0`find "$MOUNTDIR/$INNEROUTDIR" -type f 2>/dev/null| wc -l` -gt 0 ]; then
    for i in _service:* ; do
      if [ ! -f "$MOUNTDIR/$INNERSRCDIR/$i" ]; then
        rm -f "$i"
      fi
    done
  fi
elif [ $RET_ERR -eq 125 ] || [ $RET_ERR -eq 126 ] || [ $RET_ERR -eq 127 ]; then
  printlog "$CMD_OUT"
  echo "$CMD_OUT"
  RETURN="3"
else
  printlog "$CMD_OUT"
  echo "$CMD_OUT"
  RETURN="2"
fi

if [[ $DEBUG_CONTAINER ]];then
  printlog "DEBUG_CONTAINER is set. Skipping cleanup"
else
  cleanup_container
fi

exit $RETURN
