#!/usr/bin/bash

# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
#
# Licensed under the MIT License. See the LICENSE accompanying this file
# for the specific language governing permissions and limitations under
# the License.

function print_help()
{
echo "ec2-metadata v0.1.2
Use to retrieve EC2 instance metadata from within a running EC2 instance. 
e.g. to retrieve instance id: ec2-metadata -i
		 to retrieve ami id: ec2-metadata -a
		 to get help: ec2-metadata --help
For more information on Amazon EC2 instance meta-data, refer to the documentation at
https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html

Usage: ec2-metadata <option>
Options:
--all                     Show all metadata information for this host (also default).
-a/--ami-id               The AMI ID used to launch this instance
-l/--ami-launch-index     The index of this instance in the reservation (per AMI).
-m/--ami-manifest-path    The manifest path of the AMI with which the instance was launched.
-n/--ancestor-ami-ids     The AMI IDs of any instances that were rebundled to create this AMI.
-b/--block-device-mapping Defines native device names to use when exposing virtual devices.
-i/--instance-id          The ID of this instance
-t/--instance-type        The type of instance to launch. For more information, see Instance Types.
-h/--local-hostname       The local hostname of the instance.
-o/--local-ipv4           Public IP address if launched with direct addressing; private IP address if launched with public addressing.
-k/--kernel-id            The ID of the kernel launched with this instance, if applicable.
-z/--availability-zone    The availability zone in which the instance launched. Same as placement
-P/--partition            The AWS partition name.
-c/--product-codes        Product codes associated with this instance.
-p/--public-hostname      The public hostname of the instance.
-v/--public-ipv4          NATted public IP Address
-u/--public-keys          Public keys. Only available if supplied at instance launch time
-r/--ramdisk-id           The ID of the RAM disk launched with this instance, if applicable.
-e/--reservation-id       ID of the reservation.
-s/--security-groups      Names of the security groups the instance is launched in. Only available if supplied at instance launch time
-d/--user-data            User-supplied data.Only available if supplied at instance launch time.
-g/--tags                 Tags assigned to this instance."
}

METADATA_BASEURL="http://169.254.169.254"
METADATA_TOKEN_PATH="latest/api/token"
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})
		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.'
			exit 1
		fi
	fi
}

# param1 = query
function get_meta()
{
	local imds_out
	imds_out=$(curl -s -q -H "X-aws-ec2-metadata-token:${IMDS_TOKEN}" -f ${METADATA_BASEURL}/latest/${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})
	if [ -n "${RESPONSE}" ]; then
		echo "$RESPONSE"
	else
		echo not available
	fi
}

#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)"
		done
	else
		echo not available
	fi
}

#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
			[ -z "$QUIET" ] && echo 'key:(begins from next line)'
			echo "$(get_meta meta-data/public-keys/$index/$format)"
		done
	else
		echo not available
	fi
}

#print tags
function print_tags()
{
	[ -z "$QUIET" ] && echo '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)"
		done
	else
		echo not available
	fi
}

function print_all()
{
	print_normal_metric ami-id meta-data/ami-id
	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_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
	print_normal_metric local-ipv4 meta-data/local-ipv4
	print_normal_metric kernel-id meta-data/kernel-id
	print_normal_metric placement meta-data/placement/availability-zone
	print_normal_metric partition meta-data/services/partition
	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_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
	print_normal_metric user-data user-data
	print_tags
}

#check if run inside an EC2 instance
set_imds_token

#command called in default mode
if [ "$#" -eq 0 ]; then
	print_all
fi

declare -a actions
shortopts=almnbithokzPcpvuresdg
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 help all quiet)

oldIFS="$IFS"
IFS=,
TEMP=$(getopt -o $shortopts --longoptions "${longopts[*]}" -n 'ec2-metadata' -- "$@")
if [ $? -ne 0 ]; then
    echo 'Terminating...' >&2
    exit 1
fi
IFS="$oldIFS"

eval set -- "$TEMP"
unset TEMP

while true; do
    case "$1" in
        --help)
            print_help ; shift
            exit 0
            ;;
        --quiet)
            QUIET=1 ; shift
            ;;
        --)
            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
for action in "${actions[@]}"; do
	case "$action" in
	    -a | --ami-id )                print_normal_metric ami-id meta-data/ami-id ;;
	    -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 ;;
	    -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 ;;
	    -o | --local-ipv4 )            print_normal_metric local-ipv4 meta-data/local-ipv4 ;;
	    -k | --kernel-id )             print_normal_metric kernel-id meta-data/kernel-id ;;
	    -z | --availability-zone )     print_normal_metric placement meta-data/placement/availability-zone ;;
	    -P | --partition )             print_normal_metric partition meta-data/services/partition ;;
	    -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 ;;
	    -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 ;;
	    -d | --user-data )             print_normal_metric user-data user-data ;;
	    -g | --tags )                  print_tags ;;
	    --all )                        print_all; exit ;;
	esac
	shift
done

exit 0
