Implement EC2 describe_vpc_endpoint_services() (#4322)

This commit is contained in:
kbalk 2021-09-24 12:01:09 -04:00 committed by GitHub
parent a02bf0022d
commit 3a203d35c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 1102 additions and 259 deletions

View File

@ -1249,7 +1249,7 @@
- [ ] describe_vpc_endpoint_connections - [ ] describe_vpc_endpoint_connections
- [ ] describe_vpc_endpoint_service_configurations - [ ] describe_vpc_endpoint_service_configurations
- [ ] describe_vpc_endpoint_service_permissions - [ ] describe_vpc_endpoint_service_permissions
- [ ] describe_vpc_endpoint_services - [X] describe_vpc_endpoint_services
- [X] describe_vpc_endpoints - [X] describe_vpc_endpoints
- [X] describe_vpc_peering_connections - [X] describe_vpc_peering_connections
- [X] describe_vpcs - [X] describe_vpcs
@ -4619,4 +4619,4 @@
- workmailmessageflow - workmailmessageflow
- workspaces - workspaces
- xray - xray
</details> </details>

View File

@ -416,6 +416,13 @@ class AWSCertificateManagerBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region) 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 @staticmethod
def _arn_not_found(arn): def _arn_not_found(arn):
msg = "Certificate with arn {0} not found in account {1}".format( msg = "Certificate with arn {0} not found in account {1}".format(

View File

@ -72,6 +72,13 @@ class ApplicationAutoscalingBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region, ecs) 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 @property
def applicationautoscaling_backend(self): def applicationautoscaling_backend(self):
return applicationautoscaling_backends[self.region] return applicationautoscaling_backends[self.region]

View File

@ -80,6 +80,13 @@ class AthenaBackend(BaseBackend):
self.executions = {} self.executions = {}
self.named_queries = {} 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): def create_work_group(self, name, configuration, description, tags):
if name in self.work_groups: if name in self.work_groups:
return None return None

View File

@ -622,6 +622,15 @@ class AutoScalingBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(ec2_backend, elb_backend, elbv2_backend) 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( def create_launch_configuration(
self, self,
name, name,

View File

@ -1095,6 +1095,13 @@ class LambdaBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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): def create_function(self, spec):
function_name = spec.get("FunctionName", None) function_name = spec.get("FunctionName", None)
if function_name is None: if function_name is None:

View File

@ -27,6 +27,11 @@ def backends():
yield _import_backend(module_name, backends_name) 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(): def loaded_backends():
loaded_modules = sys.modules.keys() loaded_modules = sys.modules.keys()
loaded_modules = [m for m in loaded_modules if m.startswith("moto.")] loaded_modules = [m for m in loaded_modules if m.startswith("moto.")]

View File

@ -499,6 +499,13 @@ class CloudFormationBackend(BaseBackend):
self.exports = OrderedDict() self.exports = OrderedDict()
self.change_sets = 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): def _resolve_update_parameters(self, instance, incoming_params):
parameters = dict( parameters = dict(
[ [

View File

@ -312,6 +312,13 @@ class CloudWatchBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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 @property
# Retrieve a list of all OOTB metrics that are provided by metrics providers # Retrieve a list of all OOTB metrics that are provided by metrics providers
# Computed on the fly # Computed on the fly

View File

@ -36,6 +36,13 @@ class CodeCommitBackend(BaseBackend):
def __init__(self): def __init__(self):
self.repositories = {} 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): def create_repository(self, region, repository_name, repository_description):
repository = self.repositories.get(repository_name) repository = self.repositories.get(repository_name)
if repository: if repository:

View File

@ -71,6 +71,13 @@ class CodePipelineBackend(BaseBackend):
def __init__(self): def __init__(self):
self.pipelines = {} 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 @property
def iam_backend(self): def iam_backend(self):
return iam_backends["global"] return iam_backends["global"]

View File

@ -854,6 +854,13 @@ class ConfigBackend(BaseBackend):
self.config_rules = {} self.config_rules = {}
self.config_schema = None 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): def _validate_resource_types(self, resource_list):
if not self.config_schema: if not self.config_schema:
self.config_schema = AWSServiceSpec( self.config_schema = AWSServiceSpec(

View File

@ -1,11 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
from __future__ import absolute_import
import functools import functools
import inspect import inspect
import os import os
import random
import re import re
import string
import types import types
from abc import abstractmethod from abc import abstractmethod
from io import BytesIO from io import BytesIO
@ -698,6 +697,63 @@ class BaseBackend:
return paths 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): def decorator(self, func=None):
if settings.TEST_SERVER_MODE: if settings.TEST_SERVER_MODE:
mocked_backend = ServerModeMockAWS({"global": self}) mocked_backend = ServerModeMockAWS({"global": self})

View File

@ -112,6 +112,13 @@ class DataSyncBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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): def create_location(self, location_uri, typ=None, metadata=None):
""" """
# AWS DataSync allows for duplicate LocationUris # AWS DataSync allows for duplicate LocationUris

View File

@ -25,6 +25,13 @@ class DatabaseMigrationServiceBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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( def create_replication_task(
self, self,
replication_task_identifier, replication_task_identifier,

View File

@ -711,7 +711,7 @@ class Table(CloudFormationModel):
projection_expression, projection_expression,
index_name=None, index_name=None,
filter_expression=None, filter_expression=None,
**filter_kwargs **filter_kwargs,
): ):
results = [] results = []
@ -1075,6 +1075,19 @@ class DynamoDBBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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): def create_table(self, name, **params):
if name in self.tables: if name in self.tables:
return None return None
@ -1288,7 +1301,7 @@ class DynamoDBBackend(BaseBackend):
expr_names=None, expr_names=None,
expr_values=None, expr_values=None,
filter_expression=None, filter_expression=None,
**filter_kwargs **filter_kwargs,
): ):
table = self.tables.get(table_name) table = self.tables.get(table_name)
if not table: if not table:
@ -1311,7 +1324,7 @@ class DynamoDBBackend(BaseBackend):
projection_expression, projection_expression,
index_name, index_name,
filter_expression, filter_expression,
**filter_kwargs **filter_kwargs,
) )
def scan( def scan(

View File

@ -24,21 +24,19 @@ class EC2ClientError(RESTError):
request_id_tag_name = "RequestID" request_id_tag_name = "RequestID"
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
kwargs.setdefault("template", "custom_response") kwargs.setdefault("template", "custom_response")
self.templates["custom_response"] = EC2_ERROR_RESPONSE self.templates["custom_response"] = EC2_ERROR_RESPONSE
super().__init__(*args, **kwargs)
super(EC2ClientError, self).__init__(*args, **kwargs)
class DependencyViolationError(EC2ClientError): class DependencyViolationError(EC2ClientError):
def __init__(self, message): def __init__(self, message):
super(DependencyViolationError, self).__init__("DependencyViolation", message) super().__init__("DependencyViolation", message)
class MissingParameterError(EC2ClientError): class MissingParameterError(EC2ClientError):
def __init__(self, parameter): def __init__(self, parameter):
super(MissingParameterError, self).__init__( super().__init__(
"MissingParameter", "MissingParameter",
"The request must contain the parameter {0}".format(parameter), "The request must contain the parameter {0}".format(parameter),
) )
@ -46,7 +44,7 @@ class MissingParameterError(EC2ClientError):
class InvalidDHCPOptionsIdError(EC2ClientError): class InvalidDHCPOptionsIdError(EC2ClientError):
def __init__(self, dhcp_options_id): def __init__(self, dhcp_options_id):
super(InvalidDHCPOptionsIdError, self).__init__( super().__init__(
"InvalidDhcpOptionID.NotFound", "InvalidDhcpOptionID.NotFound",
"DhcpOptionID {0} does not exist.".format(dhcp_options_id), "DhcpOptionID {0} does not exist.".format(dhcp_options_id),
) )
@ -54,7 +52,7 @@ class InvalidDHCPOptionsIdError(EC2ClientError):
class MalformedDHCPOptionsIdError(EC2ClientError): class MalformedDHCPOptionsIdError(EC2ClientError):
def __init__(self, dhcp_options_id): def __init__(self, dhcp_options_id):
super(MalformedDHCPOptionsIdError, self).__init__( super().__init__(
"InvalidDhcpOptionsId.Malformed", "InvalidDhcpOptionsId.Malformed",
'Invalid id: "{0}" (expecting "dopt-...")'.format(dhcp_options_id), 'Invalid id: "{0}" (expecting "dopt-...")'.format(dhcp_options_id),
) )
@ -62,21 +60,21 @@ class MalformedDHCPOptionsIdError(EC2ClientError):
class InvalidKeyPairNameError(EC2ClientError): class InvalidKeyPairNameError(EC2ClientError):
def __init__(self, key): def __init__(self, key):
super(InvalidKeyPairNameError, self).__init__( super().__init__(
"InvalidKeyPair.NotFound", "The keypair '{0}' does not exist.".format(key) "InvalidKeyPair.NotFound", "The keypair '{0}' does not exist.".format(key)
) )
class InvalidKeyPairDuplicateError(EC2ClientError): class InvalidKeyPairDuplicateError(EC2ClientError):
def __init__(self, key): def __init__(self, key):
super(InvalidKeyPairDuplicateError, self).__init__( super().__init__(
"InvalidKeyPair.Duplicate", "The keypair '{0}' already exists.".format(key) "InvalidKeyPair.Duplicate", "The keypair '{0}' already exists.".format(key)
) )
class InvalidKeyPairFormatError(EC2ClientError): class InvalidKeyPairFormatError(EC2ClientError):
def __init__(self): def __init__(self):
super(InvalidKeyPairFormatError, self).__init__( super().__init__(
"InvalidKeyPair.Format", "Key is not in valid OpenSSH public key format" "InvalidKeyPair.Format", "Key is not in valid OpenSSH public key format"
) )
@ -84,14 +82,14 @@ class InvalidKeyPairFormatError(EC2ClientError):
class InvalidVPCIdError(EC2ClientError): class InvalidVPCIdError(EC2ClientError):
def __init__(self, vpc_id): def __init__(self, vpc_id):
super(InvalidVPCIdError, self).__init__( super().__init__(
"InvalidVpcID.NotFound", "VpcID {0} does not exist.".format(vpc_id), "InvalidVpcID.NotFound", "VpcID {0} does not exist.".format(vpc_id),
) )
class InvalidSubnetIdError(EC2ClientError): class InvalidSubnetIdError(EC2ClientError):
def __init__(self, subnet_id): def __init__(self, subnet_id):
super(InvalidSubnetIdError, self).__init__( super().__init__(
"InvalidSubnetID.NotFound", "InvalidSubnetID.NotFound",
"The subnet ID '{}' does not exist".format(subnet_id), "The subnet ID '{}' does not exist".format(subnet_id),
) )
@ -99,7 +97,7 @@ class InvalidSubnetIdError(EC2ClientError):
class InvalidFlowLogIdError(EC2ClientError): class InvalidFlowLogIdError(EC2ClientError):
def __init__(self, count, flow_log_ids): def __init__(self, count, flow_log_ids):
super(InvalidFlowLogIdError, self).__init__( super().__init__(
"InvalidFlowLogId.NotFound", "InvalidFlowLogId.NotFound",
"These flow log ids in the input list are not found: [TotalCount: {0}] {1}".format( "These flow log ids in the input list are not found: [TotalCount: {0}] {1}".format(
count, flow_log_ids count, flow_log_ids
@ -109,7 +107,7 @@ class InvalidFlowLogIdError(EC2ClientError):
class FlowLogAlreadyExists(EC2ClientError): class FlowLogAlreadyExists(EC2ClientError):
def __init__(self): def __init__(self):
super(FlowLogAlreadyExists, self).__init__( super().__init__(
"FlowLogAlreadyExists", "FlowLogAlreadyExists",
"Error. There is an existing Flow Log with the same configuration and log destination.", "Error. There is an existing Flow Log with the same configuration and log destination.",
) )
@ -117,7 +115,7 @@ class FlowLogAlreadyExists(EC2ClientError):
class InvalidNetworkAclIdError(EC2ClientError): class InvalidNetworkAclIdError(EC2ClientError):
def __init__(self, network_acl_id): def __init__(self, network_acl_id):
super(InvalidNetworkAclIdError, self).__init__( super().__init__(
"InvalidNetworkAclID.NotFound", "InvalidNetworkAclID.NotFound",
"The network acl ID '{0}' does not exist".format(network_acl_id), "The network acl ID '{0}' does not exist".format(network_acl_id),
) )
@ -125,7 +123,7 @@ class InvalidNetworkAclIdError(EC2ClientError):
class InvalidVpnGatewayIdError(EC2ClientError): class InvalidVpnGatewayIdError(EC2ClientError):
def __init__(self, vpn_gw): def __init__(self, vpn_gw):
super(InvalidVpnGatewayIdError, self).__init__( super().__init__(
"InvalidVpnGatewayID.NotFound", "InvalidVpnGatewayID.NotFound",
"The virtual private gateway ID '{0}' does not exist".format(vpn_gw), "The virtual private gateway ID '{0}' does not exist".format(vpn_gw),
) )
@ -133,7 +131,7 @@ class InvalidVpnGatewayIdError(EC2ClientError):
class InvalidVpnGatewayAttachmentError(EC2ClientError): class InvalidVpnGatewayAttachmentError(EC2ClientError):
def __init__(self, vpn_gw, vpc_id): def __init__(self, vpn_gw, vpc_id):
super(InvalidVpnGatewayAttachmentError, self).__init__( super().__init__(
"InvalidVpnGatewayAttachment.NotFound", "InvalidVpnGatewayAttachment.NotFound",
"The attachment with vpn gateway ID '{}' and vpc ID '{}' does not exist".format( "The attachment with vpn gateway ID '{}' and vpc ID '{}' does not exist".format(
vpn_gw, vpc_id vpn_gw, vpc_id
@ -143,7 +141,7 @@ class InvalidVpnGatewayAttachmentError(EC2ClientError):
class InvalidVpnConnectionIdError(EC2ClientError): class InvalidVpnConnectionIdError(EC2ClientError):
def __init__(self, network_acl_id): def __init__(self, network_acl_id):
super(InvalidVpnConnectionIdError, self).__init__( super().__init__(
"InvalidVpnConnectionID.NotFound", "InvalidVpnConnectionID.NotFound",
"The vpnConnection ID '{0}' does not exist".format(network_acl_id), "The vpnConnection ID '{0}' does not exist".format(network_acl_id),
) )
@ -151,7 +149,7 @@ class InvalidVpnConnectionIdError(EC2ClientError):
class InvalidCustomerGatewayIdError(EC2ClientError): class InvalidCustomerGatewayIdError(EC2ClientError):
def __init__(self, customer_gateway_id): def __init__(self, customer_gateway_id):
super(InvalidCustomerGatewayIdError, self).__init__( super().__init__(
"InvalidCustomerGatewayID.NotFound", "InvalidCustomerGatewayID.NotFound",
"The customer gateway ID '{0}' does not exist".format(customer_gateway_id), "The customer gateway ID '{0}' does not exist".format(customer_gateway_id),
) )
@ -159,7 +157,7 @@ class InvalidCustomerGatewayIdError(EC2ClientError):
class InvalidNetworkInterfaceIdError(EC2ClientError): class InvalidNetworkInterfaceIdError(EC2ClientError):
def __init__(self, eni_id): def __init__(self, eni_id):
super(InvalidNetworkInterfaceIdError, self).__init__( super().__init__(
"InvalidNetworkInterfaceID.NotFound", "InvalidNetworkInterfaceID.NotFound",
"The network interface ID '{0}' does not exist".format(eni_id), "The network interface ID '{0}' does not exist".format(eni_id),
) )
@ -167,7 +165,7 @@ class InvalidNetworkInterfaceIdError(EC2ClientError):
class InvalidNetworkAttachmentIdError(EC2ClientError): class InvalidNetworkAttachmentIdError(EC2ClientError):
def __init__(self, attachment_id): def __init__(self, attachment_id):
super(InvalidNetworkAttachmentIdError, self).__init__( super().__init__(
"InvalidAttachmentID.NotFound", "InvalidAttachmentID.NotFound",
"The network interface attachment ID '{0}' does not exist".format( "The network interface attachment ID '{0}' does not exist".format(
attachment_id attachment_id
@ -177,7 +175,7 @@ class InvalidNetworkAttachmentIdError(EC2ClientError):
class InvalidSecurityGroupDuplicateError(EC2ClientError): class InvalidSecurityGroupDuplicateError(EC2ClientError):
def __init__(self, name): def __init__(self, name):
super(InvalidSecurityGroupDuplicateError, self).__init__( super().__init__(
"InvalidGroup.Duplicate", "InvalidGroup.Duplicate",
"The security group '{0}' already exists".format(name), "The security group '{0}' already exists".format(name),
) )
@ -185,7 +183,7 @@ class InvalidSecurityGroupDuplicateError(EC2ClientError):
class InvalidSecurityGroupNotFoundError(EC2ClientError): class InvalidSecurityGroupNotFoundError(EC2ClientError):
def __init__(self, name): def __init__(self, name):
super(InvalidSecurityGroupNotFoundError, self).__init__( super().__init__(
"InvalidGroup.NotFound", "InvalidGroup.NotFound",
"The security group '{0}' does not exist".format(name), "The security group '{0}' does not exist".format(name),
) )
@ -193,7 +191,7 @@ class InvalidSecurityGroupNotFoundError(EC2ClientError):
class InvalidPermissionNotFoundError(EC2ClientError): class InvalidPermissionNotFoundError(EC2ClientError):
def __init__(self): def __init__(self):
super(InvalidPermissionNotFoundError, self).__init__( super().__init__(
"InvalidPermission.NotFound", "InvalidPermission.NotFound",
"The specified rule does not exist in this security group", "The specified rule does not exist in this security group",
) )
@ -201,15 +199,14 @@ class InvalidPermissionNotFoundError(EC2ClientError):
class InvalidPermissionDuplicateError(EC2ClientError): class InvalidPermissionDuplicateError(EC2ClientError):
def __init__(self): def __init__(self):
super(InvalidPermissionDuplicateError, self).__init__( super().__init__(
"InvalidPermission.Duplicate", "The specified rule already exists" "InvalidPermission.Duplicate", "The specified rule already exists"
) )
class InvalidRouteTableIdError(EC2ClientError): class InvalidRouteTableIdError(EC2ClientError):
def __init__(self, route_table_id): def __init__(self, route_table_id):
super().__init__(
super(InvalidRouteTableIdError, self).__init__(
"InvalidRouteTableID.NotFound", "InvalidRouteTableID.NotFound",
"The routeTable ID '{0}' does not exist".format(route_table_id), "The routeTable ID '{0}' does not exist".format(route_table_id),
) )
@ -217,7 +214,7 @@ class InvalidRouteTableIdError(EC2ClientError):
class InvalidRouteError(EC2ClientError): class InvalidRouteError(EC2ClientError):
def __init__(self, route_table_id, cidr): def __init__(self, route_table_id, cidr):
super(InvalidRouteError, self).__init__( super().__init__(
"InvalidRoute.NotFound", "InvalidRoute.NotFound",
"no route with destination-cidr-block {0} in route table {1}".format( "no route with destination-cidr-block {0} in route table {1}".format(
cidr, route_table_id cidr, route_table_id
@ -227,7 +224,7 @@ class InvalidRouteError(EC2ClientError):
class InvalidInstanceIdError(EC2ClientError): class InvalidInstanceIdError(EC2ClientError):
def __init__(self, instance_id): def __init__(self, instance_id):
super(InvalidInstanceIdError, self).__init__( super().__init__(
"InvalidInstanceID.NotFound", "InvalidInstanceID.NotFound",
"The instance ID '{0}' does not exist".format(instance_id), "The instance ID '{0}' does not exist".format(instance_id),
) )
@ -235,7 +232,7 @@ class InvalidInstanceIdError(EC2ClientError):
class InvalidInstanceTypeError(EC2ClientError): class InvalidInstanceTypeError(EC2ClientError):
def __init__(self, instance_type): def __init__(self, instance_type):
super(InvalidInstanceTypeError, self).__init__( super().__init__(
"InvalidInstanceType.NotFound", "InvalidInstanceType.NotFound",
"The instance type '{0}' does not exist".format(instance_type), "The instance type '{0}' does not exist".format(instance_type),
) )
@ -243,7 +240,7 @@ class InvalidInstanceTypeError(EC2ClientError):
class InvalidAMIIdError(EC2ClientError): class InvalidAMIIdError(EC2ClientError):
def __init__(self, ami_id): def __init__(self, ami_id):
super(InvalidAMIIdError, self).__init__( super().__init__(
"InvalidAMIID.NotFound", "InvalidAMIID.NotFound",
"The image id '[{0}]' does not exist".format(ami_id), "The image id '[{0}]' does not exist".format(ami_id),
) )
@ -251,7 +248,7 @@ class InvalidAMIIdError(EC2ClientError):
class InvalidAMIAttributeItemValueError(EC2ClientError): class InvalidAMIAttributeItemValueError(EC2ClientError):
def __init__(self, attribute, value): def __init__(self, attribute, value):
super(InvalidAMIAttributeItemValueError, self).__init__( super().__init__(
"InvalidAMIAttributeItemValue", "InvalidAMIAttributeItemValue",
'Invalid attribute item value "{0}" for {1} item type.'.format( 'Invalid attribute item value "{0}" for {1} item type.'.format(
value, attribute value, attribute
@ -261,7 +258,7 @@ class InvalidAMIAttributeItemValueError(EC2ClientError):
class MalformedAMIIdError(EC2ClientError): class MalformedAMIIdError(EC2ClientError):
def __init__(self, ami_id): def __init__(self, ami_id):
super(MalformedAMIIdError, self).__init__( super().__init__(
"InvalidAMIID.Malformed", "InvalidAMIID.Malformed",
'Invalid id: "{0}" (expecting "ami-...")'.format(ami_id), 'Invalid id: "{0}" (expecting "ami-...")'.format(ami_id),
) )
@ -269,14 +266,14 @@ class MalformedAMIIdError(EC2ClientError):
class InvalidSnapshotIdError(EC2ClientError): class InvalidSnapshotIdError(EC2ClientError):
def __init__(self, snapshot_id): def __init__(self, snapshot_id):
super(InvalidSnapshotIdError, self).__init__( super().__init__(
"InvalidSnapshot.NotFound", "" "InvalidSnapshot.NotFound", ""
) # Note: AWS returns empty message for this, as of 2014.08.22. ) # Note: AWS returns empty message for this, as of 2014.08.22.
class InvalidVolumeIdError(EC2ClientError): class InvalidVolumeIdError(EC2ClientError):
def __init__(self, volume_id): def __init__(self, volume_id):
super(InvalidVolumeIdError, self).__init__( super().__init__(
"InvalidVolume.NotFound", "InvalidVolume.NotFound",
"The volume '{0}' does not exist.".format(volume_id), "The volume '{0}' does not exist.".format(volume_id),
) )
@ -284,7 +281,7 @@ class InvalidVolumeIdError(EC2ClientError):
class InvalidVolumeAttachmentError(EC2ClientError): class InvalidVolumeAttachmentError(EC2ClientError):
def __init__(self, volume_id, instance_id): def __init__(self, volume_id, instance_id):
super(InvalidVolumeAttachmentError, self).__init__( super().__init__(
"InvalidAttachment.NotFound", "InvalidAttachment.NotFound",
"Volume {0} can not be detached from {1} because it is not attached".format( "Volume {0} can not be detached from {1} because it is not attached".format(
volume_id, instance_id volume_id, instance_id
@ -294,7 +291,7 @@ class InvalidVolumeAttachmentError(EC2ClientError):
class InvalidVolumeDetachmentError(EC2ClientError): class InvalidVolumeDetachmentError(EC2ClientError):
def __init__(self, volume_id, instance_id, device): def __init__(self, volume_id, instance_id, device):
super(InvalidVolumeDetachmentError, self).__init__( super().__init__(
"InvalidAttachment.NotFound", "InvalidAttachment.NotFound",
"The volume {0} is not attached to instance {1} as device {2}".format( "The volume {0} is not attached to instance {1} as device {2}".format(
volume_id, instance_id, device volume_id, instance_id, device
@ -304,7 +301,7 @@ class InvalidVolumeDetachmentError(EC2ClientError):
class VolumeInUseError(EC2ClientError): class VolumeInUseError(EC2ClientError):
def __init__(self, volume_id, instance_id): def __init__(self, volume_id, instance_id):
super(VolumeInUseError, self).__init__( super().__init__(
"VolumeInUse", "VolumeInUse",
"Volume {0} is currently attached to {1}".format(volume_id, instance_id), "Volume {0} is currently attached to {1}".format(volume_id, instance_id),
) )
@ -312,21 +309,21 @@ class VolumeInUseError(EC2ClientError):
class InvalidDomainError(EC2ClientError): class InvalidDomainError(EC2ClientError):
def __init__(self, domain): def __init__(self, domain):
super(InvalidDomainError, self).__init__( super().__init__(
"InvalidParameterValue", "Invalid value '{0}' for domain.".format(domain) "InvalidParameterValue", "Invalid value '{0}' for domain.".format(domain)
) )
class InvalidAddressError(EC2ClientError): class InvalidAddressError(EC2ClientError):
def __init__(self, ip): def __init__(self, ip):
super(InvalidAddressError, self).__init__( super().__init__(
"InvalidAddress.NotFound", "Address '{0}' not found.".format(ip) "InvalidAddress.NotFound", "Address '{0}' not found.".format(ip)
) )
class LogDestinationNotFoundError(EC2ClientError): class LogDestinationNotFoundError(EC2ClientError):
def __init__(self, bucket_name): def __init__(self, bucket_name):
super(LogDestinationNotFoundError, self).__init__( super().__init__(
"LogDestinationNotFoundException", "LogDestinationNotFoundException",
"LogDestination: '{0}' does not exist.".format(bucket_name), "LogDestination: '{0}' does not exist.".format(bucket_name),
) )
@ -334,7 +331,7 @@ class LogDestinationNotFoundError(EC2ClientError):
class InvalidAllocationIdError(EC2ClientError): class InvalidAllocationIdError(EC2ClientError):
def __init__(self, allocation_id): def __init__(self, allocation_id):
super(InvalidAllocationIdError, self).__init__( super().__init__(
"InvalidAllocationID.NotFound", "InvalidAllocationID.NotFound",
"Allocation ID '{0}' not found.".format(allocation_id), "Allocation ID '{0}' not found.".format(allocation_id),
) )
@ -342,7 +339,7 @@ class InvalidAllocationIdError(EC2ClientError):
class InvalidAssociationIdError(EC2ClientError): class InvalidAssociationIdError(EC2ClientError):
def __init__(self, association_id): def __init__(self, association_id):
super(InvalidAssociationIdError, self).__init__( super().__init__(
"InvalidAssociationID.NotFound", "InvalidAssociationID.NotFound",
"Association ID '{0}' not found.".format(association_id), "Association ID '{0}' not found.".format(association_id),
) )
@ -350,7 +347,7 @@ class InvalidAssociationIdError(EC2ClientError):
class InvalidVpcCidrBlockAssociationIdError(EC2ClientError): class InvalidVpcCidrBlockAssociationIdError(EC2ClientError):
def __init__(self, association_id): def __init__(self, association_id):
super(InvalidVpcCidrBlockAssociationIdError, self).__init__( super().__init__(
"InvalidVpcCidrBlockAssociationIdError.NotFound", "InvalidVpcCidrBlockAssociationIdError.NotFound",
"The vpc CIDR block association ID '{0}' does not exist".format( "The vpc CIDR block association ID '{0}' does not exist".format(
association_id association_id
@ -360,7 +357,7 @@ class InvalidVpcCidrBlockAssociationIdError(EC2ClientError):
class InvalidVPCPeeringConnectionIdError(EC2ClientError): class InvalidVPCPeeringConnectionIdError(EC2ClientError):
def __init__(self, vpc_peering_connection_id): def __init__(self, vpc_peering_connection_id):
super(InvalidVPCPeeringConnectionIdError, self).__init__( super().__init__(
"InvalidVpcPeeringConnectionId.NotFound", "InvalidVpcPeeringConnectionId.NotFound",
"VpcPeeringConnectionID {0} does not exist.".format( "VpcPeeringConnectionID {0} does not exist.".format(
vpc_peering_connection_id vpc_peering_connection_id
@ -370,7 +367,7 @@ class InvalidVPCPeeringConnectionIdError(EC2ClientError):
class InvalidVPCPeeringConnectionStateTransitionError(EC2ClientError): class InvalidVPCPeeringConnectionStateTransitionError(EC2ClientError):
def __init__(self, vpc_peering_connection_id): def __init__(self, vpc_peering_connection_id):
super(InvalidVPCPeeringConnectionStateTransitionError, self).__init__( super().__init__(
"InvalidStateTransition", "InvalidStateTransition",
"VpcPeeringConnectionID {0} is not in the correct state for the request.".format( "VpcPeeringConnectionID {0} is not in the correct state for the request.".format(
vpc_peering_connection_id 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): class InvalidDependantParameterError(EC2ClientError):
def __init__(self, dependant_parameter, parameter, parameter_value): def __init__(self, dependant_parameter, parameter, parameter_value):
super(InvalidDependantParameterError, self).__init__( super().__init__(
"InvalidParameter", "InvalidParameter",
"{0} can't be empty if {1} is {2}.".format( "{0} can't be empty if {1} is {2}.".format(
dependant_parameter, parameter, parameter_value, dependant_parameter, parameter, parameter_value,
@ -390,7 +405,7 @@ class InvalidDependantParameterError(EC2ClientError):
class InvalidDependantParameterTypeError(EC2ClientError): class InvalidDependantParameterTypeError(EC2ClientError):
def __init__(self, dependant_parameter, parameter_value, parameter): def __init__(self, dependant_parameter, parameter_value, parameter):
super(InvalidDependantParameterTypeError, self).__init__( super().__init__(
"InvalidParameter", "InvalidParameter",
"{0} type must be {1} if {2} is provided.".format( "{0} type must be {1} if {2} is provided.".format(
dependant_parameter, parameter_value, parameter, dependant_parameter, parameter_value, parameter,
@ -400,14 +415,14 @@ class InvalidDependantParameterTypeError(EC2ClientError):
class InvalidAggregationIntervalParameterError(EC2ClientError): class InvalidAggregationIntervalParameterError(EC2ClientError):
def __init__(self, parameter): def __init__(self, parameter):
super(InvalidAggregationIntervalParameterError, self).__init__( super().__init__(
"InvalidParameter", "Invalid {0}".format(parameter), "InvalidParameter", "Invalid {0}".format(parameter),
) )
class InvalidParameterValueError(EC2ClientError): class InvalidParameterValueError(EC2ClientError):
def __init__(self, parameter_value): def __init__(self, parameter_value):
super(InvalidParameterValueError, self).__init__( super().__init__(
"InvalidParameterValue", "InvalidParameterValue",
"Value {0} is invalid for parameter.".format(parameter_value), "Value {0} is invalid for parameter.".format(parameter_value),
) )
@ -415,7 +430,7 @@ class InvalidParameterValueError(EC2ClientError):
class InvalidParameterValueErrorTagNull(EC2ClientError): class InvalidParameterValueErrorTagNull(EC2ClientError):
def __init__(self): def __init__(self):
super(InvalidParameterValueErrorTagNull, self).__init__( super().__init__(
"InvalidParameterValue", "InvalidParameterValue",
"Tag value cannot be null. Use empty string instead.", "Tag value cannot be null. Use empty string instead.",
) )
@ -423,7 +438,7 @@ class InvalidParameterValueErrorTagNull(EC2ClientError):
class InvalidParameterValueErrorUnknownAttribute(EC2ClientError): class InvalidParameterValueErrorUnknownAttribute(EC2ClientError):
def __init__(self, parameter_value): def __init__(self, parameter_value):
super(InvalidParameterValueErrorUnknownAttribute, self).__init__( super().__init__(
"InvalidParameterValue", "InvalidParameterValue",
"Value ({0}) for parameter attribute is invalid. Unknown attribute.".format( "Value ({0}) for parameter attribute is invalid. Unknown attribute.".format(
parameter_value parameter_value
@ -433,7 +448,7 @@ class InvalidParameterValueErrorUnknownAttribute(EC2ClientError):
class InvalidGatewayIDError(EC2ClientError): class InvalidGatewayIDError(EC2ClientError):
def __init__(self, gateway_id): def __init__(self, gateway_id):
super(InvalidGatewayIDError, self).__init__( super().__init__(
"InvalidGatewayID.NotFound", "InvalidGatewayID.NotFound",
"The eigw ID '{0}' does not exist".format(gateway_id), "The eigw ID '{0}' does not exist".format(gateway_id),
) )
@ -441,7 +456,7 @@ class InvalidGatewayIDError(EC2ClientError):
class InvalidInternetGatewayIdError(EC2ClientError): class InvalidInternetGatewayIdError(EC2ClientError):
def __init__(self, internet_gateway_id): def __init__(self, internet_gateway_id):
super(InvalidInternetGatewayIdError, self).__init__( super().__init__(
"InvalidInternetGatewayID.NotFound", "InvalidInternetGatewayID.NotFound",
"InternetGatewayID {0} does not exist.".format(internet_gateway_id), "InternetGatewayID {0} does not exist.".format(internet_gateway_id),
) )
@ -449,7 +464,7 @@ class InvalidInternetGatewayIdError(EC2ClientError):
class GatewayNotAttachedError(EC2ClientError): class GatewayNotAttachedError(EC2ClientError):
def __init__(self, internet_gateway_id, vpc_id): def __init__(self, internet_gateway_id, vpc_id):
super(GatewayNotAttachedError, self).__init__( super().__init__(
"Gateway.NotAttached", "Gateway.NotAttached",
"InternetGatewayID {0} is not attached to a VPC {1}.".format( "InternetGatewayID {0} is not attached to a VPC {1}.".format(
internet_gateway_id, vpc_id internet_gateway_id, vpc_id
@ -459,7 +474,7 @@ class GatewayNotAttachedError(EC2ClientError):
class ResourceAlreadyAssociatedError(EC2ClientError): class ResourceAlreadyAssociatedError(EC2ClientError):
def __init__(self, resource_id): def __init__(self, resource_id):
super(ResourceAlreadyAssociatedError, self).__init__( super().__init__(
"Resource.AlreadyAssociated", "Resource.AlreadyAssociated",
"Resource {0} is already associated.".format(resource_id), "Resource {0} is already associated.".format(resource_id),
) )
@ -467,7 +482,7 @@ class ResourceAlreadyAssociatedError(EC2ClientError):
class TagLimitExceeded(EC2ClientError): class TagLimitExceeded(EC2ClientError):
def __init__(self): def __init__(self):
super(TagLimitExceeded, self).__init__( super().__init__(
"TagLimitExceeded", "TagLimitExceeded",
"The maximum number of Tags for a resource has been reached.", "The maximum number of Tags for a resource has been reached.",
) )
@ -475,14 +490,12 @@ class TagLimitExceeded(EC2ClientError):
class InvalidID(EC2ClientError): class InvalidID(EC2ClientError):
def __init__(self, resource_id): def __init__(self, resource_id):
super(InvalidID, self).__init__( super().__init__("InvalidID", "The ID '{0}' is not valid".format(resource_id))
"InvalidID", "The ID '{0}' is not valid".format(resource_id)
)
class InvalidCIDRSubnetError(EC2ClientError): class InvalidCIDRSubnetError(EC2ClientError):
def __init__(self, cidr): def __init__(self, cidr):
super(InvalidCIDRSubnetError, self).__init__( super().__init__(
"InvalidParameterValue", "InvalidParameterValue",
"invalid CIDR subnet specification: {0}".format(cidr), "invalid CIDR subnet specification: {0}".format(cidr),
) )
@ -490,7 +503,7 @@ class InvalidCIDRSubnetError(EC2ClientError):
class RulesPerSecurityGroupLimitExceededError(EC2ClientError): class RulesPerSecurityGroupLimitExceededError(EC2ClientError):
def __init__(self): def __init__(self):
super(RulesPerSecurityGroupLimitExceededError, self).__init__( super().__init__(
"RulesPerSecurityGroupLimitExceeded", "RulesPerSecurityGroupLimitExceeded",
"The maximum number of rules per security group " "has been reached.", "The maximum number of rules per security group " "has been reached.",
) )
@ -498,7 +511,7 @@ class RulesPerSecurityGroupLimitExceededError(EC2ClientError):
class MotoNotImplementedError(NotImplementedError): class MotoNotImplementedError(NotImplementedError):
def __init__(self, blurb): def __init__(self, blurb):
super(MotoNotImplementedError, self).__init__( super().__init__(
"{0} has not been implemented in Moto yet." "{0} has not been implemented in Moto yet."
" Feel free to open an issue at" " Feel free to open an issue at"
" https://github.com/spulec/moto/issues".format(blurb) " https://github.com/spulec/moto/issues".format(blurb)
@ -507,14 +520,12 @@ class MotoNotImplementedError(NotImplementedError):
class FilterNotImplementedError(MotoNotImplementedError): class FilterNotImplementedError(MotoNotImplementedError):
def __init__(self, filter_name, method_name): def __init__(self, filter_name, method_name):
super(FilterNotImplementedError, self).__init__( super().__init__("The filter '{0}' for {1}".format(filter_name, method_name))
"The filter '{0}' for {1}".format(filter_name, method_name)
)
class CidrLimitExceeded(EC2ClientError): class CidrLimitExceeded(EC2ClientError):
def __init__(self, vpc_id, max_cidr_limit): def __init__(self, vpc_id, max_cidr_limit):
super(CidrLimitExceeded, self).__init__( super().__init__(
"CidrLimitExceeded", "CidrLimitExceeded",
"This network '{0}' has met its maximum number of allowed CIDRs: {1}".format( "This network '{0}' has met its maximum number of allowed CIDRs: {1}".format(
vpc_id, max_cidr_limit vpc_id, max_cidr_limit
@ -524,7 +535,7 @@ class CidrLimitExceeded(EC2ClientError):
class UnsupportedTenancy(EC2ClientError): class UnsupportedTenancy(EC2ClientError):
def __init__(self, tenancy): def __init__(self, tenancy):
super(UnsupportedTenancy, self).__init__( super().__init__(
"UnsupportedTenancy", "UnsupportedTenancy",
"The tenancy value {0} is not supported.".format(tenancy), "The tenancy value {0} is not supported.".format(tenancy),
) )
@ -532,7 +543,7 @@ class UnsupportedTenancy(EC2ClientError):
class OperationNotPermitted(EC2ClientError): class OperationNotPermitted(EC2ClientError):
def __init__(self, association_id): def __init__(self, association_id):
super(OperationNotPermitted, self).__init__( super().__init__(
"OperationNotPermitted", "OperationNotPermitted",
"The vpc CIDR block with association ID {} may not be disassociated. " "The vpc CIDR block with association ID {} may not be disassociated. "
"It is the primary IPv4 CIDR block of the VPC".format(association_id), "It is the primary IPv4 CIDR block of the VPC".format(association_id),
@ -541,7 +552,7 @@ class OperationNotPermitted(EC2ClientError):
class InvalidAvailabilityZoneError(EC2ClientError): class InvalidAvailabilityZoneError(EC2ClientError):
def __init__(self, availability_zone_value, valid_availability_zones): def __init__(self, availability_zone_value, valid_availability_zones):
super(InvalidAvailabilityZoneError, self).__init__( super().__init__(
"InvalidParameterValue", "InvalidParameterValue",
"Value ({0}) for parameter availabilityZone is invalid. " "Value ({0}) for parameter availabilityZone is invalid. "
"Subnets can currently only be created in the following availability zones: {1}.".format( "Subnets can currently only be created in the following availability zones: {1}.".format(
@ -552,7 +563,7 @@ class InvalidAvailabilityZoneError(EC2ClientError):
class NetworkAclEntryAlreadyExistsError(EC2ClientError): class NetworkAclEntryAlreadyExistsError(EC2ClientError):
def __init__(self, rule_number): def __init__(self, rule_number):
super(NetworkAclEntryAlreadyExistsError, self).__init__( super().__init__(
"NetworkAclEntryAlreadyExists", "NetworkAclEntryAlreadyExists",
"The network acl entry identified by {} already exists.".format( "The network acl entry identified by {} already exists.".format(
rule_number rule_number
@ -562,14 +573,14 @@ class NetworkAclEntryAlreadyExistsError(EC2ClientError):
class InvalidSubnetRangeError(EC2ClientError): class InvalidSubnetRangeError(EC2ClientError):
def __init__(self, cidr_block): def __init__(self, cidr_block):
super(InvalidSubnetRangeError, self).__init__( super().__init__(
"InvalidSubnet.Range", "The CIDR '{}' is invalid.".format(cidr_block) "InvalidSubnet.Range", "The CIDR '{}' is invalid.".format(cidr_block)
) )
class InvalidCIDRBlockParameterError(EC2ClientError): class InvalidCIDRBlockParameterError(EC2ClientError):
def __init__(self, cidr_block): def __init__(self, cidr_block):
super(InvalidCIDRBlockParameterError, self).__init__( super().__init__(
"InvalidParameterValue", "InvalidParameterValue",
"Value ({}) for parameter cidrBlock is invalid. This is not a valid CIDR block.".format( "Value ({}) for parameter cidrBlock is invalid. This is not a valid CIDR block.".format(
cidr_block cidr_block
@ -579,7 +590,7 @@ class InvalidCIDRBlockParameterError(EC2ClientError):
class InvalidDestinationCIDRBlockParameterError(EC2ClientError): class InvalidDestinationCIDRBlockParameterError(EC2ClientError):
def __init__(self, cidr_block): def __init__(self, cidr_block):
super(InvalidDestinationCIDRBlockParameterError, self).__init__( super().__init__(
"InvalidParameterValue", "InvalidParameterValue",
"Value ({}) for parameter destinationCidrBlock is invalid. This is not a valid CIDR block.".format( "Value ({}) for parameter destinationCidrBlock is invalid. This is not a valid CIDR block.".format(
cidr_block cidr_block
@ -589,7 +600,7 @@ class InvalidDestinationCIDRBlockParameterError(EC2ClientError):
class InvalidSubnetConflictError(EC2ClientError): class InvalidSubnetConflictError(EC2ClientError):
def __init__(self, cidr_block): def __init__(self, cidr_block):
super(InvalidSubnetConflictError, self).__init__( super().__init__(
"InvalidSubnet.Conflict", "InvalidSubnet.Conflict",
"The CIDR '{}' conflicts with another subnet".format(cidr_block), "The CIDR '{}' conflicts with another subnet".format(cidr_block),
) )
@ -597,7 +608,7 @@ class InvalidSubnetConflictError(EC2ClientError):
class InvalidVPCRangeError(EC2ClientError): class InvalidVPCRangeError(EC2ClientError):
def __init__(self, cidr_block): def __init__(self, cidr_block):
super(InvalidVPCRangeError, self).__init__( super().__init__(
"InvalidVpc.Range", "The CIDR '{}' is invalid.".format(cidr_block) "InvalidVpc.Range", "The CIDR '{}' is invalid.".format(cidr_block)
) )
@ -605,7 +616,7 @@ class InvalidVPCRangeError(EC2ClientError):
# accept exception # accept exception
class OperationNotPermitted2(EC2ClientError): class OperationNotPermitted2(EC2ClientError):
def __init__(self, client_region, pcx_id, acceptor_region): def __init__(self, client_region, pcx_id, acceptor_region):
super(OperationNotPermitted2, self).__init__( super().__init__(
"OperationNotPermitted", "OperationNotPermitted",
"Incorrect region ({0}) specified for this request." "Incorrect region ({0}) specified for this request."
"VPC peering connection {1} must be accepted in region {2}".format( "VPC peering connection {1} must be accepted in region {2}".format(
@ -617,7 +628,7 @@ class OperationNotPermitted2(EC2ClientError):
# reject exception # reject exception
class OperationNotPermitted3(EC2ClientError): class OperationNotPermitted3(EC2ClientError):
def __init__(self, client_region, pcx_id, acceptor_region): def __init__(self, client_region, pcx_id, acceptor_region):
super(OperationNotPermitted3, self).__init__( super().__init__(
"OperationNotPermitted", "OperationNotPermitted",
"Incorrect region ({0}) specified for this request." "Incorrect region ({0}) specified for this request."
"VPC peering connection {1} must be accepted or rejected in region {2}".format( "VPC peering connection {1} must be accepted or rejected in region {2}".format(
@ -628,7 +639,7 @@ class OperationNotPermitted3(EC2ClientError):
class OperationNotPermitted4(EC2ClientError): class OperationNotPermitted4(EC2ClientError):
def __init__(self, instance_id): def __init__(self, instance_id):
super(OperationNotPermitted4, self).__init__( super().__init__(
"OperationNotPermitted", "OperationNotPermitted",
"The instance '{0}' may not be terminated. Modify its 'disableApiTermination' " "The instance '{0}' may not be terminated. Modify its 'disableApiTermination' "
"instance attribute and try again.".format(instance_id), "instance attribute and try again.".format(instance_id),
@ -637,7 +648,7 @@ class OperationNotPermitted4(EC2ClientError):
class InvalidLaunchTemplateNameError(EC2ClientError): class InvalidLaunchTemplateNameError(EC2ClientError):
def __init__(self): def __init__(self):
super(InvalidLaunchTemplateNameError, self).__init__( super().__init__(
"InvalidLaunchTemplateName.AlreadyExistsException", "InvalidLaunchTemplateName.AlreadyExistsException",
"Launch template name already in use.", "Launch template name already in use.",
) )
@ -645,7 +656,7 @@ class InvalidLaunchTemplateNameError(EC2ClientError):
class InvalidParameterDependency(EC2ClientError): class InvalidParameterDependency(EC2ClientError):
def __init__(self, param, param_needed): def __init__(self, param, param_needed):
super(InvalidParameterDependency, self).__init__( super().__init__(
"InvalidParameterDependency", "InvalidParameterDependency",
"The parameter [{0}] requires the parameter {1} to be set.".format( "The parameter [{0}] requires the parameter {1} to be set.".format(
param, param_needed param, param_needed
@ -655,7 +666,7 @@ class InvalidParameterDependency(EC2ClientError):
class IncorrectStateIamProfileAssociationError(EC2ClientError): class IncorrectStateIamProfileAssociationError(EC2ClientError):
def __init__(self, instance_id): def __init__(self, instance_id):
super(IncorrectStateIamProfileAssociationError, self).__init__( super().__init__(
"IncorrectState", "IncorrectState",
"There is an existing association for instance {0}".format(instance_id), "There is an existing association for instance {0}".format(instance_id),
) )
@ -663,7 +674,7 @@ class IncorrectStateIamProfileAssociationError(EC2ClientError):
class InvalidAssociationIDIamProfileAssociationError(EC2ClientError): class InvalidAssociationIDIamProfileAssociationError(EC2ClientError):
def __init__(self, association_id): def __init__(self, association_id):
super(InvalidAssociationIDIamProfileAssociationError, self).__init__( super().__init__(
"InvalidAssociationID.NotFound", "InvalidAssociationID.NotFound",
"An invalid association-id of '{0}' was given".format(association_id), "An invalid association-id of '{0}' was given".format(association_id),
) )
@ -671,7 +682,7 @@ class InvalidAssociationIDIamProfileAssociationError(EC2ClientError):
class InvalidVpcEndPointIdError(EC2ClientError): class InvalidVpcEndPointIdError(EC2ClientError):
def __init__(self, vpc_end_point_id): def __init__(self, vpc_end_point_id):
super(InvalidVpcEndPointIdError, self).__init__( super().__init__(
"InvalidVpcEndpointId.NotFound", "InvalidVpcEndpointId.NotFound",
"The VpcEndPoint ID '{0}' does not exist".format(vpc_end_point_id), "The VpcEndPoint ID '{0}' does not exist".format(vpc_end_point_id),
) )
@ -679,7 +690,7 @@ class InvalidVpcEndPointIdError(EC2ClientError):
class InvalidTaggableResourceType(EC2ClientError): class InvalidTaggableResourceType(EC2ClientError):
def __init__(self, resource_type): def __init__(self, resource_type):
super(InvalidTaggableResourceType, self).__init__( super().__init__(
"InvalidParameterValue", "InvalidParameterValue",
"'{}' is not a valid taggable resource type for this operation.".format( "'{}' is not a valid taggable resource type for this operation.".format(
resource_type resource_type
@ -689,7 +700,7 @@ class InvalidTaggableResourceType(EC2ClientError):
class GenericInvalidParameterValueError(EC2ClientError): class GenericInvalidParameterValueError(EC2ClientError):
def __init__(self, attribute, value): def __init__(self, attribute, value):
super(GenericInvalidParameterValueError, self).__init__( super().__init__(
"InvalidParameterValue", "InvalidParameterValue",
"invalid value for parameter {0}: {1}".format(attribute, value), "invalid value for parameter {0}: {1}".format(attribute, value),
) )
@ -697,7 +708,7 @@ class GenericInvalidParameterValueError(EC2ClientError):
class InvalidSubnetCidrBlockAssociationID(EC2ClientError): class InvalidSubnetCidrBlockAssociationID(EC2ClientError):
def __init__(self, association_id): def __init__(self, association_id):
super(InvalidSubnetCidrBlockAssociationID, self).__init__( super().__init__(
"InvalidSubnetCidrBlockAssociationID.NotFound", "InvalidSubnetCidrBlockAssociationID.NotFound",
"The subnet CIDR block with association ID '{0}' does not exist".format( "The subnet CIDR block with association ID '{0}' does not exist".format(
association_id association_id
@ -707,7 +718,7 @@ class InvalidSubnetCidrBlockAssociationID(EC2ClientError):
class InvalidCarrierGatewayID(EC2ClientError): class InvalidCarrierGatewayID(EC2ClientError):
def __init__(self, carrier_gateway_id): def __init__(self, carrier_gateway_id):
super(InvalidCarrierGatewayID, self).__init__( super().__init__(
"InvalidCarrierGatewayID.NotFound", "InvalidCarrierGatewayID.NotFound",
"The CarrierGateway ID '{0}' does not exist".format(carrier_gateway_id), "The CarrierGateway ID '{0}' does not exist".format(carrier_gateway_id),
) )

View File

@ -1,19 +1,23 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import copy import copy
from datetime import datetime
import itertools import itertools
import ipaddress import ipaddress
import json import json
import os from operator import itemgetter
from os import listdir
from os import environ
import pathlib import pathlib
import re import re
import warnings import warnings
import weakref
from collections import defaultdict
from collections import OrderedDict
from boto3 import Session 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.instance import Instance as BotoInstance, Reservation
from moto.packages.boto.ec2.blockdevicemapping import ( from moto.packages.boto.ec2.blockdevicemapping import (
BlockDeviceMapping, BlockDeviceMapping,
@ -24,7 +28,6 @@ from moto.packages.boto.ec2.spotinstancerequest import (
) )
from moto.packages.boto.ec2.launchspecification import LaunchSpecification from moto.packages.boto.ec2.launchspecification import LaunchSpecification
from collections import OrderedDict
from moto.core import BaseBackend from moto.core import BaseBackend
from moto.core.models import Model, BaseModel, CloudFormationModel from moto.core.models import Model, BaseModel, CloudFormationModel
from moto.core.utils import ( from moto.core.utils import (
@ -34,7 +37,6 @@ from moto.core.utils import (
from moto.core import ACCOUNT_ID from moto.core import ACCOUNT_ID
from moto.kms import kms_backends from moto.kms import kms_backends
from moto.utilities.utils import load_resource, merge_multiple_dicts, filter_resources from moto.utilities.utils import load_resource, merge_multiple_dicts, filter_resources
from os import listdir
from .exceptions import ( from .exceptions import (
CidrLimitExceeded, CidrLimitExceeded,
@ -65,6 +67,9 @@ from .exceptions import (
InvalidKeyPairFormatError, InvalidKeyPairFormatError,
InvalidKeyPairNameError, InvalidKeyPairNameError,
InvalidAggregationIntervalParameterError, InvalidAggregationIntervalParameterError,
InvalidServiceName,
InvalidFilter,
InvalidNextToken,
InvalidDependantParameterError, InvalidDependantParameterError,
InvalidDependantParameterTypeError, InvalidDependantParameterTypeError,
InvalidFlowLogIdError, InvalidFlowLogIdError,
@ -192,20 +197,22 @@ offerings_path = "resources/instance_type_offerings"
INSTANCE_TYPE_OFFERINGS = {} INSTANCE_TYPE_OFFERINGS = {}
for location_type in listdir(root / offerings_path): for location_type in listdir(root / offerings_path):
INSTANCE_TYPE_OFFERINGS[location_type] = {} INSTANCE_TYPE_OFFERINGS[location_type] = {}
for region in listdir(root / offerings_path / location_type): for _region in listdir(root / offerings_path / location_type):
full_path = offerings_path + "/" + location_type + "/" + region full_path = offerings_path + "/" + location_type + "/" + _region
INSTANCE_TYPE_OFFERINGS[location_type][ INSTANCE_TYPE_OFFERINGS[location_type][
region.replace(".json", "") _region.replace(".json", "")
] = load_resource(__name__, full_path) ] = load_resource(__name__, full_path)
if "MOTO_AMIS_PATH" in os.environ: if "MOTO_AMIS_PATH" in environ:
with open(os.environ.get("MOTO_AMIS_PATH"), "r", encoding="utf-8") as f: with open(environ.get("MOTO_AMIS_PATH"), "r", encoding="utf-8") as f:
AMIS = json.load(f) AMIS = json.load(f)
else: else:
AMIS = load_resource(__name__, "resources/amis.json") AMIS = load_resource(__name__, "resources/amis.json")
OWNER_ID = ACCOUNT_ID OWNER_ID = ACCOUNT_ID
MAX_NUMBER_OF_ENDPOINT_SERVICES_RESULTS = 1000
DEFAULT_VPC_ENDPOINT_SERVICES = []
def utc_date_and_time(): def utc_date_and_time():
@ -441,15 +448,13 @@ class NetworkInterface(TaggedEC2Resource, CloudFormationModel):
elif filter_name == "description": elif filter_name == "description":
return self.description return self.description
else: else:
return super(NetworkInterface, self).get_filter_value( return super().get_filter_value(filter_name, "DescribeNetworkInterfaces")
filter_name, "DescribeNetworkInterfaces"
)
class NetworkInterfaceBackend(object): class NetworkInterfaceBackend(object):
def __init__(self): def __init__(self):
self.enis = {} self.enis = {}
super(NetworkInterfaceBackend, self).__init__() super().__init__()
def create_network_interface( def create_network_interface(
self, self,
@ -459,7 +464,7 @@ class NetworkInterfaceBackend(object):
group_ids=None, group_ids=None,
description=None, description=None,
tags=None, tags=None,
**kwargs **kwargs,
): ):
eni = NetworkInterface( eni = NetworkInterface(
self, self,
@ -469,7 +474,7 @@ class NetworkInterfaceBackend(object):
group_ids=group_ids, group_ids=group_ids,
description=description, description=description,
tags=tags, tags=tags,
**kwargs **kwargs,
) )
self.enis[eni.id] = eni self.enis[eni.id] = eni
return eni return eni
@ -563,7 +568,7 @@ class Instance(TaggedEC2Resource, BotoInstance, CloudFormationModel):
} }
def __init__(self, ec2_backend, image_id, user_data, security_groups, **kwargs): def __init__(self, ec2_backend, image_id, user_data, security_groups, **kwargs):
super(Instance, self).__init__() super().__init__()
self.ec2_backend = ec2_backend self.ec2_backend = ec2_backend
self.id = random_instance_id() self.id = random_instance_id()
self.lifecycle = kwargs.get("lifecycle") self.lifecycle = kwargs.get("lifecycle")
@ -990,7 +995,7 @@ class Instance(TaggedEC2Resource, BotoInstance, CloudFormationModel):
class InstanceBackend(object): class InstanceBackend(object):
def __init__(self): def __init__(self):
self.reservations = OrderedDict() self.reservations = OrderedDict()
super(InstanceBackend, self).__init__() super().__init__()
def get_instance(self, instance_id): def get_instance(self, instance_id):
for instance in self.all_instances(): for instance in self.all_instances():
@ -1220,7 +1225,7 @@ class InstanceBackend(object):
class InstanceTypeBackend(object): class InstanceTypeBackend(object):
def __init__(self): def __init__(self):
super(InstanceTypeBackend, self).__init__() super().__init__()
def describe_instance_types(self, instance_types=None): def describe_instance_types(self, instance_types=None):
matches = INSTANCE_TYPES.values() matches = INSTANCE_TYPES.values()
@ -1236,7 +1241,7 @@ class InstanceTypeBackend(object):
class InstanceTypeOfferingBackend(object): class InstanceTypeOfferingBackend(object):
def __init__(self): def __init__(self):
super(InstanceTypeOfferingBackend, self).__init__() super().__init__()
def describe_instance_type_offerings(self, location_type=None, filters=None): def describe_instance_type_offerings(self, location_type=None, filters=None):
location_type = location_type or "region" location_type = location_type or "region"
@ -1283,7 +1288,7 @@ class KeyPair(object):
class KeyPairBackend(object): class KeyPairBackend(object):
def __init__(self): def __init__(self):
self.keypairs = {} self.keypairs = {}
super(KeyPairBackend, self).__init__() super().__init__()
def create_key_pair(self, name): def create_key_pair(self, name):
if name in self.keypairs: if name in self.keypairs:
@ -1359,7 +1364,7 @@ class TagBackend(object):
def __init__(self): def __init__(self):
self.tags = defaultdict(dict) self.tags = defaultdict(dict)
super(TagBackend, self).__init__() super().__init__()
def create_tags(self, resource_ids, tags): def create_tags(self, resource_ids, tags):
if None in set([tags[tag] for tag in tags]): if None in set([tags[tag] for tag in tags]):
@ -1581,7 +1586,7 @@ class Ami(TaggedEC2Resource):
elif filter_name == "owner-alias": elif filter_name == "owner-alias":
return self.owner_alias return self.owner_alias
else: else:
return super(Ami, self).get_filter_value(filter_name, "DescribeImages") return super().get_filter_value(filter_name, "DescribeImages")
class AmiBackend(object): class AmiBackend(object):
@ -1589,10 +1594,8 @@ class AmiBackend(object):
def __init__(self): def __init__(self):
self.amis = {} self.amis = {}
self._load_amis() self._load_amis()
super().__init__()
super(AmiBackend, self).__init__()
def _load_amis(self): def _load_amis(self):
for ami in AMIS: for ami in AMIS:
@ -2335,7 +2338,7 @@ class SecurityGroupBackend(object):
self.sg_old_ingress_ruls = {} self.sg_old_ingress_ruls = {}
self.sg_old_egress_ruls = {} self.sg_old_egress_ruls = {}
super(SecurityGroupBackend, self).__init__() super().__init__()
def create_security_group( def create_security_group(
self, name, description, vpc_id=None, tags=None, force=False, is_default=None 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": elif filter_name == "availability-zone":
return self.zone.name return self.zone.name
else: else:
return super(Volume, self).get_filter_value(filter_name, "DescribeVolumes") return super().get_filter_value(filter_name, "DescribeVolumes")
class Snapshot(TaggedEC2Resource): class Snapshot(TaggedEC2Resource):
@ -3144,9 +3147,7 @@ class Snapshot(TaggedEC2Resource):
elif filter_name == "owner-id": elif filter_name == "owner-id":
return self.owner_id return self.owner_id
else: else:
return super(Snapshot, self).get_filter_value( return super().get_filter_value(filter_name, "DescribeSnapshots")
filter_name, "DescribeSnapshots"
)
class EBSBackend(object): class EBSBackend(object):
@ -3154,7 +3155,7 @@ class EBSBackend(object):
self.volumes = {} self.volumes = {}
self.attachments = {} self.attachments = {}
self.snapshots = {} self.snapshots = {}
super(EBSBackend, self).__init__() super().__init__()
def create_volume( def create_volume(
self, size, zone_name, snapshot_id=None, encrypted=False, kms_key_id=None self, size, zone_name, snapshot_id=None, encrypted=False, kms_key_id=None
@ -3444,7 +3445,7 @@ class VPC(TaggedEC2Resource, CloudFormationModel):
return None return None
return self.dhcp_options.id return self.dhcp_options.id
else: 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): def modify_vpc_tenancy(self, tenancy):
if tenancy != "default": if tenancy != "default":
@ -3539,7 +3540,7 @@ class VPCBackend(object):
self.vpcs = {} self.vpcs = {}
self.vpc_end_points = {} self.vpc_end_points = {}
self.vpc_refs[self.__class__].add(weakref.ref(self)) self.vpc_refs[self.__class__].add(weakref.ref(self))
super(VPCBackend, self).__init__() super().__init__()
@classmethod @classmethod
def get_vpc_refs(cls): def get_vpc_refs(cls):
@ -3831,19 +3832,172 @@ class VPCBackend(object):
return generic_filter(filters, vpc_end_points) return generic_filter(filters, vpc_end_points)
def get_vpc_end_point_services(self): @staticmethod
vpc_end_point_services = self.vpc_end_points.values() 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 = [] zones = [
for value in vpc_end_point_services: zone.name
services.append(value.service_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 { return {
"servicesDetails": vpc_end_point_services, "servicesDetails": filtered_services[start : start + max_results],
"services": services, "serviceNames": [
"availability_zones": availability_zones, x["ServiceName"] for x in filtered_services[start : start + max_results]
],
"nextToken": next_token,
} }
def get_vpc_end_point(self, vpc_end_point_id): def get_vpc_end_point(self, vpc_end_point_id):
@ -3931,7 +4085,7 @@ class VPCPeeringConnectionBackend(object):
def __init__(self): def __init__(self):
self.vpc_pcxs = {} self.vpc_pcxs = {}
self.vpc_pcx_refs[self.__class__].add(weakref.ref(self)) self.vpc_pcx_refs[self.__class__].add(weakref.ref(self))
super(VPCPeeringConnectionBackend, self).__init__() super().__init__()
@classmethod @classmethod
def get_vpc_pcx_refs(cls): def get_vpc_pcx_refs(cls):
@ -4130,7 +4284,7 @@ class Subnet(TaggedEC2Resource, CloudFormationModel):
elif filter_name == "state": elif filter_name == "state":
return self.state return self.state
else: 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): def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
@ -4202,7 +4356,7 @@ class SubnetBackend(object):
def __init__(self): def __init__(self):
# maps availability zone to dict of (subnet_id, subnet) # maps availability zone to dict of (subnet_id, subnet)
self.subnets = defaultdict(dict) self.subnets = defaultdict(dict)
super(SubnetBackend, self).__init__() super().__init__()
def get_subnet(self, subnet_id): def get_subnet(self, subnet_id):
for subnets in self.subnets.values(): for subnets in self.subnets.values():
@ -4467,15 +4621,13 @@ class FlowLogs(TaggedEC2Resource, CloudFormationModel):
elif filter_name == "deliver-log-status": elif filter_name == "deliver-log-status":
return "SUCCESS" return "SUCCESS"
else: else:
return super(FlowLogs, self).get_filter_value( return super().get_filter_value(filter_name, "DescribeFlowLogs")
filter_name, "DescribeFlowLogs"
)
class FlowLogsBackend(object): class FlowLogsBackend(object):
def __init__(self): def __init__(self):
self.flow_logs = defaultdict(dict) self.flow_logs = defaultdict(dict)
super(FlowLogsBackend, self).__init__() super().__init__()
def _validate_request( def _validate_request(
self, self,
@ -4683,7 +4835,7 @@ class SubnetRouteTableAssociation(CloudFormationModel):
class SubnetRouteTableAssociationBackend(object): class SubnetRouteTableAssociationBackend(object):
def __init__(self): def __init__(self):
self.subnet_associations = {} self.subnet_associations = {}
super(SubnetRouteTableAssociationBackend, self).__init__() super().__init__()
def create_subnet_association(self, route_table_id, subnet_id): def create_subnet_association(self, route_table_id, subnet_id):
subnet_association = SubnetRouteTableAssociation(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": elif filter_name == "association.subnet-id":
return self.associations.values() return self.associations.values()
else: else:
return super(RouteTable, self).get_filter_value( return super().get_filter_value(filter_name, "DescribeRouteTables")
filter_name, "DescribeRouteTables"
)
class RouteTableBackend(object): class RouteTableBackend(object):
def __init__(self): def __init__(self):
self.route_tables = {} self.route_tables = {}
super(RouteTableBackend, self).__init__() super().__init__()
def create_route_table(self, vpc_id, tags=[], main=False): def create_route_table(self, vpc_id, tags=[], main=False):
route_table_id = random_route_table_id() route_table_id = random_route_table_id()
@ -5035,7 +5185,7 @@ class ManagedPrefixListBackend(object):
def __init__(self): def __init__(self):
self.managed_prefix_lists = {} self.managed_prefix_lists = {}
self.create_default_pls() self.create_default_pls()
super(ManagedPrefixListBackend, self).__init__() super().__init__()
def create_managed_prefix_list( def create_managed_prefix_list(
self, self,
@ -5161,7 +5311,7 @@ class ManagedPrefixListBackend(object):
class RouteBackend(object): class RouteBackend(object):
def __init__(self): def __init__(self):
super(RouteBackend, self).__init__() super().__init__()
def create_route( def create_route(
self, self,
@ -5362,7 +5512,7 @@ class InternetGateway(TaggedEC2Resource, CloudFormationModel):
class InternetGatewayBackend(object): class InternetGatewayBackend(object):
def __init__(self): def __init__(self):
self.internet_gateways = {} self.internet_gateways = {}
super(InternetGatewayBackend, self).__init__() super().__init__()
def create_internet_gateway(self, tags=[]): def create_internet_gateway(self, tags=[]):
igw = InternetGateway(self) igw = InternetGateway(self)
@ -5434,7 +5584,7 @@ class CarrierGateway(TaggedEC2Resource):
class CarrierGatewayBackend(object): class CarrierGatewayBackend(object):
def __init__(self): def __init__(self):
self.carrier_gateways = {} self.carrier_gateways = {}
super(CarrierGatewayBackend, self).__init__() super().__init__()
def create_carrier_gateway(self, vpc_id, tags=None): def create_carrier_gateway(self, vpc_id, tags=None):
vpc = self.get_vpc(vpc_id) vpc = self.get_vpc(vpc_id)
@ -5490,7 +5640,7 @@ class EgressOnlyInternetGateway(TaggedEC2Resource):
class EgressOnlyInternetGatewayBackend(object): class EgressOnlyInternetGatewayBackend(object):
def __init__(self): def __init__(self):
self.egress_only_internet_gateway_backend = {} self.egress_only_internet_gateway_backend = {}
super(EgressOnlyInternetGatewayBackend, self).__init__() super().__init__()
def create_egress_only_internet_gateway(self, vpc_id, tags=None): def create_egress_only_internet_gateway(self, vpc_id, tags=None):
vpc = self.get_vpc(vpc_id) vpc = self.get_vpc(vpc_id)
@ -5563,7 +5713,7 @@ class VPCGatewayAttachment(CloudFormationModel):
class VPCGatewayAttachmentBackend(object): class VPCGatewayAttachmentBackend(object):
def __init__(self): def __init__(self):
self.gateway_attachments = {} self.gateway_attachments = {}
super(VPCGatewayAttachmentBackend, self).__init__() super().__init__()
def create_vpc_gateway_attachment(self, vpc_id, gateway_id): def create_vpc_gateway_attachment(self, vpc_id, gateway_id):
attachment = VPCGatewayAttachment(vpc_id, gateway_id) attachment = VPCGatewayAttachment(vpc_id, gateway_id)
@ -5594,9 +5744,9 @@ class SpotInstanceRequest(BotoSpotRequest, TaggedEC2Resource):
subnet_id, subnet_id,
tags, tags,
spot_fleet_id, spot_fleet_id,
**kwargs **kwargs,
): ):
super(SpotInstanceRequest, self).__init__(**kwargs) super().__init__(**kwargs)
ls = LaunchSpecification() ls = LaunchSpecification()
self.ec2_backend = ec2_backend self.ec2_backend = ec2_backend
self.launch_specification = ls self.launch_specification = ls
@ -5638,9 +5788,7 @@ class SpotInstanceRequest(BotoSpotRequest, TaggedEC2Resource):
elif filter_name == "spot-instance-request-id": elif filter_name == "spot-instance-request-id":
return self.id return self.id
else: else:
return super(SpotInstanceRequest, self).get_filter_value( return super().get_filter_value(filter_name, "DescribeSpotInstanceRequests")
filter_name, "DescribeSpotInstanceRequests"
)
def launch_instance(self): def launch_instance(self):
reservation = self.ec2_backend.add_instances( reservation = self.ec2_backend.add_instances(
@ -5663,7 +5811,7 @@ class SpotInstanceRequest(BotoSpotRequest, TaggedEC2Resource):
class SpotRequestBackend(object, metaclass=Model): class SpotRequestBackend(object, metaclass=Model):
def __init__(self): def __init__(self):
self.spot_instance_requests = {} self.spot_instance_requests = {}
super(SpotRequestBackend, self).__init__() super().__init__()
def request_spot_instances( def request_spot_instances(
self, self,
@ -5974,7 +6122,7 @@ class SpotFleetRequest(TaggedEC2Resource, CloudFormationModel):
class SpotFleetBackend(object): class SpotFleetBackend(object):
def __init__(self): def __init__(self):
self.spot_fleet_requests = {} self.spot_fleet_requests = {}
super(SpotFleetBackend, self).__init__() super().__init__()
def request_spot_fleet( def request_spot_fleet(
self, self,
@ -6141,15 +6289,13 @@ class ElasticAddress(TaggedEC2Resource, CloudFormationModel):
# TODO: implement network-interface-owner-id # TODO: implement network-interface-owner-id
raise FilterNotImplementedError(filter_name, "DescribeAddresses") raise FilterNotImplementedError(filter_name, "DescribeAddresses")
else: else:
return super(ElasticAddress, self).get_filter_value( return super().get_filter_value(filter_name, "DescribeAddresses")
filter_name, "DescribeAddresses"
)
class ElasticAddressBackend(object): class ElasticAddressBackend(object):
def __init__(self): def __init__(self):
self.addresses = [] self.addresses = []
super(ElasticAddressBackend, self).__init__() super().__init__()
def allocate_address(self, domain, address=None, tags=None): def allocate_address(self, domain, address=None, tags=None):
if domain not in ["standard", "vpc"]: if domain not in ["standard", "vpc"]:
@ -6322,9 +6468,7 @@ class DHCPOptionsSet(TaggedEC2Resource):
values = [item for item in list(self._options.values()) if item] values = [item for item in list(self._options.values()) if item]
return itertools.chain(*values) return itertools.chain(*values)
else: else:
return super(DHCPOptionsSet, self).get_filter_value( return super().get_filter_value(filter_name, "DescribeDhcpOptions")
filter_name, "DescribeDhcpOptions"
)
@property @property
def options(self): def options(self):
@ -6334,7 +6478,7 @@ class DHCPOptionsSet(TaggedEC2Resource):
class DHCPOptionsSetBackend(object): class DHCPOptionsSetBackend(object):
def __init__(self): def __init__(self):
self.dhcp_options_sets = {} self.dhcp_options_sets = {}
super(DHCPOptionsSetBackend, self).__init__() super().__init__()
def associate_dhcp_options(self, dhcp_options, vpc): def associate_dhcp_options(self, dhcp_options, vpc):
dhcp_options.vpc = vpc dhcp_options.vpc = vpc
@ -6440,15 +6584,13 @@ class VPNConnection(TaggedEC2Resource):
self.add_tags(tags or {}) self.add_tags(tags or {})
def get_filter_value(self, filter_name): def get_filter_value(self, filter_name):
return super(VPNConnection, self).get_filter_value( return super().get_filter_value(filter_name, "DescribeVpnConnections")
filter_name, "DescribeVpnConnections"
)
class VPNConnectionBackend(object): class VPNConnectionBackend(object):
def __init__(self): def __init__(self):
self.vpn_connections = {} self.vpn_connections = {}
super(VPNConnectionBackend, self).__init__() super().__init__()
def create_vpn_connection( def create_vpn_connection(
self, self,
@ -6514,7 +6656,7 @@ class VPNConnectionBackend(object):
class NetworkAclBackend(object): class NetworkAclBackend(object):
def __init__(self): def __init__(self):
self.network_acls = {} self.network_acls = {}
super(NetworkAclBackend, self).__init__() super().__init__()
def get_network_acl(self, network_acl_id): def get_network_acl(self, network_acl_id):
network_acl = self.network_acls.get(network_acl_id, None) 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.new_association_id = new_association_id
self.subnet_id = subnet_id self.subnet_id = subnet_id
self.network_acl_id = network_acl_id self.network_acl_id = network_acl_id
super(NetworkAclAssociation, self).__init__() super().__init__()
class NetworkAcl(TaggedEC2Resource): class NetworkAcl(TaggedEC2Resource):
@ -6729,9 +6871,7 @@ class NetworkAcl(TaggedEC2Resource):
elif filter_name == "owner-id": elif filter_name == "owner-id":
return self.owner_id return self.owner_id
else: else:
return super(NetworkAcl, self).get_filter_value( return super().get_filter_value(filter_name, "DescribeNetworkAcls")
filter_name, "DescribeNetworkAcls"
)
class NetworkAclEntry(TaggedEC2Resource): class NetworkAclEntry(TaggedEC2Resource):
@ -6781,7 +6921,7 @@ class VpnGateway(TaggedEC2Resource):
self.state = state self.state = state
self.add_tags(tags or {}) self.add_tags(tags or {})
self.attachments = {} self.attachments = {}
super(VpnGateway, self).__init__() super().__init__()
def get_filter_value(self, filter_name): def get_filter_value(self, filter_name):
if filter_name == "attachment.vpc-id": if filter_name == "attachment.vpc-id":
@ -6792,22 +6932,20 @@ class VpnGateway(TaggedEC2Resource):
return self.id return self.id
elif filter_name == "type": elif filter_name == "type":
return self.type return self.type
return super(VpnGateway, self).get_filter_value( return super().get_filter_value(filter_name, "DescribeVpnGateways")
filter_name, "DescribeVpnGateways"
)
class VpnGatewayAttachment(object): class VpnGatewayAttachment(object):
def __init__(self, vpc_id, state): def __init__(self, vpc_id, state):
self.vpc_id = vpc_id self.vpc_id = vpc_id
self.state = state self.state = state
super(VpnGatewayAttachment, self).__init__() super().__init__()
class VpnGatewayBackend(object): class VpnGatewayBackend(object):
def __init__(self): def __init__(self):
self.vpn_gateways = {} self.vpn_gateways = {}
super(VpnGatewayBackend, self).__init__() super().__init__()
def create_vpn_gateway( def create_vpn_gateway(
self, type="ipsec.1", amazon_side_asn=None, availability_zone=None, tags=None self, type="ipsec.1", amazon_side_asn=None, availability_zone=None, tags=None
@ -6870,18 +7008,16 @@ class CustomerGateway(TaggedEC2Resource):
self.attachments = {} self.attachments = {}
self.state = state self.state = state
self.add_tags(tags or {}) self.add_tags(tags or {})
super(CustomerGateway, self).__init__() super().__init__()
def get_filter_value(self, filter_name): def get_filter_value(self, filter_name):
return super(CustomerGateway, self).get_filter_value( return super().get_filter_value(filter_name, "DescribeCustomerGateways")
filter_name, "DescribeCustomerGateways"
)
class CustomerGatewayBackend(object): class CustomerGatewayBackend(object):
def __init__(self): def __init__(self):
self.customer_gateways = {} self.customer_gateways = {}
super(CustomerGatewayBackend, self).__init__() super().__init__()
def create_customer_gateway( def create_customer_gateway(
self, type="ipsec.1", ip_address=None, bgp_asn=None, tags=None self, type="ipsec.1", ip_address=None, bgp_asn=None, tags=None
@ -7006,7 +7142,7 @@ class TransitGateway(TaggedEC2Resource, CloudFormationModel):
class TransitGatewayBackend(object): class TransitGatewayBackend(object):
def __init__(self): def __init__(self):
self.transit_gateways = {} self.transit_gateways = {}
super(TransitGatewayBackend, self).__init__() super().__init__()
def create_transit_gateway(self, description=None, options=None, tags=[]): def create_transit_gateway(self, description=None, options=None, tags=[]):
transit_gateway = TransitGateway(self, description, options) transit_gateway = TransitGateway(self, description, options)
@ -7081,7 +7217,7 @@ class TransitGatewayRouteTable(TaggedEC2Resource):
class TransitGatewayRouteTableBackend(object): class TransitGatewayRouteTableBackend(object):
def __init__(self): def __init__(self):
self.transit_gateways_route_tables = {} self.transit_gateways_route_tables = {}
super(TransitGatewayRouteTableBackend, self).__init__() super().__init__()
def create_transit_gateway_route_table( def create_transit_gateway_route_table(
self, self,
@ -7400,7 +7536,7 @@ class TransitGatewayPeeringAttachment(TransitGatewayAttachment):
class TransitGatewayAttachmentBackend(object): class TransitGatewayAttachmentBackend(object):
def __init__(self): def __init__(self):
self.transit_gateway_attachments = {} self.transit_gateway_attachments = {}
super(TransitGatewayAttachmentBackend, self).__init__() super().__init__()
def create_transit_gateway_vpn_attachment( def create_transit_gateway_vpn_attachment(
self, vpn_id, transit_gateway_id, tags=[] self, vpn_id, transit_gateway_id, tags=[]
@ -7645,7 +7781,7 @@ class TransitGatewayRelationsBackend(object):
def __init__(self): def __init__(self):
self.transit_gateway_associations = {} self.transit_gateway_associations = {}
self.transit_gateway_propagations = {} self.transit_gateway_propagations = {}
super(TransitGatewayRelationsBackend, self).__init__() super().__init__()
def associate_transit_gateway_route_table( def associate_transit_gateway_route_table(
self, transit_gateway_attachment_id=None, transit_gateway_route_table_id=None self, transit_gateway_attachment_id=None, transit_gateway_route_table_id=None
@ -7793,7 +7929,7 @@ class NatGateway(CloudFormationModel, TaggedEC2Resource):
class NatGatewayBackend(object): class NatGatewayBackend(object):
def __init__(self): def __init__(self):
self.nat_gateways = {} self.nat_gateways = {}
super(NatGatewayBackend, self).__init__() super().__init__()
def describe_nat_gateways(self, filters, nat_gateway_ids): def describe_nat_gateways(self, filters, nat_gateway_ids):
nat_gateways = list(self.nat_gateways.values()) nat_gateways = list(self.nat_gateways.values())
@ -7916,9 +8052,7 @@ class LaunchTemplate(TaggedEC2Resource):
if filter_name == "launch-template-name": if filter_name == "launch-template-name":
return self.name return self.name
else: else:
return super(LaunchTemplate, self).get_filter_value( return super().get_filter_value(filter_name, "DescribeLaunchTemplates")
filter_name, "DescribeLaunchTemplates"
)
class LaunchTemplateBackend(object): class LaunchTemplateBackend(object):
@ -7926,7 +8060,7 @@ class LaunchTemplateBackend(object):
self.launch_template_name_to_ids = {} self.launch_template_name_to_ids = {}
self.launch_templates = OrderedDict() self.launch_templates = OrderedDict()
self.launch_template_insert_order = [] self.launch_template_insert_order = []
super(LaunchTemplateBackend, self).__init__() super().__init__()
def create_launch_template(self, name, description, template_data): def create_launch_template(self, name, description, template_data):
if name in self.launch_template_name_to_ids: if name in self.launch_template_name_to_ids:
@ -7971,7 +8105,7 @@ class IamInstanceProfileAssociation(CloudFormationModel):
class IamInstanceProfileAssociationBackend(object): class IamInstanceProfileAssociationBackend(object):
def __init__(self): def __init__(self):
self.iam_instance_profile_associations = {} self.iam_instance_profile_associations = {}
super(IamInstanceProfileAssociationBackend, self).__init__() super().__init__()
def associate_iam_instance_profile( def associate_iam_instance_profile(
self, self,
@ -8117,7 +8251,7 @@ class EC2Backend(
): ):
def __init__(self, region_name): def __init__(self, region_name):
self.region_name = region_name self.region_name = region_name
super(EC2Backend, self).__init__() super().__init__()
# Default VPC exists by default, which is the current behavior # Default VPC exists by default, which is the current behavior
# of EC2-VPC. See for detail: # of EC2-VPC. See for detail:
@ -8149,6 +8283,15 @@ class EC2Backend(
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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 # Use this to generate a proper error template response when in a response
# handler. # handler.
def raise_error(self, code, message): def raise_error(self, code, message):

View File

@ -133,6 +133,7 @@ class VPCs(BaseResponse):
attr_value = self.querystring.get("%s.Value" % attribute)[0] attr_value = self.querystring.get("%s.Value" % attribute)[0]
self.ec2_backend.modify_vpc_attribute(vpc_id, attr_name, attr_value) self.ec2_backend.modify_vpc_attribute(vpc_id, attr_name, attr_value)
return MODIFY_VPC_ATTRIBUTE_RESPONSE return MODIFY_VPC_ATTRIBUTE_RESPONSE
return None
def associate_vpc_cidr_block(self): def associate_vpc_cidr_block(self):
vpc_id = self._get_param("VpcId") vpc_id = self._get_param("VpcId")
@ -181,7 +182,7 @@ class VPCs(BaseResponse):
service_name = self._get_param("ServiceName") service_name = self._get_param("ServiceName")
route_table_ids = self._get_multi_param("RouteTableId") route_table_ids = self._get_multi_param("RouteTableId")
subnet_ids = self._get_multi_param("SubnetId") subnet_ids = self._get_multi_param("SubnetId")
type = self._get_param("VpcEndpointType") endpoint_type = self._get_param("VpcEndpointType")
policy_document = self._get_param("PolicyDocument") policy_document = self._get_param("PolicyDocument")
client_token = self._get_param("ClientToken") client_token = self._get_param("ClientToken")
tags = self._get_multi_param("TagSpecification") tags = self._get_multi_param("TagSpecification")
@ -192,7 +193,7 @@ class VPCs(BaseResponse):
vpc_end_point = self.ec2_backend.create_vpc_endpoint( vpc_end_point = self.ec2_backend.create_vpc_endpoint(
vpc_id=vpc_id, vpc_id=vpc_id,
service_name=service_name, service_name=service_name,
type=type, type=endpoint_type,
policy_document=policy_document, policy_document=policy_document,
route_table_ids=route_table_ids, route_table_ids=route_table_ids,
subnet_ids=subnet_ids, subnet_ids=subnet_ids,
@ -205,7 +206,14 @@ class VPCs(BaseResponse):
return template.render(vpc_end_point=vpc_end_point) return template.render(vpc_end_point=vpc_end_point)
def describe_vpc_endpoint_services(self): 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) template = self.response_template(DESCRIBE_VPC_ENDPOINT_SERVICES_RESPONSE)
return template.render(vpc_end_points=vpc_end_point_services) 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/"> DESCRIBE_VPC_ENDPOINT_SERVICES_RESPONSE = """<DescribeVpcEndpointServicesResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>19a9ff46-7df6-49b8-9726-3df27527089d</requestId> <requestId>19a9ff46-7df6-49b8-9726-3df27527089d</requestId>
<serviceNameSet> <serviceNameSet>
{% for serviceName in vpc_end_points.services %} {% for serviceName in vpc_end_points.serviceNames %}
<item>{{ serviceName }}</item> <item>{{ serviceName }}</item>
{% endfor %} {% endfor %}
</serviceNameSet> </serviceNameSet>
<serviceDetailSet> <serviceDetailSet>
{% for service in vpc_end_points.servicesDetails %} {% for service in vpc_end_points.servicesDetails %}
<item> <item>
<owner>amazon</owner> <acceptanceRequired>{{ 'true' if service.AcceptanceRequired else 'false' }}</acceptanceRequired>
<serviceType>
<item>
<serviceType>{{ service.type }}</serviceType>
</item>
</serviceType>
<baseEndpointDnsNameSet>
<item>{{ ".".join((service.service_name.split(".")[::-1])) }}</item>
</baseEndpointDnsNameSet>
<acceptanceRequired>false</acceptanceRequired>
<availabilityZoneSet> <availabilityZoneSet>
{% for zone in vpc_end_points.availability_zones %} {% for zone in service.AvailabilityZones %}
<item>{{ zone.name }}</item> <item>{{ zone }}</item>
{% endfor %} {% endfor %}
</availabilityZoneSet> </availabilityZoneSet>
<serviceName>{{ service.service_name }}</serviceName> <baseEndpointDnsNameSet>
<vpcEndpointPolicySupported>true</vpcEndpointPolicySupported> {% for endpoint in service.BaseEndpointDnsNames %}
</item> <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 %} {% endfor %}
</serviceDetailSet> </serviceDetailSet>
{% if vpc_end_points.nextToken|length %}
<nextToken>{{ vpc_end_points.nextToken }}</nextToken>
{% endif %}
</DescribeVpcEndpointServicesResponse>""" </DescribeVpcEndpointServicesResponse>"""
DESCRIBE_VPC_ENDPOINT_RESPONSE = """<DescribeVpcEndpointsResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/"> DESCRIBE_VPC_ENDPOINT_RESPONSE = """<DescribeVpcEndpointsResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">

View File

@ -335,6 +335,30 @@ class ECRBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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: def _get_repository(self, name, registry_id=None) -> Repository:
repo = self.repositories.get(name) repo = self.repositories.get(name)
reg_id = registry_id or DEFAULT_REGISTRY_ID reg_id = registry_id or DEFAULT_REGISTRY_ID

View File

@ -675,6 +675,13 @@ class EC2ContainerServiceBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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): def _get_cluster(self, name):
# short name or full ARN of the cluster # short name or full ARN of the cluster
cluster_name = name.split("/")[-1] cluster_name = name.split("/")[-1]

View File

@ -79,6 +79,15 @@ class EBBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region) 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): def create_application(self, application_name):
if application_name in self.applications: if application_name in self.applications:
raise InvalidParameterValueError( raise InvalidParameterValueError(

View File

@ -553,6 +553,13 @@ class ELBv2Backend(BaseBackend):
self.target_groups = OrderedDict() self.target_groups = OrderedDict()
self.load_balancers = 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 @property
def ec2_backend(self): def ec2_backend(self):
""" """

View File

@ -397,6 +397,13 @@ class ElasticMapReduceBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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 @property
def ec2_backend(self): def ec2_backend(self):
""" """

View File

@ -915,6 +915,13 @@ class EventsBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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): def _add_default_event_bus(self):
self.event_buses["default"] = EventBus(self.region_name, "default") self.event_buses["default"] = EventBus(self.region_name, "default")

View File

@ -174,6 +174,13 @@ class FirehoseBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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( def create_delivery_stream(
self, self,
region, region,

View File

@ -24,6 +24,13 @@ class GlueBackend(BaseBackend):
self.databases = OrderedDict() self.databases = OrderedDict()
self.crawlers = 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): def create_database(self, database_name, database_input):
if database_name in self.databases: if database_name in self.databases:
raise DatabaseAlreadyExistsException() raise DatabaseAlreadyExistsException()

View File

@ -505,6 +505,20 @@ class IoTBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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): def create_thing(self, thing_name, thing_type_name, attribute_payload):
thing_types = self.list_thing_types() thing_types = self.list_thing_types()
thing_type = None thing_type = None

View File

@ -325,6 +325,13 @@ class KinesisBackend(BaseBackend):
def __init__(self): def __init__(self):
self.streams = OrderedDict() 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( def create_stream(
self, stream_name, shard_count, retention_period_hours, region_name self, stream_name, shard_count, retention_period_hours, region_name
): ):

View File

@ -159,6 +159,13 @@ class KmsBackend(BaseBackend):
self.key_to_aliases = defaultdict(set) self.key_to_aliases = defaultdict(set)
self.tagger = TaggingService(key_name="TagKey", value_name="TagValue") 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( def create_key(
self, policy, key_usage, customer_master_key_spec, description, tags, region self, policy, key_usage, customer_master_key_spec, description, tags, region
): ):

View File

@ -551,6 +551,13 @@ class LogsBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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): def create_log_group(self, log_group_name, tags, **kwargs):
if log_group_name in self.groups: if log_group_name in self.groups:
raise ResourceAlreadyExistsException() raise ResourceAlreadyExistsException()

View File

@ -847,6 +847,15 @@ class RDS2Backend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region) 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): def create_database(self, db_kwargs):
database_id = db_kwargs["db_instance_identifier"] database_id = db_kwargs["db_instance_identifier"]
database = Database(**db_kwargs) database = Database(**db_kwargs)

View File

@ -574,6 +574,15 @@ class RedshiftBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(ec2_backend, region_name) 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): def enable_snapshot_copy(self, **kwargs):
cluster_identifier = kwargs["cluster_identifier"] cluster_identifier = kwargs["cluster_identifier"]
cluster = self.clusters[cluster_identifier] cluster = self.clusters[cluster_identifier]

View File

@ -1,11 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals
import json import json
import os import os
import base64 import base64
import datetime import datetime
import pytz
import hashlib import hashlib
import copy import copy
import itertools import itertools
@ -18,8 +15,9 @@ import sys
import time import time
import uuid import uuid
from bisect import insort from bisect import insort
import pytz
from moto.core import ACCOUNT_ID, BaseBackend, BaseModel, CloudFormationModel 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.core.utils import iso_8601_datetime_without_milliseconds_s3, rfc_1123_datetime
from moto.cloudwatch.models import MetricDatum from moto.cloudwatch.models import MetricDatum
@ -1301,6 +1299,38 @@ class S3Backend(BaseBackend):
self.account_public_access_block = None self.account_public_access_block = None
self.tagger = TaggingService() 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! # TODO: This is broken! DO NOT IMPORT MUTABLE DATA TYPES FROM OTHER AREAS -- THIS BREAKS UNMOCKING!
# WRAP WITH A GETTER/SETTER FUNCTION # WRAP WITH A GETTER/SETTER FUNCTION
# Register this class as a CloudWatch Metric Provider # Register this class as a CloudWatch Metric Provider

View File

@ -877,6 +877,58 @@ class SageMakerModelBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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): def create_model(self, **kwargs):
model_obj = Model( model_obj = Model(
region_name=self.region_name, region_name=self.region_name,

View File

@ -182,6 +182,13 @@ class SecretsManagerBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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): def _is_valid_identifier(self, identifier):
return identifier in self.secrets return identifier in self.secrets

View File

@ -387,6 +387,13 @@ class SNSBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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): def update_sms_attributes(self, attrs):
self.sms_attributes.update(attrs) self.sms_attributes.update(attrs)

View File

@ -584,6 +584,13 @@ class SQSBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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): def create_queue(self, name, tags=None, **kwargs):
queue = self.queues.get(name) queue = self.queues.get(name)
if queue: if queue:

View File

@ -688,6 +688,15 @@ class SimpleSystemManagerBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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): def _generate_document_information(self, ssm_document, document_format):
content = self._get_document_content(document_format, ssm_document) content = self._get_document_content(document_format, ssm_document)
base = { base = {

View File

@ -60,6 +60,13 @@ class STSBackend(BaseBackend):
def __init__(self): def __init__(self):
self.assumed_roles = [] 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): def get_session_token(self, duration):
token = Token(duration=duration) token = Token(duration=duration)
return token return token

View File

@ -450,6 +450,15 @@ class TranscribeBackend(BaseBackend):
self.__dict__ = {} self.__dict__ = {}
self.__init__(region_name) 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): def start_transcription_job(self, **kwargs):
name = kwargs.get("transcription_job_name") name = kwargs.get("transcription_job_name")

View File

@ -236,6 +236,13 @@ class XRayBackend(BaseBackend):
self._telemetry_records = [] self._telemetry_records = []
self._segment_collection = SegmentCollection() 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): def add_telemetry_records(self, json):
self._telemetry_records.append(TelemetryRecords.from_json(json)) self._telemetry_records.append(TelemetryRecords.from_json(json))

View 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

View File

@ -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 @mock_ec2
def test_describe_vpc_end_points(): def test_describe_vpc_end_points():
ec2 = boto3.client("ec2", region_name="us-west-1") ec2 = boto3.client("ec2", region_name="us-west-1")