# NoCloud Instance Metadata
# vim:set filetype=sh:
# shellcheck shell=sh

NOCLOUD_FILES="meta-data user-data vendor-data network-config"
IMDS_NETWORK_INTERFACES="meta-data/network-interfaces"
: "${IMDS_NAMESERVERS:=meta-data/resolv_conf/nameservers}"

_imds_nameservers_metadata() {
	local indexes index server

	indexes="$(_imds "$IMDS_NAMESERVERS")" || return
	for index in $indexes; do
		server="$(_imds "$IMDS_NAMESERVERS/$index")" || continue
		printf '%s\n' "$server"
	done
}

_load_nocloud_cmdline() {
	local options kv k v data loaded seedfrom source tmpfile

	options=$(nocloud_ds_options) || return
	set -- $options
	shift
	for kv; do
		k="${kv%%=*}"
		v="${kv#*=}"
		case "$k" in
			h|local-hostname)
				printf "\nlocal-hostname: %s" "$v" >> "$TINY_CLOUD_VAR/meta-data"
				loaded=1
				;;
			i|instance-id)
				printf "\ninstance-id: %s" "$v" >> "$TINY_CLOUD_VAR/meta-data"
				loaded=1
				;;
			s|seedfrom)
				v=$(expand_nocloud_dmi_seedfrom "$v") || return 1
				seedfrom="${v%/}"
				for data in $NOCLOUD_FILES; do
					case "${v#file:/}" in
						/*)
							source="${seedfrom#file:}/$data"
							[ -f "$source" ] || continue
							cat "$source" >> "$TINY_CLOUD_VAR/$data" || continue
							echo >> "$TINY_CLOUD_VAR/$data"
							loaded=1
							;;
						http://*|https://*)
							tmpfile=$(mktemp "$TINY_CLOUD_VAR/$data.XXXXXX") ||
								continue
							wget -qO - "$seedfrom/$data" > "$tmpfile" || {
								rm -f "$tmpfile"
								continue
							}
							echo >> "$tmpfile" &&
								mv "$tmpfile" "$TINY_CLOUD_VAR/$data" || {
								rm -f "$tmpfile"
								continue
							}
							loaded=1
							;;
						*) log warning -s "Unknown NoCloud seedfrom value '$v'"
							;;
					esac
				done
				;;
			*)  log warning -s "Unknown NoCloud kernel cmdline key '$k'"
				;;
		esac
	done
	[ -n "$loaded" ]
}

_load_nocloud_volume() (
	local mntdir stagedir data mounted loaded

	. "$LIBDIR/tiny-cloud/metadata-volume"
	mntdir=$(mktemp -d "$TINY_CLOUD_RUN/metadata-volume.XXXXXX") || return
	trap '
		[ -z "$stagedir" ] || rm -rf "$stagedir"
		if [ -n "$mounted" ]; then
			metadata_volume_umount "$mntdir" || :
		else
			rmdir "$mntdir" 2>/dev/null || :
		fi
	' 0
	trap 'exit 1' HUP INT TERM

	metadata_volume_mount "$mntdir" "cidata CIDATA" "vfat iso9660" || return
	mounted=1
	stagedir=$(mktemp -d "$TINY_CLOUD_VAR/.nocloud.XXXXXX") || return
	for data in $NOCLOUD_FILES; do
		[ -f "$mntdir/$data" ] || continue
		cp "$mntdir/$data" "$stagedir/$data" || return
		loaded=1
	done
	[ -n "$loaded" ] || return 1

	metadata_volume_umount "$mntdir" || return
	mounted=
	for data in $NOCLOUD_FILES; do
		[ -f "$stagedir/$data" ] || continue
		mv "$stagedir/$data" "$TINY_CLOUD_VAR/$data" || return
	done
)

load_nocloud() {
	# start with a clean slate
	(cd "$TINY_CLOUD_VAR" && rm -f $NOCLOUD_FILES)

	if _load_nocloud_cmdline || _load_nocloud_volume; then
		touch "$TINY_CLOUD_VAR/.nocloud_loaded"
	else
		log err -s "Unable to load NoCloud datasource"
		return 1
	fi

	# minimally, we expect some content in meta-data
	[ -s "$TINY_CLOUD_VAR/meta-data" ] ||
		log warning -s "NoCloud 'meta-data' is empty"
}

_imds() {
	local file="$TINY_CLOUD_VAR/$(echo "$1" | cut -d/ -f1)"
	local keypath="$(echo "$1" | cut -d/ -f2- | tr / ' ')"

	[ -f "$TINY_CLOUD_VAR/.nocloud_loaded" ] || load_nocloud || return

	# does file exist?
	[ -f "$file" ] || return 1

	# use 'file/' to get top-level keys
	if [ $(basename "$file") = "$keypath" ]; then
		cat "$file"
	else
		yx -f "$file" $keypath 2>/dev/null
	fi
}
