--- /dev/null
+#!/bin/sh
+
+MD_URL="http://169.254.169.254/latest"
+OIFS="$IFS"
+TIMEOUT=10
+CR="
+"
+
+Usage() {
+ cat <<EOF
+Usage: ${0##*/} [options]
+ -u | --url URL use URL (default: $MD_URL)
+ -h | --help display usage
+
+ --user-data dump user data
+ --<item> dump 'item' from the metadata service
+
+ Special items:
+ --block-device-mappings dump the block device mappings, space delimited
+ --public-keys dump the public keys
+
+ with no options given, metadata service will be crawled and
+ dumped. This will not include user-data.
+EOF
+}
+
+error() { echo "$@" 1>&2; }
+fail() { [ $# -eq 0 ] || error "$@"; exit 1; }
+
+get_field_list() {
+ local under="$1" x="" out="" found=""
+ mdget "$under"
+ out="$_RET"
+ for x in $out; do
+ case "$x" in
+ */) get_field_list "${under:+${under}/}${x%/}"
+ found="${found} $_RET";;
+ *) found="${found} ${under:+$under/}$x";;
+ esac
+ done
+ _RET="${found# }"
+}
+
+caturl() {
+ curl --fail --silent --max-time "${TIMEOUT}" "$1"
+}
+
+mdget() {
+ local u="$1" t1="" t2="" out=""
+ case "$u" in
+ user-data) :;;
+ public-keys|public-keys/)
+ out=$(caturl "$MD_URL/meta-data/$u") ||
+ fail "failed to get $MD_URL/meta-data/$u";
+ # output of public-keys is lines of 'X=keyname'
+ # so we return a carriage return list of the tokens before =
+ _RET=""
+ IFS="$CR"
+ for t1 in $out; do
+ t1="${t1%%=*}"
+ _RET="${_RET:+${_RET}${CR}}${t1%/}"
+ done
+ IFS="$OIFS"
+ return
+ ;;
+ public-keys/*)
+ t1=${u#public-keys/[0-9]}
+ # t2 will now have 'public-keys/[0-9]'
+ t2=${u%${t1}}
+ # if t1 has a / (ie, u=public-keys/0=brickies/openssh-keys)
+ # then set t1 to just "/openssh-keys". if not, set it to ""
+ [ "${t1#*/}" = "${t1}" ] && t1="" || t1="/${t1#*/}"
+ u="meta-data/${t2}${t1}"
+ ;;
+ *) u="meta-data/$u";;
+ esac
+ _RET=$(caturl "$MD_URL/$u") ||
+ fail "failed to get ${MD_URL}/$u"
+}
+special() {
+ local out="" x="" t="" ret=""
+ case "$1" in
+ availability-zone)
+ mdget "placement/availability-zone";;
+ public-keys)
+ mdget public-keys
+ out="$_RET"
+ IFS="$CR"
+ for x in ${out}; do
+ IFS="$OIFS" mdget \
+ "public-keys/${x}/openssh-key" &&
+ ret="${ret:+${ret}${CR}}${_RET}"
+ done
+ IFS="$OIFS"
+ _RET="$ret"
+ ;;
+ block-device-mappings)
+ mdget block-device-mapping
+ out="$_RET"
+ for x in ${out}; do
+ mdget "block-device-mapping/$x"
+ ret="${ret:+${ret} }${x}=$_RET";
+ done
+ _RET="$ret"
+ esac
+}
+
+fields=""
+while [ $# -ne 0 ]; do
+ cur=${1}; next=${2};
+ case "$cur" in
+ -h|--help) Usage ; exit 0;;
+ --url=*) MD_URL=${cur#*=}; MD_URL=${MD_URL%/};;
+ --url|-u) MD_URL="${next%/}"; shift;;
+ --availability-zone|--public-keys|--block-device-mappings)
+ fields="$fields special_${cur#--}";;
+ --*) fields="$fields ${cur#--}";;
+ esac
+ shift;
+done
+
+fields="${fields# }"
+if [ -z "$fields" ]; then
+ get_field_list ""
+ fields="${_RET}"
+ prefix=true
+else
+ prefix=false
+fi
+
+for f in $fields; do
+ case "$f" in
+ special_*) special "${f#special_}";;
+ *) mdget "$f";;
+ esac
+ ret=$?
+ [ $ret -eq 0 ] || fail "failed to get $f"
+ if $prefix; then
+ if [ "${_RET#*${CR}}" != "${_RET}" ]; then
+ _RET=$(echo "$_RET" | sed 's,^,|,g')
+ _RET="${_RET#|}"
+ fi
+ echo "${f#special_}: $_RET"
+ else
+ echo "$_RET"
+ fi
+done
+
+exit 0
+
+# vi: ts=4 noexpandtab