Use boto3 to get current price for given EC2 instance type
Here is the solution I ended up with. Using Boto3's own Pricing API with a filter for the instance type, region and operating system. The API still returns a lot of information, so I needed to do a bit of post-processing.
import boto3import jsonfrom pkg_resources import resource_filename# Search product filterFLT = '[{{"Field": "tenancy", "Value": "shared", "Type": "TERM_MATCH"}},'\ '{{"Field": "operatingSystem", "Value": "{o}", "Type": "TERM_MATCH"}},'\ '{{"Field": "preInstalledSw", "Value": "NA", "Type": "TERM_MATCH"}},'\ '{{"Field": "instanceType", "Value": "{t}", "Type": "TERM_MATCH"}},'\ '{{"Field": "location", "Value": "{r}", "Type": "TERM_MATCH"}},'\ '{{"Field": "capacitystatus", "Value": "Used", "Type": "TERM_MATCH"}}]'# Get current AWS price for an on-demand instancedef get_price(region, instance, os): f = FLT.format(r=region, t=instance, o=os) data = client.get_products(ServiceCode='AmazonEC2', Filters=json.loads(f)) od = json.loads(data['PriceList'][0])['terms']['OnDemand'] id1 = list(od)[0] id2 = list(od[id1]['priceDimensions'])[0] return od[id1]['priceDimensions'][id2]['pricePerUnit']['USD']# Translate region code to region namedef get_region_name(region_code): default_region = 'EU (Ireland)' endpoint_file = resource_filename('botocore', 'data/endpoints.json') try: with open(endpoint_file, 'r') as f: data = json.load(f) return data['partitions'][0]['regions'][region_code]['description'] except IOError: return default_region# Use AWS Pricing API at US-East-1client = boto3.client('pricing', region_name='us-east-1')# Get current price for a given instance, region and osprice = get_price(get_region_name('eu-west-1'), 'c5.xlarge', 'Linux')print(price)
This example outputs 0.1920000000
(hourly price in USD) fairly quickly. But any further optimizations would indeed be appreciated.
If you don't like the native function, then look at Lyft's awspricing library for Python. Here's an example:
import awspricingec2_offer = awspricing.offer('AmazonEC2')p = ec2_offer.ondemand_hourly( 't2.micro', operating_system='Linux', region='eu-west-1')print(p) # 0.0126
I'd recommend enabling caching (see AWSPRICING_USE_CACHE) otherwise it will be slow.
I have updated toringe's solution a bit to handle different key errors
def price_information(self, instance_type, os, region): # Search product filter FLT = '[{{"Field": "operatingSystem", "Value": "{o}", "Type": "TERM_MATCH"}},' \ '{{"Field": "instanceType", "Value": "{t}", "Type": "TERM_MATCH"}}]' f = FLT.format(t=instance_type, o=os) try: data = self.pricing_client.get_products(ServiceCode='AmazonEC2', Filters=json.loads(f)) instance_price = 0 for price in data['PriceList']: try: first_id = list(eval(price)['terms']['OnDemand'].keys())[0] price_data = eval(price)['terms']['OnDemand'][first_id] second_id = list(price_data['priceDimensions'].keys())[0] instance_price = price_data['priceDimensions'][second_id]['pricePerUnit']['USD'] if float(price) > 0: break except Exception as e: print(e) print(instance_price) return instance_price except Exception as e: print(e) return 0