From 4e35161517d344704d4504af433c34b1c5f93ce7 Mon Sep 17 00:00:00 2001 From: Frederick Lefebvre Date: Thu, 2 Apr 2026 01:35:57 +0000 Subject: [PATCH 1/2] Fix inconcistent formatting, unquoted variables and function naming --- ec2-metadata | 104 +++++++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/ec2-metadata b/ec2-metadata index 5f168b0..0dea7cf 100755 --- a/ec2-metadata +++ b/ec2-metadata @@ -53,7 +53,7 @@ QUIET="" function set_imds_token() { if [ -z "${IMDS_TOKEN}" ];then - IMDS_TOKEN=$(curl -s -f -X PUT -H "X-aws-ec2-metadata-token-ttl-seconds: 900" ${METADATA_BASEURL}/${METADATA_TOKEN_PATH}) + IMDS_TOKEN=$(curl -s -f -X PUT -H "X-aws-ec2-metadata-token-ttl-seconds: 900" "${METADATA_BASEURL}/${METADATA_TOKEN_PATH}") if [ "${?}" -gt 0 ] || [ -z "${IMDS_TOKEN}" ]; then echo '[ERROR] Could not get IMDSv2 token. Instance Metadata might have been disabled or this is not an EC2 instance.' >&2 exit 1 @@ -65,15 +65,15 @@ function set_imds_token() function get_meta() { local imds_out - imds_out=$(curl -s -q -H "X-aws-ec2-metadata-token:${IMDS_TOKEN}" -f ${METADATA_BASEURL}/${METADATA_VERSION}/${1}) + imds_out=$(curl -s -q -H "X-aws-ec2-metadata-token:${IMDS_TOKEN}" -f "${METADATA_BASEURL}/${METADATA_VERSION}/${1}") echo -n "${imds_out}" } #print standard metric function print_normal_metric() { metric_path=$2 - [ -z "$QUIET" ] && echo -n $1": " - RESPONSE=$(get_meta ${metric_path}) + [ -z "$QUIET" ] && echo -n "$1: " + RESPONSE=$(get_meta "${metric_path}") if [ -n "${RESPONSE}" ]; then echo "$RESPONSE" else @@ -82,14 +82,14 @@ function print_normal_metric() { } #print block-device-mapping -function print_block-device-mapping() +function print_block_device_mapping() { [ -z "$QUIET" ] && echo 'block-device-mapping: ' x=$(get_meta meta-data/block-device-mapping/) if [ -n "${x}" ]; then for i in $x; do - [ -z "$QUIET" ] && echo -ne '\t' "$i: " - echo "$(get_meta meta-data/block-device-mapping/$i)" + [ -z "$QUIET" ] && echo -ne '\t' "$i: " + echo "$(get_meta "meta-data/block-device-mapping/$i")" done else echo not available @@ -97,20 +97,20 @@ function print_block-device-mapping() } #print public-keys -function print_public-keys() +function print_public_keys() { [ -z "$QUIET" ] && echo 'public-keys: ' x=$(get_meta meta-data/public-keys/) if [ -n "${x}" ]; then for i in $x; do - index=$(echo $i|cut -d = -f 1) - keyname=$(echo $i|cut -d = -f 2) - [ -z "$QUIET" ] && echo keyname:$keyname - [ -z "$QUIET" ] && echo index:$index - format=$(get_meta meta-data/public-keys/$index/) - [ -z "$QUIET" ] && echo format:$format + index=$(echo "$i" | cut -d = -f 1) + keyname=$(echo "$i" | cut -d = -f 2) + [ -z "$QUIET" ] && echo "keyname:$keyname" + [ -z "$QUIET" ] && echo "index:$index" + format=$(get_meta "meta-data/public-keys/$index/") + [ -z "$QUIET" ] && echo "format:$format" [ -z "$QUIET" ] && echo 'key:(begins from next line)' - echo "$(get_meta meta-data/public-keys/$index/$format)" + echo "$(get_meta "meta-data/public-keys/$index/$format")" done else echo not available @@ -124,8 +124,8 @@ function print_tags() x=$(get_meta meta-data/tags/instance/) if [ -n "${x}" ]; then for i in $x; do - echo -n -e '\t' "$i: " - echo "$(get_meta meta-data/tags/instance/$i)" + echo -n -e '\t' "$i: " + echo "$(get_meta "meta-data/tags/instance/$i")" done else echo not available @@ -138,7 +138,7 @@ function print_all() print_normal_metric ami-launch-index meta-data/ami-launch-index print_normal_metric ami-manifest-path meta-data/ami-manifest-path print_normal_metric ancestor-ami-ids meta-data/ancestor-ami-ids - print_block-device-mapping + print_block_device_mapping print_normal_metric instance-id meta-data/instance-id print_normal_metric instance-type meta-data/instance-type print_normal_metric local-hostname meta-data/local-hostname @@ -150,7 +150,7 @@ function print_all() print_normal_metric product-codes meta-data/product-codes print_normal_metric public-hostname meta-data/public-hostname print_normal_metric public-ipv4 meta-data/public-ipv4 - print_public-keys + print_public_keys print_normal_metric ramdisk-id /meta-data/ramdisk-id print_normal_metric reservation-id /meta-data/reservation-id print_normal_metric security-groups meta-data/security-groups @@ -191,16 +191,16 @@ declare -a actions declare -a paths shortopts=almnbithokzPcpvuresdgR longopts=(ami-id ami-launch-index ami-manifest-path ancestor-ami-ids block-device-mapping - instance-id instance-type local-hostname local-ipv4 kernel-id availability-zone - partition product-codes public-hostname public-ipv4 public-keys ramdisk-id - reservation-id security-groups user-data tags region help all quiet path:) + instance-id instance-type local-hostname local-ipv4 kernel-id availability-zone + partition product-codes public-hostname public-ipv4 public-keys ramdisk-id + reservation-id security-groups user-data tags region help all quiet path:) oldIFS="$IFS" IFS=, TEMP=$(getopt -o $shortopts --longoptions "${longopts[*]}" -n 'ec2-metadata' -- "$@") if [ $? -ne 0 ]; then - echo 'Terminating...' >&2 - exit 1 + echo 'Terminating...' >&2 + exit 1 fi IFS="$oldIFS" @@ -208,32 +208,32 @@ eval set -- "$TEMP" unset TEMP while true; do - case "$1" in - --help) - print_help ; shift - exit 0 - ;; - --quiet) - QUIET=1 ; shift - ;; - --path) - actions+=("$1") - paths+=("$2") - shift 2 - ;; - --) - shift ; break - ;; - --?*|-?) - # pass most arguments to the original action processing - # code after setting options - actions+=("$1"); shift - ;; - *) - echo 'Unknown error: ' "[$1]" >&2 - exit 1 - ;; - esac + case "$1" in + --help) + print_help ; shift + exit 0 + ;; + --quiet) + QUIET=1 ; shift + ;; + --path) + actions+=("$1") + paths+=("$2") + shift 2 + ;; + --) + shift ; break + ;; + --?*|-?) + # pass most arguments to the original action processing + # code after setting options + actions+=("$1"); shift + ;; + *) + echo 'Unknown error: ' "[$1]" >&2 + exit 1 + ;; + esac done #start processing command line arguments @@ -243,7 +243,7 @@ for action in "${actions[@]}"; do -l | --ami-launch-index ) print_normal_metric ami-launch-index meta-data/ami-launch-index ;; -m | --ami-manifest-path ) print_normal_metric ami-manifest-path meta-data/ami-manifest-path ;; -n | --ancestor-ami-ids ) print_normal_metric ancestor-ami-ids meta-data/ancestor-ami-ids ;; - -b | --block-device-mapping ) print_block-device-mapping ;; + -b | --block-device-mapping ) print_block_device_mapping ;; -i | --instance-id ) print_normal_metric instance-id meta-data/instance-id ;; -t | --instance-type ) print_normal_metric instance-type meta-data/instance-type ;; -h | --local-hostname ) print_normal_metric local-hostname meta-data/local-hostname ;; @@ -255,7 +255,7 @@ for action in "${actions[@]}"; do -c | --product-codes ) print_normal_metric product-codes meta-data/product-codes ;; -p | --public-hostname ) print_normal_metric public-hostname meta-data/public-hostname ;; -v | --public-ipv4 ) print_normal_metric public-ipv4 meta-data/public-ipv4 ;; - -u | --public-keys ) print_public-keys ;; + -u | --public-keys ) print_public_keys ;; -r | --ramdisk-id ) print_normal_metric ramdisk-id /meta-data/ramdisk-id ;; -e | --reservation-id ) print_normal_metric reservation-id /meta-data/reservation-id ;; -s | --security-groups ) print_normal_metric security-groups meta-data/security-groups ;; From a04c33150616825ed18b5de9ae9a8271440286cf Mon Sep 17 00:00:00 2001 From: Frederick Lefebvre Date: Thu, 2 Apr 2026 02:14:36 +0000 Subject: [PATCH 2/2] Add tests/capture-output.sh to help with regression testing --- tests/README.md | 26 ++++++++++++++++++++++++++ tests/capture-output.sh | 29 +++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 tests/README.md create mode 100755 tests/capture-output.sh diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 0000000..2a81244 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,26 @@ +# ec2-metadata regression testing + +`capture-output.sh` runs every `ec2-metadata` subcommand and saves each output to a separate file. This lets you compare output before and after a code change to catch regressions. + +## Usage + +```bash +# 1. Capture baseline output (before your changes) +./capture-output.sh output-before + +# 2. Make your changes to ec2-metadata + +# 3. Capture output again +./capture-output.sh output-after + +# 4. Compare +diff -r output-before output-after +``` + +No diff output means the change is behavior-preserving. Any differences will show exactly which subcommand's output changed and how. + +## Notes + +- Must be run on an EC2 instance (requires IMDS access). +- The subcommand list is derived dynamically from `ec2-metadata --help`, so new options are picked up automatically. +- Individual subcommand failures are logged as warnings but don't stop the run, so you get partial results even if some metadata categories are unavailable. diff --git a/tests/capture-output.sh b/tests/capture-output.sh new file mode 100755 index 0000000..20a32e7 --- /dev/null +++ b/tests/capture-output.sh @@ -0,0 +1,29 @@ +#!/usr/bin/bash +# Capture ec2-metadata output for each subcommand into a directory. +# Usage: ./capture-output.sh [output-dir] +# default output-dir: output + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +EC2_METADATA="${SCRIPT_DIR}/../ec2-metadata" +OUTDIR="${1:-output}" + +[[ -x "$EC2_METADATA" ]] || { echo "ERROR: ec2-metadata not found at $EC2_METADATA" >&2; exit 1; } + +mapfile -t cmds < <("$EC2_METADATA" --help | grep -oP '(?<=/--)[a-z][-a-z0-9]+' | grep -v 'help\|quiet\|all\|path') +if [[ ${#cmds[@]} -eq 0 ]]; then + echo "ERROR: No subcommands found in --help output" >&2 + exit 1 +fi + +mkdir -p "$OUTDIR" + +for cmd in "${cmds[@]}"; do + "$EC2_METADATA" --"$cmd" > "$OUTDIR/$cmd.txt" 2>&1 || echo "WARN: --$cmd failed" >&2 +done + +"$EC2_METADATA" > "$OUTDIR/default.txt" 2>&1 || echo "WARN: default (no args) failed" >&2 + +files=("$OUTDIR"/*.txt) +echo "Captured ${#files[@]} files in $OUTDIR/"