EnumerateAllEc2Instances

nicolaw 25th July 2023 at 3:52pm
awscli
#!/usr/bin/env bash
# vim:ts=2:sw=2:tw=79

set -Eeuo pipefail
shopt -s extglob
shopt -s nocasematch
shopt -s extdebug

# Secure environment.
IFS=$' \t\n'
unset -f unalias
# shellcheck disable=SC1001
\unalias -a
unset -f command
if ! PATH="$(command -p getconf PATH 2>/dev/null)" && [[ -z "$PATH" ]]; then
  PATH="/usr/bin:/bin"
fi
PATH+=":/usr/local/bin" # Optionally necessary for Homebrew on Darwin.

# shellcheck disable=SC2154
trap 'declare rc=$?;
      >&2 echo "Unexpected error (exit-code $rc) executing $BASH_COMMAND at ${BASH_SOURCE[0]} line $LINENO";
      exit $rc' ERR

activeAwsEc2 () {
  # https://docs.aws.amazon.com/cli/latest/reference/ce/get-cost-and-usage.html
  myFilter () {
    printf '{"And":[%s{"Dimensions":{"Key":"SERVICE","Values":["Amazon Elastic Compute Cloud - Compute"]}},
      {"Dimensions":{"Key":"RECORD_TYPE","Values":["Usage"]}},
      {"Not":{"Dimensions":{"Key":"INSTANCE_TYPE","Values":[""]}}}]}' \
      "${1:-}"
  }

  aws ce get-cost-and-usage \
    --time-period "Start=$(printf "%(%Y-%m-%d)T" "$(($(date +%s)-(60*60*48)))"),End=$(date +%Y-%m-%d)" \
    --granularity MONTHLY \
    --metrics "UsageQuantity" \
    --group-by "Type=DIMENSION,Key=${1:-REGION}" \
    --output json \
    --profile CostExplorer \
    --filter "$(myFilter "${2:-}")" \
    | jq -re '[.ResultsByTime[].Groups[].Keys|add]|unique[]|select(. != "global")'
}

getProfileByAccountId () {
  while read -r profile
  do
    if [[ "$(aws configure get "profile.$profile.sso_account_id")" == "$1" ]]
    then
      echo "$profile"
      break
    fi
  done < <(aws configure list-profiles | grep -- ReadOnly)
}

main () {
  while read -r accountId
  do
    while read -r region
    do

      profile="$(getProfileByAccountId "$accountId")"
      >&2 printf "account=%s profile=%s region=%s\n" "$accountId" "$profile" "$region"

      if ! aws sts get-caller-identity >/dev/null 2>&1
      then
        aws sso login --profile "$profile"
      fi

      accountAlias="$(aws iam list-account-aliases --query AccountAliases[0] --output text --profile "$profile")"
      accountId="$(aws sts get-caller-identity --query Account --output text --profile="$profile")"

      while read -r instance tagName
      do
        (
          printf '["%s","%s","%s","%s","%s"]' "$accountId" "$accountAlias" "$region" "$instance" "$tagName"
          aws ssm describe-instance-information \
              --output json --profile "$profile" --region "$region" \
              --filters "Key=InstanceIds,Values=$instance" \
              --query 'InstanceInformationList[].[PlatformType, PlatformName, PlatformVersion][0]'
        ) | jq -res 'add|@csv'

      done < <(aws ec2 describe-instances \
                --output text --profile "$profile" --region "$region" \
                --query "Reservations[].Instances[].[InstanceId, Tags[?Key=='Name'].Value|[0]]")

    done < <(activeAwsEc2 REGION "$(printf '{"Dimensions":{"Key":"LINKED_ACCOUNT","Values":["%s"]}},' "$accountId")")
  done < <(activeAwsEc2 LINKED_ACCOUNT)
}

main "$@"