#!/bin/sh

set -e
#set -x

if [ -e /etc/supply-bootstrap/supply-bootstrap.conf ] ; then
	. /etc/supply-bootstrap/supply-bootstrap.conf
fi

ME=$(basename $0)

usage () {
	echo "${ME} [OPTIONS]"
	echo "Options are:"
	echo "   <--vm-name|-vm> VM_NAME"
	echo "  <--os-cloud|-oc> OS_CLOUD"
	echo "         <--image> IMAGE"
	echo "        <--flavor> FLAVOR"
	exit 1
}

OS=openstack
for i in $@ ; do
	case "${1}" in
	"--vm-name"|"-vm")
		VM_NAME="${2}"
		shift
		shift
	;;
	"--domain-name")
		DOMAIN_NAME="${2}"
		shift
		shift
	;;
	"--os-cloud"|"-oc")
		OS_CLOUD="--os-cloud ${2}"
		OS="openstack --os-cloud ${2}"
		shift
		shift
	;;
	"--image")
		IMAGE_NAME=${2}
		shift
		shift
	;;
	"--key")
		KEY=${2}
		shift
		shift
	;;
	"--flavor")
		FLAVOR=${2}
		shift
		shift
	;;
	"--os-release")
		OS_RELEASE=${2}
		shift
		shift
	;;
	"--deb-release")
		DEB_RELEASE=${2}
		shift
		shift
	;;
	*)
	;;
	esac
done

if [ -z "${VM_NAME}" ] ; then
	VM_NAME="${MY_VM_NAME}"
fi

if [ -z "${DOMAIN_NAME}" ] ; then
	DOMAIN_NAME="${MY_DOMAIN_NAME}"
fi

FQDN=${VM_NAME}.${DOMAIN_NAME}

if [ -z "${OS_CLOUD}" ] ; then
	OS_CLOUD="--os-cloud ${MY_OS_CLOUD}"
	OS="openstack --os-cloud ${MY_OS_CLOUD}"
fi


if [ -z "${KEY}" ] ; then
	KEY=${MY_KEY}
fi

if [ -z "${FLAVOR}" ] ; then
	FLAVOR=${MY_FLAVOR}
fi

if [ -z "${NET_ID}" ] ; then
	NET_ID=${MY_NETID}
fi

if [ -z "${OS_RELEASE}" ] ; then
	OS_RELEASE=${MY_OS_RELEASE}
fi

if [ -z "${DEB_RELEASE}" ] ; then
	DEB_RELEASE=${MY_DEB_RELEASE}
fi

case "${DEB_RELEASE}" in
"buster")
	DEB_RELEASE_NUM=10
;;
"bullseye")
	DEB_RELEASE_NUM=11
;;
"bookworm")
	DEB_RELEASE_NUM=12
;;
"trixie")
	DEB_RELEASE_NUM=13
;;
"forky")
	DEB_RELEASE_NUM=14
;;
*)
	echo "Unknown debian release."
	exit 1
esac

MY_IMAGE_NAME="Debian ${DEB_RELEASE_NUM} ${DEB_RELEASE}"
if [ -z "${IMAGE_NAME}" ] ; then
	IMAGE_NAME=${MY_IMAGE_NAME}
fi


search_vm_id_and_status () {
	TMP_FILE=$(mktemp -t ${ME}-get-server-id.XXXXXX)
	if ${OS} server show ${VM_NAME} --format value -c id -c status 2>/dev/null >${TMP_FILE} ; then
		VM_ID=$(head -n 1 ${TMP_FILE})
		STATUS=$(tail -n 1 ${TMP_FILE})
	else
		VM_ID=""
		STATUS=""
	fi
	rm -f ${TMP_FILE}
}

wait_for_vm_status_active () {
	echo -n "Waiting for server to be active:."

	TIMESTAMP_TIMEOUT=$(date -d "now + 1 min" +%s)
	while [ "${STATUS}" != "ACTIVE" ] && [ $(date +%s) -lt "${TIMESTAMP_TIMEOUT}" ] ; do
		TMP_FILE=$(mktemp -t ${ME}-get-server-status.XXXXXX)
		if ! ${OS} server show --format value -c status ${VM_ID} 2>/dev/null >${TMP_FILE} ; then
			echo "could not fetch server status."
			exit 1
			VM_STATUS=ERROR
		else
			VM_STATUS=$(head -n 1 ${TMP_FILE})
		fi
		rm -f ${TMP_FILE}
		if [ "${VM_STATUS}" != "ACTIVE" ] ; then
			sleep 2
			echo -n "."
		fi
	done
	echo "ok."
}

wait_for_ssh () {
	local COUNT CYCLES OTCI_CAN_SSH SSH_HOST
	COUNT=120
	CYCLES=0
	OTCI_CAN_SSH=no
	SSH_HOST=${1}
#	set -x
	echo -n "-> Waiting for ssh: "
	while [ "${OTCI_CAN_SSH}" != "yes" ] && [ ${COUNT} != 0 ] ; do
		if ssh -o GlobalKnownHostsFile=/dev/null -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o ConnectTimeout=2 root@${SSH_HOST} 'echo -n ""' 1>/dev/null 2>/dev/null ; then
			OTCI_CAN_SSH=yes
		else
			echo -n "."
			COUNT=$(( ${COUNT} - 1 ))
			CYCLES=$(( ${CYCLES} + 1 ))
			sleep 1
		fi
	done
	echo "ok."
	ssh -o GlobalKnownHostsFile=/dev/null -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o ConnectTimeout=2 root@${SSH_HOST} 'echo -n ""' 1>/dev/null 2>/dev/null
}

get_vm_ip_address () {
	VM_IP_ADDRESS=$(${OS} port list --device-id ${VM_ID} --format json -c 'Fixed IP Addresses' | jq -r '.[]["Fixed IP Addresses"][]["ip_address"]')
}

ssh_cmd () {
	ssh -o GlobalKnownHostsFile=/dev/null -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no root@${VM_IP_ADDRESS} "$@"
}

fix_server_hostname () {
	ssh_cmd "echo ${FQDN} >/etc/hostname && hostname ${FQDN}"
	ssh_cmd "if ! grep -q ${FQDN} /etc/hosts ; then echo '${VM_IP_ADDRESS} ${FQDN} ${VM_NAME}' >>/etc/hosts ; fi"
}

install_supply_baremetal () {
#	ssh_cmd "if ! dpkg-query -W extrepo ; then apt-get update && apt-get install extrepo -y ] ; fi ; if ! [ -e /etc/apt/sources.list.d/extrepo_openstack_${OS_RELEASE}.sources ] ; then extrepo enable openstack_${OS_RELEASE} && apt-get update ; fi"
#	ssh_cmd "apt-get update && apt-get install supply-baremetal -y"
	ssh_cmd "apt-get update && apt-get install wget curl gnupg dirmngr joe screen -y"
	ssh_cmd "curl http://${DEB_RELEASE}-${OS_RELEASE}.debian.net/debian/dists/pubkey.gpg | apt-key add -"
	ssh_cmd "echo 'deb http://${DEB_RELEASE}-${OS_RELEASE}.debian.net/debian ${DEB_RELEASE}-${OS_RELEASE}-backports main' >/etc/apt/sources.list.d/openstack_${OS_RELEASE}.list && echo 'deb http://${DEB_RELEASE}-${OS_RELEASE}.debian.net/debian ${DEB_RELEASE}-${OS_RELEASE}-backports-nochange main' >>/etc/apt/sources.list.d/openstack_${OS_RELEASE}.list"
	ssh_cmd "apt-get update && apt-get install supply-baremetal -y"
	ssh_cmd "supply-baremetal-bootstrap"
}

gen_rootca_and_node_cert () {
	ssh_cmd "supply-gen-pki-root-ca"
	ssh_cmd "supply-gen-pki-node ${FQDN}"
	# TODO: This is a hack because puppetserver runs the ENC as puppet,
	# which otherwise cannot access the certificates and keys.
	ssh_cmd "chown -R puppet /var/lib/supply ; chown puppet /etc/supply-baremetal/supply-baremetal.conf ; chown puppet /etc/supply-baremetal"
}

run_puppet_agent () {
	ssh_cmd "puppet agent -t"
}

do_vm_rebuild () {
	$OS server rebuild --image "${MY_IMAGE_NAME}" ${VM_ID}
	echo "Sleeping 5 seconds after rebuild command."
	sleep 5
	wait_for_vm_status_active
}

search_vm_id_and_status

if [ -z "${VM_ID}" ] ; then
	echo "VM not found: creating..."
	${OS} server create --image "${IMAGE_NAME}" --key-name "${KEY}" --flavor "${FLAVOR}" --nic net-id="${NET_ID}" "${VM_NAME}"
	search_vm_id_and_status
fi

wait_for_vm_status_active
get_vm_ip_address

echo "VM ID: ${VM_ID}"
echo "STATUS: ${STATUS}"
echo "VM_IP: ${VM_IP_ADDRESS}"

#set -x
do_vm_rebuild
wait_for_ssh ${VM_IP_ADDRESS}
set -x
fix_server_hostname
install_supply_baremetal
gen_rootca_and_node_cert
run_puppet_agent
