Last active
May 9, 2023 11:00
-
-
Save omerh/302a9615d6d24eeead2449b36c10b13e to your computer and use it in GitHub Desktop.
This file contains 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
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