Skip to content

Instantly share code, notes, and snippets.

@omerh
Last active May 9, 2023 11:00
Show Gist options
  • Save omerh/302a9615d6d24eeead2449b36c10b13e to your computer and use it in GitHub Desktop.
Save omerh/302a9615d6d24eeead2449b36c10b13e to your computer and use it in GitHub Desktop.
import csv
from datetime import datetime
import boto3
import json
from pkg_resources import resource_filename
def get_ec2_spot_pricing(instance_type, region_code):
client = boto3.client('ec2', region_name=region_code)
today_date = datetime.utcnow()
response = client.get_paginator('describe_spot_price_history').paginate(
InstanceTypes=[instance_type],
ProductDescriptions=['Linux/UNIX'],
StartTime=today_date,
EndTime=today_date,).build_full_result()
return response['SpotPriceHistory']
def get_region_name(region_code):
endpoint_file = resource_filename('botocore', 'data/endpoints.json')
with open(endpoint_file, 'r') as f:
endpoint_data = json.load(f)
region_name = endpoint_data['partitions'][0]['regions'][region_code]['description']
region_name = region_name.replace('Europe', 'EU')
return region_name
def get_ec2_instance_hourly_price(region_code,
instance_type,
operating_system,
preinstalled_software='NA',
tenancy='Shared',
is_byol=False):
region_name = get_region_name(region_code)
if is_byol:
license_model = 'Bring your own license'
else:
license_model = 'No License required'
if tenancy == 'Host':
capacity_status = 'AllocatedHost'
else:
capacity_status = 'Used'
filters = [
{'Type': 'TERM_MATCH', 'Field': 'termType', 'Value': 'OnDemand'},
{'Type': 'TERM_MATCH', 'Field': 'capacitystatus', 'Value': capacity_status},
{'Type': 'TERM_MATCH', 'Field': 'location', 'Value': region_name},
{'Type': 'TERM_MATCH', 'Field': 'instanceType', 'Value': instance_type},
{'Type': 'TERM_MATCH', 'Field': 'tenancy', 'Value': tenancy},
{'Type': 'TERM_MATCH', 'Field': 'operatingSystem', 'Value': operating_system},
{'Type': 'TERM_MATCH', 'Field': 'preInstalledSw', 'Value': preinstalled_software},
{'Type': 'TERM_MATCH', 'Field': 'licenseModel', 'Value': license_model},
]
pricing_client = boto3.client('pricing', region_name='us-east-1')
response = pricing_client.get_paginator('get_products').paginate(ServiceCode='AmazonEC2', Filters=filters).build_full_result()
for price in response['PriceList']:
price = json.loads(price)
for on_demand in price['terms']['OnDemand'].values():
for price_dimensions in on_demand['priceDimensions'].values():
price_value = price_dimensions['pricePerUnit']['USD']
return float(price_value)
return None
def get_all_instances_offering(region):
ec2_client = boto3.client('ec2', region_name=region)
response = ec2_client.get_paginator('describe_instance_type_offerings').paginate().build_full_result()
return response['InstanceTypeOfferings']
def write_to_csv(result_list, region_code):
# Get all possible keys
all_keys = []
for d in result_list:
for key in d.keys():
if key not in all_keys:
all_keys.append(key)
for d in result_list:
for key in all_keys:
d.setdefault(key, None)
file_name_with_date = "ec2-report-{}-{}.csv".format(region_code, datetime.now().strftime("%Y%m%d%H%M%S"))
with open(file_name_with_date, 'w', newline='') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=all_keys)
writer.writeheader()
for row in result_list:
writer.writerow(row)
if __name__ == "__main__":
region_code = 'us-east-1'
full_pricing = []
result = {}
# Get all instance offerings in the region
offerings = get_all_instances_offering(region_code)
# debug
# i = 1
for offering in offerings:
# Get the hourly price of the instance
ec2_instance_price = get_ec2_instance_hourly_price(
region_code=region_code,
instance_type=offering['InstanceType'],
operating_system='Linux',
)
# Create a dict with the instance offering and the price
on_demand = {
"region": region_code,
"instance_type": offering['InstanceType'],
"on-demand_price": ec2_instance_price,
}
# Add the result to temp r dict
r = on_demand.copy()
# Get spot price for the instance type in the region
spot_pricing = get_ec2_spot_pricing(instance_type=offering['InstanceType'], region_code=region_code)
# Iterate over the spot result, as each AZ has its offering
for record in spot_pricing:
spot_price_az = {
"instance_type": offering['InstanceType'],
record['AvailabilityZone']: record['SpotPrice'],
record['AvailabilityZone'] + "-price-diff-percent": (float(record['SpotPrice']) - float(
ec2_instance_price)) / float(ec2_instance_price) * 100,
}
# Update the r dict with the spot price in the AZ, and its diff in percent
r.update(spot_price_az)
# Add the result to the full pricing list
full_pricing.append(r)
# Working indicator
print(".", end="", flush=True)
# debug
# i = i + 1
# if i > 2:
# break
write_to_csv(full_pricing, region_code)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment