#!/bin/bash
set -u

metadata_file=
metadata_temporary=
once=0
destination=${XCATDEST:-}
request_pid=

usage() {
	printf '%s\n' 'Usage: getdestiny [ENDPOINT] [--metadata FILE] [--once]' >&2
	exit 2
}

while (($# > 0)); do
	case "$1" in
		--metadata)
			(($# >= 2)) || usage
			metadata_file=$2
			shift 2
			;;
		--once)
			once=1
			shift
			;;
		--)
			shift
			(($# <= 1)) || usage
			if (($# == 1)); then
				destination=$1
			fi
			break
			;;
		-*) usage ;;
		*)
			if [[ -z $destination ]]; then
				destination=$1
			fi
			shift
			;;
	esac
done

[[ -n $destination ]] || usage

temporary_dir=$(mktemp -d "${TMPDIR:-/tmp}/getdestiny.XXXXXX") || exit 1
request_file=$temporary_dir/request.xml
response_file=$temporary_dir/response.xml

cleanup() {
	rm -rf -- "$temporary_dir"
	[[ -z $metadata_temporary ]] || rm -f -- "$metadata_temporary"
}

terminate() {
	local status=$1

	trap - HUP INT TERM
	if [[ -n $request_pid ]]; then
		kill -TERM "$request_pid" 2>/dev/null || true
		wait "$request_pid" 2>/dev/null || true
	fi
	exit "$status"
}

trap cleanup EXIT
trap 'terminate 129' HUP
trap 'terminate 130' INT
trap 'terminate 143' TERM

printf '%s\n' \
	'<xcatrequest>' \
	'<command>getdestiny</command>' \
	'<callback_port>300</callback_port>' \
	'</xcatrequest>' >"$request_file"

request_destiny() {
	local request_status=0

	if [[ -f /etc/xcat/cert.pem && -f /etc/xcat/certkey.pem ]]; then
		openssl s_client -key /etc/xcat/certkey.pem \
			-cert /etc/xcat/cert.pem -connect "$destination" -quiet \
			2>/dev/null <"$request_file" >"$response_file" &
	else
		openssl s_client -connect "$destination" -quiet \
			2>/dev/null <"$request_file" >"$response_file" &
	fi
	request_pid=$!
	wait "$request_pid" || request_status=$?
	request_pid=
	if ((request_status != 0)) && [[ ! -s $response_file ]]; then
		return 1
	fi
	! grep -q '<error>' "$response_file"
}

while ! request_destiny; do
	if ((once)); then
		exit 1
	fi
	for ((timer = 60; timer > 0; timer--)); do
		printf 'Retrying in %s seconds  \r' "$timer" >&2
		sleep 1
	done
	printf '%*s\r' 48 '' >&2
done

extract_element() {
	local element=$1

	sed -n "s:.*<$element>\([^<]*\)</$element>.*:\1:p" "$response_file" \
		| head -n 1 | tr -cd '\40-\176'
}

destiny=$(extract_element destiny)
if [[ -z $destiny ]]; then
	((once)) && exit 1
	printf '\n'
	exit 0
fi

if [[ -n $metadata_file ]]; then
	metadata_dir=${metadata_file%/*}
	if [[ $metadata_dir == "$metadata_file" ]]; then
		metadata_dir=.
	elif [[ -z $metadata_dir ]]; then
		metadata_dir=/
	fi
	[[ -d $metadata_dir ]] || exit 1
	metadata_temporary=$(mktemp "$metadata_dir/.getdestiny.XXXXXX") || exit 1
	{
		printf 'XCAT_NODE_NAME=%s\n' "$(extract_element name)"
		printf 'XCAT_DESTINY=%s\n' "$destiny"
		printf 'XCAT_IMAGE_SERVER=%s\n' "$(extract_element imgserver)"
		printf 'XCAT_KERNEL=%s\n' "$(extract_element kernel)"
		printf 'XCAT_INITRD=%s\n' "$(extract_element initrd)"
		printf 'XCAT_KERNEL_COMMAND_LINE=%s\n' "$(extract_element kcmdline)"
	} >"$metadata_temporary"
	chmod 0600 "$metadata_temporary"
	mv -f -- "$metadata_temporary" "$metadata_file"
fi

printf '%s\n' "$destiny"
