Merge pull request #3508 from bblommers/feature/ec2-describe-instance-type-offerings

EC2: describe instance type offerings
This commit is contained in:
Steve Pulec 2020-12-03 18:06:06 -06:00 committed by GitHub
commit 51928f2410
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
67 changed files with 346 additions and 9 deletions

View file

@ -198,6 +198,14 @@ class InvalidInstanceIdError(EC2ClientError):
)
class InvalidInstanceTypeError(EC2ClientError):
def __init__(self, instance_type):
super(InvalidInstanceTypeError, self).__init__(
"InvalidInstanceType.NotFound",
"The instance type '{0}' does not exist".format(instance_type),
)
class InvalidAMIIdError(EC2ClientError):
def __init__(self, ami_id):
super(InvalidAMIIdError, self).__init__(

View file

@ -34,6 +34,7 @@ from moto.core.utils import (
)
from moto.core import ACCOUNT_ID
from moto.kms import kms_backends
from os import listdir
from .exceptions import (
CidrLimitExceeded,
@ -56,6 +57,7 @@ from .exceptions import (
InvalidDomainError,
InvalidID,
InvalidInstanceIdError,
InvalidInstanceTypeError,
InvalidInternetGatewayIdError,
InvalidKeyPairDuplicateError,
InvalidKeyPairFormatError,
@ -174,6 +176,21 @@ INSTANCE_TYPES = _load_resource(
resource_filename(__name__, "resources/instance_types.json")
)
offerings_path = "resources/instance_type_offerings"
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(
os.environ.get("MOTO_AMIS_PATH")
or resource_filename(__name__, "resources/amis.json"),
@ -1127,6 +1144,51 @@ class InstanceBackend(object):
return reservations
class InstanceTypeBackend(object):
def __init__(self):
super(InstanceTypeBackend, self).__init__()
def describe_instance_types(self, instance_types=None):
matches = INSTANCE_TYPES.values()
if instance_types:
matches = [t for t in matches if t.get("apiname") in instance_types]
if len(instance_types) > len(matches):
unknown_ids = set(instance_types) - set(matches)
raise InvalidInstanceTypeError(unknown_ids)
return matches
class InstanceTypeOfferingBackend(object):
def __init__(self):
super(InstanceTypeOfferingBackend, self).__init__()
def describe_instance_type_offerings(self, location_type=None, filters=None):
location_type = location_type or "region"
matches = INSTANCE_TYPE_OFFERINGS[location_type]
matches = matches[self.region_name]
def matches_filters(offering, filters):
def matches_filter(key, values):
if key == "location":
if location_type in ("availability-zone", "availability-zone-id"):
return offering.get("Location") in values
elif location_type == "region":
return any(
v for v in values if offering.get("Location").startswith(v)
)
else:
return False
elif key == "instance-type":
return offering.get("InstanceType") in values
else:
return False
return all([matches_filter(key, values) for key, values in filters.items()])
matches = [o for o in matches if matches_filters(o, filters)]
return matches
class KeyPair(object):
def __init__(self, name, fingerprint, material):
self.name = name
@ -6015,6 +6077,8 @@ class IamInstanceProfileAssociationBackend(object):
class EC2Backend(
BaseBackend,
InstanceBackend,
InstanceTypeBackend,
InstanceTypeOfferingBackend,
TagBackend,
EBSBackend,
RegionsAndZonesBackend,

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

View file

@ -1,5 +1,4 @@
from __future__ import unicode_literals
from moto.packages.boto.ec2.instancetype import InstanceType
from moto.autoscaling import autoscaling_backends
from moto.core.responses import BaseResponse
@ -144,12 +143,20 @@ class InstanceResponse(BaseResponse):
return template.render(instances=instances)
def describe_instance_types(self):
instance_types = [
InstanceType(name="t1.micro", cores=1, memory=644874240, disk=0)
]
instance_type_filters = self._get_multi_param("InstanceType")
instance_types = self.ec2_backend.describe_instance_types(instance_type_filters)
template = self.response_template(EC2_DESCRIBE_INSTANCE_TYPES)
return template.render(instance_types=instance_types)
def describe_instance_type_offerings(self):
location_type_filters = self._get_param("LocationType")
filter_dict = filters_from_querystring(self.querystring)
offerings = self.ec2_backend.describe_instance_type_offerings(
location_type_filters, filter_dict
)
template = self.response_template(EC2_DESCRIBE_INSTANCE_TYPE_OFFERINGS)
return template.render(instance_type_offerings=offerings)
def describe_instance_attribute(self):
# TODO this and modify below should raise IncorrectInstanceState if
# instance not in stopped state
@ -818,17 +825,17 @@ EC2_DESCRIBE_INSTANCE_TYPES = """<?xml version="1.0" encoding="UTF-8"?>
<instanceTypeSet>
{% for instance_type in instance_types %}
<item>
<instanceType>{{ instance_type.name }}</instanceType>
<instanceType>{{ instance_type.apiname }}</instanceType>
<vCpuInfo>
<defaultVCpus>{{ instance_type.cores }}</defaultVCpus>
<defaultCores>{{ instance_type.cores }}</defaultCores>
<defaultVCpus>{{ instance_type.vcpus|int }}</defaultVCpus>
<defaultCores>{{ instance_type.vcpus|int }}</defaultCores>
<defaultThreadsPerCore>1</defaultThreadsPerCore>
</vCpuInfo>
<memoryInfo>
<sizeInMiB>{{ instance_type.memory }}</sizeInMiB>
<sizeInMiB>{{ instance_type.memory|int }}</sizeInMiB>
</memoryInfo>
<instanceStorageInfo>
<totalSizeInGB>{{ instance_type.disk }}</totalSizeInGB>
<totalSizeInGB>{{ instance_type.storage|int }}</totalSizeInGB>
</instanceStorageInfo>
<processorInfo>
<supportedArchitectures>
@ -841,3 +848,18 @@ EC2_DESCRIBE_INSTANCE_TYPES = """<?xml version="1.0" encoding="UTF-8"?>
{% endfor %}
</instanceTypeSet>
</DescribeInstanceTypesResponse>"""
EC2_DESCRIBE_INSTANCE_TYPE_OFFERINGS = """<?xml version="1.0" encoding="UTF-8"?>
<DescribeInstanceTypeOfferingsResponse xmlns="http://api.outscale.com/wsdl/fcuext/2014-04-15/">
<requestId>f8b86168-d034-4e65-b48d-3b84c78e64af</requestId>
<instanceTypeOfferingSet>
{% for offering in instance_type_offerings %}
<item>
<instanceType>{{ offering.InstanceType }}</instanceType>
<location>{{ offering.Location }}</location>
<locationType>{{ offering.LocationType }}</locationType>
</item>
{% endfor %}
</instanceTypeOfferingSet>
</DescribeInstanceTypeOfferingsResponse>"""