diff --git a/bin/imds b/bin/imds index 45d7a18..2a1de30 100755 --- a/bin/imds +++ b/bin/imds @@ -35,6 +35,12 @@ unset -f \ CLOUD="${CLOUD:-unknown}" IMDS_ENDPOINT="169.254.169.254" +_imds() { + wget --quiet --timeout 1 --output-document - \ + --header "$(_imds_header)" \ + "http://$IMDS_ENDPOINT/$IMDS_URI/$1$IMDS_QUERY" +} + _imds_ssh_keys() { _imds "$IMDS_SSH_KEYS"; } _imds_userdata() { _imds "$IMDS_USERDATA"; } @@ -48,12 +54,6 @@ source /lib/tiny-cloud/"$CLOUD"/imds ### non-overrideable functions -_imds() { - wget --quiet --timeout 1 --output-document - \ - --header "$(_imds_header)" \ - "http://$IMDS_ENDPOINT/$IMDS_URI/$1$IMDS_QUERY" -} - imds() { local cmd args key rv err=1 if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then diff --git a/lib/tiny-cloud/init-final b/lib/tiny-cloud/init-final index 46a104f..696d3eb 100644 --- a/lib/tiny-cloud/init-final +++ b/lib/tiny-cloud/init-final @@ -3,10 +3,40 @@ source /lib/tiny-cloud/init-common + +match_header() { + local bytes=$(echo -en "$1") + [ "$bytes" = $(dd bs=1 count=${#bytes} if="$2" 2>/dev/null) ] +} + +# TODO: also do this for nocloud meta-data and vendor-data? save_userdata() { skip_action save_userdata && return - imds -e @userdata > "$TINY_CLOUD_VAR/$CLOUD_USERDATA" + local userdata="$TINY_CLOUD_VAR/$CLOUD_USERDATA" + local tmpfile=$(mktemp "$userdata.XXXXXX") + local cmd + + imds -e @userdata > "$tmpfile" + if match_header '\037\213\010' "$tmpfile"; then + cmd='gzip -dc' + elif match_header 'BZh' "$tmpfile"; then + cmd='bzip2 -dc' + elif match_header '\3757zXZ\000' "$tmpfile"; then + cmd='xz -dc' + elif match_header '\135\0\0\0' "$tmpfile"; then + cmd='lzma -dc' + elif match_header '\211\114\132' "$tmpfile"; then + cmd='lzop -dc' + elif match_header '\002!L\030' "$tmpfile"; then + cmd='lz4 -dc' + elif match_header '(\265/\375' "$tmpfile"; then + cmd='zstd -dc' + else + cmd='cat' + fi + $cmd "$tmpfile" > "$userdata" + rm "$tmpfile" } is_userdata_script() { diff --git a/lib/tiny-cloud/nocloud/imds b/lib/tiny-cloud/nocloud/imds new file mode 100644 index 0000000..f45e7d2 --- /dev/null +++ b/lib/tiny-cloud/nocloud/imds @@ -0,0 +1,59 @@ +# NoCloud Instance Metadata +# vim: ts=4 et ft=sh: + +IMDS_HOSTNAME=meta-data/hostname +IMDS_SSH_KEYS=meta-data/ssh-keys +IMDS_USERDATA=user-data + +# have we loaded the nocloud meta/user/vendor data? +is_nocloud_loaded() { [ -f "$TINY_CLOUD_VAR/.nocloud_loaded" ]; } + +# from location specified in kernel cmdline +_load_nocloud_cmdline() { + # TODO +} + +# from volume labeled cidata|CIDATA +_load_nocloud_volume() { + local mntdir='/mnt/cidata' + + mkdir "$mntdir" + mount -L cidata "$mntdir" || mount -L CIDATA "$mntdir" || return 1 + for data in meta user vendor; do + if ! cp "$mntdir/$data-data" "$TINY_CLOUD_VAR/$data-data"; then + [ "$data" = vendor ] && continue + echo "ERROR: Required $data-data not found on CIDATA volume" + umount "$mntdir" + return 1 + fi + done + umount "$mntdir" +} + +load_nocloud() { + is_nocloud_loaded && return + if grep -qE ' ds=nocloud(-net)?[; ]' /proc/cmdline; then + if ! _load_nocloud_cmdline; then + echo 'ERROR: Unable to load nocloud data specified in kernel cmdline' >&2 + return 1 + fi + elif ! _load_nocloud_volume; then + echo 'ERROR: Unable to load nocloud data from CIDATA volume' >&2 + return 1 + fi + touch "$TINY_CLOUD_VAR/.nocloud_loaded" +} + +_imds() { + local file="$TINY_CLOUD_VAR"/$(echo "$1" | cut -d/ -f1) + local key=$(echo "$1" | cut -d/ -f2-) + local data value + + is_nocloud_loaded || load_nocloud || return 1 + + # does file exist? + [ -f "$file" ] || return 1 + + # use 'file/' to get top-level keys + [ "$1" = "$file" ] && cat "$file" || yx -f "$file" "$key" +}