Created
July 17, 2025 17:59
-
-
Save EvgeniGordeev/ed98d5d4d3218bf6bbbe1e0a3f2d7cac to your computer and use it in GitHub Desktop.
List EC2 instances by a filter and list prices
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function ec2-ls-price() { | |
| local name_filter=${1:?} | |
| local year=${2:-1yr} | |
| local offering=${3:-All Upfront} | |
| local region=${AWS_REGION:-$(aws configure get region)} | |
| local pricing_region="$region" | |
| local pricing_location | |
| pricing_location=$(get_aws_pricing_location "$region") | |
| if [[ -z "$pricing_location" ]]; then | |
| echo "Unsupported region for pricing lookup: $region" >&2 | |
| return 1 | |
| fi | |
| local duration | |
| case "$year" in | |
| 1yr) duration=31536000 ;; | |
| 3yr) duration=94608000 ;; | |
| *) echo "Unsupported year value: $year (must be 1yr or 3yr)" >&2; return 1 ;; | |
| esac | |
| case "$offering" in | |
| "All Upfront"|"Partial Upfront"|"No Upfront") ;; | |
| *) echo "Unsupported offering value: '$offering' (must be 'All Upfront', 'Partial Upfront', or 'No Upfront')" >&2; return 1 ;; | |
| esac | |
| local instances | |
| instances=$(aws ec2 describe-instances \ | |
| --region "$region" \ | |
| --filters "Name=tag:Name,Values=$name_filter" \ | |
| --query "Reservations[].Instances[].[InstanceId, Tags[?Key=='Name'].Value | [0], InstanceType, State.Name, LaunchTime, InstanceLifecycle]" \ | |
| --output json) | |
| local reserved_label="$(echo "$year" | sed 's/yr/Yr/') ${offering} Price" | |
| printf "%-20s\t%-45s\t%-10s\t%-10s\t%-25s\t%-10s\t%-15s\t%-14s\t%-20s\n" \ | |
| "InstanceId" "Name" "Type" "State" "LaunchTime" "Lifecycle" "CurrentPrice" "OnDemandPrice" "$reserved_label" | |
| echo "$instances" | jq -r --arg pricing_location "$pricing_location" --arg pricing_region "$pricing_region" ' | |
| .[] | @tsv' | while IFS=$'\t' read -r instance_id name type state launchtime lifecycle; do | |
| lifecycle=${lifecycle:-on-demand} | |
| # On-Demand price | |
| on_demand_price=$(aws pricing get-products --region "$pricing_region" \ | |
| --service-code AmazonEC2 \ | |
| --filters \ | |
| "Type=TERM_MATCH,Field=instanceType,Value=$type" \ | |
| "Type=TERM_MATCH,Field=location,Value=$pricing_location" \ | |
| "Type=TERM_MATCH,Field=operatingSystem,Value=Linux" \ | |
| "Type=TERM_MATCH,Field=preInstalledSw,Value=NA" \ | |
| "Type=TERM_MATCH,Field=tenancy,Value=Shared" \ | |
| "Type=TERM_MATCH,Field=capacitystatus,Value=Used" \ | |
| --query 'PriceList[0]' --output text 2>/dev/null | \ | |
| jq -r 'try (.terms.OnDemand | to_entries[0].value.priceDimensions | to_entries[0].value.pricePerUnit.USD) catch "N/A"' 2>/dev/null) | |
| on_demand_price=${on_demand_price:-"N/A"} | |
| # Reserved price (1yr/3yr, offering) | |
| reserved_price="N/A" | |
| offering_json=$(aws ec2 describe-reserved-instances-offerings \ | |
| --region "$region" \ | |
| --instance-type "$type" \ | |
| --offering-class standard \ | |
| --offering-type "$offering" \ | |
| --filters \ | |
| "Name=product-description,Values=Linux/UNIX" \ | |
| "Name=duration,Values=$duration" \ | |
| "Name=scope,Values=Region" \ | |
| --query 'ReservedInstancesOfferings[0]' \ | |
| --output json 2>/dev/null) | |
| if [[ -n "$offering_json" && "$offering_json" != "null" ]]; then | |
| fixed_price=$(echo "$offering_json" | jq -r '.FixedPrice') | |
| recurring_hourly=$(echo "$offering_json" | jq -r '.RecurringCharges[0].Amount // 0') | |
| if [[ "$fixed_price" != "null" && "$fixed_price" != "0" ]]; then | |
| # Calculate effective hourly rate: upfront cost spread hourly + recurring hourly | |
| hourly_rate=$(awk "BEGIN { printf \"%.10f\", ($fixed_price / ($duration/3600)) + $recurring_hourly }") | |
| reserved_price="$hourly_rate" | |
| else | |
| # No upfront fee, just recurring hourly (No Upfront offering) | |
| if [[ "$recurring_hourly" != "0" ]]; then | |
| reserved_price="$recurring_hourly" | |
| else | |
| reserved_price="N/A" | |
| fi | |
| fi | |
| fi | |
| # Spot price | |
| current_price="$on_demand_price" | |
| if [[ "$lifecycle" == "spot" ]]; then | |
| az=$(aws ec2 describe-instances --region "$region" --instance-ids "$instance_id" \ | |
| --query "Reservations[0].Instances[0].Placement.AvailabilityZone" --output text 2>/dev/null) | |
| if [[ -n "$az" ]]; then | |
| spot_price=$(aws ec2 describe-spot-price-history --region "$region" --instance-types "$type" \ | |
| --availability-zone "$az" --product-descriptions "Linux/UNIX" --max-items 1 \ | |
| --query 'SpotPriceHistory[0].SpotPrice' --output text | head -n1) | |
| current_price="${spot_price:-N/A}" | |
| else | |
| current_price="N/A" | |
| fi | |
| fi | |
| printf "%-20s\t%-45s\t%-10s\t%-10s\t%-25s\t%-10s\t\$%-14s\t\$%-13s\t\$%-19s\n" \ | |
| "$instance_id" "$name" "$type" "$state" "$launchtime" "$lifecycle" "$current_price" "$on_demand_price" "$reserved_price" | |
| done | |
| } |
Author
EvgeniGordeev
commented
Jul 17, 2025
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment