# OpenStack Nova Instance Metadata
# vim:set filetype=sh:
# shellcheck shell=sh

: "${IMDS_FORMAT:=auto}"

_imds_document() {
	local path="$1" document file

	document=$(imds_document_name "$path") || return
	file="$IMDS_DOCUMENT_DIR/$document"
	if [ ! -f "$file" ]; then
		[ "$IMDS_SELECTED_SOURCE" != configdrive ] || return 1
		_imds_fetch_cached "$file" _imds "$document" || return
	fi
	imds_document "$IMDS_DOCUMENT_DIR" "$path"
}

_openstack_select_format() (
	local format METADATA_LOCKED= error="$IMDS_TMP_DIR/format-error"
	format=$(metadata_format) || return
	case "$format" in native|ec2) printf '%s\n' "$format"; return;; esac
	if [ "$(metadata_dir)" = "$TINY_CLOUD_RUN/metadata" ] && [ "$(id -u)" = 0 ]; then
		lock_metadata || return
		METADATA_LOCKED=1
		format=$(metadata_format) || return
		case "$format" in native|ec2) printf '%s\n' "$format"; return;; esac
	fi
	format="$IMDS_FORMAT"
	if [ "$format" = auto ]; then
		(umask 077; : > "$error") || return
		IMDS_URI=openstack
		if _imds '' /dev/null 2>"$error"; then
			format=native
		elif [ "$WGET_STATUS" = 404 ]; then
			format=ec2
			IMDS_URI="${IMDS_API_VERSION:-latest}"
			_imds '' /dev/null || return
		else
			cat "$error" >&2
			return 1
		fi
	fi
	case "$format" in native|ec2) metadata_set_format "$format";; *) return 1;; esac
)

_imds_init() {
	[ -z "$IMDS_SELECTED_FORMAT" ] || return 0

	case "$IMDS_FORMAT" in
		auto|native|ec2) ;;
		*) echo "imds: invalid OpenStack format '$IMDS_FORMAT'" >&2; return 1;;
	esac
	IMDS_SELECTED_SOURCE=$(_openstack_select_source) || return
	if [ "$IMDS_SELECTED_SOURCE" = configdrive ]; then
		IMDS_DOCUMENT_DIR=$(metadata_dir) || return
		IMDS_SELECTED_FORMAT=$(metadata_format) || return
		# Resolve disk paths locally; never fill missing files from HTTP.
		_imds() {
			local path="$1"
			if [ "$IMDS_SELECTED_FORMAT" = ec2 ]; then
				case "$path" in
					meta-data) path=meta-data.json/;;
					meta-data/*) path="meta-data.json/${path#meta-data/}";;
				esac
			fi
			_imds_document "$path"
		}
	else
		IMDS_SELECTED_FORMAT=$(_openstack_select_format) || return
	fi
	case "$IMDS_SELECTED_FORMAT" in
		native)
			IMDS_URI="openstack/${IMDS_API_VERSION:-latest}"
			IMDS_HOSTNAME="meta_data.json/hostname"
			IMDS_LOCAL_HOSTNAME="$IMDS_HOSTNAME"
			IMDS_SSH_KEYS="meta_data.json/public_keys"
			IMDS_USERDATA="user_data"
			if [ "$IMDS_SELECTED_SOURCE" = http ]; then
				IMDS_DOCUMENT_DIR="$IMDS_TMP_DIR/metadata"
				private_mkdir "$IMDS_DOCUMENT_DIR" || {
					unset IMDS_SELECTED_FORMAT
					return 1
				}
			fi
			. "$LIBDIR/tiny-cloud/imds-network-openstack"
			;;
		ec2)
			. "$LIBDIR/tiny-cloud/imds-ec2"
			IMDS_URI="${IMDS_API_VERSION:-latest}"
			;;
	esac
	if [ -n "$IMDS_DOCUMENT_DIR" ]; then
		[ "$IMDS_SELECTED_FORMAT" != ec2 ] || IMDS_SSH_KEYS=meta-data.json/public-keys

		_imds_ssh_keys() {
			if [ "$IMDS_SELECTED_SOURCE" = http ]; then
				_imds_document "${IMDS_SSH_KEYS%%/*}" >/dev/null || return
			fi
			configdrive_ssh_keys "$IMDS_DOCUMENT_DIR" "$IMDS_SSH_KEYS" \
				"$IMDS_SELECTED_FORMAT"
		}
	fi
}
