Skip to content

Instantly share code, notes, and snippets.

@EvgeniGordeev
Created July 17, 2025 17:59
Show Gist options
  • Select an option

  • Save EvgeniGordeev/ed98d5d4d3218bf6bbbe1e0a3f2d7cac to your computer and use it in GitHub Desktop.

Select an option

Save EvgeniGordeev/ed98d5d4d3218bf6bbbe1e0a3f2d7cac to your computer and use it in GitHub Desktop.
List EC2 instances by a filter and list prices
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
}
@EvgeniGordeev
Copy link
Author

$ ec2-ls-price "eks-cluster-devops-2*" 1yr "All Upfront"
InstanceId          	Name                                         	Type      	State     	LaunchTime               	Lifecycle 	CurrentPrice   	OnDemandPrice 	1Yr All Upfront Price
i-0123456789abcdef0 	eks-cluster-nodes-default-Node      	t3.large  	running   	2025-07-07T18:20:43+00:00	on-demand 	$0.0832000000  	$0.0832000000 	$0.0486301370       
i-0abcdef1234567890 	eks-cluster-karpenter-Node  	        m3.medium 	running   	2025-07-17T02:44:08+00:00	spot      	$0.016000      	$0.0670000000 	$0.0402968037       
i-0fedcba9876543210 	eks-cluster-nodes-default-Node     	t3.large  	running   	2025-07-03T20:01:39+00:00	on-demand 	$0.0832000000  	$0.0832000000 	$0.0486301370

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment