Source code for infrahouse_core.aws.vpc
"""
VPC resource wrapper.
Provides ``exists`` / ``delete()`` support for EC2 VPCs.
"""
from __future__ import annotations
from logging import getLogger
from botocore.exceptions import ClientError
from infrahouse_core.aws.base import AWSResource
from infrahouse_core.aws.vpc_endpoint import VPCEndpoint
from infrahouse_core.aws.vpc_flow_log import VPCFlowLog
LOG = getLogger(__name__)
[docs]
class VPC(AWSResource):
"""Wrapper around an EC2 VPC.
:param vpc_id: VPC ID (e.g. ``vpc-0123456789abcdef0``).
:param region: AWS region.
:param role_arn: IAM role ARN for cross-account access.
"""
def __init__(self, vpc_id, region=None, role_arn=None, session=None):
super().__init__(vpc_id, "ec2", region=region, role_arn=role_arn, session=session)
@property
def vpc_id(self) -> str:
"""Return the VPC ID.
:rtype: str
"""
return self._resource_id
@property
def exists(self) -> bool:
"""Return ``True`` if the VPC exists."""
try:
self._client.describe_vpcs(VpcIds=[self._resource_id])
return True
except ClientError as err:
if err.response["Error"]["Code"] == "InvalidVpcID.NotFound":
return False
raise
@property
def vpc_endpoints(self) -> list[VPCEndpoint]:
"""Return all VPC endpoints associated with this VPC.
:rtype: list[VPCEndpoint]
"""
endpoints = []
paginator = self._client.get_paginator("describe_vpc_endpoints")
for page in paginator.paginate(Filters=[{"Name": "vpc-id", "Values": [self._resource_id]}]):
for ep in page.get("VpcEndpoints", []):
endpoints.append(
VPCEndpoint(
ep["VpcEndpointId"],
region=self._region,
role_arn=self._role_arn,
session=self._session,
)
)
return endpoints
@property
def flow_logs(self) -> list[VPCFlowLog]:
"""Return all flow logs associated with this VPC.
:rtype: list[VPCFlowLog]
"""
flow_logs = []
paginator = self._client.get_paginator("describe_flow_logs")
for page in paginator.paginate(Filters=[{"Name": "resource-id", "Values": [self._resource_id]}]):
for fl in page.get("FlowLogs", []):
flow_logs.append(
VPCFlowLog(
fl["FlowLogId"],
region=self._region,
role_arn=self._role_arn,
session=self._session,
)
)
return flow_logs
[docs]
def delete(self) -> None:
"""Delete the VPC.
Idempotent -- does nothing if the VPC does not exist.
.. warning::
All dependent resources (subnets, route tables, internet gateways,
VPC endpoints, etc.) must be deleted before the VPC can be removed.
"""
try:
self._client.delete_vpc(VpcId=self._resource_id)
LOG.info("Deleted VPC %s", self._resource_id)
except ClientError as err:
if err.response["Error"]["Code"] == "InvalidVpcID.NotFound":
LOG.info("VPC %s does not exist.", self._resource_id)
else:
raise