mirror of
https://gitlab.alpinelinux.org/alpine/cloud/tiny-cloud.git
synced 2026-06-21 00:07:16 +03:00
253 lines
5.9 KiB
Bash
Executable File
253 lines
5.9 KiB
Bash
Executable File
#!/bin/sh
|
|
# vim:set filetype=sh:
|
|
|
|
# Tiny Cloud - Instance MetaData Service client
|
|
|
|
### configuration, common functions
|
|
|
|
: "${PREFIX:=/usr}"
|
|
: "${LIBDIR:=$PREFIX/lib}"
|
|
. "$LIBDIR/tiny-cloud/common"
|
|
|
|
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
|
|
cat <<-EOT
|
|
Usage: imds [-h] { -e | +e | +n | +s | +t | @<alias> | <imds-path> } ...
|
|
-h : help
|
|
-e / +e : ignore / catch errors
|
|
-E / +E : hide / show STDERR
|
|
+n / +s / +t : insert newline / space / tab
|
|
<alias> :-
|
|
hostname : instance hostname
|
|
local-hostname : instance local hostname
|
|
ssh-keys : instance SSH keys
|
|
userdata : instance user data
|
|
nics : instance NICs
|
|
nic:<iface>[,<nic-key> ...] : specific NIC interface
|
|
<iface> : network interface (i.e. eth1)
|
|
<nic-key> :- { -e | +e | +n | +s | +t | @<nic-alias> | <nic-path> }
|
|
<nic-alias> :-
|
|
mac : mac address
|
|
ipv4 : ipv4 address(es)
|
|
ipv6 : ipv6 address(es)
|
|
ipv4-net : subnet ipv4 network(s)
|
|
ipv6-net : subnet ipv6 network(s)
|
|
ipv4-prefix : delegated ipv4 CIDR(s)
|
|
ipv6-prefix : delegated ipv6 CIDR(s)
|
|
EOT
|
|
exit 0
|
|
fi
|
|
|
|
### cloud-specific variables/functions
|
|
|
|
unset \
|
|
IMDS_HEADER \
|
|
IMDS_QUERY
|
|
unset -f \
|
|
_imds_token \
|
|
_imds_header \
|
|
_imds_nic_index \
|
|
2>/dev/null || true
|
|
|
|
### default variables/functions
|
|
|
|
# Common to many clouds
|
|
# Can be overridden in /etc/tiny-cloud.conf
|
|
: "${IMDS_ENDPOINT:=169.254.169.254}"
|
|
: "${IMDS_ENDPOINTS:=$IMDS_ENDPOINT}"
|
|
: "${IMDS_ENDPOINT_CACHE:=$TINY_CLOUD_VAR/.imds-endpoint}"
|
|
: "${IMDS_ENDPOINT_WAIT_ATTEMPTS:=10}"
|
|
|
|
# Common to AWS and NoCloud(ish)
|
|
IMDS_HOSTNAME="meta-data/hostname"
|
|
IMDS_LOCAL_HOSTNAME="meta-data/local-hostname"
|
|
IMDS_SSH_KEYS="meta-data/public-keys"
|
|
IMDS_USERDATA="user-data"
|
|
IMDS_NICS="meta-data/network/interfaces/macs"
|
|
IMDS_MAC="mac"
|
|
IMDS_IPV4="local-ipv4s"
|
|
IMDS_IPV6="ipv6s"
|
|
IMDS_IPV4_NET="subnet-ipv4-cidr-block"
|
|
IMDS_IPV6_NET="subnet-ipv6-cidr-blocks"
|
|
IMDS_IPV4_PREFIX="ipv4-prefix"
|
|
IMDS_IPV6_PREFIX="ipv6-prefix"
|
|
|
|
_imds_endpoints() {
|
|
local cached e
|
|
cached="$(cat "$IMDS_ENDPOINT_CACHE" 2>/dev/null)" || :
|
|
for e in $IMDS_ENDPOINTS; do
|
|
[ "$e" = "$cached" ] && echo "$e"
|
|
done
|
|
for e in $IMDS_ENDPOINTS; do
|
|
[ "$e" != "$cached" ] && echo "$e"
|
|
done
|
|
}
|
|
|
|
_imds_host_port() {
|
|
local host port
|
|
case "$1" in
|
|
\[*\]:*)
|
|
host="${1#\[}"
|
|
host="${host%%\]*}"
|
|
port="${1##*\]:}"
|
|
;;
|
|
\[*\])
|
|
host="${1#\[}"
|
|
host="${host%\]}"
|
|
port=80
|
|
;;
|
|
*:*)
|
|
host="${1%:*}"
|
|
port="${1##*:}"
|
|
;;
|
|
*)
|
|
host="$1"
|
|
port=80
|
|
;;
|
|
esac
|
|
echo "$host"
|
|
echo "$port"
|
|
}
|
|
|
|
_imds_has_route() {
|
|
local host
|
|
set -- $(_imds_host_port "$1")
|
|
host="$1"
|
|
case "$host" in
|
|
*:*) ip -6 route get "$host" >/dev/null 2>&1 ;;
|
|
[0-9]*.[0-9]*.[0-9]*.[0-9]*) ip route get "$host" >/dev/null 2>&1 ;;
|
|
*) return 0 ;;
|
|
esac
|
|
}
|
|
|
|
_imds() {
|
|
local endpoint endpoints routed attempts=1 cached
|
|
if [ "$IMDS_ENDPOINT_WAIT_ATTEMPTS" -le 0 ]; then
|
|
endpoints="$(_imds_endpoints)"
|
|
fi
|
|
while :; do
|
|
[ -n "$endpoints" ] && break
|
|
endpoints=
|
|
routed=
|
|
for endpoint in $(_imds_endpoints); do
|
|
if _imds_has_route "$endpoint"; then
|
|
endpoints="$endpoints $endpoint"
|
|
routed=1
|
|
fi
|
|
done
|
|
[ -n "$routed" ] && break
|
|
[ "$attempts" -ge "$IMDS_ENDPOINT_WAIT_ATTEMPTS" ] && {
|
|
endpoints="$(_imds_endpoints)"
|
|
break
|
|
}
|
|
sleep 1
|
|
attempts=$((attempts + 1))
|
|
done
|
|
for endpoint in $endpoints; do
|
|
IMDS_ENDPOINT="$endpoint"
|
|
IMDS_CURRENT_ENDPOINT="$endpoint"
|
|
wget --quiet --timeout 1 --output-document - \
|
|
--header "$(_imds_header)" \
|
|
"http://$endpoint/$IMDS_URI/$1$IMDS_QUERY" && {
|
|
cached="$(cat "$IMDS_ENDPOINT_CACHE" 2>/dev/null)" || :
|
|
[ "$endpoint" = "$cached" ] || echo "$endpoint" 2>/dev/null > "$IMDS_ENDPOINT_CACHE" || :
|
|
return 0
|
|
}
|
|
done
|
|
return 1
|
|
}
|
|
|
|
_imds_userdata() { _imds "$IMDS_USERDATA"; }
|
|
|
|
_imds_ssh_keys() {
|
|
local key
|
|
for key in $(_imds "$IMDS_SSH_KEYS"); do
|
|
_imds "$IMDS_SSH_KEYS/${key%=*}/openssh-key"
|
|
echo
|
|
done | sort -u
|
|
}
|
|
|
|
_imds_nic_index() { cat "$SYS/class/net/$1/address"; }
|
|
|
|
### load cloud-specific variables and functions
|
|
|
|
if [ "$CLOUD" = "auto" ]; then
|
|
CLOUD=$(cat "$TINY_CLOUD_VAR/.autodetect")
|
|
fi
|
|
|
|
if [ ! -d "$LIBDIR/tiny-cloud/cloud/$CLOUD" ]; then
|
|
echo "ERROR: Unknown Cloud '$CLOUD'" >&2
|
|
fi
|
|
. "$LIBDIR/tiny-cloud/cloud/$CLOUD/imds"
|
|
|
|
### non-overrideable functions
|
|
|
|
imds() {
|
|
local cmd args key rv err=1 stderr=1
|
|
while [ -n "$1" ]; do
|
|
cmd=_imds
|
|
args=
|
|
key="$1"; shift
|
|
case $key in
|
|
# error handling/output
|
|
-e) err=0; continue ;; # ignore
|
|
+e) err=1; continue ;; # return
|
|
-E) stderr=0; continue ;; # hide
|
|
+E) stderr=1; continue ;; # show
|
|
# TODO: retry/deadline
|
|
# output control
|
|
+n) printf "\n"; continue ;; # insert newline
|
|
+s) printf " "; continue ;; # insert space
|
|
+t) printf "\t"; continue ;; # insert tab
|
|
# key aliasing
|
|
@hostname) args="$IMDS_HOSTNAME" ;;
|
|
@local-hostname) args="$IMDS_LOCAL_HOSTNAME" ;;
|
|
@ssh-keys) cmd=_imds_ssh_keys ;;
|
|
@userdata) cmd=_imds_userdata ;;
|
|
@nics) args="$IMDS_NICS" ;;
|
|
@nic:*)
|
|
cmd=imds
|
|
args=$(_imds_nic_args $(echo "${key#@nic:}" | tr , ' '))
|
|
;;
|
|
# use key verbatim
|
|
*) args="$key" ;;
|
|
esac
|
|
# TODO: retry/deadline
|
|
if [ $stderr = 1 ]; then
|
|
"$cmd" $args
|
|
rv=$?
|
|
else
|
|
"$cmd" $args 2>/dev/null
|
|
rv=$?
|
|
fi
|
|
[ $err -eq 0 ] && continue
|
|
[ $rv = "0" ] || return $rv
|
|
done
|
|
}
|
|
|
|
_imds_nic_args() {
|
|
local key nic
|
|
nic=$(_imds_nic_index "$1") || return 1
|
|
if [ -z "$2" ]; then
|
|
echo "$IMDS_NICS/$nic"
|
|
return
|
|
fi
|
|
while [ -n "$2" ]; do
|
|
key="$2"
|
|
shift
|
|
case "$key" in
|
|
@mac) key="$IMDS_MAC" ;;
|
|
@ipv4) key="$IMDS_IPV4" ;;
|
|
@ipv6) key="$IMDS_IPV6" ;;
|
|
@ipv4-net) key="$IMDS_IPV4_NET" ;;
|
|
@ipv6-net) key="$IMDS_IPV6_NET" ;;
|
|
@ipv4-prefix) key="$IMDS_IPV4_PREFIX" ;;
|
|
@ipv6-prefix) key="$IMDS_IPV6_PREFIX" ;;
|
|
# error/output control passthrough
|
|
-e|+[enst]) printf "$key\n"; continue ;;
|
|
esac
|
|
printf "$IMDS_NICS/$nic/$key\n"
|
|
done
|
|
}
|
|
|
|
imds "$@"
|