from typing import Any, Dict, List, Optional from moto.core.common_models import CloudFormationModel from moto.core.utils import iso_8601_datetime_with_milliseconds, utcnow from ..utils import random_nat_gateway_id, random_private_ip from .core import TaggedEC2Resource class NatGateway(CloudFormationModel, TaggedEC2Resource): def __init__( self, backend: Any, subnet_id: str, allocation_id: str, tags: Optional[Dict[str, str]] = None, connectivity_type: str = "public", ): # public properties self.id = random_nat_gateway_id() self.subnet_id = subnet_id self.address_set: List[Dict[str, Any]] = [] self.state = "available" self.private_ip = random_private_ip() self.connectivity_type = connectivity_type # protected properties self._created_at = utcnow() self.ec2_backend = backend # NOTE: this is the core of NAT Gateways creation self._eni = self.ec2_backend.create_network_interface( backend.get_subnet(self.subnet_id), self.private_ip ) # associate allocation with ENI if allocation_id and connectivity_type != "private": self.ec2_backend.associate_address( eni=self._eni, allocation_id=allocation_id ) self.add_tags(tags or {}) self.vpc_id = self.ec2_backend.get_subnet(subnet_id).vpc_id @property def physical_resource_id(self) -> str: return self.id @property def create_time(self) -> str: return iso_8601_datetime_with_milliseconds(self._created_at) @staticmethod def cloudformation_name_type() -> str: return "" @staticmethod def cloudformation_type() -> str: # https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ec2-natgateway.html return "AWS::EC2::NatGateway" @classmethod def create_from_cloudformation_json( # type: ignore[misc] cls, resource_name: str, cloudformation_json: Any, account_id: str, region_name: str, **kwargs: Any, ) -> "NatGateway": from ..models import ec2_backends ec2_backend = ec2_backends[account_id][region_name] nat_gateway = ec2_backend.create_nat_gateway( cloudformation_json["Properties"]["SubnetId"], cloudformation_json["Properties"]["AllocationId"], ) return nat_gateway class NatGatewayBackend: def __init__(self) -> None: self.nat_gateways: Dict[str, NatGateway] = {} def describe_nat_gateways( self, filters: Any, nat_gateway_ids: Optional[List[str]] ) -> List[NatGateway]: nat_gateways = list(self.nat_gateways.values()) if nat_gateway_ids: nat_gateways = [item for item in nat_gateways if item.id in nat_gateway_ids] if filters is not None: if filters.get("nat-gateway-id") is not None: nat_gateways = [ nat_gateway for nat_gateway in nat_gateways if nat_gateway.id in filters["nat-gateway-id"] ] if filters.get("vpc-id") is not None: nat_gateways = [ nat_gateway for nat_gateway in nat_gateways if nat_gateway.vpc_id in filters["vpc-id"] ] if filters.get("subnet-id") is not None: nat_gateways = [ nat_gateway for nat_gateway in nat_gateways if nat_gateway.subnet_id in filters["subnet-id"] ] if filters.get("state") is not None: nat_gateways = [ nat_gateway for nat_gateway in nat_gateways if nat_gateway.state in filters["state"] ] return nat_gateways def create_nat_gateway( self, subnet_id: str, allocation_id: str, tags: Optional[Dict[str, str]] = None, connectivity_type: str = "public", ) -> NatGateway: nat_gateway = NatGateway( self, subnet_id, allocation_id, tags, connectivity_type ) address_set: Dict[str, Any] = {} if allocation_id: eips = self.address_by_allocation([allocation_id]) # type: ignore[attr-defined] eip = eips[0] if len(eips) > 0 else None if eip: address_set["allocationId"] = allocation_id address_set["publicIp"] = eip.public_ip or None address_set["associationId"] = eip.association_id or None address_set["networkInterfaceId"] = nat_gateway._eni.id address_set["privateIp"] = nat_gateway._eni.private_ip_address nat_gateway.address_set.append(address_set) self.nat_gateways[nat_gateway.id] = nat_gateway return nat_gateway def delete_nat_gateway(self, nat_gateway_id: str) -> NatGateway: nat_gw: NatGateway = self.nat_gateways.get(nat_gateway_id) # type: ignore nat_gw.state = "deleted" return nat_gw
Memory