#!/usr/bin/env bash
LAYEROPS_USER=layerops
LAYEROPS_GROUP=$LAYEROPS_USER
LAYEROPS_HOME_DIR=/home/layerops
LAYEROPS_BIN_DIR=${LAYEROPS_HOME_DIR}/bin
LAYEROPS_SUPPORT_SCRIPT_PATH=/usr/local/bin/layerops-provider-support.sh
LAYEROPS_UPDATE_CHECK_SCRIPT_PATH=/usr/local/bin/layerops-image-check-update.sh
LAYEROPS_SCRIPT_PATH=/usr/local/bin/layerops
SUDO_FILE=/etc/sudoers.d/99-layerops-users
LAYEROPS_ROOT_DIR=/data/layerops
VGNAME=layerops
LVNAME=data

function usage {
  cat << EOF
Usage: $(basename "${BASH_SOURCE[0]}") [init|enable_support|disable_support|clean]
EOF
  exit 0
}

function check_envvars() {
  MISSING=""
  for envvar in PROVIDER_UUID API_URL LAYEROPS_SCRIPT_URL
  do
    [ -z "${!envvar}" ] && MISSING="$envvar $MISSING"
  done

  if [ ! -z "$MISSING" ]
  then
    echo "Missing following environment variables:"
    for var in $MISSING
    do
      echo "  $var"
    done
    exit 1
  fi
}

function _init() {

  # Install required packages
  while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do sleep 1; done;
  while fuser /var/lib/apt/lists/lock >/dev/null 2>&1; do sleep 1; done;
  apt-get update && apt-get install -y --no-install-recommends coreutils jq lvm2 ubuntu-drivers-common || exit 1

  # Install NVIDIA drivers if needed:
  if [ "$LXC_USE_NVIDIA_GPU" == "true" ]
  then
    NVIDIA_INSTALLED=$(nvidia-smi > /dev/null 2>&1 && echo 1 || echo 0)
    if [ $NVIDIA_INSTALLED -eq 0 ]
    then
      add-apt-repository -y ppa:graphics-drivers/ppa
      apt-get install -y --no-install-recommends $(nvidia-detector)
    fi
  fi

  # Get layerops run script
  wget -O $LAYEROPS_SCRIPT_PATH ${LAYEROPS_SCRIPT_URL}
  chmod 755 $LAYEROPS_SCRIPT_PATH

  # Create layerops user
  id $LAYEROPS_USER > /dev/null 2>&1 || adduser -q --gecos "" --disabled-password --home $LAYEROPS_HOME_DIR $LAYEROPS_USER
  mkdir -p $LAYEROPS_HOME_DIR/.ssh
  touch $LAYEROPS_HOME_DIR/.ssh/authorized_keys
  chown -R $LAYEROPS_USER:$LAYEROPS_GROUP $LAYEROPS_HOME_DIR

  # Set sudo access to layerops user
  cat > $SUDO_FILE <<EOF
# Group rules for layerops
%layerops ALL=(ALL) NOPASSWD: ALL
EOF

  # Create volumes if available
  FS_TYPE=ext4
  FSTAB_OPTIONS=defaults
  FSTAB_FILE=/etc/fstab

  mkdir -p $LAYEROPS_ROOT_DIR

  DEVICE=$(lsblk --json | jq -r '[.blockdevices[] | select(.type == "disk") | select(.children == null)]  | first | .name')
  if [[ ! -z "$DEVICE" && "$DEVICE" != "null" ]]
  then
    DISK=/dev/$DEVICE

    pvcreate $DISK
    vgcreate $VGNAME $DISK
    LV_SIZE=$(vgs --reportformat=json --units B $VGNAME | jq -r '.report[].vg[].vg_free' | tr '<' ' ')
    lvcreate -L $LV_SIZE -n $LVNAME $VGNAME

    PARTITION=/dev/${VGNAME}/${LVNAME}
    mkfs.$FS_TYPE -F $PARTITION

    echo "MOUNT $LAYEROPS_ROOT_DIR on $PARTITION"
    FSTAB_LINE="$PARTITION $LAYEROPS_ROOT_DIR $FS_TYPE $FSTAB_OPTIONS 0 2"
    grep -q "^$PARTITION" $FSTAB_FILE && sed "s=^${PARTITION}.*=$FSTAB_LINE=" -i $FSTAB_FILE || echo "$FSTAB_LINE" >>  $FSTAB_FILE

    mount $LAYEROPS_ROOT_DIR
  fi
}

function _init_support() {
  # Init Support scripts
  cat > $LAYEROPS_SUPPORT_SCRIPT_PATH <<EOF
#!/bin/bash
set -e

API_URL=${API_URL}
PROVIDER_UUID=${PROVIDER_UUID}

AUTHORIZED_KEYS_FILE_PATH=${LAYEROPS_HOME_DIR}/.ssh/authorized_keys
EOF
  cat >> $LAYEROPS_SUPPORT_SCRIPT_PATH <<'EOF'
START_DELIMITER="# LAYEROPS PROVIDER SUPPORT PUBLIC KEY START"
END_DELIMITER="# LAYEROPS PROVIDER SUPPORT PUBLIC KEY END"

echo "fetching new provider support public key"

RESPONSE=$(curl -A Nimeops-UA -q $API_URL/v1/providers/$PROVIDER_UUID/support/sshPublicKey)

PUBLIC_KEY=$(echo $RESPONSE | jq -r .publicKey )

if [ "$PUBLIC_KEY" == "null" ]; then
  echo "provider support is disabled -> check and remove public key if present"
  sed -e "/^$START_DELIMITER/,/^$END_DELIMITER/d" $AUTHORIZED_KEYS_FILE_PATH > $AUTHORIZED_KEYS_FILE_PATH.tmp && mv $AUTHORIZED_KEYS_FILE_PATH.tmp $AUTHORIZED_KEYS_FILE_PATH
else
  echo "provider support is enabled -> check and add new public key if not already present"
  grep -qxF "$START_DELIMITER" $AUTHORIZED_KEYS_FILE_PATH ||
    (echo $START_DELIMITER >> $AUTHORIZED_KEYS_FILE_PATH && \
    echo -e $PUBLIC_KEY >> $AUTHORIZED_KEYS_FILE_PATH && \
    echo $END_DELIMITER >> $AUTHORIZED_KEYS_FILE_PATH)
fi
EOF

  chmod 755 $LAYEROPS_SUPPORT_SCRIPT_PATH

  cat > /etc/systemd/system/ly-provider-support.service <<EOF
[Unit]
Description=Check provider support to add public key to authorized keys

[Service]
Type=oneshot
ExecStart=$LAYEROPS_SUPPORT_SCRIPT_PATH
StandardOutput=journal

[Install]
WantedBy=multi-user.target
EOF

  cat > /etc/systemd/system/ly-provider-support.timer <<EOF
[Unit]
Description=Wait for layerops config to be fetched from "ly-provider-support" service

[Timer]
OnBootSec=5m
OnUnitActiveSec=1m

[Install]
WantedBy=timers.target
EOF
}

function _init_update_check() {
  # Instance Check Update Scripts
  cat > $LAYEROPS_UPDATE_CHECK_SCRIPT_PATH <<EOF
#!/bin/bash
set -e
LAYEROPS_SCRIPT_PATH=${LAYEROPS_SCRIPT_PATH}
EOF

  cat >> $LAYEROPS_UPDATE_CHECK_SCRIPT_PATH <<'EOF'
LXC_CONTAINER_ID="$(lxc ls | grep layerops | grep RUNNING | awk '{print $2}' 2> /dev/null || echo '')"
[ -z "$LXC_CONTAINER_ID" ] && exit 0

IMAGE_VERSION_CONTENT=$(lxc exec $LXC_CONTAINER_ID cat /etc/layerops/image_version.json)
CURRENT_VERSION=$(echo $IMAGE_VERSION_CONTENT | jq -r '.current_version')
export LXC_IMAGE_VERSION=$(echo $IMAGE_VERSION_CONTENT | jq -r '.required_version')
export LXC_IMAGE_URL=$(echo $IMAGE_VERSION_CONTENT | jq -r '.image_url')

[ -z "$LXC_IMAGE_VERSION" ] && exit 0
[ "$LXC_IMAGE_VERSION" == "null" ] && exit 0
[ "$LXC_IMAGE_VERSION" == "$CURRENT_VERSION" ] && exit 0

[ -z "$LXC_IMAGE_URL" ] && exit 0
[ "$LXC_IMAGE_URL" == "null" ] && exit 0

export INSTANCE_UUID=${LXC_CONTAINER_ID#layerops-}
$LAYEROPS_SCRIPT_PATH upgrade
EOF

  chmod 755 $LAYEROPS_UPDATE_CHECK_SCRIPT_PATH

  cat > /etc/systemd/system/ly-image-update-check.service <<EOF
[Unit]
Description=Check layerops instance updates

[Service]
Type=oneshot
ExecStart=$LAYEROPS_UPDATE_CHECK_SCRIPT_PATH
StandardOutput=journal

[Install]
WantedBy=multi-user.target
EOF

  cat > /etc/systemd/system/ly-image-update-check.timer <<EOF
[Unit]
Description=Wait for layerops config to be fetched from "ly-image-update-check" service

[Timer]
OnBootSec=5m
OnUnitActiveSec=1m

[Install]
WantedBy=timers.target
EOF
}

function _enable_support() {
  systemctl daemon-reload
  systemctl enable --now ly-provider-support.timer
  systemctl enable --now ly-image-update-check.timer
}

function _disable_support() {
  systemctl disable --now ly-provider-support.timer
  systemctl disable --now ly-image-update-check.timer
}


function _clean() {
  rm -f /etc/systemd/system/ly-provider-support.*
  systemctl daemon-reload

  # Remove layerops sudo config
  rm -f $SUDO_FILE

  # delete layerops user
  id $LAYEROPS_USER > /dev/null 2>&1 && userdel $LAYEROPS_USER

  # Clean files
  rm -fR $LAYEROPS_HOME_DIR $LAYEROPS_SUPPORT_SCRIPT_PATH
}

if [[ "$#" -eq 0 ]]; then
  usage
fi

case "$1" in
  init)
    check_envvars
    _init
    ;;
  init_support)
    _init_update_check
    _init_support
    ;;
  enable_support)
    _enable_support
    ;;
  disable_support)
    _disable_support
    ;;
  clean)
    _clean;;
  *)
    usage;;
esac
