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_service_configurations
- [ ] describe_vpc_endpoint_service_permissions
- [ ] describe_vpc_endpoint_services
- [X] describe_vpc_endpoint_services
- [X] describe_vpc_endpoints
- [X] describe_vpc_peering_connections
- [X] describe_vpcs
@ -4619,4 +4619,4 @@
- workmailmessageflow
- workspaces
- xray
</details>
</details>

View File

@ -416,6 +416,13 @@ class AWSCertificateManagerBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "acm-pca"
)
@staticmethod
def _arn_not_found(arn):
msg = "Certificate with arn {0} not found in account {1}".format(

View File

@ -72,6 +72,13 @@ class ApplicationAutoscalingBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region, ecs)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "application-autoscaling"
)
@property
def applicationautoscaling_backend(self):
return applicationautoscaling_backends[self.region]

View File

@ -80,6 +80,13 @@ class AthenaBackend(BaseBackend):
self.executions = {}
self.named_queries = {}
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "athena"
)
def create_work_group(self, name, configuration, description, tags):
if name in self.work_groups:
return None

View File

@ -622,6 +622,15 @@ class AutoScalingBackend(BaseBackend):
self.__dict__ = {}
self.__init__(ec2_backend, elb_backend, elbv2_backend)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "autoscaling"
) + BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "autoscaling-plans"
)
def create_launch_configuration(
self,
name,

View File

@ -1095,6 +1095,13 @@ class LambdaBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "lambda"
)
def create_function(self, spec):
function_name = spec.get("FunctionName", None)
if function_name is None:

View File

@ -27,6 +27,11 @@ def backends():
yield _import_backend(module_name, backends_name)
def unique_backends():
for module_name, backends_name in sorted(set(BACKENDS.values())):
yield _import_backend(module_name, backends_name)
def loaded_backends():
loaded_modules = sys.modules.keys()
loaded_modules = [m for m in loaded_modules if m.startswith("moto.")]

View File

@ -499,6 +499,13 @@ class CloudFormationBackend(BaseBackend):
self.exports = OrderedDict()
self.change_sets = OrderedDict()
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "cloudformation", policy_supported=False
)
def _resolve_update_parameters(self, instance, incoming_params):
parameters = dict(
[

View File

@ -312,6 +312,13 @@ class CloudWatchBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "monitoring"
)
@property
# Retrieve a list of all OOTB metrics that are provided by metrics providers
# Computed on the fly

View File

@ -36,6 +36,13 @@ class CodeCommitBackend(BaseBackend):
def __init__(self):
self.repositories = {}
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "codecommit"
)
def create_repository(self, region, repository_name, repository_description):
repository = self.repositories.get(repository_name)
if repository:

View File

@ -71,6 +71,13 @@ class CodePipelineBackend(BaseBackend):
def __init__(self):
self.pipelines = {}
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "codepipeline", policy_supported=False
)
@property
def iam_backend(self):
return iam_backends["global"]

View File

@ -854,6 +854,13 @@ class ConfigBackend(BaseBackend):
self.config_rules = {}
self.config_schema = None
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""List of dicts representing default VPC endpoints for this service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "config"
)
def _validate_resource_types(self, resource_list):
if not self.config_schema:
self.config_schema = AWSServiceSpec(

View File

@ -1,11 +1,10 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from __future__ import absolute_import
import functools
import inspect
import os
import random
import re
import string
import types
from abc import abstractmethod
from io import BytesIO
@ -698,6 +697,63 @@ class BaseBackend:
return paths
@staticmethod
def default_vpc_endpoint_service(
service_region, zones,
): # pylint: disable=unused-argument
"""Invoke the factory method for any VPC endpoint(s) services."""
return None
@staticmethod
def vpce_random_number():
"""Return random number for a VPC endpoint service ID."""
return "".join([random.choice(string.hexdigits.lower()) for i in range(17)])
@staticmethod
def default_vpc_endpoint_service_factory(
service_region,
zones,
service="",
service_type="Interface",
private_dns_names=True,
special_service_name="",
policy_supported=True,
base_endpoint_dns_names=None,
): # pylint: disable=too-many-arguments
"""List of dicts representing default VPC endpoints for this service."""
if special_service_name:
service_name = f"com.amazonaws.{service_region}.{special_service_name}"
else:
service_name = f"com.amazonaws.{service_region}.{service}"
if not base_endpoint_dns_names:
base_endpoint_dns_names = [f"{service}.{service_region}.vpce.amazonaws.com"]
endpoint_service = {
"AcceptanceRequired": False,
"AvailabilityZones": zones,
"BaseEndpointDnsNames": base_endpoint_dns_names,
"ManagesVpcEndpoints": False,
"Owner": "amazon",
"ServiceId": f"vpce-svc-{BaseBackend.vpce_random_number()}",
"ServiceName": service_name,
"ServiceType": [{"ServiceType": service_type}],
"Tags": [],
"VpcEndpointPolicySupported": policy_supported,
}
# Don't know how private DNS names are different, so for now just
# one will be added.
if private_dns_names:
endpoint_service[
"PrivateDnsName"
] = f"{service}.{service_region}.amazonaws.com"
endpoint_service["PrivateDnsNameVerificationState"] = "verified"
endpoint_service["PrivateDnsNames"] = [
{"PrivateDnsName": f"{service}.{service_region}.amazonaws.com"}
]
return [endpoint_service]
def decorator(self, func=None):
if settings.TEST_SERVER_MODE:
mocked_backend = ServerModeMockAWS({"global": self})

View File

@ -112,6 +112,13 @@ class DataSyncBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "datasync"
)
def create_location(self, location_uri, typ=None, metadata=None):
"""
# AWS DataSync allows for duplicate LocationUris

View File

@ -25,6 +25,13 @@ class DatabaseMigrationServiceBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "dms"
)
def create_replication_task(
self,
replication_task_identifier,

View File

@ -711,7 +711,7 @@ class Table(CloudFormationModel):
projection_expression,
index_name=None,
filter_expression=None,
**filter_kwargs
**filter_kwargs,
):
results = []
@ -1075,6 +1075,19 @@ class DynamoDBBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
# No 'vpce' in the base endpoint DNS name
return BaseBackend.default_vpc_endpoint_service_factory(
service_region,
zones,
"dynamodb",
"Gateway",
private_dns_names=False,
base_endpoint_dns_names=[f"dynamodb.{service_region}.amazonaws.com"],
)
def create_table(self, name, **params):
if name in self.tables:
return None
@ -1288,7 +1301,7 @@ class DynamoDBBackend(BaseBackend):
expr_names=None,
expr_values=None,
filter_expression=None,
**filter_kwargs
**filter_kwargs,
):
table = self.tables.get(table_name)
if not table:
@ -1311,7 +1324,7 @@ class DynamoDBBackend(BaseBackend):
projection_expression,
index_name,
filter_expression,
**filter_kwargs
**filter_kwargs,
)
def scan(

View File

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

View File

@ -1,19 +1,23 @@
from __future__ import unicode_literals
import copy
from datetime import datetime
import itertools
import ipaddress
import json
import os
from operator import itemgetter
from os import listdir
from os import environ
import pathlib
import re
import warnings
import weakref
from collections import defaultdict
from collections import OrderedDict
from boto3 import Session
from collections import defaultdict
import weakref
from datetime import datetime
from moto.packages.boto.ec2.instance import Instance as BotoInstance, Reservation
from moto.packages.boto.ec2.blockdevicemapping import (
BlockDeviceMapping,
@ -24,7 +28,6 @@ from moto.packages.boto.ec2.spotinstancerequest import (
)
from moto.packages.boto.ec2.launchspecification import LaunchSpecification
from collections import OrderedDict
from moto.core import BaseBackend
from moto.core.models import Model, BaseModel, CloudFormationModel
from moto.core.utils import (
@ -34,7 +37,6 @@ from moto.core.utils import (
from moto.core import ACCOUNT_ID
from moto.kms import kms_backends
from moto.utilities.utils import load_resource, merge_multiple_dicts, filter_resources
from os import listdir
from .exceptions import (
CidrLimitExceeded,
@ -65,6 +67,9 @@ from .exceptions import (
InvalidKeyPairFormatError,
InvalidKeyPairNameError,
InvalidAggregationIntervalParameterError,
InvalidServiceName,
InvalidFilter,
InvalidNextToken,
InvalidDependantParameterError,
InvalidDependantParameterTypeError,
InvalidFlowLogIdError,
@ -192,20 +197,22 @@ offerings_path = "resources/instance_type_offerings"
INSTANCE_TYPE_OFFERINGS = {}
for location_type in listdir(root / offerings_path):
INSTANCE_TYPE_OFFERINGS[location_type] = {}
for region in listdir(root / offerings_path / location_type):
full_path = offerings_path + "/" + location_type + "/" + region
for _region in listdir(root / offerings_path / location_type):
full_path = offerings_path + "/" + location_type + "/" + _region
INSTANCE_TYPE_OFFERINGS[location_type][
region.replace(".json", "")
_region.replace(".json", "")
] = load_resource(__name__, full_path)
if "MOTO_AMIS_PATH" in os.environ:
with open(os.environ.get("MOTO_AMIS_PATH"), "r", encoding="utf-8") as f:
if "MOTO_AMIS_PATH" in environ:
with open(environ.get("MOTO_AMIS_PATH"), "r", encoding="utf-8") as f:
AMIS = json.load(f)
else:
AMIS = load_resource(__name__, "resources/amis.json")
OWNER_ID = ACCOUNT_ID
MAX_NUMBER_OF_ENDPOINT_SERVICES_RESULTS = 1000
DEFAULT_VPC_ENDPOINT_SERVICES = []
def utc_date_and_time():
@ -441,15 +448,13 @@ class NetworkInterface(TaggedEC2Resource, CloudFormationModel):
elif filter_name == "description":
return self.description
else:
return super(NetworkInterface, self).get_filter_value(
filter_name, "DescribeNetworkInterfaces"
)
return super().get_filter_value(filter_name, "DescribeNetworkInterfaces")
class NetworkInterfaceBackend(object):
def __init__(self):
self.enis = {}
super(NetworkInterfaceBackend, self).__init__()
super().__init__()
def create_network_interface(
self,
@ -459,7 +464,7 @@ class NetworkInterfaceBackend(object):
group_ids=None,
description=None,
tags=None,
**kwargs
**kwargs,
):
eni = NetworkInterface(
self,
@ -469,7 +474,7 @@ class NetworkInterfaceBackend(object):
group_ids=group_ids,
description=description,
tags=tags,
**kwargs
**kwargs,
)
self.enis[eni.id] = eni
return eni
@ -563,7 +568,7 @@ class Instance(TaggedEC2Resource, BotoInstance, CloudFormationModel):
}
def __init__(self, ec2_backend, image_id, user_data, security_groups, **kwargs):
super(Instance, self).__init__()
super().__init__()
self.ec2_backend = ec2_backend
self.id = random_instance_id()
self.lifecycle = kwargs.get("lifecycle")
@ -990,7 +995,7 @@ class Instance(TaggedEC2Resource, BotoInstance, CloudFormationModel):
class InstanceBackend(object):
def __init__(self):
self.reservations = OrderedDict()
super(InstanceBackend, self).__init__()
super().__init__()
def get_instance(self, instance_id):
for instance in self.all_instances():
@ -1220,7 +1225,7 @@ class InstanceBackend(object):
class InstanceTypeBackend(object):
def __init__(self):
super(InstanceTypeBackend, self).__init__()
super().__init__()
def describe_instance_types(self, instance_types=None):
matches = INSTANCE_TYPES.values()
@ -1236,7 +1241,7 @@ class InstanceTypeBackend(object):
class InstanceTypeOfferingBackend(object):
def __init__(self):
super(InstanceTypeOfferingBackend, self).__init__()
super().__init__()
def describe_instance_type_offerings(self, location_type=None, filters=None):
location_type = location_type or "region"
@ -1283,7 +1288,7 @@ class KeyPair(object):
class KeyPairBackend(object):
def __init__(self):
self.keypairs = {}
super(KeyPairBackend, self).__init__()
super().__init__()
def create_key_pair(self, name):
if name in self.keypairs:
@ -1359,7 +1364,7 @@ class TagBackend(object):
def __init__(self):
self.tags = defaultdict(dict)
super(TagBackend, self).__init__()
super().__init__()
def create_tags(self, resource_ids, tags):
if None in set([tags[tag] for tag in tags]):
@ -1581,7 +1586,7 @@ class Ami(TaggedEC2Resource):
elif filter_name == "owner-alias":
return self.owner_alias
else:
return super(Ami, self).get_filter_value(filter_name, "DescribeImages")
return super().get_filter_value(filter_name, "DescribeImages")
class AmiBackend(object):
@ -1589,10 +1594,8 @@ class AmiBackend(object):
def __init__(self):
self.amis = {}
self._load_amis()
super(AmiBackend, self).__init__()
super().__init__()
def _load_amis(self):
for ami in AMIS:
@ -2335,7 +2338,7 @@ class SecurityGroupBackend(object):
self.sg_old_ingress_ruls = {}
self.sg_old_egress_ruls = {}
super(SecurityGroupBackend, self).__init__()
super().__init__()
def create_security_group(
self, name, description, vpc_id=None, tags=None, force=False, is_default=None
@ -3102,7 +3105,7 @@ class Volume(TaggedEC2Resource, CloudFormationModel):
elif filter_name == "availability-zone":
return self.zone.name
else:
return super(Volume, self).get_filter_value(filter_name, "DescribeVolumes")
return super().get_filter_value(filter_name, "DescribeVolumes")
class Snapshot(TaggedEC2Resource):
@ -3144,9 +3147,7 @@ class Snapshot(TaggedEC2Resource):
elif filter_name == "owner-id":
return self.owner_id
else:
return super(Snapshot, self).get_filter_value(
filter_name, "DescribeSnapshots"
)
return super().get_filter_value(filter_name, "DescribeSnapshots")
class EBSBackend(object):
@ -3154,7 +3155,7 @@ class EBSBackend(object):
self.volumes = {}
self.attachments = {}
self.snapshots = {}
super(EBSBackend, self).__init__()
super().__init__()
def create_volume(
self, size, zone_name, snapshot_id=None, encrypted=False, kms_key_id=None
@ -3444,7 +3445,7 @@ class VPC(TaggedEC2Resource, CloudFormationModel):
return None
return self.dhcp_options.id
else:
return super(VPC, self).get_filter_value(filter_name, "DescribeVpcs")
return super().get_filter_value(filter_name, "DescribeVpcs")
def modify_vpc_tenancy(self, tenancy):
if tenancy != "default":
@ -3539,7 +3540,7 @@ class VPCBackend(object):
self.vpcs = {}
self.vpc_end_points = {}
self.vpc_refs[self.__class__].add(weakref.ref(self))
super(VPCBackend, self).__init__()
super().__init__()
@classmethod
def get_vpc_refs(cls):
@ -3831,19 +3832,172 @@ class VPCBackend(object):
return generic_filter(filters, vpc_end_points)
def get_vpc_end_point_services(self):
vpc_end_point_services = self.vpc_end_points.values()
@staticmethod
def _collect_default_endpoint_services(region):
"""Return list of default services using list of backends."""
if DEFAULT_VPC_ENDPOINT_SERVICES:
return DEFAULT_VPC_ENDPOINT_SERVICES
services = []
for value in vpc_end_point_services:
services.append(value.service_name)
zones = [
zone.name
for zones in RegionsAndZonesBackend.zones.values()
for zone in zones
if zone.name.startswith(region)
]
availability_zones = EC2Backend.describe_availability_zones(self)
from moto import backends # pylint: disable=import-outside-toplevel
for _backends in backends.unique_backends():
if region in _backends:
service = _backends[region].default_vpc_endpoint_service(region, zones)
if service:
DEFAULT_VPC_ENDPOINT_SERVICES.extend(service)
if "global" in _backends:
service = _backends["global"].default_vpc_endpoint_service(
region, zones
)
if service:
DEFAULT_VPC_ENDPOINT_SERVICES.extend(service)
return DEFAULT_VPC_ENDPOINT_SERVICES
@staticmethod
def _matches_service_by_tags(service, filter_item):
"""Return True if service tags are not filtered by their tags.
Note that the API specifies a key of "Values" for a filter, but
the botocore library returns "Value" instead.
"""
# For convenience, collect the tags for this service.
service_tag_keys = {x["Key"] for x in service["Tags"]}
if not service_tag_keys:
return False
matched = True # assume the best
if filter_item["Name"] == "tag-key":
# Filters=[{"Name":"tag-key", "Values":["Name"]}],
# Any tag with this name, regardless of the tag value.
if not service_tag_keys & set(filter_item["Value"]):
matched = False
elif filter_item["Name"].startswith("tag:"):
# Filters=[{"Name":"tag:Name", "Values":["my-load-balancer"]}],
tag_name = filter_item["Name"].split(":")[1]
if not service_tag_keys & {tag_name}:
matched = False
else:
for tag in service["Tags"]:
if tag["Key"] == tag_name and tag["Value"] in filter_item["Value"]:
break
else:
matched = False
return matched
@staticmethod
def _filter_endpoint_services(service_names_filters, filters, services):
"""Return filtered list of VPC endpoint services."""
if not service_names_filters and not filters:
return services
# Verify the filters are valid.
for filter_item in filters:
if filter_item["Name"] not in [
"service-name",
"service-type",
"tag-key",
] and not filter_item["Name"].startswith("tag:"):
raise InvalidFilter(filter_item["Name"])
# Apply both the service_names filter and the filters themselves.
filtered_services = []
for service in services:
if (
service_names_filters
and service["ServiceName"] not in service_names_filters
):
continue
# Note that the API specifies a key of "Values" for a filter, but
# the botocore library returns "Value" instead.
matched = True
for filter_item in filters:
if filter_item["Name"] == "service-name":
if service["ServiceName"] not in filter_item["Value"]:
matched = False
elif filter_item["Name"] == "service-type":
service_types = {x["ServiceType"] for x in service["ServiceType"]}
if not service_types & set(filter_item["Value"]):
matched = False
elif filter_item["Name"] == "tag-key" or filter_item["Name"].startswith(
"tag:"
):
if not VPCBackend._matches_service_by_tags(service, filter_item):
matched = False
# Exit early -- don't bother checking the remaining filters
# as a non-match was found.
if not matched:
break
# Does the service have a matching service name or does it match
# a filter?
if matched:
filtered_services.append(service)
return filtered_services
def describe_vpc_endpoint_services(
self, dry_run, service_names, filters, max_results, next_token, region
): # pylint: disable=unused-argument,too-many-arguments
"""Return info on services to which you can create a VPC endpoint.
Currently only the default endpoing services are returned. When
create_vpc_endpoint_service_configuration() is implemented, a
list of those private endpoints would be kept and when this API
is invoked, those private endpoints would be added to the list of
default endpoint services.
The DryRun parameter is ignored.
"""
default_services = self._collect_default_endpoint_services(region)
for service_name in service_names:
if service_name not in [x["ServiceName"] for x in default_services]:
raise InvalidServiceName(service_name)
# Apply filters specified in the service_names and filters arguments.
filtered_services = sorted(
self._filter_endpoint_services(service_names, filters, default_services),
key=itemgetter("ServiceName"),
)
# Determine the start index into list of services based on the
# next_token argument.
start = 0
vpce_ids = [x["ServiceId"] for x in filtered_services]
if next_token:
if next_token not in vpce_ids:
raise InvalidNextToken(next_token)
start = vpce_ids.index(next_token)
# Determine the stop index into the list of services based on the
# max_results argument.
if not max_results or max_results > MAX_NUMBER_OF_ENDPOINT_SERVICES_RESULTS:
max_results = MAX_NUMBER_OF_ENDPOINT_SERVICES_RESULTS
# If necessary, set the value of the next_token.
next_token = ""
if len(filtered_services) > (start + max_results):
service = filtered_services[start + max_results]
next_token = service["ServiceId"]
return {
"servicesDetails": vpc_end_point_services,
"services": services,
"availability_zones": availability_zones,
"servicesDetails": filtered_services[start : start + max_results],
"serviceNames": [
x["ServiceName"] for x in filtered_services[start : start + max_results]
],
"nextToken": next_token,
}
def get_vpc_end_point(self, vpc_end_point_id):
@ -3931,7 +4085,7 @@ class VPCPeeringConnectionBackend(object):
def __init__(self):
self.vpc_pcxs = {}
self.vpc_pcx_refs[self.__class__].add(weakref.ref(self))
super(VPCPeeringConnectionBackend, self).__init__()
super().__init__()
@classmethod
def get_vpc_pcx_refs(cls):
@ -4130,7 +4284,7 @@ class Subnet(TaggedEC2Resource, CloudFormationModel):
elif filter_name == "state":
return self.state
else:
return super(Subnet, self).get_filter_value(filter_name, "DescribeSubnets")
return super().get_filter_value(filter_name, "DescribeSubnets")
def get_cfn_attribute(self, attribute_name):
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
@ -4202,7 +4356,7 @@ class SubnetBackend(object):
def __init__(self):
# maps availability zone to dict of (subnet_id, subnet)
self.subnets = defaultdict(dict)
super(SubnetBackend, self).__init__()
super().__init__()
def get_subnet(self, subnet_id):
for subnets in self.subnets.values():
@ -4467,15 +4621,13 @@ class FlowLogs(TaggedEC2Resource, CloudFormationModel):
elif filter_name == "deliver-log-status":
return "SUCCESS"
else:
return super(FlowLogs, self).get_filter_value(
filter_name, "DescribeFlowLogs"
)
return super().get_filter_value(filter_name, "DescribeFlowLogs")
class FlowLogsBackend(object):
def __init__(self):
self.flow_logs = defaultdict(dict)
super(FlowLogsBackend, self).__init__()
super().__init__()
def _validate_request(
self,
@ -4683,7 +4835,7 @@ class SubnetRouteTableAssociation(CloudFormationModel):
class SubnetRouteTableAssociationBackend(object):
def __init__(self):
self.subnet_associations = {}
super(SubnetRouteTableAssociationBackend, self).__init__()
super().__init__()
def create_subnet_association(self, route_table_id, subnet_id):
subnet_association = SubnetRouteTableAssociation(route_table_id, subnet_id)
@ -4749,15 +4901,13 @@ class RouteTable(TaggedEC2Resource, CloudFormationModel):
elif filter_name == "association.subnet-id":
return self.associations.values()
else:
return super(RouteTable, self).get_filter_value(
filter_name, "DescribeRouteTables"
)
return super().get_filter_value(filter_name, "DescribeRouteTables")
class RouteTableBackend(object):
def __init__(self):
self.route_tables = {}
super(RouteTableBackend, self).__init__()
super().__init__()
def create_route_table(self, vpc_id, tags=[], main=False):
route_table_id = random_route_table_id()
@ -5035,7 +5185,7 @@ class ManagedPrefixListBackend(object):
def __init__(self):
self.managed_prefix_lists = {}
self.create_default_pls()
super(ManagedPrefixListBackend, self).__init__()
super().__init__()
def create_managed_prefix_list(
self,
@ -5161,7 +5311,7 @@ class ManagedPrefixListBackend(object):
class RouteBackend(object):
def __init__(self):
super(RouteBackend, self).__init__()
super().__init__()
def create_route(
self,
@ -5362,7 +5512,7 @@ class InternetGateway(TaggedEC2Resource, CloudFormationModel):
class InternetGatewayBackend(object):
def __init__(self):
self.internet_gateways = {}
super(InternetGatewayBackend, self).__init__()
super().__init__()
def create_internet_gateway(self, tags=[]):
igw = InternetGateway(self)
@ -5434,7 +5584,7 @@ class CarrierGateway(TaggedEC2Resource):
class CarrierGatewayBackend(object):
def __init__(self):
self.carrier_gateways = {}
super(CarrierGatewayBackend, self).__init__()
super().__init__()
def create_carrier_gateway(self, vpc_id, tags=None):
vpc = self.get_vpc(vpc_id)
@ -5490,7 +5640,7 @@ class EgressOnlyInternetGateway(TaggedEC2Resource):
class EgressOnlyInternetGatewayBackend(object):
def __init__(self):
self.egress_only_internet_gateway_backend = {}
super(EgressOnlyInternetGatewayBackend, self).__init__()
super().__init__()
def create_egress_only_internet_gateway(self, vpc_id, tags=None):
vpc = self.get_vpc(vpc_id)
@ -5563,7 +5713,7 @@ class VPCGatewayAttachment(CloudFormationModel):
class VPCGatewayAttachmentBackend(object):
def __init__(self):
self.gateway_attachments = {}
super(VPCGatewayAttachmentBackend, self).__init__()
super().__init__()
def create_vpc_gateway_attachment(self, vpc_id, gateway_id):
attachment = VPCGatewayAttachment(vpc_id, gateway_id)
@ -5594,9 +5744,9 @@ class SpotInstanceRequest(BotoSpotRequest, TaggedEC2Resource):
subnet_id,
tags,
spot_fleet_id,
**kwargs
**kwargs,
):
super(SpotInstanceRequest, self).__init__(**kwargs)
super().__init__(**kwargs)
ls = LaunchSpecification()
self.ec2_backend = ec2_backend
self.launch_specification = ls
@ -5638,9 +5788,7 @@ class SpotInstanceRequest(BotoSpotRequest, TaggedEC2Resource):
elif filter_name == "spot-instance-request-id":
return self.id
else:
return super(SpotInstanceRequest, self).get_filter_value(
filter_name, "DescribeSpotInstanceRequests"
)
return super().get_filter_value(filter_name, "DescribeSpotInstanceRequests")
def launch_instance(self):
reservation = self.ec2_backend.add_instances(
@ -5663,7 +5811,7 @@ class SpotInstanceRequest(BotoSpotRequest, TaggedEC2Resource):
class SpotRequestBackend(object, metaclass=Model):
def __init__(self):
self.spot_instance_requests = {}
super(SpotRequestBackend, self).__init__()
super().__init__()
def request_spot_instances(
self,
@ -5974,7 +6122,7 @@ class SpotFleetRequest(TaggedEC2Resource, CloudFormationModel):
class SpotFleetBackend(object):
def __init__(self):
self.spot_fleet_requests = {}
super(SpotFleetBackend, self).__init__()
super().__init__()
def request_spot_fleet(
self,
@ -6141,15 +6289,13 @@ class ElasticAddress(TaggedEC2Resource, CloudFormationModel):
# TODO: implement network-interface-owner-id
raise FilterNotImplementedError(filter_name, "DescribeAddresses")
else:
return super(ElasticAddress, self).get_filter_value(
filter_name, "DescribeAddresses"
)
return super().get_filter_value(filter_name, "DescribeAddresses")
class ElasticAddressBackend(object):
def __init__(self):
self.addresses = []
super(ElasticAddressBackend, self).__init__()
super().__init__()
def allocate_address(self, domain, address=None, tags=None):
if domain not in ["standard", "vpc"]:
@ -6322,9 +6468,7 @@ class DHCPOptionsSet(TaggedEC2Resource):
values = [item for item in list(self._options.values()) if item]
return itertools.chain(*values)
else:
return super(DHCPOptionsSet, self).get_filter_value(
filter_name, "DescribeDhcpOptions"
)
return super().get_filter_value(filter_name, "DescribeDhcpOptions")
@property
def options(self):
@ -6334,7 +6478,7 @@ class DHCPOptionsSet(TaggedEC2Resource):
class DHCPOptionsSetBackend(object):
def __init__(self):
self.dhcp_options_sets = {}
super(DHCPOptionsSetBackend, self).__init__()
super().__init__()
def associate_dhcp_options(self, dhcp_options, vpc):
dhcp_options.vpc = vpc
@ -6440,15 +6584,13 @@ class VPNConnection(TaggedEC2Resource):
self.add_tags(tags or {})
def get_filter_value(self, filter_name):
return super(VPNConnection, self).get_filter_value(
filter_name, "DescribeVpnConnections"
)
return super().get_filter_value(filter_name, "DescribeVpnConnections")
class VPNConnectionBackend(object):
def __init__(self):
self.vpn_connections = {}
super(VPNConnectionBackend, self).__init__()
super().__init__()
def create_vpn_connection(
self,
@ -6514,7 +6656,7 @@ class VPNConnectionBackend(object):
class NetworkAclBackend(object):
def __init__(self):
self.network_acls = {}
super(NetworkAclBackend, self).__init__()
super().__init__()
def get_network_acl(self, network_acl_id):
network_acl = self.network_acls.get(network_acl_id, None)
@ -6702,7 +6844,7 @@ class NetworkAclAssociation(object):
self.new_association_id = new_association_id
self.subnet_id = subnet_id
self.network_acl_id = network_acl_id
super(NetworkAclAssociation, self).__init__()
super().__init__()
class NetworkAcl(TaggedEC2Resource):
@ -6729,9 +6871,7 @@ class NetworkAcl(TaggedEC2Resource):
elif filter_name == "owner-id":
return self.owner_id
else:
return super(NetworkAcl, self).get_filter_value(
filter_name, "DescribeNetworkAcls"
)
return super().get_filter_value(filter_name, "DescribeNetworkAcls")
class NetworkAclEntry(TaggedEC2Resource):
@ -6781,7 +6921,7 @@ class VpnGateway(TaggedEC2Resource):
self.state = state
self.add_tags(tags or {})
self.attachments = {}
super(VpnGateway, self).__init__()
super().__init__()
def get_filter_value(self, filter_name):
if filter_name == "attachment.vpc-id":
@ -6792,22 +6932,20 @@ class VpnGateway(TaggedEC2Resource):
return self.id
elif filter_name == "type":
return self.type
return super(VpnGateway, self).get_filter_value(
filter_name, "DescribeVpnGateways"
)
return super().get_filter_value(filter_name, "DescribeVpnGateways")
class VpnGatewayAttachment(object):
def __init__(self, vpc_id, state):
self.vpc_id = vpc_id
self.state = state
super(VpnGatewayAttachment, self).__init__()
super().__init__()
class VpnGatewayBackend(object):
def __init__(self):
self.vpn_gateways = {}
super(VpnGatewayBackend, self).__init__()
super().__init__()
def create_vpn_gateway(
self, type="ipsec.1", amazon_side_asn=None, availability_zone=None, tags=None
@ -6870,18 +7008,16 @@ class CustomerGateway(TaggedEC2Resource):
self.attachments = {}
self.state = state
self.add_tags(tags or {})
super(CustomerGateway, self).__init__()
super().__init__()
def get_filter_value(self, filter_name):
return super(CustomerGateway, self).get_filter_value(
filter_name, "DescribeCustomerGateways"
)
return super().get_filter_value(filter_name, "DescribeCustomerGateways")
class CustomerGatewayBackend(object):
def __init__(self):
self.customer_gateways = {}
super(CustomerGatewayBackend, self).__init__()
super().__init__()
def create_customer_gateway(
self, type="ipsec.1", ip_address=None, bgp_asn=None, tags=None
@ -7006,7 +7142,7 @@ class TransitGateway(TaggedEC2Resource, CloudFormationModel):
class TransitGatewayBackend(object):
def __init__(self):
self.transit_gateways = {}
super(TransitGatewayBackend, self).__init__()
super().__init__()
def create_transit_gateway(self, description=None, options=None, tags=[]):
transit_gateway = TransitGateway(self, description, options)
@ -7081,7 +7217,7 @@ class TransitGatewayRouteTable(TaggedEC2Resource):
class TransitGatewayRouteTableBackend(object):
def __init__(self):
self.transit_gateways_route_tables = {}
super(TransitGatewayRouteTableBackend, self).__init__()
super().__init__()
def create_transit_gateway_route_table(
self,
@ -7400,7 +7536,7 @@ class TransitGatewayPeeringAttachment(TransitGatewayAttachment):
class TransitGatewayAttachmentBackend(object):
def __init__(self):
self.transit_gateway_attachments = {}
super(TransitGatewayAttachmentBackend, self).__init__()
super().__init__()
def create_transit_gateway_vpn_attachment(
self, vpn_id, transit_gateway_id, tags=[]
@ -7645,7 +7781,7 @@ class TransitGatewayRelationsBackend(object):
def __init__(self):
self.transit_gateway_associations = {}
self.transit_gateway_propagations = {}
super(TransitGatewayRelationsBackend, self).__init__()
super().__init__()
def associate_transit_gateway_route_table(
self, transit_gateway_attachment_id=None, transit_gateway_route_table_id=None
@ -7793,7 +7929,7 @@ class NatGateway(CloudFormationModel, TaggedEC2Resource):
class NatGatewayBackend(object):
def __init__(self):
self.nat_gateways = {}
super(NatGatewayBackend, self).__init__()
super().__init__()
def describe_nat_gateways(self, filters, nat_gateway_ids):
nat_gateways = list(self.nat_gateways.values())
@ -7916,9 +8052,7 @@ class LaunchTemplate(TaggedEC2Resource):
if filter_name == "launch-template-name":
return self.name
else:
return super(LaunchTemplate, self).get_filter_value(
filter_name, "DescribeLaunchTemplates"
)
return super().get_filter_value(filter_name, "DescribeLaunchTemplates")
class LaunchTemplateBackend(object):
@ -7926,7 +8060,7 @@ class LaunchTemplateBackend(object):
self.launch_template_name_to_ids = {}
self.launch_templates = OrderedDict()
self.launch_template_insert_order = []
super(LaunchTemplateBackend, self).__init__()
super().__init__()
def create_launch_template(self, name, description, template_data):
if name in self.launch_template_name_to_ids:
@ -7971,7 +8105,7 @@ class IamInstanceProfileAssociation(CloudFormationModel):
class IamInstanceProfileAssociationBackend(object):
def __init__(self):
self.iam_instance_profile_associations = {}
super(IamInstanceProfileAssociationBackend, self).__init__()
super().__init__()
def associate_iam_instance_profile(
self,
@ -8117,7 +8251,7 @@ class EC2Backend(
):
def __init__(self, region_name):
self.region_name = region_name
super(EC2Backend, self).__init__()
super().__init__()
# Default VPC exists by default, which is the current behavior
# of EC2-VPC. See for detail:
@ -8149,6 +8283,15 @@ class EC2Backend(
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "ec2"
) + BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "ec2messages"
)
# Use this to generate a proper error template response when in a response
# handler.
def raise_error(self, code, message):

View File

@ -133,6 +133,7 @@ class VPCs(BaseResponse):
attr_value = self.querystring.get("%s.Value" % attribute)[0]
self.ec2_backend.modify_vpc_attribute(vpc_id, attr_name, attr_value)
return MODIFY_VPC_ATTRIBUTE_RESPONSE
return None
def associate_vpc_cidr_block(self):
vpc_id = self._get_param("VpcId")
@ -181,7 +182,7 @@ class VPCs(BaseResponse):
service_name = self._get_param("ServiceName")
route_table_ids = self._get_multi_param("RouteTableId")
subnet_ids = self._get_multi_param("SubnetId")
type = self._get_param("VpcEndpointType")
endpoint_type = self._get_param("VpcEndpointType")
policy_document = self._get_param("PolicyDocument")
client_token = self._get_param("ClientToken")
tags = self._get_multi_param("TagSpecification")
@ -192,7 +193,7 @@ class VPCs(BaseResponse):
vpc_end_point = self.ec2_backend.create_vpc_endpoint(
vpc_id=vpc_id,
service_name=service_name,
type=type,
type=endpoint_type,
policy_document=policy_document,
route_table_ids=route_table_ids,
subnet_ids=subnet_ids,
@ -205,7 +206,14 @@ class VPCs(BaseResponse):
return template.render(vpc_end_point=vpc_end_point)
def describe_vpc_endpoint_services(self):
vpc_end_point_services = self.ec2_backend.get_vpc_end_point_services()
vpc_end_point_services = self.ec2_backend.describe_vpc_endpoint_services(
dry_run=self._get_bool_param("DryRun"),
service_names=self._get_multi_param("ServiceName"),
filters=self._get_multi_param("Filter"),
max_results=self._get_int_param("MaxResults"),
next_token=self._get_param("NextToken"),
region=self.region,
)
template = self.response_template(DESCRIBE_VPC_ENDPOINT_SERVICES_RESPONSE)
return template.render(vpc_end_points=vpc_end_point_services)
@ -589,33 +597,63 @@ CREATE_VPC_END_POINT = """ <CreateVpcEndpointResponse xmlns="http://monitoring.a
DESCRIBE_VPC_ENDPOINT_SERVICES_RESPONSE = """<DescribeVpcEndpointServicesResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>19a9ff46-7df6-49b8-9726-3df27527089d</requestId>
<serviceNameSet>
{% for serviceName in vpc_end_points.services %}
{% for serviceName in vpc_end_points.serviceNames %}
<item>{{ serviceName }}</item>
{% endfor %}
</serviceNameSet>
<serviceDetailSet>
{% for service in vpc_end_points.servicesDetails %}
<item>
<owner>amazon</owner>
<serviceType>
<item>
<serviceType>{{ service.type }}</serviceType>
</item>
</serviceType>
<baseEndpointDnsNameSet>
<item>{{ ".".join((service.service_name.split(".")[::-1])) }}</item>
</baseEndpointDnsNameSet>
<acceptanceRequired>false</acceptanceRequired>
<item>
<acceptanceRequired>{{ 'true' if service.AcceptanceRequired else 'false' }}</acceptanceRequired>
<availabilityZoneSet>
{% for zone in vpc_end_points.availability_zones %}
<item>{{ zone.name }}</item>
{% for zone in service.AvailabilityZones %}
<item>{{ zone }}</item>
{% endfor %}
</availabilityZoneSet>
<serviceName>{{ service.service_name }}</serviceName>
<vpcEndpointPolicySupported>true</vpcEndpointPolicySupported>
</item>
<baseEndpointDnsNameSet>
{% for endpoint in service.BaseEndpointDnsNames %}
<item>{{ endpoint }}</item>
{% endfor %}
</baseEndpointDnsNameSet>
<managesVpcEndpoints>{{ 'true' if service.ManagesVpcEndpoints else 'false' }}</managesVpcEndpoints>
<owner>{{ service.Owner }}</owner>
{% if service.PrivateDnsName is defined %}
<privateDnsName>{{ service.PrivateDnsName }}</privateDnsName>
<privateDnsNameSet>
{% for dns_name in service.PrivateDnsNames %}
<item>
<privateDnsName>{{ dns_name.PrivateDnsName }}</privateDnsName>
</item>
{% endfor %}
</privateDnsNameSet>
<privateDnsNameVerificationState>{{ service.PrivateDnsNameVerificationState }}</privateDnsNameVerificationState>
{% endif %}
<serviceId>{{ service.ServiceId }}</serviceId>
<serviceName>{{ service.ServiceName }}</serviceName>
<serviceType>
{% for service_type in service.ServiceType %}
<item>
<serviceType>{{ service_type.ServiceType }}</serviceType>
</item>
{% endfor %}
</serviceType>
<tagSet>
{% for tag in service.Tags %}
{% for key, value in tag.items() %}
<item>
<key>{{ key }}</key>
<value>{{ value }}</value>
</item>
{% endfor %}
{% endfor %}
</tagSet>
<vpcEndpointPolicySupported>{{ 'true' if service.VpcEndpointPolicySupported else 'false' }}</vpcEndpointPolicySupported>
</item>
{% endfor %}
</serviceDetailSet>
{% if vpc_end_points.nextToken|length %}
<nextToken>{{ vpc_end_points.nextToken }}</nextToken>
{% endif %}
</DescribeVpcEndpointServicesResponse>"""
DESCRIBE_VPC_ENDPOINT_RESPONSE = """<DescribeVpcEndpointsResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">

View File

@ -335,6 +335,30 @@ class ECRBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
docker_endpoint = {
"AcceptanceRequired": False,
"AvailabilityZones": zones,
"BaseEndpointDnsNames": [f"dkr.ecr.{service_region}.vpce.amazonaws.com"],
"ManagesVpcEndpoints": False,
"Owner": "amazon",
"PrivateDnsName": f"*.dkr.ecr.{service_region}.amazonaws.com",
"PrivateDnsNameVerificationState": "verified",
"PrivateDnsNames": [
{"PrivateDnsName": f"*.dkr.ecr.{service_region}.amazonaws.com"}
],
"ServiceId": f"vpce-svc-{BaseBackend.vpce_random_number()}",
"ServiceName": f"com.amazonaws.{service_region}.ecr.dkr",
"ServiceType": [{"ServiceType": "Interface"}],
"Tags": [],
"VpcEndpointPolicySupported": True,
}
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "api.ecr", special_service_name="ecr.api",
) + [docker_endpoint]
def _get_repository(self, name, registry_id=None) -> Repository:
repo = self.repositories.get(name)
reg_id = registry_id or DEFAULT_REGISTRY_ID

View File

@ -675,6 +675,13 @@ class EC2ContainerServiceBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "ecs"
)
def _get_cluster(self, name):
# short name or full ARN of the cluster
cluster_name = name.split("/")[-1]

View File

@ -79,6 +79,15 @@ class EBBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "elasticbeanstalk"
) + BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "elasticbeanstalk-health"
)
def create_application(self, application_name):
if application_name in self.applications:
raise InvalidParameterValueError(

View File

@ -553,6 +553,13 @@ class ELBv2Backend(BaseBackend):
self.target_groups = OrderedDict()
self.load_balancers = OrderedDict()
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "elasticloadbalancing"
)
@property
def ec2_backend(self):
"""

View File

@ -397,6 +397,13 @@ class ElasticMapReduceBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "elasticmapreduce"
)
@property
def ec2_backend(self):
"""

View File

@ -915,6 +915,13 @@ class EventsBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "events"
)
def _add_default_event_bus(self):
self.event_buses["default"] = EventBus(self.region_name, "default")

View File

@ -174,6 +174,13 @@ class FirehoseBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "firehose", special_service_name="kinesis-firehose"
)
def create_delivery_stream(
self,
region,

View File

@ -24,6 +24,13 @@ class GlueBackend(BaseBackend):
self.databases = OrderedDict()
self.crawlers = OrderedDict()
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "glue"
)
def create_database(self, database_name, database_input):
if database_name in self.databases:
raise DatabaseAlreadyExistsException()

View File

@ -505,6 +505,20 @@ class IoTBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "iot"
) + BaseBackend.default_vpc_endpoint_service_factory(
service_region,
zones,
"data.iot",
private_dns_names=False,
special_service_name="iot.data",
policy_supported=False,
)
def create_thing(self, thing_name, thing_type_name, attribute_payload):
thing_types = self.list_thing_types()
thing_type = None

View File

@ -325,6 +325,13 @@ class KinesisBackend(BaseBackend):
def __init__(self):
self.streams = OrderedDict()
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "kinesis", special_service_name="kinesis-streams"
)
def create_stream(
self, stream_name, shard_count, retention_period_hours, region_name
):

View File

@ -159,6 +159,13 @@ class KmsBackend(BaseBackend):
self.key_to_aliases = defaultdict(set)
self.tagger = TaggingService(key_name="TagKey", value_name="TagValue")
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "kms"
)
def create_key(
self, policy, key_usage, customer_master_key_spec, description, tags, region
):

View File

@ -551,6 +551,13 @@ class LogsBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "logs"
)
def create_log_group(self, log_group_name, tags, **kwargs):
if log_group_name in self.groups:
raise ResourceAlreadyExistsException()

View File

@ -847,6 +847,15 @@ class RDS2Backend(BaseBackend):
self.__dict__ = {}
self.__init__(region)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "rds"
) + BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "rds-data"
)
def create_database(self, db_kwargs):
database_id = db_kwargs["db_instance_identifier"]
database = Database(**db_kwargs)

View File

@ -574,6 +574,15 @@ class RedshiftBackend(BaseBackend):
self.__dict__ = {}
self.__init__(ec2_backend, region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "redshift"
) + BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "redshift-data", policy_supported=False
)
def enable_snapshot_copy(self, **kwargs):
cluster_identifier = kwargs["cluster_identifier"]
cluster = self.clusters[cluster_identifier]

View File

@ -1,11 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import json
import os
import base64
import datetime
import pytz
import hashlib
import copy
import itertools
@ -18,8 +15,9 @@ import sys
import time
import uuid
from bisect import insort
import pytz
from moto.core import ACCOUNT_ID, BaseBackend, BaseModel, CloudFormationModel
from moto.core.utils import iso_8601_datetime_without_milliseconds_s3, rfc_1123_datetime
from moto.cloudwatch.models import MetricDatum
@ -1301,6 +1299,38 @@ class S3Backend(BaseBackend):
self.account_public_access_block = None
self.tagger = TaggingService()
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""List of dicts representing default VPC endpoints for this service."""
accesspoint = {
"AcceptanceRequired": False,
"AvailabilityZones": zones,
"BaseEndpointDnsNames": [
f"accesspoint.s3-global.{service_region}.vpce.amazonaws.com",
],
"ManagesVpcEndpoints": False,
"Owner": "amazon",
"PrivateDnsName": "*.accesspoint.s3-global.amazonaws.com",
"PrivateDnsNameVerificationState": "verified",
"PrivateDnsNames": [
{"PrivateDnsName": "*.accesspoint.s3-global.amazonaws.com"}
],
"ServiceId": f"vpce-svc-{BaseBackend.vpce_random_number()}",
"ServiceName": "com.amazonaws.s3-global.accesspoint",
"ServiceType": [{"ServiceType": "Interface"}],
"Tags": [],
"VpcEndpointPolicySupported": True,
}
return (
BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "s3", "Interface"
)
+ BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "s3", "Gateway"
)
+ [accesspoint]
)
# TODO: This is broken! DO NOT IMPORT MUTABLE DATA TYPES FROM OTHER AREAS -- THIS BREAKS UNMOCKING!
# WRAP WITH A GETTER/SETTER FUNCTION
# Register this class as a CloudWatch Metric Provider

View File

@ -877,6 +877,58 @@ class SageMakerModelBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint services."""
api_service = BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "api.sagemaker", special_service_name="sagemaker.api"
)
notebook_service_id = f"vpce-svc-{BaseBackend.vpce_random_number()}"
studio_service_id = f"vpce-svc-{BaseBackend.vpce_random_number()}"
notebook_service = {
"AcceptanceRequired": False,
"AvailabilityZones": zones,
"BaseEndpointDnsNames": [
f"{notebook_service_id}.{service_region}.vpce.amazonaws.com",
f"notebook.{service_region}.vpce.sagemaker.aws",
],
"ManagesVpcEndpoints": False,
"Owner": "amazon",
"PrivateDnsName": f"*.notebook.{service_region}.sagemaker.aws",
"PrivateDnsNameVerificationState": "verified",
"PrivateDnsNames": [
{"PrivateDnsName": f"*.notebook.{service_region}.sagemaker.aws"}
],
"ServiceId": notebook_service_id,
"ServiceName": f"aws.sagemaker.{service_region}.notebook",
"ServiceType": [{"ServiceType": "Interface"}],
"Tags": [],
"VpcEndpointPolicySupported": True,
}
studio_service = {
"AcceptanceRequired": False,
"AvailabilityZones": zones,
"BaseEndpointDnsNames": [
f"{studio_service_id}.{service_region}.vpce.amazonaws.com",
f"studio.{service_region}.vpce.sagemaker.aws",
],
"ManagesVpcEndpoints": False,
"Owner": "amazon",
"PrivateDnsName": f"*.studio.{service_region}.sagemaker.aws",
"PrivateDnsNameVerificationState": "verified",
"PrivateDnsNames": [
{"PrivateDnsName": f"*.studio.{service_region}.sagemaker.aws"}
],
"ServiceId": studio_service_id,
"ServiceName": f"aws.sagemaker.{service_region}.studio",
"ServiceType": [{"ServiceType": "Interface"}],
"Tags": [],
"VpcEndpointPolicySupported": True,
}
return api_service + [notebook_service, studio_service]
def create_model(self, **kwargs):
model_obj = Model(
region_name=self.region_name,

View File

@ -182,6 +182,13 @@ class SecretsManagerBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint services."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "secretsmanager"
)
def _is_valid_identifier(self, identifier):
return identifier in self.secrets

View File

@ -387,6 +387,13 @@ class SNSBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""List of dicts representing default VPC endpoints for this service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "sns"
)
def update_sms_attributes(self, attrs):
self.sms_attributes.update(attrs)

View File

@ -584,6 +584,13 @@ class SQSBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "sqs"
)
def create_queue(self, name, tags=None, **kwargs):
queue = self.queues.get(name)
if queue:

View File

@ -688,6 +688,15 @@ class SimpleSystemManagerBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint services."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "ssm"
) + BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "ssmmessages"
)
def _generate_document_information(self, ssm_document, document_format):
content = self._get_document_content(document_format, ssm_document)
base = {

View File

@ -60,6 +60,13 @@ class STSBackend(BaseBackend):
def __init__(self):
self.assumed_roles = []
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "sts"
)
def get_session_token(self, duration):
token = Token(duration=duration)
return token

View File

@ -450,6 +450,15 @@ class TranscribeBackend(BaseBackend):
self.__dict__ = {}
self.__init__(region_name)
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint services."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "transcribe"
) + BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "transcribestreaming"
)
def start_transcription_job(self, **kwargs):
name = kwargs.get("transcription_job_name")

View File

@ -236,6 +236,13 @@ class XRayBackend(BaseBackend):
self._telemetry_records = []
self._segment_collection = SegmentCollection()
@staticmethod
def default_vpc_endpoint_service(service_region, zones):
"""Default VPC endpoint service."""
return BaseBackend.default_vpc_endpoint_service_factory(
service_region, zones, "xray"
)
def add_telemetry_records(self, json):
self._telemetry_records.append(TelemetryRecords.from_json(json))

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