Skip to content

Instantly share code, notes, and snippets.

@omerh
Last active May 9, 2023 11:00
Show Gist options
  • Select an option

  • Save omerh/302a9615d6d24eeead2449b36c10b13e to your computer and use it in GitHub Desktop.

Select an option

Save omerh/302a9615d6d24eeead2449b36c10b13e to your computer and use it in GitHub Desktop.

Revisions

  1. Omer Haim revised this gist May 9, 2023. 1 changed file with 3 additions and 5 deletions.
    8 changes: 3 additions & 5 deletions spot-report.py
    Original file line number Diff line number Diff line change
    @@ -8,18 +8,16 @@
    def get_ec2_spot_pricing(instance_type, region_code):
    client = boto3.client('ec2', region_name=region_code)
    today_date = datetime.utcnow()
    response = client.describe_spot_price_history(
    response = client.get_paginator('describe_spot_price_history').paginate(
    InstanceTypes=[instance_type],
    ProductDescriptions=['Linux/UNIX'],
    StartTime=today_date,
    EndTime=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)

    @@ -58,7 +56,7 @@ def get_ec2_instance_hourly_price(region_code,
    ]

    pricing_client = boto3.client('pricing', region_name='us-east-1')
    response = pricing_client.get_products(ServiceCode='AmazonEC2', Filters=filters)
    response = pricing_client.get_paginator('get_products').paginate(ServiceCode='AmazonEC2', Filters=filters).build_full_result()
    for price in response['PriceList']:
    price = json.loads(price)

  2. Omer Haim created this gist May 9, 2023.
    145 changes: 145 additions & 0 deletions spot-report.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,145 @@
    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.describe_spot_price_history(
    InstanceTypes=[instance_type],
    ProductDescriptions=['Linux/UNIX'],
    StartTime=today_date,
    EndTime=today_date,
    )
    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_products(ServiceCode='AmazonEC2', Filters=filters)
    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)