DescribeInstanceTypeOfferings - script that hardcodes all offerings
This commit is contained in:
parent
5d208bfd04
commit
936fb19539
@ -34,6 +34,7 @@ from moto.core.utils import (
|
|||||||
)
|
)
|
||||||
from moto.core import ACCOUNT_ID
|
from moto.core import ACCOUNT_ID
|
||||||
from moto.kms import kms_backends
|
from moto.kms import kms_backends
|
||||||
|
from os import listdir
|
||||||
|
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
CidrLimitExceeded,
|
CidrLimitExceeded,
|
||||||
@ -175,9 +176,20 @@ INSTANCE_TYPES = _load_resource(
|
|||||||
resource_filename(__name__, "resources/instance_types.json")
|
resource_filename(__name__, "resources/instance_types.json")
|
||||||
)
|
)
|
||||||
|
|
||||||
INSTANCE_TYPE_OFFERINGS = _load_resource(
|
offerings_path = "resources/instance_type_offerings"
|
||||||
resource_filename(__name__, "resources/instance_type_offerings.json")
|
INSTANCE_TYPE_OFFERINGS = {}
|
||||||
)
|
for location_type in listdir(resource_filename(__name__, offerings_path)):
|
||||||
|
INSTANCE_TYPE_OFFERINGS[location_type] = {}
|
||||||
|
for region in listdir(
|
||||||
|
resource_filename(__name__, offerings_path + "/" + location_type)
|
||||||
|
):
|
||||||
|
full_path = resource_filename(
|
||||||
|
__name__, offerings_path + "/" + location_type + "/" + region
|
||||||
|
)
|
||||||
|
INSTANCE_TYPE_OFFERINGS[location_type][
|
||||||
|
region.replace(".json", "")
|
||||||
|
] = _load_resource(full_path)
|
||||||
|
|
||||||
|
|
||||||
AMIS = _load_resource(
|
AMIS = _load_resource(
|
||||||
os.environ.get("MOTO_AMIS_PATH")
|
os.environ.get("MOTO_AMIS_PATH")
|
||||||
@ -1151,25 +1163,27 @@ class InstanceTypeOfferingBackend(object):
|
|||||||
super(InstanceTypeOfferingBackend, self).__init__()
|
super(InstanceTypeOfferingBackend, self).__init__()
|
||||||
|
|
||||||
def describe_instance_type_offerings(self, location_type=None, filters=None):
|
def describe_instance_type_offerings(self, location_type=None, filters=None):
|
||||||
matches = INSTANCE_TYPE_OFFERINGS
|
|
||||||
location_type = location_type or "region"
|
location_type = location_type or "region"
|
||||||
|
matches = INSTANCE_TYPE_OFFERINGS[location_type]
|
||||||
|
matches = matches[self.region_name]
|
||||||
|
|
||||||
def matches_filters(offering, filters):
|
def matches_filters(offering, filters):
|
||||||
for key, values in filters.items():
|
def matches_filter(key, values):
|
||||||
if key == "location":
|
if key == "location":
|
||||||
if location_type in ("availability-zone", "availability-zone-id"):
|
if location_type in ("availability-zone", "availability-zone-id"):
|
||||||
return offering.get("location") in values
|
return offering.get("Location") in values
|
||||||
elif location_type == "region":
|
elif location_type == "region":
|
||||||
return any(
|
return any(
|
||||||
v for v in values if offering.get("location").startswith(v)
|
v for v in values if offering.get("Location").startswith(v)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
elif key == "instance-type":
|
elif key == "instance-type":
|
||||||
return offering.get("instance_type") in values
|
return offering.get("InstanceType") in values
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
return True
|
|
||||||
|
return all([matches_filter(key, values) for key, values in filters.items()])
|
||||||
|
|
||||||
matches = [o for o in matches if matches_filters(o, filters)]
|
matches = [o for o in matches if matches_filters(o, filters)]
|
||||||
return matches
|
return matches
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -149,7 +149,7 @@ class InstanceResponse(BaseResponse):
|
|||||||
return template.render(instance_types=instance_types)
|
return template.render(instance_types=instance_types)
|
||||||
|
|
||||||
def describe_instance_type_offerings(self):
|
def describe_instance_type_offerings(self):
|
||||||
location_type_filters = self._get_multi_param("LocationType")
|
location_type_filters = self._get_param("LocationType")
|
||||||
filter_dict = filters_from_querystring(self.querystring)
|
filter_dict = filters_from_querystring(self.querystring)
|
||||||
offerings = self.ec2_backend.describe_instance_type_offerings(
|
offerings = self.ec2_backend.describe_instance_type_offerings(
|
||||||
location_type_filters, filter_dict
|
location_type_filters, filter_dict
|
||||||
@ -856,9 +856,9 @@ EC2_DESCRIBE_INSTANCE_TYPE_OFFERINGS = """<?xml version="1.0" encoding="UTF-8"?>
|
|||||||
<instanceTypeOfferingSet>
|
<instanceTypeOfferingSet>
|
||||||
{% for offering in instance_type_offerings %}
|
{% for offering in instance_type_offerings %}
|
||||||
<item>
|
<item>
|
||||||
<instanceType>{{ offering.instance_type }}</instanceType>
|
<instanceType>{{ offering.InstanceType }}</instanceType>
|
||||||
<location>{{ offering.location }}</location>
|
<location>{{ offering.Location }}</location>
|
||||||
<locationType>{{ offering.location_type }}</locationType>
|
<locationType>{{ offering.LocationType }}</locationType>
|
||||||
</item>
|
</item>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</instanceTypeOfferingSet>
|
</instanceTypeOfferingSet>
|
||||||
|
63
scripts/ec2_get_instance_type_offerings.py
Normal file
63
scripts/ec2_get_instance_type_offerings.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
"""
|
||||||
|
Get InstanceTypeOfferings from AWS
|
||||||
|
Stores result in moto/ec2/resources/instance_type_offerings/{location_type}/{region}.json
|
||||||
|
Where {location_type} is one of region/availability-zone/availability-zone-id
|
||||||
|
|
||||||
|
Note that you will get the following error if a region is not available to you:
|
||||||
|
An error occurred (AuthFailure) when calling the DescribeInstanceTypeOfferings operation:
|
||||||
|
AWS was not able to validate the provided access credentials
|
||||||
|
"""
|
||||||
|
import boto3
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from boto3 import Session
|
||||||
|
from time import sleep
|
||||||
|
|
||||||
|
PATH = "moto/ec2/resources/instance_type_offerings"
|
||||||
|
TYPES = ["region", "availability-zone", "availability-zone-id"]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print("Getting InstanceTypeOfferings from all regions")
|
||||||
|
regions = []
|
||||||
|
regions.extend(Session().get_available_regions("ec2"))
|
||||||
|
regions.extend(Session().get_available_regions("ec2", partition_name="aws-us-gov"))
|
||||||
|
regions.extend(Session().get_available_regions("ec2", partition_name="aws-cn"))
|
||||||
|
print("Found " + str(len(regions)) + " regions")
|
||||||
|
|
||||||
|
root_dir = (
|
||||||
|
subprocess.check_output(["git", "rev-parse", "--show-toplevel"])
|
||||||
|
.decode()
|
||||||
|
.strip()
|
||||||
|
)
|
||||||
|
for region in regions:
|
||||||
|
for location_type in TYPES:
|
||||||
|
ec2 = boto3.client("ec2", region_name=region)
|
||||||
|
dest = os.path.join(root_dir, "{0}/{1}/{2}.json".format(PATH, location_type, region))
|
||||||
|
try:
|
||||||
|
instances = []
|
||||||
|
offerings = ec2.describe_instance_type_offerings(
|
||||||
|
LocationType=location_type
|
||||||
|
)
|
||||||
|
instances.extend(offerings["InstanceTypeOfferings"])
|
||||||
|
next_token = offerings.get("NextToken", "")
|
||||||
|
while next_token:
|
||||||
|
offerings = ec2.describe_instance_type_offerings(
|
||||||
|
LocationType=location_type,
|
||||||
|
NextToken=next_token
|
||||||
|
)
|
||||||
|
instances.extend(offerings["InstanceTypeOfferings"])
|
||||||
|
next_token = offerings.get("NextToken", None)
|
||||||
|
print("Writing data to {0}".format(dest))
|
||||||
|
with open(dest, "w+") as open_file:
|
||||||
|
json.dump(instances, open_file, sort_keys=True)
|
||||||
|
except Exception as e:
|
||||||
|
print("Unable to write data to {0}".format(dest))
|
||||||
|
print(e)
|
||||||
|
# We don't want it to look like we're DDOS'ing AWS
|
||||||
|
sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
@ -21,16 +21,31 @@ def test_describe_instance_type_offerings():
|
|||||||
@mock_ec2
|
@mock_ec2
|
||||||
def test_describe_instance_type_offering_filter_by_type():
|
def test_describe_instance_type_offering_filter_by_type():
|
||||||
client = boto3.client("ec2", "us-east-1")
|
client = boto3.client("ec2", "us-east-1")
|
||||||
|
|
||||||
|
# Verify offerings of a specific instance type
|
||||||
offerings = client.describe_instance_type_offerings(
|
offerings = client.describe_instance_type_offerings(
|
||||||
Filters=[{"Name": "instance-type", "Values": ["t2.nano"]}]
|
Filters=[{"Name": "instance-type", "Values": ["t2.nano"]}]
|
||||||
)
|
)
|
||||||
|
|
||||||
offerings.should.have.key("InstanceTypeOfferings")
|
offerings.should.have.key("InstanceTypeOfferings")
|
||||||
offerings["InstanceTypeOfferings"].should_not.be.empty
|
offerings["InstanceTypeOfferings"].should_not.be.empty
|
||||||
offerings["InstanceTypeOfferings"].should.have.length_of(2)
|
offerings = offerings["InstanceTypeOfferings"]
|
||||||
offerings["InstanceTypeOfferings"][0]["InstanceType"].should.equal("t2.nano")
|
offerings.should.have.length_of(1)
|
||||||
offerings["InstanceTypeOfferings"][-1]["InstanceType"].should.equal("t2.nano")
|
offerings[0]["InstanceType"].should.equal("t2.nano")
|
||||||
offerings["InstanceTypeOfferings"][0]["Location"].should.equal("us-east-1a")
|
offerings[0]["Location"].should.equal("us-east-1")
|
||||||
|
|
||||||
|
# Verify offerings of that instance type per availibility zone
|
||||||
|
offerings = client.describe_instance_type_offerings(
|
||||||
|
LocationType="availability-zone",
|
||||||
|
Filters=[{"Name": "instance-type", "Values": ["t2.nano"]}],
|
||||||
|
)
|
||||||
|
offerings.should.have.key("InstanceTypeOfferings")
|
||||||
|
offerings = offerings["InstanceTypeOfferings"]
|
||||||
|
offerings.should.have.length_of(6)
|
||||||
|
for offering in offerings:
|
||||||
|
offering["InstanceType"].should.equal("t2.nano")
|
||||||
|
offering["LocationType"].should.equal("availability-zone")
|
||||||
|
offering["Location"].should.match("us-east-1[a-f]")
|
||||||
|
|
||||||
|
|
||||||
@mock_ec2
|
@mock_ec2
|
||||||
@ -42,21 +57,29 @@ def test_describe_instance_type_offering_filter_by_zone():
|
|||||||
)
|
)
|
||||||
|
|
||||||
offerings.should.have.key("InstanceTypeOfferings")
|
offerings.should.have.key("InstanceTypeOfferings")
|
||||||
offerings["InstanceTypeOfferings"].should_not.be.empty
|
offerings = offerings["InstanceTypeOfferings"]
|
||||||
offerings["InstanceTypeOfferings"].should.have.length_of(1)
|
offerings.should_not.be.empty
|
||||||
offerings["InstanceTypeOfferings"][0]["InstanceType"].should.equal("a1.2xlarge")
|
offerings.should.have.length_of(353)
|
||||||
offerings["InstanceTypeOfferings"][0]["Location"].should.equal("us-east-1c")
|
assert all([o["LocationType"] == "availability-zone" for o in offerings])
|
||||||
|
assert all([o["Location"] == "us-east-1c" for o in offerings])
|
||||||
|
assert any([o["InstanceType"] == "a1.2xlarge" for o in offerings])
|
||||||
|
|
||||||
|
|
||||||
@mock_ec2
|
@mock_ec2
|
||||||
def test_describe_instance_type_offering_filter_by_region():
|
def test_describe_instance_type_offering_filter_by_zone_id():
|
||||||
client = boto3.client("ec2", "us-east-1")
|
client = boto3.client("ec2", "ca-central-1")
|
||||||
offerings = client.describe_instance_type_offerings(
|
offerings = client.describe_instance_type_offerings(
|
||||||
LocationType="region", Filters=[{"Name": "location", "Values": ["us-west-1"]}]
|
LocationType="availability-zone-id",
|
||||||
|
Filters=[
|
||||||
|
{"Name": "location", "Values": ["cac1-az1"]},
|
||||||
|
{"Name": "instance-type", "Values": ["c5.9xlarge"]},
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
offerings.should.have.key("InstanceTypeOfferings")
|
offerings.should.have.key("InstanceTypeOfferings")
|
||||||
offerings["InstanceTypeOfferings"].should_not.be.empty
|
offerings = offerings["InstanceTypeOfferings"]
|
||||||
offerings["InstanceTypeOfferings"].should.have.length_of(2)
|
offerings.should_not.be.empty
|
||||||
offerings["InstanceTypeOfferings"][0]["InstanceType"].should.equal("a1.4xlarge")
|
offerings.should.have.length_of(1)
|
||||||
offerings["InstanceTypeOfferings"][0]["Location"].should.equal("us-west-1a")
|
offerings[0]["LocationType"].should.equal("availability-zone-id")
|
||||||
|
offerings[0]["InstanceType"].should.equal("c5.9xlarge")
|
||||||
|
offerings[0]["Location"].should.equal("cac1-az1")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user