# OpenStack network_data.json mappings and query hooks.
# Used by OpenStack native HTTP/ConfigDrive and DigitalOcean ConfigDrive.
# vim:set filetype=sh:
# shellcheck shell=sh

. "$LIBDIR/tiny-cloud/imds-network"

IMDS_NICS="network_data.json/links"
IMDS_MAC="ethernet_mac_address"
IMDS_IPV4="ipv4"
IMDS_IPV6="ipv6"
IMDS_IPV4_NET="ipv4"
IMDS_IPV6_NET="ipv6"

_imds_network_file() {
	local file="$IMDS_DOCUMENT_DIR/network_data.json"

	if [ "$IMDS_SELECTED_SOURCE" = http ]; then
		_imds_document network_data.json >/dev/null || return 1
	fi
	[ -f "$file" ] || return 1
	yx -f "$file" >/dev/null || return 1
	printf '%s\n' "$file"
}

_imds_nics() {
	local file
	file=$(_imds_network_file) || return 1
	_imds_optional_value "$file" links
}

_imds_nic_index() {
	local file mac indexes index address

	mac=$(cat "$SYS/class/net/$1/address") || return 1
	mac=$(printf '%s' "$mac" | lower)
	[ -n "$mac" ] || return 1
	file=$(_imds_network_file) || return 1
	indexes=$(_imds_optional_value "$file" links) || return 1
	for index in $indexes; do
		address=$(_imds_optional_value "$file" ethernet_mac_address links "$index") || return 1
		address=$(printf '%s' "$address" | lower)
		[ "$address" = "$mac" ] || continue
		echo "$index"
		return 0
	done
	return 1
}

_imds_nic_value() {
	local file link network_link indexes index type address mask prefix
	file=$(_imds_network_file) || return 1
	case "$2" in
		@mac)
			address=$(_imds_optional_value "$file" "$3" links "$1") || return 1
			printf '%s\n' "$address" | lower
			return 0
			;;
		@ipv4|@ipv6|@ipv4-net|@ipv6-net) ;;
		*)
			imds_document "$IMDS_DOCUMENT_DIR" "$IMDS_NICS/$1${3:+/$3}"
			return $?
			;;
	esac
	link=$(yx -f "$file" -- links "$1" id) || return 1
	[ -n "$link" ] || return 1
	indexes=$(_imds_optional_value "$file" networks) || return 1
	for index in $indexes; do
		network_link=$(yx -f "$file" -- networks "$index" link) || return 1
		[ "$network_link" = "$link" ] || continue
		type=$(yx -f "$file" -- networks "$index" type) || return 1
		case "$type" in "$3"|"$3"_*) ;; *) continue;; esac
		address=$(_imds_optional_value "$file" ip_address networks "$index") || return 1
		[ -n "$address" ] || continue
		case "$2" in
			@ipv4|@ipv6) printf '%s\n' "${address%/*}";;
			*)
				case "$address" in
					*/*) mask="${address#*/}"; address="${address%/*}";;
					*) mask=$(_imds_optional_value "$file" netmask networks "$index") || return 1;;
				esac
				[ -n "$mask" ] || return 1
				if [ "$3" = ipv4 ]; then
					_imds_ipv4_network "$address" "$mask" || return 1
				else
					prefix=$(_imds_ipv6_netmask_prefix "$mask") || return 1
					_imds_ipv6_network "$address" "$prefix" || return 1
				fi
				;;
		esac
	done
	return 0
}

_imds_network_dns() {
	local file="$1" indexes index type address
	shift
	indexes=$(_imds_optional_value "$file" services "$@") || return 1
	for index in $indexes; do
		type=$(yx -f "$file" -- "$@" services "$index" type) || return 1
		[ "$type" = dns ] || continue
		address=$(_imds_optional_value "$file" address "$@" services "$index") || return 1
		[ -z "$address" ] || printf '%s\n' "$address"
	done
}

_imds_nameservers_metadata() {
	local file indexes index values result
	file=$(_imds_network_file) || return 1
	result=$(_imds_network_dns "$file") || return 1
	indexes=$(_imds_optional_value "$file" networks) || return 1
	for index in $indexes; do
		values=$(_imds_network_dns "$file" networks "$index") || return 1
		[ -z "$values" ] || result="${result}${result:+
}$values"
	done
	[ -z "$result" ] || printf '%s\n' "$result" | sort -u
}
