Skip to content

Commit

Permalink
Ignore pricing lists for capacity blocks (#201)
Browse files Browse the repository at this point in the history
Add filters when getting pricing lists to ignore capacity blocks.

Resolves #200
  • Loading branch information
cartalla authored Feb 5, 2024
1 parent eba2c5f commit 9d3c16f
Showing 1 changed file with 22 additions and 16 deletions.
38 changes: 22 additions & 16 deletions source/EC2InstanceTypeInfoPkg/EC2InstanceTypeInfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,30 +169,36 @@ def get_instance_type_and_family_info(self, region):
instance_types = sorted(instance_type_info.keys())

logger.debug(f"Getting pricing info for {len(instance_types)} instance types:\n{json.dumps(instance_types, indent=4, sort_keys=True)}")
logger.debug("{} instance types in {}".format(len(instance_types), region))
logger.debug(f"{len(instance_types)} instance types in {region}")

if self.get_savings_plans:
savingsPlanInfo = SavingsPlanInfo(region)

count = 1
for instanceType in sorted(instance_types):
logger.debug("instanceType: {}".format(instanceType))
logger.debug(f"instanceType: {instanceType}")
os = 'Linux'
pricing_filter = [
{'Field': 'ServiceCode', 'Value': 'AmazonEC2', 'Type': 'TERM_MATCH'},
{'Field': 'instanceType', 'Value': instanceType, 'Type': 'TERM_MATCH'},
{'Field': 'tenancy', 'Value': 'shared', 'Type': 'TERM_MATCH'},
{'Field': 'preInstalledSw', 'Value': 'NA', 'Type': 'TERM_MATCH'},
{'Field': 'location', 'Value': region_name, 'Type': 'TERM_MATCH'},
{'Field': 'operatingSystem', 'Value': os, 'Type': 'TERM_MATCH'},
{'Field': 'capacitystatus', 'Value': 'Used', 'Type': 'TERM_MATCH'},
{'Field': 'location', 'Value': region_name, 'Type': 'TERM_MATCH'},
{'Field': 'instanceType', 'Value': instanceType, 'Type': 'TERM_MATCH'},
{'Field': 'operatingSystem', 'Value': os, 'Type': 'TERM_MATCH'},
{'Field': 'ServiceCode', 'Value': 'AmazonEC2', 'Type': 'TERM_MATCH'},
{'Field': 'tenancy', 'Value': 'shared', 'Type': 'TERM_MATCH'},
{'Field': 'preInstalledSw', 'Value': 'NA', 'Type': 'TERM_MATCH'},
{'Field': 'capacitystatus', 'Value': 'Used', 'Type': 'TERM_MATCH'},
{'Field': 'vpcnetworkingsupport', 'Value': 'true', 'Type': 'TERM_MATCH'},
{'Field': 'operation', 'Value': 'RunInstances', 'Type': 'TERM_MATCH'},
]
priceLists = self.get_products(pricing_filter)
if len(priceLists) == 0:
logger.warning(f"No pricelist for {instanceType} {region} ({region_name}). Instance type may not be available in this region.")
continue
if len(priceLists) > 1:
raise RuntimeError("Number of PriceLists > 1 for {}".format(instanceType))
logger.error(f"Number of PriceLists > 1 for {instanceType}")
for index, priceListJson in enumerate(priceLists):
priceList = json.loads(priceListJson)
logger.info(f"priceList[{index}]:\n{json.dumps(priceList, indent=4)}")
raise RuntimeError(f"Number of PriceLists > 1 for {instanceType}")

instance_type_info[instanceType]['pricing'] = {}
instance_type_info[instanceType]['pricing']['Reserved'] = {}
Expand All @@ -209,7 +215,7 @@ def get_instance_type_and_family_info(self, region):
# instance_type_info[instanceType]['priceLists'] = []
for priceListJson in priceLists:
priceList = json.loads(priceListJson)
#logger.debug("pricelist:\n{}".format(pp.pformat(priceList)))
#logger.debug(f"pricelist:\n{pp.pformat(priceList)}")
#instance_type_info[instanceType]['priceLists'].append(priceList)
if 'physicalProcessor' in priceList['product']['attributes']:
physicalProcessor = priceList['product']['attributes']['physicalProcessor']
Expand All @@ -219,18 +225,18 @@ def get_instance_type_and_family_info(self, region):
for dimensionKey, priceDimension in rateCode['priceDimensions'].items():
unit = priceDimension['unit']
if unit != 'Hrs':
raise RuntimeError("Unknown pricing unit: {}".format(unit))
raise RuntimeError(f"Unknown pricing unit: {unit}")
currency = list(priceDimension['pricePerUnit'])[0]
if currency != 'USD':
raise RuntimeError("Unknown currency: {}".format(currency))
raise RuntimeError(f"Unknown currency: {currency}")
on_demand_price = float(priceDimension['pricePerUnit']['USD'])
elif term == 'Reserved':
for ri_info_key, ri_info in termInfo.items():
attributes = ri_info['termAttributes']
ri_length = attributes['LeaseContractLength']
ri_class = attributes['OfferingClass']
ri_PurchaseOption = attributes['PurchaseOption']
ri_terms = "RI {} {} {}".format(ri_length, ri_class, ri_PurchaseOption)
ri_terms = f"RI {ri_length} {ri_class} {ri_PurchaseOption}"
ri_length_hours = float(ri_length.split('yr')[0]) * 365 * 24
ri_price = float(0)
for priceDimensionKey, priceDimension in ri_info['priceDimensions'].items():
Expand All @@ -241,7 +247,7 @@ def get_instance_type_and_family_info(self, region):
elif unit == 'Hrs':
ri_price += pricePerUnit
else:
raise RuntimeError("Invalid reserved instance unit {}".format(unit))
raise RuntimeError(f"Invalid reserved instance unit {unit}")
instance_type_info[instanceType]['pricing']['Reserved'][ri_terms] = ri_price
if ri_price > ri_max_price:
ri_max_price = max(ri_max_price, ri_price)
Expand All @@ -250,7 +256,7 @@ def get_instance_type_and_family_info(self, region):
ri_min_price = ri_price
ri_min_price_terms = ri_terms
else:
raise RuntimeError("Invalid term {}".format(term))
raise RuntimeError(f"Invalid term {term}")
instance_type_info[instanceType]['pricing']['Reserved_min'] = ri_min_price
instance_type_info[instanceType]['pricing']['Reserved_min_terms'] = ri_min_price_terms
instance_type_info[instanceType]['pricing']['Reserved_max'] = ri_max_price
Expand Down

0 comments on commit 9d3c16f

Please sign in to comment.