#!/usr/bin/env bash
#
# nspawn - nspawn is a wrapper around machinectl pull
#
# Copyright (c) 2021 by Christian Rebischke <chris@nullday.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http: #www.gnu.org/licenses/
#
#======================================================================
# Author: Christian Rebischke
# Email : chris@nullday.de
# Github: www.github.com/shibumi
# Contributor: Eduard Tolosa
# Email: edu4rdshl@protonmail.com
# Github: www.github.com/edu4rdshl

set -e
VERSION="0.6"
STATIC_NAME="Nspawn (https://nspawn.org)"

#
# Defaults
#

BASEURL="https://hub.nspawn.org/storage"
LISTURL="https://hub.nspawn.org/storage/list.txt"
KEYLOCATION="https://hub.nspawn.org/storage/masterkey.pgp"

#
# Get vars from local configs if they exist - overriding the defaults
# Last found config file wins
# e.g. can be used for local mirrors without changing this file
#

LOCAL_CONFIGS=( "/etc/nspawn.conf" "$( dirname "${BASH_SOURCE[0]}" )/nspawn.conf")

for local_config in "${LOCAL_CONFIGS[@]}"; do
  [[ -f "${local_config}" ]] && source "${local_config}"
done

ctrl_c() {
  echo "Keyboard Interrupt detected, leaving."
  exit
}

trap ctrl_c 2

version() {
  echo "$STATIC_NAME $VERSION"
}

helpout() {
  local program="${0##*/}"
  echo "Menu usage for $STATIC_NAME $VERSION"
  echo
  echo "$program {COMMAND} [PARAMETER]"
  echo
  echo "Wrapper around systemd-machined and https://nspawn.org"
  echo
  echo "Commands:"
  echo -e "  -i/--init          \tInitializes an image for systemd-machined with the following parameters: <distribution>/<release>/<type>"
  echo -e "  -l/--list          \tLists all available images"
  echo -e "  -h/--help          \tPrints this help message"
  echo -e "  -v/--version       \tPrints version info"
  echo
  echo "Parameters:"
  echo -e "  <distribution>\tCheck $program -l/--list for more information and which distribution names to use."
  echo -e "  <release>     \tThe release of the distribution"
  echo -e "  <type>        \tOne out of (raw,tar)"

}

if [[ $# -eq 0 ]]; then
  helpout
  exit
fi

escalate_privilege() {
  if [ "$EUID" -ne 0 ]; then
    echo "nspawn needs root privileges for the following action:"
    echo " $1"
    exit 1
  fi
}

check_pubring() {

if ! [ -f "/etc/systemd/import-pubring.gpg" ]; then
  echo "/etc/systemd/import-pubring.gpg does not exist"
  read -rp "Do you want to create it [y/n]: " choice
  case "$choice" in
  y | Y)
    escalate_privilege "Setting up the GPG keyring"
    gpg --no-default-keyring --keyring=/etc/systemd/import-pubring.gpg --fingerprint
    tfile=$(mktemp -u /tmp/masterkey.nspawn.org.XXXXXXXXXXX)
    curl "$KEYLOCATION" -o "$tfile"
    gpg --no-default-keyring --keyring=/etc/systemd/import-pubring.gpg --import "$tfile"
    ;;
  n | N)
    exit 2
    ;;
  *)
    exit 2
    ;;
  esac
fi
}

list() {
  echo
  echo -e "\t$LISTURL"
  echo
  curl "$LISTURL"
}

init() {
  check_pubring
  distribution=$(echo "$1" | cut -d"/" -f1)
  release=$(echo "$1" | cut -d"/" -f2)
  type=$(basename "$1")
  image_url="$BASEURL/$distribution/$release/$type/image.$type.xz"
  output_image="$distribution-$release-$type"
  check_image_location=$(curl -o /dev/null -sIw '%{http_code}' "$image_url")
  if [[ $check_image_location -eq 200 ]]; then
    if machinectl show-image "$output_image" &>/dev/null; then
      echo "Machine $output_image already exists. Details:"
      echo
      machinectl show-image "$output_image"
      echo
      exit
    fi
    escalate_privilege "Pulling the image via machinectl-$type..."
    if machinectl pull-"$type" "$image_url" "$output_image" 2>/dev/null; then
      echo
      echo "Removing read-only flag if present from image $output_image..."
      if machinectl read-only "$output_image" false &>/dev/null; then
        echo "Image deployed locally as $output_image. Details:"
        echo
        machinectl show-image "$output_image"
        echo
      fi
    else
      echo "Error while deploying image."
    fi
  else
    echo "Error: $check_image_location. Wrong type, distribution or release in $output_image. Try 'nspawn --list'."
  fi
}

POSITIONAL=()
while [[ $# -gt 0 ]]; do
  key="$1"
  case $key in
  -v | --version)
    version
    exit
    ;;
  -h | --help)
    helpout
    exit
    ;;
  -l | --list)
    list
    exit
    ;;
  -i | --init)
    init "$2"
    shift
    shift
    ;;
  *)
    POSITIONAL+=("$1")
    shift
    ;;
  esac
done
set -- "${POSITIONAL[@]}"
