239 lines
9.8 KiB
Python
239 lines
9.8 KiB
Python
from typing import Any, Dict, List
|
|
from moto.core import BaseBackend, BackendDict
|
|
from ..exceptions import (
|
|
EC2ClientError,
|
|
InvalidID,
|
|
MissingParameterError,
|
|
MotoNotImplementedError,
|
|
)
|
|
from .amis import AmiBackend
|
|
from .carrier_gateways import CarrierGatewayBackend
|
|
from .customer_gateways import CustomerGatewayBackend
|
|
from .dhcp_options import DHCPOptionsSetBackend
|
|
from .elastic_block_store import EBSBackend
|
|
from .elastic_ip_addresses import ElasticAddressBackend
|
|
from .elastic_network_interfaces import NetworkInterfaceBackend
|
|
from .hosts import HostsBackend
|
|
from .fleets import FleetsBackend
|
|
from .flow_logs import FlowLogsBackend
|
|
from .key_pairs import KeyPairBackend
|
|
from .launch_templates import LaunchTemplateBackend
|
|
from .managed_prefixes import ManagedPrefixListBackend
|
|
from .iam_instance_profile import IamInstanceProfileAssociationBackend
|
|
from .internet_gateways import (
|
|
InternetGatewayBackend,
|
|
EgressOnlyInternetGatewayBackend,
|
|
)
|
|
from .instances import InstanceBackend
|
|
from .instance_types import InstanceTypeBackend, InstanceTypeOfferingBackend
|
|
from .nat_gateways import NatGatewayBackend
|
|
from .network_acls import NetworkAclBackend
|
|
from .availability_zones_and_regions import RegionsAndZonesBackend
|
|
from .route_tables import RouteBackend
|
|
from .security_groups import SecurityGroupBackend
|
|
from .spot_requests import SpotRequestBackend
|
|
from .subnets import SubnetBackend
|
|
from .tags import TagBackend
|
|
from .transit_gateway import TransitGatewayBackend
|
|
from .transit_gateway_route_tables import TransitGatewayRouteTableBackend
|
|
from .transit_gateway_attachments import TransitGatewayAttachmentBackend
|
|
from .vpn_gateway import VpnGatewayBackend
|
|
from .vpn_connections import VPNConnectionBackend
|
|
from .vpcs import VPCBackend
|
|
from .vpc_peering_connections import VPCPeeringConnectionBackend
|
|
from .vpc_service_configuration import VPCServiceConfigurationBackend
|
|
from .windows import WindowsBackend
|
|
from ..utils import (
|
|
EC2_RESOURCE_TO_PREFIX,
|
|
is_valid_resource_id,
|
|
get_prefix,
|
|
)
|
|
|
|
|
|
def validate_resource_ids(resource_ids: List[str]) -> bool:
|
|
if not resource_ids:
|
|
raise MissingParameterError(parameter="resourceIdSet")
|
|
for resource_id in resource_ids:
|
|
if not is_valid_resource_id(resource_id):
|
|
raise InvalidID(resource_id=resource_id)
|
|
return True
|
|
|
|
|
|
class SettingsBackend:
|
|
def __init__(self) -> None:
|
|
self.ebs_encryption_by_default = False
|
|
|
|
def disable_ebs_encryption_by_default(self) -> None:
|
|
ec2_backend = ec2_backends[self.account_id][self.region_name] # type: ignore[attr-defined]
|
|
ec2_backend.ebs_encryption_by_default = False
|
|
|
|
def enable_ebs_encryption_by_default(self) -> None:
|
|
ec2_backend = ec2_backends[self.account_id][self.region_name] # type: ignore[attr-defined]
|
|
ec2_backend.ebs_encryption_by_default = True
|
|
|
|
def get_ebs_encryption_by_default(self) -> None:
|
|
ec2_backend = ec2_backends[self.account_id][self.region_name] # type: ignore[attr-defined]
|
|
return ec2_backend.ebs_encryption_by_default
|
|
|
|
|
|
class EC2Backend(
|
|
BaseBackend,
|
|
InstanceBackend,
|
|
InstanceTypeBackend,
|
|
InstanceTypeOfferingBackend,
|
|
TagBackend,
|
|
EBSBackend,
|
|
RegionsAndZonesBackend,
|
|
AmiBackend,
|
|
SecurityGroupBackend,
|
|
VPCBackend,
|
|
ManagedPrefixListBackend,
|
|
SubnetBackend,
|
|
FlowLogsBackend,
|
|
NetworkInterfaceBackend,
|
|
VPNConnectionBackend,
|
|
VPCServiceConfigurationBackend,
|
|
VPCPeeringConnectionBackend,
|
|
RouteBackend,
|
|
InternetGatewayBackend,
|
|
EgressOnlyInternetGatewayBackend,
|
|
SpotRequestBackend,
|
|
ElasticAddressBackend,
|
|
KeyPairBackend,
|
|
SettingsBackend,
|
|
DHCPOptionsSetBackend,
|
|
NetworkAclBackend,
|
|
VpnGatewayBackend,
|
|
CustomerGatewayBackend,
|
|
NatGatewayBackend,
|
|
TransitGatewayBackend,
|
|
TransitGatewayRouteTableBackend,
|
|
TransitGatewayAttachmentBackend,
|
|
LaunchTemplateBackend,
|
|
IamInstanceProfileAssociationBackend,
|
|
CarrierGatewayBackend,
|
|
FleetsBackend,
|
|
WindowsBackend,
|
|
HostsBackend,
|
|
):
|
|
"""
|
|
moto includes a limited set of AMIs in `moto/ec2/resources/amis.json`.
|
|
Additionally, the default AMI's specified by SSM will be provided.
|
|
|
|
If you require specific AMIs to be available during your tests, you can provide your own AMI definitions by setting the
|
|
environment variable `MOTO_AMIS_PATH` to point to a JSON file containing definitions of the required AMIs.
|
|
No other AMI's will be loaded if this environment variable is set.
|
|
|
|
To create such a file, refer to `scripts/get_amis.py`
|
|
|
|
.. note:: You must set `MOTO_AMIS_PATH` before importing moto.
|
|
|
|
"""
|
|
|
|
def __init__(self, region_name: str, account_id: str):
|
|
BaseBackend.__init__(self, region_name, account_id)
|
|
for backend in EC2Backend.__mro__:
|
|
if backend not in [EC2Backend, BaseBackend, object]:
|
|
backend.__init__(self) # type: ignore
|
|
|
|
# Default VPC exists by default, which is the current behavior
|
|
# of EC2-VPC. See for detail:
|
|
#
|
|
# docs.aws.amazon.com/AmazonVPC/latest/UserGuide/default-vpc.html
|
|
#
|
|
if not self.vpcs:
|
|
vpc = self.create_default_vpc()
|
|
else:
|
|
# For now this is included for potential
|
|
# backward-compatibility issues
|
|
vpc = list(self.vpcs.values())[0]
|
|
|
|
self.default_vpc = vpc
|
|
|
|
# Create default subnet for each availability zone
|
|
ip, _ = vpc.cidr_block.split("/")
|
|
ip = ip.split(".") # type: ignore
|
|
ip[2] = 0 # type: ignore
|
|
|
|
for zone in self.describe_availability_zones():
|
|
az_name = zone.name
|
|
cidr_block = ".".join(str(i) for i in ip) + "/20"
|
|
self.create_subnet(vpc.id, cidr_block, availability_zone=az_name)
|
|
ip[2] += 16 # type: ignore
|
|
|
|
@staticmethod
|
|
def default_vpc_endpoint_service(service_region: str, zones: List[str]) -> List[Dict[str, Any]]: # type: ignore[misc]
|
|
"""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: str, message: str) -> None:
|
|
raise EC2ClientError(code, message)
|
|
|
|
def raise_not_implemented_error(self, blurb: str) -> None:
|
|
raise MotoNotImplementedError(blurb)
|
|
|
|
def do_resources_exist(self, resource_ids: List[str]) -> bool:
|
|
for resource_id in resource_ids:
|
|
resource_prefix = get_prefix(resource_id)
|
|
if resource_prefix == EC2_RESOURCE_TO_PREFIX["customer-gateway"]:
|
|
self.get_customer_gateway(customer_gateway_id=resource_id)
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["dhcp-options"]:
|
|
self.describe_dhcp_options(dhcp_options_ids=[resource_id])
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["image"]:
|
|
self.describe_images(ami_ids=[resource_id])
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["instance"]:
|
|
self.get_instance_by_id(instance_id=resource_id)
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["internet-gateway"]:
|
|
self.describe_internet_gateways(internet_gateway_ids=[resource_id])
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["launch-template"]:
|
|
self.get_launch_template(resource_id)
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["network-acl"]:
|
|
self.describe_network_acls()
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["network-interface"]:
|
|
self.describe_network_interfaces(
|
|
filters={"network-interface-id": resource_id}
|
|
)
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["reserved-instance"]:
|
|
self.raise_not_implemented_error("DescribeReservedInstances")
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["route-table"]:
|
|
self.get_route_table(route_table_id=resource_id)
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["security-group"]:
|
|
self.describe_security_groups(group_ids=[resource_id])
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["snapshot"]:
|
|
self.get_snapshot(snapshot_id=resource_id)
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["spot-instance-request"]:
|
|
self.describe_spot_instance_requests(
|
|
filters={"spot-instance-request-id": resource_id}
|
|
)
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["subnet"]:
|
|
self.get_subnet(subnet_id=resource_id)
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["volume"]:
|
|
self.get_volume(volume_id=resource_id)
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["vpc"]:
|
|
self.get_vpc(vpc_id=resource_id)
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["vpc-endpoint-service"]:
|
|
self.get_vpc_endpoint_service(resource_id)
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["vpc-peering-connection"]:
|
|
self.get_vpc_peering_connection(vpc_pcx_id=resource_id)
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["vpn-connection"]:
|
|
self.describe_vpn_connections(vpn_connection_ids=[resource_id])
|
|
elif resource_prefix == EC2_RESOURCE_TO_PREFIX["vpn-gateway"]:
|
|
self.get_vpn_gateway(vpn_gateway_id=resource_id)
|
|
elif (
|
|
resource_prefix
|
|
== EC2_RESOURCE_TO_PREFIX["iam-instance-profile-association"]
|
|
):
|
|
self.describe_iam_instance_profile_associations(
|
|
association_ids=[resource_id]
|
|
)
|
|
return True
|
|
|
|
|
|
ec2_backends = BackendDict(EC2Backend, "ec2")
|