Implement EC2 describe_vpc_endpoint_services() (#4322)
This commit is contained in:
parent
a02bf0022d
commit
3a203d35c9
@ -1249,7 +1249,7 @@
|
||||
- [ ] describe_vpc_endpoint_connections
|
||||
- [ ] describe_vpc_endpoint_service_configurations
|
||||
- [ ] describe_vpc_endpoint_service_permissions
|
||||
- [ ] describe_vpc_endpoint_services
|
||||
- [X] describe_vpc_endpoint_services
|
||||
- [X] describe_vpc_endpoints
|
||||
- [X] describe_vpc_peering_connections
|
||||
- [X] describe_vpcs
|
||||
@ -4619,4 +4619,4 @@
|
||||
- workmailmessageflow
|
||||
- workspaces
|
||||
- xray
|
||||
</details>
|
||||
</details>
|
||||
|
@ -416,6 +416,13 @@ class AWSCertificateManagerBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "acm-pca"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _arn_not_found(arn):
|
||||
msg = "Certificate with arn {0} not found in account {1}".format(
|
||||
|
@ -72,6 +72,13 @@ class ApplicationAutoscalingBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region, ecs)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "application-autoscaling"
|
||||
)
|
||||
|
||||
@property
|
||||
def applicationautoscaling_backend(self):
|
||||
return applicationautoscaling_backends[self.region]
|
||||
|
@ -80,6 +80,13 @@ class AthenaBackend(BaseBackend):
|
||||
self.executions = {}
|
||||
self.named_queries = {}
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "athena"
|
||||
)
|
||||
|
||||
def create_work_group(self, name, configuration, description, tags):
|
||||
if name in self.work_groups:
|
||||
return None
|
||||
|
@ -622,6 +622,15 @@ class AutoScalingBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(ec2_backend, elb_backend, elbv2_backend)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "autoscaling"
|
||||
) + BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "autoscaling-plans"
|
||||
)
|
||||
|
||||
def create_launch_configuration(
|
||||
self,
|
||||
name,
|
||||
|
@ -1095,6 +1095,13 @@ class LambdaBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "lambda"
|
||||
)
|
||||
|
||||
def create_function(self, spec):
|
||||
function_name = spec.get("FunctionName", None)
|
||||
if function_name is None:
|
||||
|
@ -27,6 +27,11 @@ def backends():
|
||||
yield _import_backend(module_name, backends_name)
|
||||
|
||||
|
||||
def unique_backends():
|
||||
for module_name, backends_name in sorted(set(BACKENDS.values())):
|
||||
yield _import_backend(module_name, backends_name)
|
||||
|
||||
|
||||
def loaded_backends():
|
||||
loaded_modules = sys.modules.keys()
|
||||
loaded_modules = [m for m in loaded_modules if m.startswith("moto.")]
|
||||
|
@ -499,6 +499,13 @@ class CloudFormationBackend(BaseBackend):
|
||||
self.exports = OrderedDict()
|
||||
self.change_sets = OrderedDict()
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "cloudformation", policy_supported=False
|
||||
)
|
||||
|
||||
def _resolve_update_parameters(self, instance, incoming_params):
|
||||
parameters = dict(
|
||||
[
|
||||
|
@ -312,6 +312,13 @@ class CloudWatchBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "monitoring"
|
||||
)
|
||||
|
||||
@property
|
||||
# Retrieve a list of all OOTB metrics that are provided by metrics providers
|
||||
# Computed on the fly
|
||||
|
@ -36,6 +36,13 @@ class CodeCommitBackend(BaseBackend):
|
||||
def __init__(self):
|
||||
self.repositories = {}
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "codecommit"
|
||||
)
|
||||
|
||||
def create_repository(self, region, repository_name, repository_description):
|
||||
repository = self.repositories.get(repository_name)
|
||||
if repository:
|
||||
|
@ -71,6 +71,13 @@ class CodePipelineBackend(BaseBackend):
|
||||
def __init__(self):
|
||||
self.pipelines = {}
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "codepipeline", policy_supported=False
|
||||
)
|
||||
|
||||
@property
|
||||
def iam_backend(self):
|
||||
return iam_backends["global"]
|
||||
|
@ -854,6 +854,13 @@ class ConfigBackend(BaseBackend):
|
||||
self.config_rules = {}
|
||||
self.config_schema = None
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""List of dicts representing default VPC endpoints for this service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "config"
|
||||
)
|
||||
|
||||
def _validate_resource_types(self, resource_list):
|
||||
if not self.config_schema:
|
||||
self.config_schema = AWSServiceSpec(
|
||||
|
@ -1,11 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
from __future__ import absolute_import
|
||||
|
||||
import functools
|
||||
import inspect
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import string
|
||||
import types
|
||||
from abc import abstractmethod
|
||||
from io import BytesIO
|
||||
@ -698,6 +697,63 @@ class BaseBackend:
|
||||
|
||||
return paths
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(
|
||||
service_region, zones,
|
||||
): # pylint: disable=unused-argument
|
||||
"""Invoke the factory method for any VPC endpoint(s) services."""
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def vpce_random_number():
|
||||
"""Return random number for a VPC endpoint service ID."""
|
||||
return "".join([random.choice(string.hexdigits.lower()) for i in range(17)])
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service_factory(
|
||||
service_region,
|
||||
zones,
|
||||
service="",
|
||||
service_type="Interface",
|
||||
private_dns_names=True,
|
||||
special_service_name="",
|
||||
policy_supported=True,
|
||||
base_endpoint_dns_names=None,
|
||||
): # pylint: disable=too-many-arguments
|
||||
"""List of dicts representing default VPC endpoints for this service."""
|
||||
if special_service_name:
|
||||
service_name = f"com.amazonaws.{service_region}.{special_service_name}"
|
||||
else:
|
||||
service_name = f"com.amazonaws.{service_region}.{service}"
|
||||
|
||||
if not base_endpoint_dns_names:
|
||||
base_endpoint_dns_names = [f"{service}.{service_region}.vpce.amazonaws.com"]
|
||||
|
||||
endpoint_service = {
|
||||
"AcceptanceRequired": False,
|
||||
"AvailabilityZones": zones,
|
||||
"BaseEndpointDnsNames": base_endpoint_dns_names,
|
||||
"ManagesVpcEndpoints": False,
|
||||
"Owner": "amazon",
|
||||
"ServiceId": f"vpce-svc-{BaseBackend.vpce_random_number()}",
|
||||
"ServiceName": service_name,
|
||||
"ServiceType": [{"ServiceType": service_type}],
|
||||
"Tags": [],
|
||||
"VpcEndpointPolicySupported": policy_supported,
|
||||
}
|
||||
|
||||
# Don't know how private DNS names are different, so for now just
|
||||
# one will be added.
|
||||
if private_dns_names:
|
||||
endpoint_service[
|
||||
"PrivateDnsName"
|
||||
] = f"{service}.{service_region}.amazonaws.com"
|
||||
endpoint_service["PrivateDnsNameVerificationState"] = "verified"
|
||||
endpoint_service["PrivateDnsNames"] = [
|
||||
{"PrivateDnsName": f"{service}.{service_region}.amazonaws.com"}
|
||||
]
|
||||
return [endpoint_service]
|
||||
|
||||
def decorator(self, func=None):
|
||||
if settings.TEST_SERVER_MODE:
|
||||
mocked_backend = ServerModeMockAWS({"global": self})
|
||||
|
@ -112,6 +112,13 @@ class DataSyncBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "datasync"
|
||||
)
|
||||
|
||||
def create_location(self, location_uri, typ=None, metadata=None):
|
||||
"""
|
||||
# AWS DataSync allows for duplicate LocationUris
|
||||
|
@ -25,6 +25,13 @@ class DatabaseMigrationServiceBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "dms"
|
||||
)
|
||||
|
||||
def create_replication_task(
|
||||
self,
|
||||
replication_task_identifier,
|
||||
|
@ -711,7 +711,7 @@ class Table(CloudFormationModel):
|
||||
projection_expression,
|
||||
index_name=None,
|
||||
filter_expression=None,
|
||||
**filter_kwargs
|
||||
**filter_kwargs,
|
||||
):
|
||||
results = []
|
||||
|
||||
@ -1075,6 +1075,19 @@ class DynamoDBBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
# No 'vpce' in the base endpoint DNS name
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region,
|
||||
zones,
|
||||
"dynamodb",
|
||||
"Gateway",
|
||||
private_dns_names=False,
|
||||
base_endpoint_dns_names=[f"dynamodb.{service_region}.amazonaws.com"],
|
||||
)
|
||||
|
||||
def create_table(self, name, **params):
|
||||
if name in self.tables:
|
||||
return None
|
||||
@ -1288,7 +1301,7 @@ class DynamoDBBackend(BaseBackend):
|
||||
expr_names=None,
|
||||
expr_values=None,
|
||||
filter_expression=None,
|
||||
**filter_kwargs
|
||||
**filter_kwargs,
|
||||
):
|
||||
table = self.tables.get(table_name)
|
||||
if not table:
|
||||
@ -1311,7 +1324,7 @@ class DynamoDBBackend(BaseBackend):
|
||||
projection_expression,
|
||||
index_name,
|
||||
filter_expression,
|
||||
**filter_kwargs
|
||||
**filter_kwargs,
|
||||
)
|
||||
|
||||
def scan(
|
||||
|
@ -24,21 +24,19 @@ class EC2ClientError(RESTError):
|
||||
request_id_tag_name = "RequestID"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
kwargs.setdefault("template", "custom_response")
|
||||
self.templates["custom_response"] = EC2_ERROR_RESPONSE
|
||||
|
||||
super(EC2ClientError, self).__init__(*args, **kwargs)
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class DependencyViolationError(EC2ClientError):
|
||||
def __init__(self, message):
|
||||
super(DependencyViolationError, self).__init__("DependencyViolation", message)
|
||||
super().__init__("DependencyViolation", message)
|
||||
|
||||
|
||||
class MissingParameterError(EC2ClientError):
|
||||
def __init__(self, parameter):
|
||||
super(MissingParameterError, self).__init__(
|
||||
super().__init__(
|
||||
"MissingParameter",
|
||||
"The request must contain the parameter {0}".format(parameter),
|
||||
)
|
||||
@ -46,7 +44,7 @@ class MissingParameterError(EC2ClientError):
|
||||
|
||||
class InvalidDHCPOptionsIdError(EC2ClientError):
|
||||
def __init__(self, dhcp_options_id):
|
||||
super(InvalidDHCPOptionsIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidDhcpOptionID.NotFound",
|
||||
"DhcpOptionID {0} does not exist.".format(dhcp_options_id),
|
||||
)
|
||||
@ -54,7 +52,7 @@ class InvalidDHCPOptionsIdError(EC2ClientError):
|
||||
|
||||
class MalformedDHCPOptionsIdError(EC2ClientError):
|
||||
def __init__(self, dhcp_options_id):
|
||||
super(MalformedDHCPOptionsIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidDhcpOptionsId.Malformed",
|
||||
'Invalid id: "{0}" (expecting "dopt-...")'.format(dhcp_options_id),
|
||||
)
|
||||
@ -62,21 +60,21 @@ class MalformedDHCPOptionsIdError(EC2ClientError):
|
||||
|
||||
class InvalidKeyPairNameError(EC2ClientError):
|
||||
def __init__(self, key):
|
||||
super(InvalidKeyPairNameError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidKeyPair.NotFound", "The keypair '{0}' does not exist.".format(key)
|
||||
)
|
||||
|
||||
|
||||
class InvalidKeyPairDuplicateError(EC2ClientError):
|
||||
def __init__(self, key):
|
||||
super(InvalidKeyPairDuplicateError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidKeyPair.Duplicate", "The keypair '{0}' already exists.".format(key)
|
||||
)
|
||||
|
||||
|
||||
class InvalidKeyPairFormatError(EC2ClientError):
|
||||
def __init__(self):
|
||||
super(InvalidKeyPairFormatError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidKeyPair.Format", "Key is not in valid OpenSSH public key format"
|
||||
)
|
||||
|
||||
@ -84,14 +82,14 @@ class InvalidKeyPairFormatError(EC2ClientError):
|
||||
class InvalidVPCIdError(EC2ClientError):
|
||||
def __init__(self, vpc_id):
|
||||
|
||||
super(InvalidVPCIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidVpcID.NotFound", "VpcID {0} does not exist.".format(vpc_id),
|
||||
)
|
||||
|
||||
|
||||
class InvalidSubnetIdError(EC2ClientError):
|
||||
def __init__(self, subnet_id):
|
||||
super(InvalidSubnetIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidSubnetID.NotFound",
|
||||
"The subnet ID '{}' does not exist".format(subnet_id),
|
||||
)
|
||||
@ -99,7 +97,7 @@ class InvalidSubnetIdError(EC2ClientError):
|
||||
|
||||
class InvalidFlowLogIdError(EC2ClientError):
|
||||
def __init__(self, count, flow_log_ids):
|
||||
super(InvalidFlowLogIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidFlowLogId.NotFound",
|
||||
"These flow log ids in the input list are not found: [TotalCount: {0}] {1}".format(
|
||||
count, flow_log_ids
|
||||
@ -109,7 +107,7 @@ class InvalidFlowLogIdError(EC2ClientError):
|
||||
|
||||
class FlowLogAlreadyExists(EC2ClientError):
|
||||
def __init__(self):
|
||||
super(FlowLogAlreadyExists, self).__init__(
|
||||
super().__init__(
|
||||
"FlowLogAlreadyExists",
|
||||
"Error. There is an existing Flow Log with the same configuration and log destination.",
|
||||
)
|
||||
@ -117,7 +115,7 @@ class FlowLogAlreadyExists(EC2ClientError):
|
||||
|
||||
class InvalidNetworkAclIdError(EC2ClientError):
|
||||
def __init__(self, network_acl_id):
|
||||
super(InvalidNetworkAclIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidNetworkAclID.NotFound",
|
||||
"The network acl ID '{0}' does not exist".format(network_acl_id),
|
||||
)
|
||||
@ -125,7 +123,7 @@ class InvalidNetworkAclIdError(EC2ClientError):
|
||||
|
||||
class InvalidVpnGatewayIdError(EC2ClientError):
|
||||
def __init__(self, vpn_gw):
|
||||
super(InvalidVpnGatewayIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidVpnGatewayID.NotFound",
|
||||
"The virtual private gateway ID '{0}' does not exist".format(vpn_gw),
|
||||
)
|
||||
@ -133,7 +131,7 @@ class InvalidVpnGatewayIdError(EC2ClientError):
|
||||
|
||||
class InvalidVpnGatewayAttachmentError(EC2ClientError):
|
||||
def __init__(self, vpn_gw, vpc_id):
|
||||
super(InvalidVpnGatewayAttachmentError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidVpnGatewayAttachment.NotFound",
|
||||
"The attachment with vpn gateway ID '{}' and vpc ID '{}' does not exist".format(
|
||||
vpn_gw, vpc_id
|
||||
@ -143,7 +141,7 @@ class InvalidVpnGatewayAttachmentError(EC2ClientError):
|
||||
|
||||
class InvalidVpnConnectionIdError(EC2ClientError):
|
||||
def __init__(self, network_acl_id):
|
||||
super(InvalidVpnConnectionIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidVpnConnectionID.NotFound",
|
||||
"The vpnConnection ID '{0}' does not exist".format(network_acl_id),
|
||||
)
|
||||
@ -151,7 +149,7 @@ class InvalidVpnConnectionIdError(EC2ClientError):
|
||||
|
||||
class InvalidCustomerGatewayIdError(EC2ClientError):
|
||||
def __init__(self, customer_gateway_id):
|
||||
super(InvalidCustomerGatewayIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidCustomerGatewayID.NotFound",
|
||||
"The customer gateway ID '{0}' does not exist".format(customer_gateway_id),
|
||||
)
|
||||
@ -159,7 +157,7 @@ class InvalidCustomerGatewayIdError(EC2ClientError):
|
||||
|
||||
class InvalidNetworkInterfaceIdError(EC2ClientError):
|
||||
def __init__(self, eni_id):
|
||||
super(InvalidNetworkInterfaceIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidNetworkInterfaceID.NotFound",
|
||||
"The network interface ID '{0}' does not exist".format(eni_id),
|
||||
)
|
||||
@ -167,7 +165,7 @@ class InvalidNetworkInterfaceIdError(EC2ClientError):
|
||||
|
||||
class InvalidNetworkAttachmentIdError(EC2ClientError):
|
||||
def __init__(self, attachment_id):
|
||||
super(InvalidNetworkAttachmentIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidAttachmentID.NotFound",
|
||||
"The network interface attachment ID '{0}' does not exist".format(
|
||||
attachment_id
|
||||
@ -177,7 +175,7 @@ class InvalidNetworkAttachmentIdError(EC2ClientError):
|
||||
|
||||
class InvalidSecurityGroupDuplicateError(EC2ClientError):
|
||||
def __init__(self, name):
|
||||
super(InvalidSecurityGroupDuplicateError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidGroup.Duplicate",
|
||||
"The security group '{0}' already exists".format(name),
|
||||
)
|
||||
@ -185,7 +183,7 @@ class InvalidSecurityGroupDuplicateError(EC2ClientError):
|
||||
|
||||
class InvalidSecurityGroupNotFoundError(EC2ClientError):
|
||||
def __init__(self, name):
|
||||
super(InvalidSecurityGroupNotFoundError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidGroup.NotFound",
|
||||
"The security group '{0}' does not exist".format(name),
|
||||
)
|
||||
@ -193,7 +191,7 @@ class InvalidSecurityGroupNotFoundError(EC2ClientError):
|
||||
|
||||
class InvalidPermissionNotFoundError(EC2ClientError):
|
||||
def __init__(self):
|
||||
super(InvalidPermissionNotFoundError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidPermission.NotFound",
|
||||
"The specified rule does not exist in this security group",
|
||||
)
|
||||
@ -201,15 +199,14 @@ class InvalidPermissionNotFoundError(EC2ClientError):
|
||||
|
||||
class InvalidPermissionDuplicateError(EC2ClientError):
|
||||
def __init__(self):
|
||||
super(InvalidPermissionDuplicateError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidPermission.Duplicate", "The specified rule already exists"
|
||||
)
|
||||
|
||||
|
||||
class InvalidRouteTableIdError(EC2ClientError):
|
||||
def __init__(self, route_table_id):
|
||||
|
||||
super(InvalidRouteTableIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidRouteTableID.NotFound",
|
||||
"The routeTable ID '{0}' does not exist".format(route_table_id),
|
||||
)
|
||||
@ -217,7 +214,7 @@ class InvalidRouteTableIdError(EC2ClientError):
|
||||
|
||||
class InvalidRouteError(EC2ClientError):
|
||||
def __init__(self, route_table_id, cidr):
|
||||
super(InvalidRouteError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidRoute.NotFound",
|
||||
"no route with destination-cidr-block {0} in route table {1}".format(
|
||||
cidr, route_table_id
|
||||
@ -227,7 +224,7 @@ class InvalidRouteError(EC2ClientError):
|
||||
|
||||
class InvalidInstanceIdError(EC2ClientError):
|
||||
def __init__(self, instance_id):
|
||||
super(InvalidInstanceIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidInstanceID.NotFound",
|
||||
"The instance ID '{0}' does not exist".format(instance_id),
|
||||
)
|
||||
@ -235,7 +232,7 @@ class InvalidInstanceIdError(EC2ClientError):
|
||||
|
||||
class InvalidInstanceTypeError(EC2ClientError):
|
||||
def __init__(self, instance_type):
|
||||
super(InvalidInstanceTypeError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidInstanceType.NotFound",
|
||||
"The instance type '{0}' does not exist".format(instance_type),
|
||||
)
|
||||
@ -243,7 +240,7 @@ class InvalidInstanceTypeError(EC2ClientError):
|
||||
|
||||
class InvalidAMIIdError(EC2ClientError):
|
||||
def __init__(self, ami_id):
|
||||
super(InvalidAMIIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidAMIID.NotFound",
|
||||
"The image id '[{0}]' does not exist".format(ami_id),
|
||||
)
|
||||
@ -251,7 +248,7 @@ class InvalidAMIIdError(EC2ClientError):
|
||||
|
||||
class InvalidAMIAttributeItemValueError(EC2ClientError):
|
||||
def __init__(self, attribute, value):
|
||||
super(InvalidAMIAttributeItemValueError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidAMIAttributeItemValue",
|
||||
'Invalid attribute item value "{0}" for {1} item type.'.format(
|
||||
value, attribute
|
||||
@ -261,7 +258,7 @@ class InvalidAMIAttributeItemValueError(EC2ClientError):
|
||||
|
||||
class MalformedAMIIdError(EC2ClientError):
|
||||
def __init__(self, ami_id):
|
||||
super(MalformedAMIIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidAMIID.Malformed",
|
||||
'Invalid id: "{0}" (expecting "ami-...")'.format(ami_id),
|
||||
)
|
||||
@ -269,14 +266,14 @@ class MalformedAMIIdError(EC2ClientError):
|
||||
|
||||
class InvalidSnapshotIdError(EC2ClientError):
|
||||
def __init__(self, snapshot_id):
|
||||
super(InvalidSnapshotIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidSnapshot.NotFound", ""
|
||||
) # Note: AWS returns empty message for this, as of 2014.08.22.
|
||||
|
||||
|
||||
class InvalidVolumeIdError(EC2ClientError):
|
||||
def __init__(self, volume_id):
|
||||
super(InvalidVolumeIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidVolume.NotFound",
|
||||
"The volume '{0}' does not exist.".format(volume_id),
|
||||
)
|
||||
@ -284,7 +281,7 @@ class InvalidVolumeIdError(EC2ClientError):
|
||||
|
||||
class InvalidVolumeAttachmentError(EC2ClientError):
|
||||
def __init__(self, volume_id, instance_id):
|
||||
super(InvalidVolumeAttachmentError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidAttachment.NotFound",
|
||||
"Volume {0} can not be detached from {1} because it is not attached".format(
|
||||
volume_id, instance_id
|
||||
@ -294,7 +291,7 @@ class InvalidVolumeAttachmentError(EC2ClientError):
|
||||
|
||||
class InvalidVolumeDetachmentError(EC2ClientError):
|
||||
def __init__(self, volume_id, instance_id, device):
|
||||
super(InvalidVolumeDetachmentError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidAttachment.NotFound",
|
||||
"The volume {0} is not attached to instance {1} as device {2}".format(
|
||||
volume_id, instance_id, device
|
||||
@ -304,7 +301,7 @@ class InvalidVolumeDetachmentError(EC2ClientError):
|
||||
|
||||
class VolumeInUseError(EC2ClientError):
|
||||
def __init__(self, volume_id, instance_id):
|
||||
super(VolumeInUseError, self).__init__(
|
||||
super().__init__(
|
||||
"VolumeInUse",
|
||||
"Volume {0} is currently attached to {1}".format(volume_id, instance_id),
|
||||
)
|
||||
@ -312,21 +309,21 @@ class VolumeInUseError(EC2ClientError):
|
||||
|
||||
class InvalidDomainError(EC2ClientError):
|
||||
def __init__(self, domain):
|
||||
super(InvalidDomainError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidParameterValue", "Invalid value '{0}' for domain.".format(domain)
|
||||
)
|
||||
|
||||
|
||||
class InvalidAddressError(EC2ClientError):
|
||||
def __init__(self, ip):
|
||||
super(InvalidAddressError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidAddress.NotFound", "Address '{0}' not found.".format(ip)
|
||||
)
|
||||
|
||||
|
||||
class LogDestinationNotFoundError(EC2ClientError):
|
||||
def __init__(self, bucket_name):
|
||||
super(LogDestinationNotFoundError, self).__init__(
|
||||
super().__init__(
|
||||
"LogDestinationNotFoundException",
|
||||
"LogDestination: '{0}' does not exist.".format(bucket_name),
|
||||
)
|
||||
@ -334,7 +331,7 @@ class LogDestinationNotFoundError(EC2ClientError):
|
||||
|
||||
class InvalidAllocationIdError(EC2ClientError):
|
||||
def __init__(self, allocation_id):
|
||||
super(InvalidAllocationIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidAllocationID.NotFound",
|
||||
"Allocation ID '{0}' not found.".format(allocation_id),
|
||||
)
|
||||
@ -342,7 +339,7 @@ class InvalidAllocationIdError(EC2ClientError):
|
||||
|
||||
class InvalidAssociationIdError(EC2ClientError):
|
||||
def __init__(self, association_id):
|
||||
super(InvalidAssociationIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidAssociationID.NotFound",
|
||||
"Association ID '{0}' not found.".format(association_id),
|
||||
)
|
||||
@ -350,7 +347,7 @@ class InvalidAssociationIdError(EC2ClientError):
|
||||
|
||||
class InvalidVpcCidrBlockAssociationIdError(EC2ClientError):
|
||||
def __init__(self, association_id):
|
||||
super(InvalidVpcCidrBlockAssociationIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidVpcCidrBlockAssociationIdError.NotFound",
|
||||
"The vpc CIDR block association ID '{0}' does not exist".format(
|
||||
association_id
|
||||
@ -360,7 +357,7 @@ class InvalidVpcCidrBlockAssociationIdError(EC2ClientError):
|
||||
|
||||
class InvalidVPCPeeringConnectionIdError(EC2ClientError):
|
||||
def __init__(self, vpc_peering_connection_id):
|
||||
super(InvalidVPCPeeringConnectionIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidVpcPeeringConnectionId.NotFound",
|
||||
"VpcPeeringConnectionID {0} does not exist.".format(
|
||||
vpc_peering_connection_id
|
||||
@ -370,7 +367,7 @@ class InvalidVPCPeeringConnectionIdError(EC2ClientError):
|
||||
|
||||
class InvalidVPCPeeringConnectionStateTransitionError(EC2ClientError):
|
||||
def __init__(self, vpc_peering_connection_id):
|
||||
super(InvalidVPCPeeringConnectionStateTransitionError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidStateTransition",
|
||||
"VpcPeeringConnectionID {0} is not in the correct state for the request.".format(
|
||||
vpc_peering_connection_id
|
||||
@ -378,9 +375,27 @@ class InvalidVPCPeeringConnectionStateTransitionError(EC2ClientError):
|
||||
)
|
||||
|
||||
|
||||
class InvalidServiceName(EC2ClientError):
|
||||
def __init__(self, service_name):
|
||||
super().__init__(
|
||||
"InvalidServiceName",
|
||||
f"The Vpc Endpoint Service '{service_name}' does not exist",
|
||||
)
|
||||
|
||||
|
||||
class InvalidFilter(EC2ClientError):
|
||||
def __init__(self, filter_name):
|
||||
super().__init__("InvalidFilter", f"The filter '{filter_name}' is invalid")
|
||||
|
||||
|
||||
class InvalidNextToken(EC2ClientError):
|
||||
def __init__(self, next_token):
|
||||
super().__init__("InvalidNextToken", f"The token '{next_token}' is invalid")
|
||||
|
||||
|
||||
class InvalidDependantParameterError(EC2ClientError):
|
||||
def __init__(self, dependant_parameter, parameter, parameter_value):
|
||||
super(InvalidDependantParameterError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidParameter",
|
||||
"{0} can't be empty if {1} is {2}.".format(
|
||||
dependant_parameter, parameter, parameter_value,
|
||||
@ -390,7 +405,7 @@ class InvalidDependantParameterError(EC2ClientError):
|
||||
|
||||
class InvalidDependantParameterTypeError(EC2ClientError):
|
||||
def __init__(self, dependant_parameter, parameter_value, parameter):
|
||||
super(InvalidDependantParameterTypeError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidParameter",
|
||||
"{0} type must be {1} if {2} is provided.".format(
|
||||
dependant_parameter, parameter_value, parameter,
|
||||
@ -400,14 +415,14 @@ class InvalidDependantParameterTypeError(EC2ClientError):
|
||||
|
||||
class InvalidAggregationIntervalParameterError(EC2ClientError):
|
||||
def __init__(self, parameter):
|
||||
super(InvalidAggregationIntervalParameterError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidParameter", "Invalid {0}".format(parameter),
|
||||
)
|
||||
|
||||
|
||||
class InvalidParameterValueError(EC2ClientError):
|
||||
def __init__(self, parameter_value):
|
||||
super(InvalidParameterValueError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidParameterValue",
|
||||
"Value {0} is invalid for parameter.".format(parameter_value),
|
||||
)
|
||||
@ -415,7 +430,7 @@ class InvalidParameterValueError(EC2ClientError):
|
||||
|
||||
class InvalidParameterValueErrorTagNull(EC2ClientError):
|
||||
def __init__(self):
|
||||
super(InvalidParameterValueErrorTagNull, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidParameterValue",
|
||||
"Tag value cannot be null. Use empty string instead.",
|
||||
)
|
||||
@ -423,7 +438,7 @@ class InvalidParameterValueErrorTagNull(EC2ClientError):
|
||||
|
||||
class InvalidParameterValueErrorUnknownAttribute(EC2ClientError):
|
||||
def __init__(self, parameter_value):
|
||||
super(InvalidParameterValueErrorUnknownAttribute, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidParameterValue",
|
||||
"Value ({0}) for parameter attribute is invalid. Unknown attribute.".format(
|
||||
parameter_value
|
||||
@ -433,7 +448,7 @@ class InvalidParameterValueErrorUnknownAttribute(EC2ClientError):
|
||||
|
||||
class InvalidGatewayIDError(EC2ClientError):
|
||||
def __init__(self, gateway_id):
|
||||
super(InvalidGatewayIDError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidGatewayID.NotFound",
|
||||
"The eigw ID '{0}' does not exist".format(gateway_id),
|
||||
)
|
||||
@ -441,7 +456,7 @@ class InvalidGatewayIDError(EC2ClientError):
|
||||
|
||||
class InvalidInternetGatewayIdError(EC2ClientError):
|
||||
def __init__(self, internet_gateway_id):
|
||||
super(InvalidInternetGatewayIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidInternetGatewayID.NotFound",
|
||||
"InternetGatewayID {0} does not exist.".format(internet_gateway_id),
|
||||
)
|
||||
@ -449,7 +464,7 @@ class InvalidInternetGatewayIdError(EC2ClientError):
|
||||
|
||||
class GatewayNotAttachedError(EC2ClientError):
|
||||
def __init__(self, internet_gateway_id, vpc_id):
|
||||
super(GatewayNotAttachedError, self).__init__(
|
||||
super().__init__(
|
||||
"Gateway.NotAttached",
|
||||
"InternetGatewayID {0} is not attached to a VPC {1}.".format(
|
||||
internet_gateway_id, vpc_id
|
||||
@ -459,7 +474,7 @@ class GatewayNotAttachedError(EC2ClientError):
|
||||
|
||||
class ResourceAlreadyAssociatedError(EC2ClientError):
|
||||
def __init__(self, resource_id):
|
||||
super(ResourceAlreadyAssociatedError, self).__init__(
|
||||
super().__init__(
|
||||
"Resource.AlreadyAssociated",
|
||||
"Resource {0} is already associated.".format(resource_id),
|
||||
)
|
||||
@ -467,7 +482,7 @@ class ResourceAlreadyAssociatedError(EC2ClientError):
|
||||
|
||||
class TagLimitExceeded(EC2ClientError):
|
||||
def __init__(self):
|
||||
super(TagLimitExceeded, self).__init__(
|
||||
super().__init__(
|
||||
"TagLimitExceeded",
|
||||
"The maximum number of Tags for a resource has been reached.",
|
||||
)
|
||||
@ -475,14 +490,12 @@ class TagLimitExceeded(EC2ClientError):
|
||||
|
||||
class InvalidID(EC2ClientError):
|
||||
def __init__(self, resource_id):
|
||||
super(InvalidID, self).__init__(
|
||||
"InvalidID", "The ID '{0}' is not valid".format(resource_id)
|
||||
)
|
||||
super().__init__("InvalidID", "The ID '{0}' is not valid".format(resource_id))
|
||||
|
||||
|
||||
class InvalidCIDRSubnetError(EC2ClientError):
|
||||
def __init__(self, cidr):
|
||||
super(InvalidCIDRSubnetError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidParameterValue",
|
||||
"invalid CIDR subnet specification: {0}".format(cidr),
|
||||
)
|
||||
@ -490,7 +503,7 @@ class InvalidCIDRSubnetError(EC2ClientError):
|
||||
|
||||
class RulesPerSecurityGroupLimitExceededError(EC2ClientError):
|
||||
def __init__(self):
|
||||
super(RulesPerSecurityGroupLimitExceededError, self).__init__(
|
||||
super().__init__(
|
||||
"RulesPerSecurityGroupLimitExceeded",
|
||||
"The maximum number of rules per security group " "has been reached.",
|
||||
)
|
||||
@ -498,7 +511,7 @@ class RulesPerSecurityGroupLimitExceededError(EC2ClientError):
|
||||
|
||||
class MotoNotImplementedError(NotImplementedError):
|
||||
def __init__(self, blurb):
|
||||
super(MotoNotImplementedError, self).__init__(
|
||||
super().__init__(
|
||||
"{0} has not been implemented in Moto yet."
|
||||
" Feel free to open an issue at"
|
||||
" https://github.com/spulec/moto/issues".format(blurb)
|
||||
@ -507,14 +520,12 @@ class MotoNotImplementedError(NotImplementedError):
|
||||
|
||||
class FilterNotImplementedError(MotoNotImplementedError):
|
||||
def __init__(self, filter_name, method_name):
|
||||
super(FilterNotImplementedError, self).__init__(
|
||||
"The filter '{0}' for {1}".format(filter_name, method_name)
|
||||
)
|
||||
super().__init__("The filter '{0}' for {1}".format(filter_name, method_name))
|
||||
|
||||
|
||||
class CidrLimitExceeded(EC2ClientError):
|
||||
def __init__(self, vpc_id, max_cidr_limit):
|
||||
super(CidrLimitExceeded, self).__init__(
|
||||
super().__init__(
|
||||
"CidrLimitExceeded",
|
||||
"This network '{0}' has met its maximum number of allowed CIDRs: {1}".format(
|
||||
vpc_id, max_cidr_limit
|
||||
@ -524,7 +535,7 @@ class CidrLimitExceeded(EC2ClientError):
|
||||
|
||||
class UnsupportedTenancy(EC2ClientError):
|
||||
def __init__(self, tenancy):
|
||||
super(UnsupportedTenancy, self).__init__(
|
||||
super().__init__(
|
||||
"UnsupportedTenancy",
|
||||
"The tenancy value {0} is not supported.".format(tenancy),
|
||||
)
|
||||
@ -532,7 +543,7 @@ class UnsupportedTenancy(EC2ClientError):
|
||||
|
||||
class OperationNotPermitted(EC2ClientError):
|
||||
def __init__(self, association_id):
|
||||
super(OperationNotPermitted, self).__init__(
|
||||
super().__init__(
|
||||
"OperationNotPermitted",
|
||||
"The vpc CIDR block with association ID {} may not be disassociated. "
|
||||
"It is the primary IPv4 CIDR block of the VPC".format(association_id),
|
||||
@ -541,7 +552,7 @@ class OperationNotPermitted(EC2ClientError):
|
||||
|
||||
class InvalidAvailabilityZoneError(EC2ClientError):
|
||||
def __init__(self, availability_zone_value, valid_availability_zones):
|
||||
super(InvalidAvailabilityZoneError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidParameterValue",
|
||||
"Value ({0}) for parameter availabilityZone is invalid. "
|
||||
"Subnets can currently only be created in the following availability zones: {1}.".format(
|
||||
@ -552,7 +563,7 @@ class InvalidAvailabilityZoneError(EC2ClientError):
|
||||
|
||||
class NetworkAclEntryAlreadyExistsError(EC2ClientError):
|
||||
def __init__(self, rule_number):
|
||||
super(NetworkAclEntryAlreadyExistsError, self).__init__(
|
||||
super().__init__(
|
||||
"NetworkAclEntryAlreadyExists",
|
||||
"The network acl entry identified by {} already exists.".format(
|
||||
rule_number
|
||||
@ -562,14 +573,14 @@ class NetworkAclEntryAlreadyExistsError(EC2ClientError):
|
||||
|
||||
class InvalidSubnetRangeError(EC2ClientError):
|
||||
def __init__(self, cidr_block):
|
||||
super(InvalidSubnetRangeError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidSubnet.Range", "The CIDR '{}' is invalid.".format(cidr_block)
|
||||
)
|
||||
|
||||
|
||||
class InvalidCIDRBlockParameterError(EC2ClientError):
|
||||
def __init__(self, cidr_block):
|
||||
super(InvalidCIDRBlockParameterError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidParameterValue",
|
||||
"Value ({}) for parameter cidrBlock is invalid. This is not a valid CIDR block.".format(
|
||||
cidr_block
|
||||
@ -579,7 +590,7 @@ class InvalidCIDRBlockParameterError(EC2ClientError):
|
||||
|
||||
class InvalidDestinationCIDRBlockParameterError(EC2ClientError):
|
||||
def __init__(self, cidr_block):
|
||||
super(InvalidDestinationCIDRBlockParameterError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidParameterValue",
|
||||
"Value ({}) for parameter destinationCidrBlock is invalid. This is not a valid CIDR block.".format(
|
||||
cidr_block
|
||||
@ -589,7 +600,7 @@ class InvalidDestinationCIDRBlockParameterError(EC2ClientError):
|
||||
|
||||
class InvalidSubnetConflictError(EC2ClientError):
|
||||
def __init__(self, cidr_block):
|
||||
super(InvalidSubnetConflictError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidSubnet.Conflict",
|
||||
"The CIDR '{}' conflicts with another subnet".format(cidr_block),
|
||||
)
|
||||
@ -597,7 +608,7 @@ class InvalidSubnetConflictError(EC2ClientError):
|
||||
|
||||
class InvalidVPCRangeError(EC2ClientError):
|
||||
def __init__(self, cidr_block):
|
||||
super(InvalidVPCRangeError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidVpc.Range", "The CIDR '{}' is invalid.".format(cidr_block)
|
||||
)
|
||||
|
||||
@ -605,7 +616,7 @@ class InvalidVPCRangeError(EC2ClientError):
|
||||
# accept exception
|
||||
class OperationNotPermitted2(EC2ClientError):
|
||||
def __init__(self, client_region, pcx_id, acceptor_region):
|
||||
super(OperationNotPermitted2, self).__init__(
|
||||
super().__init__(
|
||||
"OperationNotPermitted",
|
||||
"Incorrect region ({0}) specified for this request."
|
||||
"VPC peering connection {1} must be accepted in region {2}".format(
|
||||
@ -617,7 +628,7 @@ class OperationNotPermitted2(EC2ClientError):
|
||||
# reject exception
|
||||
class OperationNotPermitted3(EC2ClientError):
|
||||
def __init__(self, client_region, pcx_id, acceptor_region):
|
||||
super(OperationNotPermitted3, self).__init__(
|
||||
super().__init__(
|
||||
"OperationNotPermitted",
|
||||
"Incorrect region ({0}) specified for this request."
|
||||
"VPC peering connection {1} must be accepted or rejected in region {2}".format(
|
||||
@ -628,7 +639,7 @@ class OperationNotPermitted3(EC2ClientError):
|
||||
|
||||
class OperationNotPermitted4(EC2ClientError):
|
||||
def __init__(self, instance_id):
|
||||
super(OperationNotPermitted4, self).__init__(
|
||||
super().__init__(
|
||||
"OperationNotPermitted",
|
||||
"The instance '{0}' may not be terminated. Modify its 'disableApiTermination' "
|
||||
"instance attribute and try again.".format(instance_id),
|
||||
@ -637,7 +648,7 @@ class OperationNotPermitted4(EC2ClientError):
|
||||
|
||||
class InvalidLaunchTemplateNameError(EC2ClientError):
|
||||
def __init__(self):
|
||||
super(InvalidLaunchTemplateNameError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidLaunchTemplateName.AlreadyExistsException",
|
||||
"Launch template name already in use.",
|
||||
)
|
||||
@ -645,7 +656,7 @@ class InvalidLaunchTemplateNameError(EC2ClientError):
|
||||
|
||||
class InvalidParameterDependency(EC2ClientError):
|
||||
def __init__(self, param, param_needed):
|
||||
super(InvalidParameterDependency, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidParameterDependency",
|
||||
"The parameter [{0}] requires the parameter {1} to be set.".format(
|
||||
param, param_needed
|
||||
@ -655,7 +666,7 @@ class InvalidParameterDependency(EC2ClientError):
|
||||
|
||||
class IncorrectStateIamProfileAssociationError(EC2ClientError):
|
||||
def __init__(self, instance_id):
|
||||
super(IncorrectStateIamProfileAssociationError, self).__init__(
|
||||
super().__init__(
|
||||
"IncorrectState",
|
||||
"There is an existing association for instance {0}".format(instance_id),
|
||||
)
|
||||
@ -663,7 +674,7 @@ class IncorrectStateIamProfileAssociationError(EC2ClientError):
|
||||
|
||||
class InvalidAssociationIDIamProfileAssociationError(EC2ClientError):
|
||||
def __init__(self, association_id):
|
||||
super(InvalidAssociationIDIamProfileAssociationError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidAssociationID.NotFound",
|
||||
"An invalid association-id of '{0}' was given".format(association_id),
|
||||
)
|
||||
@ -671,7 +682,7 @@ class InvalidAssociationIDIamProfileAssociationError(EC2ClientError):
|
||||
|
||||
class InvalidVpcEndPointIdError(EC2ClientError):
|
||||
def __init__(self, vpc_end_point_id):
|
||||
super(InvalidVpcEndPointIdError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidVpcEndpointId.NotFound",
|
||||
"The VpcEndPoint ID '{0}' does not exist".format(vpc_end_point_id),
|
||||
)
|
||||
@ -679,7 +690,7 @@ class InvalidVpcEndPointIdError(EC2ClientError):
|
||||
|
||||
class InvalidTaggableResourceType(EC2ClientError):
|
||||
def __init__(self, resource_type):
|
||||
super(InvalidTaggableResourceType, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidParameterValue",
|
||||
"'{}' is not a valid taggable resource type for this operation.".format(
|
||||
resource_type
|
||||
@ -689,7 +700,7 @@ class InvalidTaggableResourceType(EC2ClientError):
|
||||
|
||||
class GenericInvalidParameterValueError(EC2ClientError):
|
||||
def __init__(self, attribute, value):
|
||||
super(GenericInvalidParameterValueError, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidParameterValue",
|
||||
"invalid value for parameter {0}: {1}".format(attribute, value),
|
||||
)
|
||||
@ -697,7 +708,7 @@ class GenericInvalidParameterValueError(EC2ClientError):
|
||||
|
||||
class InvalidSubnetCidrBlockAssociationID(EC2ClientError):
|
||||
def __init__(self, association_id):
|
||||
super(InvalidSubnetCidrBlockAssociationID, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidSubnetCidrBlockAssociationID.NotFound",
|
||||
"The subnet CIDR block with association ID '{0}' does not exist".format(
|
||||
association_id
|
||||
@ -707,7 +718,7 @@ class InvalidSubnetCidrBlockAssociationID(EC2ClientError):
|
||||
|
||||
class InvalidCarrierGatewayID(EC2ClientError):
|
||||
def __init__(self, carrier_gateway_id):
|
||||
super(InvalidCarrierGatewayID, self).__init__(
|
||||
super().__init__(
|
||||
"InvalidCarrierGatewayID.NotFound",
|
||||
"The CarrierGateway ID '{0}' does not exist".format(carrier_gateway_id),
|
||||
)
|
||||
|
@ -1,19 +1,23 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import copy
|
||||
from datetime import datetime
|
||||
import itertools
|
||||
import ipaddress
|
||||
import json
|
||||
import os
|
||||
from operator import itemgetter
|
||||
from os import listdir
|
||||
from os import environ
|
||||
import pathlib
|
||||
import re
|
||||
import warnings
|
||||
import weakref
|
||||
|
||||
from collections import defaultdict
|
||||
from collections import OrderedDict
|
||||
|
||||
from boto3 import Session
|
||||
|
||||
from collections import defaultdict
|
||||
import weakref
|
||||
from datetime import datetime
|
||||
from moto.packages.boto.ec2.instance import Instance as BotoInstance, Reservation
|
||||
from moto.packages.boto.ec2.blockdevicemapping import (
|
||||
BlockDeviceMapping,
|
||||
@ -24,7 +28,6 @@ from moto.packages.boto.ec2.spotinstancerequest import (
|
||||
)
|
||||
from moto.packages.boto.ec2.launchspecification import LaunchSpecification
|
||||
|
||||
from collections import OrderedDict
|
||||
from moto.core import BaseBackend
|
||||
from moto.core.models import Model, BaseModel, CloudFormationModel
|
||||
from moto.core.utils import (
|
||||
@ -34,7 +37,6 @@ from moto.core.utils import (
|
||||
from moto.core import ACCOUNT_ID
|
||||
from moto.kms import kms_backends
|
||||
from moto.utilities.utils import load_resource, merge_multiple_dicts, filter_resources
|
||||
from os import listdir
|
||||
|
||||
from .exceptions import (
|
||||
CidrLimitExceeded,
|
||||
@ -65,6 +67,9 @@ from .exceptions import (
|
||||
InvalidKeyPairFormatError,
|
||||
InvalidKeyPairNameError,
|
||||
InvalidAggregationIntervalParameterError,
|
||||
InvalidServiceName,
|
||||
InvalidFilter,
|
||||
InvalidNextToken,
|
||||
InvalidDependantParameterError,
|
||||
InvalidDependantParameterTypeError,
|
||||
InvalidFlowLogIdError,
|
||||
@ -192,20 +197,22 @@ offerings_path = "resources/instance_type_offerings"
|
||||
INSTANCE_TYPE_OFFERINGS = {}
|
||||
for location_type in listdir(root / offerings_path):
|
||||
INSTANCE_TYPE_OFFERINGS[location_type] = {}
|
||||
for region in listdir(root / offerings_path / location_type):
|
||||
full_path = offerings_path + "/" + location_type + "/" + region
|
||||
for _region in listdir(root / offerings_path / location_type):
|
||||
full_path = offerings_path + "/" + location_type + "/" + _region
|
||||
INSTANCE_TYPE_OFFERINGS[location_type][
|
||||
region.replace(".json", "")
|
||||
_region.replace(".json", "")
|
||||
] = load_resource(__name__, full_path)
|
||||
|
||||
|
||||
if "MOTO_AMIS_PATH" in os.environ:
|
||||
with open(os.environ.get("MOTO_AMIS_PATH"), "r", encoding="utf-8") as f:
|
||||
if "MOTO_AMIS_PATH" in environ:
|
||||
with open(environ.get("MOTO_AMIS_PATH"), "r", encoding="utf-8") as f:
|
||||
AMIS = json.load(f)
|
||||
else:
|
||||
AMIS = load_resource(__name__, "resources/amis.json")
|
||||
|
||||
OWNER_ID = ACCOUNT_ID
|
||||
MAX_NUMBER_OF_ENDPOINT_SERVICES_RESULTS = 1000
|
||||
DEFAULT_VPC_ENDPOINT_SERVICES = []
|
||||
|
||||
|
||||
def utc_date_and_time():
|
||||
@ -441,15 +448,13 @@ class NetworkInterface(TaggedEC2Resource, CloudFormationModel):
|
||||
elif filter_name == "description":
|
||||
return self.description
|
||||
else:
|
||||
return super(NetworkInterface, self).get_filter_value(
|
||||
filter_name, "DescribeNetworkInterfaces"
|
||||
)
|
||||
return super().get_filter_value(filter_name, "DescribeNetworkInterfaces")
|
||||
|
||||
|
||||
class NetworkInterfaceBackend(object):
|
||||
def __init__(self):
|
||||
self.enis = {}
|
||||
super(NetworkInterfaceBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_network_interface(
|
||||
self,
|
||||
@ -459,7 +464,7 @@ class NetworkInterfaceBackend(object):
|
||||
group_ids=None,
|
||||
description=None,
|
||||
tags=None,
|
||||
**kwargs
|
||||
**kwargs,
|
||||
):
|
||||
eni = NetworkInterface(
|
||||
self,
|
||||
@ -469,7 +474,7 @@ class NetworkInterfaceBackend(object):
|
||||
group_ids=group_ids,
|
||||
description=description,
|
||||
tags=tags,
|
||||
**kwargs
|
||||
**kwargs,
|
||||
)
|
||||
self.enis[eni.id] = eni
|
||||
return eni
|
||||
@ -563,7 +568,7 @@ class Instance(TaggedEC2Resource, BotoInstance, CloudFormationModel):
|
||||
}
|
||||
|
||||
def __init__(self, ec2_backend, image_id, user_data, security_groups, **kwargs):
|
||||
super(Instance, self).__init__()
|
||||
super().__init__()
|
||||
self.ec2_backend = ec2_backend
|
||||
self.id = random_instance_id()
|
||||
self.lifecycle = kwargs.get("lifecycle")
|
||||
@ -990,7 +995,7 @@ class Instance(TaggedEC2Resource, BotoInstance, CloudFormationModel):
|
||||
class InstanceBackend(object):
|
||||
def __init__(self):
|
||||
self.reservations = OrderedDict()
|
||||
super(InstanceBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def get_instance(self, instance_id):
|
||||
for instance in self.all_instances():
|
||||
@ -1220,7 +1225,7 @@ class InstanceBackend(object):
|
||||
|
||||
class InstanceTypeBackend(object):
|
||||
def __init__(self):
|
||||
super(InstanceTypeBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def describe_instance_types(self, instance_types=None):
|
||||
matches = INSTANCE_TYPES.values()
|
||||
@ -1236,7 +1241,7 @@ class InstanceTypeBackend(object):
|
||||
|
||||
class InstanceTypeOfferingBackend(object):
|
||||
def __init__(self):
|
||||
super(InstanceTypeOfferingBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def describe_instance_type_offerings(self, location_type=None, filters=None):
|
||||
location_type = location_type or "region"
|
||||
@ -1283,7 +1288,7 @@ class KeyPair(object):
|
||||
class KeyPairBackend(object):
|
||||
def __init__(self):
|
||||
self.keypairs = {}
|
||||
super(KeyPairBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_key_pair(self, name):
|
||||
if name in self.keypairs:
|
||||
@ -1359,7 +1364,7 @@ class TagBackend(object):
|
||||
|
||||
def __init__(self):
|
||||
self.tags = defaultdict(dict)
|
||||
super(TagBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_tags(self, resource_ids, tags):
|
||||
if None in set([tags[tag] for tag in tags]):
|
||||
@ -1581,7 +1586,7 @@ class Ami(TaggedEC2Resource):
|
||||
elif filter_name == "owner-alias":
|
||||
return self.owner_alias
|
||||
else:
|
||||
return super(Ami, self).get_filter_value(filter_name, "DescribeImages")
|
||||
return super().get_filter_value(filter_name, "DescribeImages")
|
||||
|
||||
|
||||
class AmiBackend(object):
|
||||
@ -1589,10 +1594,8 @@ class AmiBackend(object):
|
||||
|
||||
def __init__(self):
|
||||
self.amis = {}
|
||||
|
||||
self._load_amis()
|
||||
|
||||
super(AmiBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def _load_amis(self):
|
||||
for ami in AMIS:
|
||||
@ -2335,7 +2338,7 @@ class SecurityGroupBackend(object):
|
||||
self.sg_old_ingress_ruls = {}
|
||||
self.sg_old_egress_ruls = {}
|
||||
|
||||
super(SecurityGroupBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_security_group(
|
||||
self, name, description, vpc_id=None, tags=None, force=False, is_default=None
|
||||
@ -3102,7 +3105,7 @@ class Volume(TaggedEC2Resource, CloudFormationModel):
|
||||
elif filter_name == "availability-zone":
|
||||
return self.zone.name
|
||||
else:
|
||||
return super(Volume, self).get_filter_value(filter_name, "DescribeVolumes")
|
||||
return super().get_filter_value(filter_name, "DescribeVolumes")
|
||||
|
||||
|
||||
class Snapshot(TaggedEC2Resource):
|
||||
@ -3144,9 +3147,7 @@ class Snapshot(TaggedEC2Resource):
|
||||
elif filter_name == "owner-id":
|
||||
return self.owner_id
|
||||
else:
|
||||
return super(Snapshot, self).get_filter_value(
|
||||
filter_name, "DescribeSnapshots"
|
||||
)
|
||||
return super().get_filter_value(filter_name, "DescribeSnapshots")
|
||||
|
||||
|
||||
class EBSBackend(object):
|
||||
@ -3154,7 +3155,7 @@ class EBSBackend(object):
|
||||
self.volumes = {}
|
||||
self.attachments = {}
|
||||
self.snapshots = {}
|
||||
super(EBSBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_volume(
|
||||
self, size, zone_name, snapshot_id=None, encrypted=False, kms_key_id=None
|
||||
@ -3444,7 +3445,7 @@ class VPC(TaggedEC2Resource, CloudFormationModel):
|
||||
return None
|
||||
return self.dhcp_options.id
|
||||
else:
|
||||
return super(VPC, self).get_filter_value(filter_name, "DescribeVpcs")
|
||||
return super().get_filter_value(filter_name, "DescribeVpcs")
|
||||
|
||||
def modify_vpc_tenancy(self, tenancy):
|
||||
if tenancy != "default":
|
||||
@ -3539,7 +3540,7 @@ class VPCBackend(object):
|
||||
self.vpcs = {}
|
||||
self.vpc_end_points = {}
|
||||
self.vpc_refs[self.__class__].add(weakref.ref(self))
|
||||
super(VPCBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
@classmethod
|
||||
def get_vpc_refs(cls):
|
||||
@ -3831,19 +3832,172 @@ class VPCBackend(object):
|
||||
|
||||
return generic_filter(filters, vpc_end_points)
|
||||
|
||||
def get_vpc_end_point_services(self):
|
||||
vpc_end_point_services = self.vpc_end_points.values()
|
||||
@staticmethod
|
||||
def _collect_default_endpoint_services(region):
|
||||
"""Return list of default services using list of backends."""
|
||||
if DEFAULT_VPC_ENDPOINT_SERVICES:
|
||||
return DEFAULT_VPC_ENDPOINT_SERVICES
|
||||
|
||||
services = []
|
||||
for value in vpc_end_point_services:
|
||||
services.append(value.service_name)
|
||||
zones = [
|
||||
zone.name
|
||||
for zones in RegionsAndZonesBackend.zones.values()
|
||||
for zone in zones
|
||||
if zone.name.startswith(region)
|
||||
]
|
||||
|
||||
availability_zones = EC2Backend.describe_availability_zones(self)
|
||||
from moto import backends # pylint: disable=import-outside-toplevel
|
||||
|
||||
for _backends in backends.unique_backends():
|
||||
if region in _backends:
|
||||
service = _backends[region].default_vpc_endpoint_service(region, zones)
|
||||
if service:
|
||||
DEFAULT_VPC_ENDPOINT_SERVICES.extend(service)
|
||||
|
||||
if "global" in _backends:
|
||||
service = _backends["global"].default_vpc_endpoint_service(
|
||||
region, zones
|
||||
)
|
||||
if service:
|
||||
DEFAULT_VPC_ENDPOINT_SERVICES.extend(service)
|
||||
return DEFAULT_VPC_ENDPOINT_SERVICES
|
||||
|
||||
@staticmethod
|
||||
def _matches_service_by_tags(service, filter_item):
|
||||
"""Return True if service tags are not filtered by their tags.
|
||||
|
||||
Note that the API specifies a key of "Values" for a filter, but
|
||||
the botocore library returns "Value" instead.
|
||||
"""
|
||||
# For convenience, collect the tags for this service.
|
||||
service_tag_keys = {x["Key"] for x in service["Tags"]}
|
||||
if not service_tag_keys:
|
||||
return False
|
||||
|
||||
matched = True # assume the best
|
||||
if filter_item["Name"] == "tag-key":
|
||||
# Filters=[{"Name":"tag-key", "Values":["Name"]}],
|
||||
# Any tag with this name, regardless of the tag value.
|
||||
if not service_tag_keys & set(filter_item["Value"]):
|
||||
matched = False
|
||||
|
||||
elif filter_item["Name"].startswith("tag:"):
|
||||
# Filters=[{"Name":"tag:Name", "Values":["my-load-balancer"]}],
|
||||
tag_name = filter_item["Name"].split(":")[1]
|
||||
if not service_tag_keys & {tag_name}:
|
||||
matched = False
|
||||
else:
|
||||
for tag in service["Tags"]:
|
||||
if tag["Key"] == tag_name and tag["Value"] in filter_item["Value"]:
|
||||
break
|
||||
else:
|
||||
matched = False
|
||||
return matched
|
||||
|
||||
@staticmethod
|
||||
def _filter_endpoint_services(service_names_filters, filters, services):
|
||||
"""Return filtered list of VPC endpoint services."""
|
||||
if not service_names_filters and not filters:
|
||||
return services
|
||||
|
||||
# Verify the filters are valid.
|
||||
for filter_item in filters:
|
||||
if filter_item["Name"] not in [
|
||||
"service-name",
|
||||
"service-type",
|
||||
"tag-key",
|
||||
] and not filter_item["Name"].startswith("tag:"):
|
||||
raise InvalidFilter(filter_item["Name"])
|
||||
|
||||
# Apply both the service_names filter and the filters themselves.
|
||||
filtered_services = []
|
||||
for service in services:
|
||||
if (
|
||||
service_names_filters
|
||||
and service["ServiceName"] not in service_names_filters
|
||||
):
|
||||
continue
|
||||
|
||||
# Note that the API specifies a key of "Values" for a filter, but
|
||||
# the botocore library returns "Value" instead.
|
||||
matched = True
|
||||
for filter_item in filters:
|
||||
if filter_item["Name"] == "service-name":
|
||||
if service["ServiceName"] not in filter_item["Value"]:
|
||||
matched = False
|
||||
|
||||
elif filter_item["Name"] == "service-type":
|
||||
service_types = {x["ServiceType"] for x in service["ServiceType"]}
|
||||
if not service_types & set(filter_item["Value"]):
|
||||
matched = False
|
||||
|
||||
elif filter_item["Name"] == "tag-key" or filter_item["Name"].startswith(
|
||||
"tag:"
|
||||
):
|
||||
if not VPCBackend._matches_service_by_tags(service, filter_item):
|
||||
matched = False
|
||||
|
||||
# Exit early -- don't bother checking the remaining filters
|
||||
# as a non-match was found.
|
||||
if not matched:
|
||||
break
|
||||
|
||||
# Does the service have a matching service name or does it match
|
||||
# a filter?
|
||||
if matched:
|
||||
filtered_services.append(service)
|
||||
|
||||
return filtered_services
|
||||
|
||||
def describe_vpc_endpoint_services(
|
||||
self, dry_run, service_names, filters, max_results, next_token, region
|
||||
): # pylint: disable=unused-argument,too-many-arguments
|
||||
"""Return info on services to which you can create a VPC endpoint.
|
||||
|
||||
Currently only the default endpoing services are returned. When
|
||||
create_vpc_endpoint_service_configuration() is implemented, a
|
||||
list of those private endpoints would be kept and when this API
|
||||
is invoked, those private endpoints would be added to the list of
|
||||
default endpoint services.
|
||||
|
||||
The DryRun parameter is ignored.
|
||||
"""
|
||||
default_services = self._collect_default_endpoint_services(region)
|
||||
for service_name in service_names:
|
||||
if service_name not in [x["ServiceName"] for x in default_services]:
|
||||
raise InvalidServiceName(service_name)
|
||||
|
||||
# Apply filters specified in the service_names and filters arguments.
|
||||
filtered_services = sorted(
|
||||
self._filter_endpoint_services(service_names, filters, default_services),
|
||||
key=itemgetter("ServiceName"),
|
||||
)
|
||||
|
||||
# Determine the start index into list of services based on the
|
||||
# next_token argument.
|
||||
start = 0
|
||||
vpce_ids = [x["ServiceId"] for x in filtered_services]
|
||||
if next_token:
|
||||
if next_token not in vpce_ids:
|
||||
raise InvalidNextToken(next_token)
|
||||
start = vpce_ids.index(next_token)
|
||||
|
||||
# Determine the stop index into the list of services based on the
|
||||
# max_results argument.
|
||||
if not max_results or max_results > MAX_NUMBER_OF_ENDPOINT_SERVICES_RESULTS:
|
||||
max_results = MAX_NUMBER_OF_ENDPOINT_SERVICES_RESULTS
|
||||
|
||||
# If necessary, set the value of the next_token.
|
||||
next_token = ""
|
||||
if len(filtered_services) > (start + max_results):
|
||||
service = filtered_services[start + max_results]
|
||||
next_token = service["ServiceId"]
|
||||
|
||||
return {
|
||||
"servicesDetails": vpc_end_point_services,
|
||||
"services": services,
|
||||
"availability_zones": availability_zones,
|
||||
"servicesDetails": filtered_services[start : start + max_results],
|
||||
"serviceNames": [
|
||||
x["ServiceName"] for x in filtered_services[start : start + max_results]
|
||||
],
|
||||
"nextToken": next_token,
|
||||
}
|
||||
|
||||
def get_vpc_end_point(self, vpc_end_point_id):
|
||||
@ -3931,7 +4085,7 @@ class VPCPeeringConnectionBackend(object):
|
||||
def __init__(self):
|
||||
self.vpc_pcxs = {}
|
||||
self.vpc_pcx_refs[self.__class__].add(weakref.ref(self))
|
||||
super(VPCPeeringConnectionBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
@classmethod
|
||||
def get_vpc_pcx_refs(cls):
|
||||
@ -4130,7 +4284,7 @@ class Subnet(TaggedEC2Resource, CloudFormationModel):
|
||||
elif filter_name == "state":
|
||||
return self.state
|
||||
else:
|
||||
return super(Subnet, self).get_filter_value(filter_name, "DescribeSubnets")
|
||||
return super().get_filter_value(filter_name, "DescribeSubnets")
|
||||
|
||||
def get_cfn_attribute(self, attribute_name):
|
||||
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
|
||||
@ -4202,7 +4356,7 @@ class SubnetBackend(object):
|
||||
def __init__(self):
|
||||
# maps availability zone to dict of (subnet_id, subnet)
|
||||
self.subnets = defaultdict(dict)
|
||||
super(SubnetBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def get_subnet(self, subnet_id):
|
||||
for subnets in self.subnets.values():
|
||||
@ -4467,15 +4621,13 @@ class FlowLogs(TaggedEC2Resource, CloudFormationModel):
|
||||
elif filter_name == "deliver-log-status":
|
||||
return "SUCCESS"
|
||||
else:
|
||||
return super(FlowLogs, self).get_filter_value(
|
||||
filter_name, "DescribeFlowLogs"
|
||||
)
|
||||
return super().get_filter_value(filter_name, "DescribeFlowLogs")
|
||||
|
||||
|
||||
class FlowLogsBackend(object):
|
||||
def __init__(self):
|
||||
self.flow_logs = defaultdict(dict)
|
||||
super(FlowLogsBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def _validate_request(
|
||||
self,
|
||||
@ -4683,7 +4835,7 @@ class SubnetRouteTableAssociation(CloudFormationModel):
|
||||
class SubnetRouteTableAssociationBackend(object):
|
||||
def __init__(self):
|
||||
self.subnet_associations = {}
|
||||
super(SubnetRouteTableAssociationBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_subnet_association(self, route_table_id, subnet_id):
|
||||
subnet_association = SubnetRouteTableAssociation(route_table_id, subnet_id)
|
||||
@ -4749,15 +4901,13 @@ class RouteTable(TaggedEC2Resource, CloudFormationModel):
|
||||
elif filter_name == "association.subnet-id":
|
||||
return self.associations.values()
|
||||
else:
|
||||
return super(RouteTable, self).get_filter_value(
|
||||
filter_name, "DescribeRouteTables"
|
||||
)
|
||||
return super().get_filter_value(filter_name, "DescribeRouteTables")
|
||||
|
||||
|
||||
class RouteTableBackend(object):
|
||||
def __init__(self):
|
||||
self.route_tables = {}
|
||||
super(RouteTableBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_route_table(self, vpc_id, tags=[], main=False):
|
||||
route_table_id = random_route_table_id()
|
||||
@ -5035,7 +5185,7 @@ class ManagedPrefixListBackend(object):
|
||||
def __init__(self):
|
||||
self.managed_prefix_lists = {}
|
||||
self.create_default_pls()
|
||||
super(ManagedPrefixListBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_managed_prefix_list(
|
||||
self,
|
||||
@ -5161,7 +5311,7 @@ class ManagedPrefixListBackend(object):
|
||||
|
||||
class RouteBackend(object):
|
||||
def __init__(self):
|
||||
super(RouteBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_route(
|
||||
self,
|
||||
@ -5362,7 +5512,7 @@ class InternetGateway(TaggedEC2Resource, CloudFormationModel):
|
||||
class InternetGatewayBackend(object):
|
||||
def __init__(self):
|
||||
self.internet_gateways = {}
|
||||
super(InternetGatewayBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_internet_gateway(self, tags=[]):
|
||||
igw = InternetGateway(self)
|
||||
@ -5434,7 +5584,7 @@ class CarrierGateway(TaggedEC2Resource):
|
||||
class CarrierGatewayBackend(object):
|
||||
def __init__(self):
|
||||
self.carrier_gateways = {}
|
||||
super(CarrierGatewayBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_carrier_gateway(self, vpc_id, tags=None):
|
||||
vpc = self.get_vpc(vpc_id)
|
||||
@ -5490,7 +5640,7 @@ class EgressOnlyInternetGateway(TaggedEC2Resource):
|
||||
class EgressOnlyInternetGatewayBackend(object):
|
||||
def __init__(self):
|
||||
self.egress_only_internet_gateway_backend = {}
|
||||
super(EgressOnlyInternetGatewayBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_egress_only_internet_gateway(self, vpc_id, tags=None):
|
||||
vpc = self.get_vpc(vpc_id)
|
||||
@ -5563,7 +5713,7 @@ class VPCGatewayAttachment(CloudFormationModel):
|
||||
class VPCGatewayAttachmentBackend(object):
|
||||
def __init__(self):
|
||||
self.gateway_attachments = {}
|
||||
super(VPCGatewayAttachmentBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_vpc_gateway_attachment(self, vpc_id, gateway_id):
|
||||
attachment = VPCGatewayAttachment(vpc_id, gateway_id)
|
||||
@ -5594,9 +5744,9 @@ class SpotInstanceRequest(BotoSpotRequest, TaggedEC2Resource):
|
||||
subnet_id,
|
||||
tags,
|
||||
spot_fleet_id,
|
||||
**kwargs
|
||||
**kwargs,
|
||||
):
|
||||
super(SpotInstanceRequest, self).__init__(**kwargs)
|
||||
super().__init__(**kwargs)
|
||||
ls = LaunchSpecification()
|
||||
self.ec2_backend = ec2_backend
|
||||
self.launch_specification = ls
|
||||
@ -5638,9 +5788,7 @@ class SpotInstanceRequest(BotoSpotRequest, TaggedEC2Resource):
|
||||
elif filter_name == "spot-instance-request-id":
|
||||
return self.id
|
||||
else:
|
||||
return super(SpotInstanceRequest, self).get_filter_value(
|
||||
filter_name, "DescribeSpotInstanceRequests"
|
||||
)
|
||||
return super().get_filter_value(filter_name, "DescribeSpotInstanceRequests")
|
||||
|
||||
def launch_instance(self):
|
||||
reservation = self.ec2_backend.add_instances(
|
||||
@ -5663,7 +5811,7 @@ class SpotInstanceRequest(BotoSpotRequest, TaggedEC2Resource):
|
||||
class SpotRequestBackend(object, metaclass=Model):
|
||||
def __init__(self):
|
||||
self.spot_instance_requests = {}
|
||||
super(SpotRequestBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def request_spot_instances(
|
||||
self,
|
||||
@ -5974,7 +6122,7 @@ class SpotFleetRequest(TaggedEC2Resource, CloudFormationModel):
|
||||
class SpotFleetBackend(object):
|
||||
def __init__(self):
|
||||
self.spot_fleet_requests = {}
|
||||
super(SpotFleetBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def request_spot_fleet(
|
||||
self,
|
||||
@ -6141,15 +6289,13 @@ class ElasticAddress(TaggedEC2Resource, CloudFormationModel):
|
||||
# TODO: implement network-interface-owner-id
|
||||
raise FilterNotImplementedError(filter_name, "DescribeAddresses")
|
||||
else:
|
||||
return super(ElasticAddress, self).get_filter_value(
|
||||
filter_name, "DescribeAddresses"
|
||||
)
|
||||
return super().get_filter_value(filter_name, "DescribeAddresses")
|
||||
|
||||
|
||||
class ElasticAddressBackend(object):
|
||||
def __init__(self):
|
||||
self.addresses = []
|
||||
super(ElasticAddressBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def allocate_address(self, domain, address=None, tags=None):
|
||||
if domain not in ["standard", "vpc"]:
|
||||
@ -6322,9 +6468,7 @@ class DHCPOptionsSet(TaggedEC2Resource):
|
||||
values = [item for item in list(self._options.values()) if item]
|
||||
return itertools.chain(*values)
|
||||
else:
|
||||
return super(DHCPOptionsSet, self).get_filter_value(
|
||||
filter_name, "DescribeDhcpOptions"
|
||||
)
|
||||
return super().get_filter_value(filter_name, "DescribeDhcpOptions")
|
||||
|
||||
@property
|
||||
def options(self):
|
||||
@ -6334,7 +6478,7 @@ class DHCPOptionsSet(TaggedEC2Resource):
|
||||
class DHCPOptionsSetBackend(object):
|
||||
def __init__(self):
|
||||
self.dhcp_options_sets = {}
|
||||
super(DHCPOptionsSetBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def associate_dhcp_options(self, dhcp_options, vpc):
|
||||
dhcp_options.vpc = vpc
|
||||
@ -6440,15 +6584,13 @@ class VPNConnection(TaggedEC2Resource):
|
||||
self.add_tags(tags or {})
|
||||
|
||||
def get_filter_value(self, filter_name):
|
||||
return super(VPNConnection, self).get_filter_value(
|
||||
filter_name, "DescribeVpnConnections"
|
||||
)
|
||||
return super().get_filter_value(filter_name, "DescribeVpnConnections")
|
||||
|
||||
|
||||
class VPNConnectionBackend(object):
|
||||
def __init__(self):
|
||||
self.vpn_connections = {}
|
||||
super(VPNConnectionBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_vpn_connection(
|
||||
self,
|
||||
@ -6514,7 +6656,7 @@ class VPNConnectionBackend(object):
|
||||
class NetworkAclBackend(object):
|
||||
def __init__(self):
|
||||
self.network_acls = {}
|
||||
super(NetworkAclBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def get_network_acl(self, network_acl_id):
|
||||
network_acl = self.network_acls.get(network_acl_id, None)
|
||||
@ -6702,7 +6844,7 @@ class NetworkAclAssociation(object):
|
||||
self.new_association_id = new_association_id
|
||||
self.subnet_id = subnet_id
|
||||
self.network_acl_id = network_acl_id
|
||||
super(NetworkAclAssociation, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
|
||||
class NetworkAcl(TaggedEC2Resource):
|
||||
@ -6729,9 +6871,7 @@ class NetworkAcl(TaggedEC2Resource):
|
||||
elif filter_name == "owner-id":
|
||||
return self.owner_id
|
||||
else:
|
||||
return super(NetworkAcl, self).get_filter_value(
|
||||
filter_name, "DescribeNetworkAcls"
|
||||
)
|
||||
return super().get_filter_value(filter_name, "DescribeNetworkAcls")
|
||||
|
||||
|
||||
class NetworkAclEntry(TaggedEC2Resource):
|
||||
@ -6781,7 +6921,7 @@ class VpnGateway(TaggedEC2Resource):
|
||||
self.state = state
|
||||
self.add_tags(tags or {})
|
||||
self.attachments = {}
|
||||
super(VpnGateway, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def get_filter_value(self, filter_name):
|
||||
if filter_name == "attachment.vpc-id":
|
||||
@ -6792,22 +6932,20 @@ class VpnGateway(TaggedEC2Resource):
|
||||
return self.id
|
||||
elif filter_name == "type":
|
||||
return self.type
|
||||
return super(VpnGateway, self).get_filter_value(
|
||||
filter_name, "DescribeVpnGateways"
|
||||
)
|
||||
return super().get_filter_value(filter_name, "DescribeVpnGateways")
|
||||
|
||||
|
||||
class VpnGatewayAttachment(object):
|
||||
def __init__(self, vpc_id, state):
|
||||
self.vpc_id = vpc_id
|
||||
self.state = state
|
||||
super(VpnGatewayAttachment, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
|
||||
class VpnGatewayBackend(object):
|
||||
def __init__(self):
|
||||
self.vpn_gateways = {}
|
||||
super(VpnGatewayBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_vpn_gateway(
|
||||
self, type="ipsec.1", amazon_side_asn=None, availability_zone=None, tags=None
|
||||
@ -6870,18 +7008,16 @@ class CustomerGateway(TaggedEC2Resource):
|
||||
self.attachments = {}
|
||||
self.state = state
|
||||
self.add_tags(tags or {})
|
||||
super(CustomerGateway, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def get_filter_value(self, filter_name):
|
||||
return super(CustomerGateway, self).get_filter_value(
|
||||
filter_name, "DescribeCustomerGateways"
|
||||
)
|
||||
return super().get_filter_value(filter_name, "DescribeCustomerGateways")
|
||||
|
||||
|
||||
class CustomerGatewayBackend(object):
|
||||
def __init__(self):
|
||||
self.customer_gateways = {}
|
||||
super(CustomerGatewayBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_customer_gateway(
|
||||
self, type="ipsec.1", ip_address=None, bgp_asn=None, tags=None
|
||||
@ -7006,7 +7142,7 @@ class TransitGateway(TaggedEC2Resource, CloudFormationModel):
|
||||
class TransitGatewayBackend(object):
|
||||
def __init__(self):
|
||||
self.transit_gateways = {}
|
||||
super(TransitGatewayBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_transit_gateway(self, description=None, options=None, tags=[]):
|
||||
transit_gateway = TransitGateway(self, description, options)
|
||||
@ -7081,7 +7217,7 @@ class TransitGatewayRouteTable(TaggedEC2Resource):
|
||||
class TransitGatewayRouteTableBackend(object):
|
||||
def __init__(self):
|
||||
self.transit_gateways_route_tables = {}
|
||||
super(TransitGatewayRouteTableBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_transit_gateway_route_table(
|
||||
self,
|
||||
@ -7400,7 +7536,7 @@ class TransitGatewayPeeringAttachment(TransitGatewayAttachment):
|
||||
class TransitGatewayAttachmentBackend(object):
|
||||
def __init__(self):
|
||||
self.transit_gateway_attachments = {}
|
||||
super(TransitGatewayAttachmentBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_transit_gateway_vpn_attachment(
|
||||
self, vpn_id, transit_gateway_id, tags=[]
|
||||
@ -7645,7 +7781,7 @@ class TransitGatewayRelationsBackend(object):
|
||||
def __init__(self):
|
||||
self.transit_gateway_associations = {}
|
||||
self.transit_gateway_propagations = {}
|
||||
super(TransitGatewayRelationsBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def associate_transit_gateway_route_table(
|
||||
self, transit_gateway_attachment_id=None, transit_gateway_route_table_id=None
|
||||
@ -7793,7 +7929,7 @@ class NatGateway(CloudFormationModel, TaggedEC2Resource):
|
||||
class NatGatewayBackend(object):
|
||||
def __init__(self):
|
||||
self.nat_gateways = {}
|
||||
super(NatGatewayBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def describe_nat_gateways(self, filters, nat_gateway_ids):
|
||||
nat_gateways = list(self.nat_gateways.values())
|
||||
@ -7916,9 +8052,7 @@ class LaunchTemplate(TaggedEC2Resource):
|
||||
if filter_name == "launch-template-name":
|
||||
return self.name
|
||||
else:
|
||||
return super(LaunchTemplate, self).get_filter_value(
|
||||
filter_name, "DescribeLaunchTemplates"
|
||||
)
|
||||
return super().get_filter_value(filter_name, "DescribeLaunchTemplates")
|
||||
|
||||
|
||||
class LaunchTemplateBackend(object):
|
||||
@ -7926,7 +8060,7 @@ class LaunchTemplateBackend(object):
|
||||
self.launch_template_name_to_ids = {}
|
||||
self.launch_templates = OrderedDict()
|
||||
self.launch_template_insert_order = []
|
||||
super(LaunchTemplateBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def create_launch_template(self, name, description, template_data):
|
||||
if name in self.launch_template_name_to_ids:
|
||||
@ -7971,7 +8105,7 @@ class IamInstanceProfileAssociation(CloudFormationModel):
|
||||
class IamInstanceProfileAssociationBackend(object):
|
||||
def __init__(self):
|
||||
self.iam_instance_profile_associations = {}
|
||||
super(IamInstanceProfileAssociationBackend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
def associate_iam_instance_profile(
|
||||
self,
|
||||
@ -8117,7 +8251,7 @@ class EC2Backend(
|
||||
):
|
||||
def __init__(self, region_name):
|
||||
self.region_name = region_name
|
||||
super(EC2Backend, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
# Default VPC exists by default, which is the current behavior
|
||||
# of EC2-VPC. See for detail:
|
||||
@ -8149,6 +8283,15 @@ class EC2Backend(
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "ec2"
|
||||
) + BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "ec2messages"
|
||||
)
|
||||
|
||||
# Use this to generate a proper error template response when in a response
|
||||
# handler.
|
||||
def raise_error(self, code, message):
|
||||
|
@ -133,6 +133,7 @@ class VPCs(BaseResponse):
|
||||
attr_value = self.querystring.get("%s.Value" % attribute)[0]
|
||||
self.ec2_backend.modify_vpc_attribute(vpc_id, attr_name, attr_value)
|
||||
return MODIFY_VPC_ATTRIBUTE_RESPONSE
|
||||
return None
|
||||
|
||||
def associate_vpc_cidr_block(self):
|
||||
vpc_id = self._get_param("VpcId")
|
||||
@ -181,7 +182,7 @@ class VPCs(BaseResponse):
|
||||
service_name = self._get_param("ServiceName")
|
||||
route_table_ids = self._get_multi_param("RouteTableId")
|
||||
subnet_ids = self._get_multi_param("SubnetId")
|
||||
type = self._get_param("VpcEndpointType")
|
||||
endpoint_type = self._get_param("VpcEndpointType")
|
||||
policy_document = self._get_param("PolicyDocument")
|
||||
client_token = self._get_param("ClientToken")
|
||||
tags = self._get_multi_param("TagSpecification")
|
||||
@ -192,7 +193,7 @@ class VPCs(BaseResponse):
|
||||
vpc_end_point = self.ec2_backend.create_vpc_endpoint(
|
||||
vpc_id=vpc_id,
|
||||
service_name=service_name,
|
||||
type=type,
|
||||
type=endpoint_type,
|
||||
policy_document=policy_document,
|
||||
route_table_ids=route_table_ids,
|
||||
subnet_ids=subnet_ids,
|
||||
@ -205,7 +206,14 @@ class VPCs(BaseResponse):
|
||||
return template.render(vpc_end_point=vpc_end_point)
|
||||
|
||||
def describe_vpc_endpoint_services(self):
|
||||
vpc_end_point_services = self.ec2_backend.get_vpc_end_point_services()
|
||||
vpc_end_point_services = self.ec2_backend.describe_vpc_endpoint_services(
|
||||
dry_run=self._get_bool_param("DryRun"),
|
||||
service_names=self._get_multi_param("ServiceName"),
|
||||
filters=self._get_multi_param("Filter"),
|
||||
max_results=self._get_int_param("MaxResults"),
|
||||
next_token=self._get_param("NextToken"),
|
||||
region=self.region,
|
||||
)
|
||||
template = self.response_template(DESCRIBE_VPC_ENDPOINT_SERVICES_RESPONSE)
|
||||
return template.render(vpc_end_points=vpc_end_point_services)
|
||||
|
||||
@ -589,33 +597,63 @@ CREATE_VPC_END_POINT = """ <CreateVpcEndpointResponse xmlns="http://monitoring.a
|
||||
DESCRIBE_VPC_ENDPOINT_SERVICES_RESPONSE = """<DescribeVpcEndpointServicesResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
|
||||
<requestId>19a9ff46-7df6-49b8-9726-3df27527089d</requestId>
|
||||
<serviceNameSet>
|
||||
{% for serviceName in vpc_end_points.services %}
|
||||
{% for serviceName in vpc_end_points.serviceNames %}
|
||||
<item>{{ serviceName }}</item>
|
||||
{% endfor %}
|
||||
</serviceNameSet>
|
||||
<serviceDetailSet>
|
||||
{% for service in vpc_end_points.servicesDetails %}
|
||||
<item>
|
||||
<owner>amazon</owner>
|
||||
<serviceType>
|
||||
<item>
|
||||
<serviceType>{{ service.type }}</serviceType>
|
||||
</item>
|
||||
</serviceType>
|
||||
<baseEndpointDnsNameSet>
|
||||
<item>{{ ".".join((service.service_name.split(".")[::-1])) }}</item>
|
||||
</baseEndpointDnsNameSet>
|
||||
<acceptanceRequired>false</acceptanceRequired>
|
||||
<item>
|
||||
<acceptanceRequired>{{ 'true' if service.AcceptanceRequired else 'false' }}</acceptanceRequired>
|
||||
<availabilityZoneSet>
|
||||
{% for zone in vpc_end_points.availability_zones %}
|
||||
<item>{{ zone.name }}</item>
|
||||
{% for zone in service.AvailabilityZones %}
|
||||
<item>{{ zone }}</item>
|
||||
{% endfor %}
|
||||
</availabilityZoneSet>
|
||||
<serviceName>{{ service.service_name }}</serviceName>
|
||||
<vpcEndpointPolicySupported>true</vpcEndpointPolicySupported>
|
||||
</item>
|
||||
<baseEndpointDnsNameSet>
|
||||
{% for endpoint in service.BaseEndpointDnsNames %}
|
||||
<item>{{ endpoint }}</item>
|
||||
{% endfor %}
|
||||
</baseEndpointDnsNameSet>
|
||||
<managesVpcEndpoints>{{ 'true' if service.ManagesVpcEndpoints else 'false' }}</managesVpcEndpoints>
|
||||
<owner>{{ service.Owner }}</owner>
|
||||
{% if service.PrivateDnsName is defined %}
|
||||
<privateDnsName>{{ service.PrivateDnsName }}</privateDnsName>
|
||||
<privateDnsNameSet>
|
||||
{% for dns_name in service.PrivateDnsNames %}
|
||||
<item>
|
||||
<privateDnsName>{{ dns_name.PrivateDnsName }}</privateDnsName>
|
||||
</item>
|
||||
{% endfor %}
|
||||
</privateDnsNameSet>
|
||||
<privateDnsNameVerificationState>{{ service.PrivateDnsNameVerificationState }}</privateDnsNameVerificationState>
|
||||
{% endif %}
|
||||
<serviceId>{{ service.ServiceId }}</serviceId>
|
||||
<serviceName>{{ service.ServiceName }}</serviceName>
|
||||
<serviceType>
|
||||
{% for service_type in service.ServiceType %}
|
||||
<item>
|
||||
<serviceType>{{ service_type.ServiceType }}</serviceType>
|
||||
</item>
|
||||
{% endfor %}
|
||||
</serviceType>
|
||||
<tagSet>
|
||||
{% for tag in service.Tags %}
|
||||
{% for key, value in tag.items() %}
|
||||
<item>
|
||||
<key>{{ key }}</key>
|
||||
<value>{{ value }}</value>
|
||||
</item>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</tagSet>
|
||||
<vpcEndpointPolicySupported>{{ 'true' if service.VpcEndpointPolicySupported else 'false' }}</vpcEndpointPolicySupported>
|
||||
</item>
|
||||
{% endfor %}
|
||||
</serviceDetailSet>
|
||||
{% if vpc_end_points.nextToken|length %}
|
||||
<nextToken>{{ vpc_end_points.nextToken }}</nextToken>
|
||||
{% endif %}
|
||||
</DescribeVpcEndpointServicesResponse>"""
|
||||
|
||||
DESCRIBE_VPC_ENDPOINT_RESPONSE = """<DescribeVpcEndpointsResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
|
||||
|
@ -335,6 +335,30 @@ class ECRBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
docker_endpoint = {
|
||||
"AcceptanceRequired": False,
|
||||
"AvailabilityZones": zones,
|
||||
"BaseEndpointDnsNames": [f"dkr.ecr.{service_region}.vpce.amazonaws.com"],
|
||||
"ManagesVpcEndpoints": False,
|
||||
"Owner": "amazon",
|
||||
"PrivateDnsName": f"*.dkr.ecr.{service_region}.amazonaws.com",
|
||||
"PrivateDnsNameVerificationState": "verified",
|
||||
"PrivateDnsNames": [
|
||||
{"PrivateDnsName": f"*.dkr.ecr.{service_region}.amazonaws.com"}
|
||||
],
|
||||
"ServiceId": f"vpce-svc-{BaseBackend.vpce_random_number()}",
|
||||
"ServiceName": f"com.amazonaws.{service_region}.ecr.dkr",
|
||||
"ServiceType": [{"ServiceType": "Interface"}],
|
||||
"Tags": [],
|
||||
"VpcEndpointPolicySupported": True,
|
||||
}
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "api.ecr", special_service_name="ecr.api",
|
||||
) + [docker_endpoint]
|
||||
|
||||
def _get_repository(self, name, registry_id=None) -> Repository:
|
||||
repo = self.repositories.get(name)
|
||||
reg_id = registry_id or DEFAULT_REGISTRY_ID
|
||||
|
@ -675,6 +675,13 @@ class EC2ContainerServiceBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "ecs"
|
||||
)
|
||||
|
||||
def _get_cluster(self, name):
|
||||
# short name or full ARN of the cluster
|
||||
cluster_name = name.split("/")[-1]
|
||||
|
@ -79,6 +79,15 @@ class EBBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "elasticbeanstalk"
|
||||
) + BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "elasticbeanstalk-health"
|
||||
)
|
||||
|
||||
def create_application(self, application_name):
|
||||
if application_name in self.applications:
|
||||
raise InvalidParameterValueError(
|
||||
|
@ -553,6 +553,13 @@ class ELBv2Backend(BaseBackend):
|
||||
self.target_groups = OrderedDict()
|
||||
self.load_balancers = OrderedDict()
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "elasticloadbalancing"
|
||||
)
|
||||
|
||||
@property
|
||||
def ec2_backend(self):
|
||||
"""
|
||||
|
@ -397,6 +397,13 @@ class ElasticMapReduceBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "elasticmapreduce"
|
||||
)
|
||||
|
||||
@property
|
||||
def ec2_backend(self):
|
||||
"""
|
||||
|
@ -915,6 +915,13 @@ class EventsBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "events"
|
||||
)
|
||||
|
||||
def _add_default_event_bus(self):
|
||||
self.event_buses["default"] = EventBus(self.region_name, "default")
|
||||
|
||||
|
@ -174,6 +174,13 @@ class FirehoseBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "firehose", special_service_name="kinesis-firehose"
|
||||
)
|
||||
|
||||
def create_delivery_stream(
|
||||
self,
|
||||
region,
|
||||
|
@ -24,6 +24,13 @@ class GlueBackend(BaseBackend):
|
||||
self.databases = OrderedDict()
|
||||
self.crawlers = OrderedDict()
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "glue"
|
||||
)
|
||||
|
||||
def create_database(self, database_name, database_input):
|
||||
if database_name in self.databases:
|
||||
raise DatabaseAlreadyExistsException()
|
||||
|
@ -505,6 +505,20 @@ class IoTBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "iot"
|
||||
) + BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region,
|
||||
zones,
|
||||
"data.iot",
|
||||
private_dns_names=False,
|
||||
special_service_name="iot.data",
|
||||
policy_supported=False,
|
||||
)
|
||||
|
||||
def create_thing(self, thing_name, thing_type_name, attribute_payload):
|
||||
thing_types = self.list_thing_types()
|
||||
thing_type = None
|
||||
|
@ -325,6 +325,13 @@ class KinesisBackend(BaseBackend):
|
||||
def __init__(self):
|
||||
self.streams = OrderedDict()
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "kinesis", special_service_name="kinesis-streams"
|
||||
)
|
||||
|
||||
def create_stream(
|
||||
self, stream_name, shard_count, retention_period_hours, region_name
|
||||
):
|
||||
|
@ -159,6 +159,13 @@ class KmsBackend(BaseBackend):
|
||||
self.key_to_aliases = defaultdict(set)
|
||||
self.tagger = TaggingService(key_name="TagKey", value_name="TagValue")
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "kms"
|
||||
)
|
||||
|
||||
def create_key(
|
||||
self, policy, key_usage, customer_master_key_spec, description, tags, region
|
||||
):
|
||||
|
@ -551,6 +551,13 @@ class LogsBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "logs"
|
||||
)
|
||||
|
||||
def create_log_group(self, log_group_name, tags, **kwargs):
|
||||
if log_group_name in self.groups:
|
||||
raise ResourceAlreadyExistsException()
|
||||
|
@ -847,6 +847,15 @@ class RDS2Backend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "rds"
|
||||
) + BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "rds-data"
|
||||
)
|
||||
|
||||
def create_database(self, db_kwargs):
|
||||
database_id = db_kwargs["db_instance_identifier"]
|
||||
database = Database(**db_kwargs)
|
||||
|
@ -574,6 +574,15 @@ class RedshiftBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(ec2_backend, region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "redshift"
|
||||
) + BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "redshift-data", policy_supported=False
|
||||
)
|
||||
|
||||
def enable_snapshot_copy(self, **kwargs):
|
||||
cluster_identifier = kwargs["cluster_identifier"]
|
||||
cluster = self.clusters[cluster_identifier]
|
||||
|
@ -1,11 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import json
|
||||
import os
|
||||
import base64
|
||||
import datetime
|
||||
import pytz
|
||||
import hashlib
|
||||
import copy
|
||||
import itertools
|
||||
@ -18,8 +15,9 @@ import sys
|
||||
import time
|
||||
import uuid
|
||||
|
||||
|
||||
from bisect import insort
|
||||
import pytz
|
||||
|
||||
from moto.core import ACCOUNT_ID, BaseBackend, BaseModel, CloudFormationModel
|
||||
from moto.core.utils import iso_8601_datetime_without_milliseconds_s3, rfc_1123_datetime
|
||||
from moto.cloudwatch.models import MetricDatum
|
||||
@ -1301,6 +1299,38 @@ class S3Backend(BaseBackend):
|
||||
self.account_public_access_block = None
|
||||
self.tagger = TaggingService()
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""List of dicts representing default VPC endpoints for this service."""
|
||||
accesspoint = {
|
||||
"AcceptanceRequired": False,
|
||||
"AvailabilityZones": zones,
|
||||
"BaseEndpointDnsNames": [
|
||||
f"accesspoint.s3-global.{service_region}.vpce.amazonaws.com",
|
||||
],
|
||||
"ManagesVpcEndpoints": False,
|
||||
"Owner": "amazon",
|
||||
"PrivateDnsName": "*.accesspoint.s3-global.amazonaws.com",
|
||||
"PrivateDnsNameVerificationState": "verified",
|
||||
"PrivateDnsNames": [
|
||||
{"PrivateDnsName": "*.accesspoint.s3-global.amazonaws.com"}
|
||||
],
|
||||
"ServiceId": f"vpce-svc-{BaseBackend.vpce_random_number()}",
|
||||
"ServiceName": "com.amazonaws.s3-global.accesspoint",
|
||||
"ServiceType": [{"ServiceType": "Interface"}],
|
||||
"Tags": [],
|
||||
"VpcEndpointPolicySupported": True,
|
||||
}
|
||||
return (
|
||||
BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "s3", "Interface"
|
||||
)
|
||||
+ BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "s3", "Gateway"
|
||||
)
|
||||
+ [accesspoint]
|
||||
)
|
||||
|
||||
# TODO: This is broken! DO NOT IMPORT MUTABLE DATA TYPES FROM OTHER AREAS -- THIS BREAKS UNMOCKING!
|
||||
# WRAP WITH A GETTER/SETTER FUNCTION
|
||||
# Register this class as a CloudWatch Metric Provider
|
||||
|
@ -877,6 +877,58 @@ class SageMakerModelBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint services."""
|
||||
api_service = BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "api.sagemaker", special_service_name="sagemaker.api"
|
||||
)
|
||||
|
||||
notebook_service_id = f"vpce-svc-{BaseBackend.vpce_random_number()}"
|
||||
studio_service_id = f"vpce-svc-{BaseBackend.vpce_random_number()}"
|
||||
|
||||
notebook_service = {
|
||||
"AcceptanceRequired": False,
|
||||
"AvailabilityZones": zones,
|
||||
"BaseEndpointDnsNames": [
|
||||
f"{notebook_service_id}.{service_region}.vpce.amazonaws.com",
|
||||
f"notebook.{service_region}.vpce.sagemaker.aws",
|
||||
],
|
||||
"ManagesVpcEndpoints": False,
|
||||
"Owner": "amazon",
|
||||
"PrivateDnsName": f"*.notebook.{service_region}.sagemaker.aws",
|
||||
"PrivateDnsNameVerificationState": "verified",
|
||||
"PrivateDnsNames": [
|
||||
{"PrivateDnsName": f"*.notebook.{service_region}.sagemaker.aws"}
|
||||
],
|
||||
"ServiceId": notebook_service_id,
|
||||
"ServiceName": f"aws.sagemaker.{service_region}.notebook",
|
||||
"ServiceType": [{"ServiceType": "Interface"}],
|
||||
"Tags": [],
|
||||
"VpcEndpointPolicySupported": True,
|
||||
}
|
||||
studio_service = {
|
||||
"AcceptanceRequired": False,
|
||||
"AvailabilityZones": zones,
|
||||
"BaseEndpointDnsNames": [
|
||||
f"{studio_service_id}.{service_region}.vpce.amazonaws.com",
|
||||
f"studio.{service_region}.vpce.sagemaker.aws",
|
||||
],
|
||||
"ManagesVpcEndpoints": False,
|
||||
"Owner": "amazon",
|
||||
"PrivateDnsName": f"*.studio.{service_region}.sagemaker.aws",
|
||||
"PrivateDnsNameVerificationState": "verified",
|
||||
"PrivateDnsNames": [
|
||||
{"PrivateDnsName": f"*.studio.{service_region}.sagemaker.aws"}
|
||||
],
|
||||
"ServiceId": studio_service_id,
|
||||
"ServiceName": f"aws.sagemaker.{service_region}.studio",
|
||||
"ServiceType": [{"ServiceType": "Interface"}],
|
||||
"Tags": [],
|
||||
"VpcEndpointPolicySupported": True,
|
||||
}
|
||||
return api_service + [notebook_service, studio_service]
|
||||
|
||||
def create_model(self, **kwargs):
|
||||
model_obj = Model(
|
||||
region_name=self.region_name,
|
||||
|
@ -182,6 +182,13 @@ class SecretsManagerBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint services."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "secretsmanager"
|
||||
)
|
||||
|
||||
def _is_valid_identifier(self, identifier):
|
||||
return identifier in self.secrets
|
||||
|
||||
|
@ -387,6 +387,13 @@ class SNSBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""List of dicts representing default VPC endpoints for this service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "sns"
|
||||
)
|
||||
|
||||
def update_sms_attributes(self, attrs):
|
||||
self.sms_attributes.update(attrs)
|
||||
|
||||
|
@ -584,6 +584,13 @@ class SQSBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "sqs"
|
||||
)
|
||||
|
||||
def create_queue(self, name, tags=None, **kwargs):
|
||||
queue = self.queues.get(name)
|
||||
if queue:
|
||||
|
@ -688,6 +688,15 @@ class SimpleSystemManagerBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint services."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "ssm"
|
||||
) + BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "ssmmessages"
|
||||
)
|
||||
|
||||
def _generate_document_information(self, ssm_document, document_format):
|
||||
content = self._get_document_content(document_format, ssm_document)
|
||||
base = {
|
||||
|
@ -60,6 +60,13 @@ class STSBackend(BaseBackend):
|
||||
def __init__(self):
|
||||
self.assumed_roles = []
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "sts"
|
||||
)
|
||||
|
||||
def get_session_token(self, duration):
|
||||
token = Token(duration=duration)
|
||||
return token
|
||||
|
@ -450,6 +450,15 @@ class TranscribeBackend(BaseBackend):
|
||||
self.__dict__ = {}
|
||||
self.__init__(region_name)
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint services."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "transcribe"
|
||||
) + BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "transcribestreaming"
|
||||
)
|
||||
|
||||
def start_transcription_job(self, **kwargs):
|
||||
|
||||
name = kwargs.get("transcription_job_name")
|
||||
|
@ -236,6 +236,13 @@ class XRayBackend(BaseBackend):
|
||||
self._telemetry_records = []
|
||||
self._segment_collection = SegmentCollection()
|
||||
|
||||
@staticmethod
|
||||
def default_vpc_endpoint_service(service_region, zones):
|
||||
"""Default VPC endpoint service."""
|
||||
return BaseBackend.default_vpc_endpoint_service_factory(
|
||||
service_region, zones, "xray"
|
||||
)
|
||||
|
||||
def add_telemetry_records(self, json):
|
||||
self._telemetry_records.append(TelemetryRecords.from_json(json))
|
||||
|
||||
|
259
tests/test_ec2/test_vpc_endpoint_services.py
Normal file
259
tests/test_ec2/test_vpc_endpoint_services.py
Normal file
@ -0,0 +1,259 @@
|
||||
"""Unit tests specific to VPC endpoint services."""
|
||||
import pytest
|
||||
|
||||
import boto3
|
||||
from botocore.exceptions import ClientError
|
||||
|
||||
from moto import mock_ec2
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_describe_vpc_endpoint_services_bad_args():
|
||||
"""Verify exceptions are raised for bad arguments."""
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
|
||||
# Bad service name -- a default service would typically be of the format:
|
||||
# 'com.amazonaws.<region>.<service_name>'.
|
||||
with pytest.raises(ClientError) as exc:
|
||||
ec2.describe_vpc_endpoint_services(ServiceNames=["s3"])
|
||||
err = exc.value.response["Error"]
|
||||
assert err["Code"] == "InvalidServiceName"
|
||||
assert "The Vpc Endpoint Service 's3' does not exist" in err["Message"]
|
||||
|
||||
# Bad filter specification -- the filter name should be "service-type"
|
||||
# not "ServiceType".
|
||||
with pytest.raises(ClientError) as exc:
|
||||
ec2.describe_vpc_endpoint_services(
|
||||
ServiceNames=["com.amazonaws.us-west-1.s3"],
|
||||
Filters=[{"Name": "ServiceType", "Values": ["Gateway"]}],
|
||||
)
|
||||
err = exc.value.response["Error"]
|
||||
assert err["Code"] == "InvalidFilter"
|
||||
assert "The filter 'ServiceType' is invalid" in err["Message"]
|
||||
|
||||
# Bad token -- a token of "foo" has no correlation with this data.
|
||||
with pytest.raises(ClientError) as exc:
|
||||
ec2.describe_vpc_endpoint_services(
|
||||
ServiceNames=["com.amazonaws.us-west-1.s3"],
|
||||
Filters=[{"Name": "service-type", "Values": ["Gateway"]}],
|
||||
NextToken="foo",
|
||||
)
|
||||
err = exc.value.response["Error"]
|
||||
assert err["Code"] == "InvalidNextToken"
|
||||
assert "The token 'foo' is invalid" in err["Message"]
|
||||
|
||||
|
||||
def fake_endpoint_services():
|
||||
"""Return a dummy list of default VPC endpoint services."""
|
||||
return [
|
||||
{
|
||||
"AcceptanceRequired": False,
|
||||
"AvailabilityZones": ["us-west-1a", "us-west-1b"],
|
||||
"BaseEndpointDnsNames": ["access-analyzer.us-west-1.vpce.amazonaws.com"],
|
||||
"ManagesVpcEndpoints": False,
|
||||
"Owner": "amazon",
|
||||
"PrivateDnsName": "access-analyzer.us-west-1.amazonaws.com",
|
||||
"PrivateDnsNameVerificationState": "verified",
|
||||
"PrivateDnsNames": [
|
||||
{"PrivateDnsName": "access-analyzer.us-west-1.amazonaws.com"},
|
||||
],
|
||||
"ServiceId": "vpce-svc-1",
|
||||
"ServiceName": "com.amazonaws.us-west-1.access-analyzer",
|
||||
"ServiceType": [{"ServiceType": "Interface"}],
|
||||
"Tags": [],
|
||||
"VpcEndpointPolicySupported": True,
|
||||
},
|
||||
{
|
||||
"AcceptanceRequired": False,
|
||||
"AvailabilityZones": ["us-west-1a", "us-west-1b"],
|
||||
"BaseEndpointDnsNames": ["config.us-west-1.vpce.amazonaws.com"],
|
||||
"ManagesVpcEndpoints": False,
|
||||
"Owner": "amazon",
|
||||
"PrivateDnsName": "config.us-west-1.amazonaws.com",
|
||||
"PrivateDnsNameVerificationState": "verified",
|
||||
"PrivateDnsNames": [{"PrivateDnsName": "config.us-west-1.amazonaws.com"}],
|
||||
"ServiceId": "vpce-svc-2",
|
||||
"ServiceName": "com.amazonaws.us-west-1.config",
|
||||
"ServiceType": [{"ServiceType": "Interface"}],
|
||||
"Tags": [],
|
||||
"VpcEndpointPolicySupported": True,
|
||||
},
|
||||
{
|
||||
"AcceptanceRequired": True,
|
||||
"AvailabilityZones": ["us-west-1a", "us-west-1b"],
|
||||
"BaseEndpointDnsNames": ["s3.us-west-1.amazonaws.com"],
|
||||
"ManagesVpcEndpoints": True,
|
||||
"Owner": "amazon",
|
||||
"ServiceId": "vpce-svc-3",
|
||||
"ServiceName": "com.amazonaws.us-west-1.s3",
|
||||
"ServiceType": [{"ServiceType": "Gateway"}],
|
||||
"Tags": [{"Key": "Name", "Value": "s3_gw"}],
|
||||
"VpcEndpointPolicySupported": False,
|
||||
},
|
||||
{
|
||||
"AcceptanceRequired": False,
|
||||
"AvailabilityZones": ["us-west-1a", "us-west-1b"],
|
||||
"BaseEndpointDnsNames": ["s3.us-west-1.vpce.amazonaws.com"],
|
||||
"ManagesVpcEndpoints": False,
|
||||
"Owner": "amazon",
|
||||
"ServiceId": "vpce-svc-4",
|
||||
"ServiceName": "com.amazonaws.us-west-1.s3",
|
||||
"ServiceType": [{"ServiceType": "Interface"}],
|
||||
"Tags": [
|
||||
{"Key": "Name", "Value": "s3_if"},
|
||||
{"Key": "Environ", "Value": "test"},
|
||||
],
|
||||
"VpcEndpointPolicySupported": True,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def validate_s3_service_endpoint_gateway(details):
|
||||
"""Validate response contains appropriate s3 Gateway service details."""
|
||||
assert details["AcceptanceRequired"] is True
|
||||
assert details["AvailabilityZones"] == ["us-west-1a", "us-west-1b"]
|
||||
assert details["BaseEndpointDnsNames"] == ["s3.us-west-1.amazonaws.com"]
|
||||
assert details["ManagesVpcEndpoints"] is True
|
||||
assert details["Owner"] == "amazon"
|
||||
assert details["ServiceId"] == "vpce-svc-3"
|
||||
assert details["ServiceName"] == "com.amazonaws.us-west-1.s3"
|
||||
assert details["ServiceType"] == [{"ServiceType": "Gateway"}]
|
||||
assert details["VpcEndpointPolicySupported"] is False
|
||||
assert details["Tags"][0] == {"Key": "Name", "Value": "s3_gw"}
|
||||
|
||||
|
||||
def validate_s3_service_endpoint_interface(details):
|
||||
"""Validate response contains appropriate s3 Gateway service details."""
|
||||
assert details["AcceptanceRequired"] is False
|
||||
assert details["AvailabilityZones"] == ["us-west-1a", "us-west-1b"]
|
||||
assert details["BaseEndpointDnsNames"] == ["s3.us-west-1.vpce.amazonaws.com"]
|
||||
assert details["ManagesVpcEndpoints"] is False
|
||||
assert details["Owner"] == "amazon"
|
||||
assert details["ServiceId"] == "vpce-svc-4"
|
||||
assert details["ServiceName"] == "com.amazonaws.us-west-1.s3"
|
||||
assert details["ServiceType"] == [{"ServiceType": "Interface"}]
|
||||
assert details["VpcEndpointPolicySupported"] is True
|
||||
assert details["Tags"][0] == {"Key": "Name", "Value": "s3_if"}
|
||||
assert details["Tags"][1] == {"Key": "Environ", "Value": "test"}
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_describe_vpc_endpoint_services_filters():
|
||||
"""Verify that different type of filters return the expected results."""
|
||||
from moto.ec2.models import ec2_backends # pylint: disable=import-outside-toplevel
|
||||
|
||||
ec2_backend = ec2_backends["us-west-1"]
|
||||
test_data = fake_endpoint_services()
|
||||
|
||||
# Allow access to _filter_endpoint_services as it provides the best
|
||||
# means of testing this logic.
|
||||
# pylint: disable=protected-access
|
||||
|
||||
# Test a service name filter, using s3 as the service name.
|
||||
filtered_services = ec2_backend._filter_endpoint_services(
|
||||
["com.amazonaws.us-west-1.s3"], [], test_data,
|
||||
)
|
||||
assert len(filtered_services) == 2
|
||||
validate_s3_service_endpoint_gateway(filtered_services[0])
|
||||
validate_s3_service_endpoint_interface(filtered_services[1])
|
||||
|
||||
# Test a service type filter.
|
||||
filtered_services = ec2_backend._filter_endpoint_services(
|
||||
[], [{"Name": "service-type", "Value": ["Gateway"]}], test_data,
|
||||
)
|
||||
assert len(filtered_services) == 1
|
||||
validate_s3_service_endpoint_gateway(filtered_services[0])
|
||||
|
||||
# Test a tag key/value filter.
|
||||
filtered_services = ec2_backend._filter_endpoint_services(
|
||||
[], [{"Name": "tag-key", "Value": ["Name"]}], test_data,
|
||||
)
|
||||
assert len(filtered_services) == 2
|
||||
validate_s3_service_endpoint_gateway(filtered_services[0])
|
||||
validate_s3_service_endpoint_interface(filtered_services[1])
|
||||
|
||||
# Test a tag key filter.
|
||||
filtered_services = ec2_backend._filter_endpoint_services(
|
||||
[], [{"Name": "tag:Environ", "Value": ["test"]}], test_data,
|
||||
)
|
||||
assert len(filtered_services) == 1
|
||||
validate_s3_service_endpoint_interface(filtered_services[0])
|
||||
|
||||
# Test when there are no filters.
|
||||
filtered_services = ec2_backend._filter_endpoint_services([], [], test_data)
|
||||
assert len(filtered_services) == 4
|
||||
|
||||
# Test a combo of service name and multiple filters.
|
||||
filtered_services = ec2_backend._filter_endpoint_services(
|
||||
["com.amazonaws.us-west-1.s3"],
|
||||
[{"Name": "tag:Environ", "Value": ["test"]}],
|
||||
test_data,
|
||||
)
|
||||
assert len(filtered_services) == 1
|
||||
validate_s3_service_endpoint_interface(filtered_services[0])
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_describe_vpc_default_endpoint_services():
|
||||
"""Test successfull calls as well as the next_token arg."""
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
|
||||
# Verify the major components of the response. The unit test for filters
|
||||
# verifies the contents of some of the ServicesDetails entries, so the
|
||||
# focus of this unit test will be the larger components of the response.
|
||||
all_services = ec2.describe_vpc_endpoint_services()
|
||||
assert set(all_services.keys()) == set(
|
||||
["ServiceNames", "ServiceDetails", "ResponseMetadata"]
|
||||
)
|
||||
assert len(all_services["ServiceDetails"]) == len(all_services["ServiceNames"])
|
||||
all_names = [x["ServiceName"] for x in all_services["ServiceDetails"]]
|
||||
assert set(all_names) == set(all_services["ServiceNames"])
|
||||
|
||||
# Verify the handling of the next token.
|
||||
partial_services = ec2.describe_vpc_endpoint_services(MaxResults=2)
|
||||
assert len(partial_services["ServiceDetails"]) == 2
|
||||
assert len(partial_services["ServiceNames"]) == 2
|
||||
assert all_names[0] == partial_services["ServiceNames"][0]
|
||||
assert all_names[1] == partial_services["ServiceNames"][1]
|
||||
assert all_names[0] == partial_services["ServiceDetails"][0]["ServiceName"]
|
||||
assert all_names[1] == partial_services["ServiceDetails"][1]["ServiceName"]
|
||||
assert partial_services["NextToken"] == (
|
||||
all_services["ServiceDetails"][2]["ServiceId"]
|
||||
)
|
||||
|
||||
# Use the next token to receive another service.
|
||||
more_services = ec2.describe_vpc_endpoint_services(
|
||||
MaxResults=1, NextToken=partial_services["NextToken"]
|
||||
)
|
||||
assert len(more_services["ServiceDetails"]) == 1
|
||||
assert len(more_services["ServiceNames"]) == 1
|
||||
assert all_names[2] == more_services["ServiceNames"][0]
|
||||
assert all_names[2] == more_services["ServiceDetails"][0]["ServiceName"]
|
||||
assert more_services["NextToken"] == all_services["ServiceDetails"][3]["ServiceId"]
|
||||
|
||||
# Use the next token to receive the remaining services.
|
||||
remaining_services = ec2.describe_vpc_endpoint_services(
|
||||
NextToken=more_services["NextToken"]
|
||||
)
|
||||
assert len(remaining_services["ServiceDetails"]) == len(all_names) - 3
|
||||
assert "NextToken" not in remaining_services
|
||||
|
||||
# Extract one service and verify all the fields. This time the data is
|
||||
# extracted from the actual response.
|
||||
config_service = ec2.describe_vpc_endpoint_services(
|
||||
ServiceNames=["com.amazonaws.us-west-1.config"]
|
||||
)
|
||||
details = config_service["ServiceDetails"][0]
|
||||
assert details["AcceptanceRequired"] is False
|
||||
assert details["AvailabilityZones"] == ["us-west-1a", "us-west-1b"]
|
||||
assert details["BaseEndpointDnsNames"] == ["config.us-west-1.vpce.amazonaws.com"]
|
||||
assert details["ManagesVpcEndpoints"] is False
|
||||
assert details["Owner"] == "amazon"
|
||||
assert details["PrivateDnsName"] == "config.us-west-1.amazonaws.com"
|
||||
assert details["PrivateDnsNames"] == [
|
||||
{"PrivateDnsName": "config.us-west-1.amazonaws.com"}
|
||||
]
|
||||
assert details["PrivateDnsNameVerificationState"] == "verified"
|
||||
assert details["ServiceName"] == "com.amazonaws.us-west-1.config"
|
||||
assert details["ServiceType"] == [{"ServiceType": "Interface"}]
|
||||
assert details["VpcEndpointPolicySupported"] is True
|
@ -864,37 +864,6 @@ def test_describe_classic_link_dns_support_multiple():
|
||||
)
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_describe_vpc_end_point_services():
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
vpc = ec2.create_vpc(CidrBlock="10.0.0.0/16")
|
||||
|
||||
route_table = ec2.create_route_table(VpcId=vpc["Vpc"]["VpcId"])
|
||||
|
||||
ec2.create_vpc_endpoint(
|
||||
VpcId=vpc["Vpc"]["VpcId"],
|
||||
ServiceName="com.amazonaws.us-east-1.s3",
|
||||
RouteTableIds=[route_table["RouteTable"]["RouteTableId"]],
|
||||
VpcEndpointType="gateway",
|
||||
)
|
||||
|
||||
vpc_end_point_services = ec2.describe_vpc_endpoint_services()
|
||||
|
||||
assert vpc_end_point_services.get("ServiceDetails").should.be.true
|
||||
assert vpc_end_point_services.get("ServiceNames").should.be.true
|
||||
assert vpc_end_point_services.get("ServiceNames") == ["com.amazonaws.us-east-1.s3"]
|
||||
assert (
|
||||
vpc_end_point_services.get("ServiceDetails")[0]
|
||||
.get("ServiceType", [])[0]
|
||||
.get("ServiceType")
|
||||
== "gateway"
|
||||
)
|
||||
assert vpc_end_point_services.get("ServiceDetails")[0].get("AvailabilityZones") == [
|
||||
"us-west-1a",
|
||||
"us-west-1b",
|
||||
]
|
||||
|
||||
|
||||
@mock_ec2
|
||||
def test_describe_vpc_end_points():
|
||||
ec2 = boto3.client("ec2", region_name="us-west-1")
|
||||
|
Loading…
Reference in New Issue
Block a user