k8s/pricing.py (132 lines of code) (raw):

import boto3 import json region_mapping = { "ap-east-1": "Asia Pacific (Hong Kong)", "ap-southeast-1": "Asia Pacific (Singapore)", "ap-southeast-2": "Asia Pacific (Sydney)", "ap-northeast-1": "Asia Pacific (Tokyo)", "ap-northeast-2": "Asia Pacific (Seoul)", "ap-northeast-3": "Asia Pacific (Osaka-Local)", "ap-south-1": "Asia Pacific (Mumbai)", "ca-central-1": "Canada (Central)", "eu-central-1": "EU (Frankfurt)", "eu-west-1": "EU (Ireland)", "eu-west-2": "EU (London)", "eu-west-3": "EU (Paris)", "sa-east-1": "South America (Sao Paulo)", "us-east-1": "US East (N. Virginia)", "us-west-1": "US West (N. California)", "us-east-2": "US East (Ohio)", "us-west-2": "US West (Oregon)", "cn-north-1": "China (Beijing)", "cn-northwest-1": "China (Ningxia)", "us-gov-west-1": "AWS GovCloud (US)", } def get_on_demand_price(region, instance_type): """Get on-demand price for a specific instance type in a region.""" pricing_client = boto3.client("pricing", region_name="us-east-1") try: response = pricing_client.get_products( ServiceCode="AmazonEC2", Filters=[ { "Type": "TERM_MATCH", "Field": "instanceType", "Value": instance_type, }, { "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", }, { "Type": "TERM_MATCH", "Field": "location", "Value": region_mapping[region], }, ], ) if response["PriceList"]: price_data = eval(response["PriceList"][0]) terms = price_data["terms"]["OnDemand"] price_dimensions = next(iter(terms.values()))["priceDimensions"] price = next(iter(price_dimensions.values()))["pricePerUnit"][ "USD" ] return float(price) except Exception as e: print( f"Error getting on-demand price for {instance_type} in {region}: {str(e)}" ) return None def get_reserved(region, instance_type): """Get savings plans rates for a specific instance type in a region.""" savingsplans_client = boto3.client("savingsplans", region_name="us-east-1") def request(): results = [] nt = None while True: kwargs = dict( filters=[ {"name": "instanceType", "values": [instance_type]}, {"name": "region", "values": [region]}, {"name": "tenancy", "values": ["shared"]}, {"name": "productDescription", "values": ["Linux/UNIX"]}, ], serviceCodes=["AmazonEC2"], ) if nt: kwargs["nextToken"] = nt response = ( savingsplans_client.describe_savings_plans_offering_rates( **kwargs ) ) results.extend(response["searchResults"]) if len(response["nextToken"]) > 0: nt = response["nextToken"] else: break return results try: results = request() rates = { "1.0y": {"no": None, "partial": None, "all": None}, "3.0y": {"no": None, "partial": None, "all": None}, } for result in results: # Skip unused box entries if "UnusedBox" in result["usageType"]: continue duration_seconds = result["savingsPlanOffering"]["durationSeconds"] duration_years = duration_seconds / (365 * 24 * 60 * 60) key = f"{duration_years:.1f}y" payment_option = ( result["savingsPlanOffering"]["paymentOption"] .lower() .split()[0] ) # 'no', 'partial', or 'all' rate = float(result["rate"]) if key in rates: rates[key][payment_option] = rate return ( rates if any( any(v is not None for v in year.values()) for year in rates.values() ) else None ) except Exception as e: print( f"Error getting reserved cost for {instance_type} in {region}: {str(e)}" ) return None