Add support for EC2 transit gateway associations (#4089)

Co-authored-by: Nevil Macwan <macnev2013@gmail.com>
Co-authored-by: monty16597 <alonjamohit77@gmail.com>
This commit is contained in:
Waldemar Hummer 2021-07-31 17:18:19 +02:00 committed by GitHub
parent 6803a473dc
commit 6eeb4b4b32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 595 additions and 121 deletions

View File

@ -33,7 +33,7 @@ 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
from moto.utilities.utils import load_resource, merge_multiple_dicts, filter_resources
from os import listdir
from .exceptions import (
@ -6016,29 +6016,18 @@ class TransitGatewayBackend(object):
return transit_gateway
def get_all_transit_gateways(self, filters):
transit_gateways = self.transit_gateways.values()
transit_gateways = list(self.transit_gateways.values())
if filters is not None:
if filters.get("transit-gateway-id") is not None:
transit_gateways = [
transit_gateway
for transit_gateway in transit_gateways
if transit_gateway.id in filters["transit-gateway-id"]
]
if filters.get("state") is not None:
transit_gateways = [
transit_gateway
for transit_gateway in transit_gateways
if transit_gateway.state in filters["state"]
]
if filters.get("owner-id") is not None:
transit_gateways = [
transit_gateway
for transit_gateway in transit_gateways
if transit_gateway.owner_id in filters["owner-id"]
]
attr_pairs = (
("transit-gateway-id", "id"),
("state", "state"),
("owner-id", "owner_id"),
)
return transit_gateways
result = transit_gateways
if filters:
result = filter_resources(transit_gateways, filters, attr_pairs)
return result
def delete_transit_gateway(self, transit_gateway_id):
return self.transit_gateways.pop(transit_gateway_id)
@ -6074,6 +6063,8 @@ class TransitGatewayRouteTable(TaggedEC2Resource):
self.state = "available"
self.routes = {}
self.add_tags(tags or {})
self.route_table_association = {}
self.route_table_propagation = {}
@property
def physical_resource_id(self):
@ -6109,9 +6100,9 @@ class TransitGatewayRouteTableBackend(object):
return transit_gateways_route_table
def get_all_transit_gateway_route_tables(
self, transit_gateway_ids=None, filters=None
self, transit_gateway_route_table_ids=None, filters=None
):
transit_gateway_route_tables = self.transit_gateways_route_tables.values()
transit_gateway_route_tables = list(self.transit_gateways_route_tables.values())
attr_pairs = (
("default-association-route-table", "default_association_route_table"),
@ -6121,28 +6112,24 @@ class TransitGatewayRouteTableBackend(object):
("transit-gateway-route-table-id", "id"),
)
if transit_gateway_ids:
if transit_gateway_route_table_ids:
transit_gateway_route_tables = [
transit_gateway_route_table
for transit_gateway_route_table in transit_gateway_route_tables
if transit_gateway_route_table.id in transit_gateway_ids
if transit_gateway_route_table.id in transit_gateway_route_table_ids
]
result = transit_gateway_route_tables
if filters:
for attrs in attr_pairs:
values = filters.get(attrs[0]) or None
if values is not None:
transit_gateway_route_tables = [
transit_gateway_route_table
for transit_gateway_route_table in transit_gateway_route_tables
if not values
or getattr(transit_gateway_route_table, attrs[1]) in values
]
return transit_gateway_route_tables
result = filter_resources(transit_gateway_route_tables, filters, attr_pairs)
return result
def delete_transit_gateway_route_table(self, transit_gateway_route_table_id):
return self.transit_gateways_route_tables.pop(transit_gateway_route_table_id)
transit_gateways_route_table = self.transit_gateways_route_tables[
transit_gateway_route_table_id
]
transit_gateways_route_table.state = "deleted"
return transit_gateways_route_table
def create_transit_gateway_route(
self,
@ -6151,22 +6138,31 @@ class TransitGatewayRouteTableBackend(object):
transit_gateway_attachment_id=None,
blackhole=False,
):
transit_gateways_route_table = self.transit_gateways_route_tables[
transit_gateways_route_table = self.transit_gateways_route_tables.get(
transit_gateway_route_table_id
]
)
transit_gateway_attachment = self.transit_gateway_attachments.get(
transit_gateway_attachment_id
)
transit_gateways_route_table.routes[destination_cidr_block] = {
"destinationCidrBlock": destination_cidr_block,
"prefixListId": "",
"state": "blackhole" if blackhole else "active",
# TODO: needs to be fixed once we have support for transit gateway attachments
"transitGatewayAttachments": {
"resourceId": "TODO",
"resourceType": "TODO",
"transitGatewayAttachmentId": transit_gateway_attachment_id,
},
"type": "TODO",
"type": "static",
}
return transit_gateways_route_table
if transit_gateway_attachment:
transit_gateway_attachment_dict = {
"transitGatewayAttachments": {
"resourceId": transit_gateway_attachment.resource_id,
"resourceType": transit_gateway_attachment.resource_type,
"transitGatewayAttachmentId": transit_gateway_attachment_id,
}
}
transit_gateways_route_table.routes[destination_cidr_block].update(
transit_gateway_attachment_dict
)
return transit_gateways_route_table.routes[destination_cidr_block]
def delete_transit_gateway_route(
self, transit_gateway_route_table_id, destination_cidr_block,
@ -6180,27 +6176,120 @@ class TransitGatewayRouteTableBackend(object):
def search_transit_gateway_routes(
self, transit_gateway_route_table_id, filters, max_results=None
):
transit_gateway_route_table = self.transit_gateways_route_tables[
transit_gateway_route_table = self.transit_gateways_route_tables.get(
transit_gateway_route_table_id
]
)
if not transit_gateway_route_table:
return []
attr_pairs = (
("type", "type"),
("state", "state"),
)
for attrs in attr_pairs:
values = filters.get(attrs[0]) or None
if values:
routes = [
transit_gateway_route_table.routes[key]
for key in transit_gateway_route_table.routes
if transit_gateway_route_table.routes[key][attrs[1]] in values
]
routes = transit_gateway_route_table.routes.copy()
for key in transit_gateway_route_table.routes:
for attrs in attr_pairs:
values = filters.get(attrs[0]) or None
if values:
if routes.get(key).get(attrs[1]) not in values:
routes.pop(key)
break
if max_results:
routes = routes[: int(max_results)]
return routes
def set_route_table_association(
self, transit_gateway_attachment_id, transit_gateway_route_table_id
):
self.transit_gateways_route_tables[
transit_gateway_route_table_id
].route_table_association = {
"resourceId": self.transit_gateway_attachments[
transit_gateway_attachment_id
].resource_id,
"resourceType": self.transit_gateway_attachments[
transit_gateway_attachment_id
].resource_type,
"state": "associated",
"transitGatewayAttachmentId": transit_gateway_attachment_id,
}
def set_route_table_propagation(
self, transit_gateway_attachment_id, transit_gateway_route_table_id
):
self.transit_gateways_route_tables[
transit_gateway_route_table_id
].route_table_propagation = {
"resourceId": self.transit_gateway_attachments[
transit_gateway_attachment_id
].resource_id,
"resourceType": self.transit_gateway_attachments[
transit_gateway_attachment_id
].resource_type,
"state": "enabled",
"transitGatewayAttachmentId": transit_gateway_attachment_id,
}
def disable_route_table_propagation(self, transit_gateway_route_table_id):
self.transit_gateways_route_tables[
transit_gateway_route_table_id
].route_table_propagation = {}
def get_all_transit_gateway_route_table_associations(
self, transit_gateway_route_table_id=None, filters=None
):
transit_gateway_route_tables = list(self.transit_gateways_route_tables.values())
if transit_gateway_route_tables:
transit_gateway_route_tables = [
transit_gateway_route_table
for transit_gateway_route_table in transit_gateway_route_tables
if transit_gateway_route_table.id in transit_gateway_route_table_id
]
attr_pairs = (
("resource-id", "route_table_association", "resourceId"),
("resource-type", "route_table_association", "resourceType"),
(
"transit-gateway-attachment-id",
"route_table_association",
"transitGatewayAttachmentId",
),
)
result = transit_gateway_route_tables
if filters:
result = filter_resources(transit_gateway_route_tables, filters, attr_pairs)
return result
def get_all_transit_gateway_route_table_propagations(
self, transit_gateway_route_table_id=None, filters=None
):
transit_gateway_route_tables = list(self.transit_gateways_route_tables.values())
if transit_gateway_route_tables:
transit_gateway_route_tables = [
transit_gateway_route_table
for transit_gateway_route_table in transit_gateway_route_tables
if transit_gateway_route_table.id in transit_gateway_route_table_id
]
attr_pairs = (
("resource-id", "route_table_propagation", "resourceId"),
("resource-type", "route_table_propagation", "resourceType"),
(
"transit-gateway-attachment-id",
"route_table_propagation",
"transitGatewayAttachmentId",
),
)
result = transit_gateway_route_tables
if filters:
result = filter_resources(transit_gateway_route_tables, filters, attr_pairs)
return result
class TransitGatewayAttachment(TaggedEC2Resource):
def __init__(
@ -6209,6 +6298,7 @@ class TransitGatewayAttachment(TaggedEC2Resource):
self.ec2_backend = backend
self.association = {}
self.propagation = {}
self.resource_id = resource_id
self.resource_type = resource_type
@ -6261,7 +6351,7 @@ class TransitGatewayVpcAttachment(TransitGatewayAttachment):
class TransitGatewayAttachmentBackend(object):
def __init__(self):
self.transit_gateways_attachments = {}
self.transit_gateway_attachments = {}
super(TransitGatewayAttachmentBackend, self).__init__()
def create_transit_gateway_vpn_attachment(
@ -6274,7 +6364,7 @@ class TransitGatewayAttachmentBackend(object):
transit_gateway_id=transit_gateway_id,
tags=tags,
)
self.transit_gateways_attachments[
self.transit_gateway_attachments[
transit_gateway_vpn_attachment.id
] = transit_gateway_vpn_attachment
return transit_gateway_vpn_attachment
@ -6290,7 +6380,7 @@ class TransitGatewayAttachmentBackend(object):
subnet_ids=subnet_ids,
options=options,
)
self.transit_gateways_attachments[
self.transit_gateway_attachments[
transit_gateway_vpc_attachment.id
] = transit_gateway_vpc_attachment
return transit_gateway_vpc_attachment
@ -6298,7 +6388,7 @@ class TransitGatewayAttachmentBackend(object):
def describe_transit_gateway_attachments(
self, transit_gateways_attachment_ids=None, filters=None, max_results=0
):
transit_gateways_attachments = self.transit_gateways_attachments.values()
transit_gateway_attachments = list(self.transit_gateway_attachments.values())
attr_pairs = (
("resource-id", "resource_id"),
@ -6306,28 +6396,25 @@ class TransitGatewayAttachmentBackend(object):
("transit-gateway-id", "transit_gateway_id"),
)
if transit_gateways_attachment_ids:
transit_gateways_attachments = [
if (
not transit_gateways_attachment_ids == []
and transit_gateways_attachment_ids is not None
):
transit_gateway_attachments = [
transit_gateways_attachment
for transit_gateways_attachment in transit_gateways_attachments
for transit_gateways_attachment in transit_gateway_attachments
if transit_gateways_attachment.id in transit_gateways_attachment_ids
]
result = transit_gateway_attachments
if filters:
for attrs in attr_pairs:
values = filters.get(attrs[0]) or None
if values is not None:
transit_gateways_attachments = [
transit_gateways_attachment
for transit_gateways_attachment in transit_gateways_attachments
if getattr(transit_gateways_attachment, attrs[1]) in values
]
return transit_gateways_attachments
result = filter_resources(transit_gateway_attachments, filters, attr_pairs)
return result
def describe_transit_gateway_vpc_attachments(
self, transit_gateways_attachment_ids=None, filters=None, max_results=0
):
transit_gateways_attachments = self.transit_gateways_attachments.values()
transit_gateway_attachments = list(self.transit_gateway_attachments.values())
attr_pairs = (
("state", "state"),
@ -6340,23 +6427,155 @@ class TransitGatewayAttachmentBackend(object):
not transit_gateways_attachment_ids == []
and transit_gateways_attachment_ids is not None
):
transit_gateways_attachments = [
transit_gateway_attachments = [
transit_gateways_attachment
for transit_gateways_attachment in transit_gateways_attachments
for transit_gateways_attachment in transit_gateway_attachments
if transit_gateways_attachment.id in transit_gateways_attachment_ids
]
result = transit_gateway_attachments
if filters:
for attrs in attr_pairs:
values = filters.get(attrs[0]) or None
if values is not None:
transit_gateways_attachments = [
transit_gateways_attachment
for transit_gateways_attachment in transit_gateways_attachments
if getattr(transit_gateways_attachment, attrs[1]) in values
]
result = filter_resources(transit_gateway_attachments, filters, attr_pairs)
return result
return transit_gateways_attachments
def delete_transit_gateway_vpc_attachment(self, transit_gateway_attachment_id=None):
transit_gateway_attachment = self.transit_gateway_attachments.pop(
transit_gateway_attachment_id
)
transit_gateway_attachment.state = "deleted"
return transit_gateway_attachment
def modify_transit_gateway_vpc_attachment(
self,
add_subnet_ids=None,
options=None,
remove_subnet_ids=None,
transit_gateway_attachment_id=None,
):
tgw_attachment = self.transit_gateway_attachments[transit_gateway_attachment_id]
if remove_subnet_ids:
tgw_attachment.subnet_ids = [
id for id in tgw_attachment.subnet_ids if id not in remove_subnet_ids
]
if options:
tgw_attachment.options.update(options)
if add_subnet_ids:
for id in add_subnet_ids:
tgw_attachment.subnet_ids.append(id)
return tgw_attachment
def set_attachment_association(
self, transit_gateway_attachment_id=None, transit_gateway_route_table_id=None
):
self.transit_gateway_attachments[transit_gateway_attachment_id].association = {
"state": "associated",
"transitGatewayRouteTableId": transit_gateway_route_table_id,
}
def set_attachment_propagation(
self, transit_gateway_attachment_id=None, transit_gateway_route_table_id=None
):
self.transit_gateway_attachments[transit_gateway_attachment_id].propagation = {
"state": "enabled",
"transitGatewayRouteTableId": transit_gateway_route_table_id,
}
def disable_attachment_propagation(self, transit_gateway_attachment_id=None):
self.transit_gateway_attachments[transit_gateway_attachment_id].propagation[
"state"
] = "disabled"
class TransitGatewayRelations(object):
# this class is for TransitGatewayAssociation and TransitGatewayPropagation
def __init__(
self,
backend,
transit_gateway_attachment_id=None,
transit_gateway_route_table_id=None,
state=None,
):
self.ec2_backend = backend
self.transit_gateway_attachment_id = transit_gateway_attachment_id
self.transit_gateway_route_table_id = transit_gateway_route_table_id
self.resource_id = backend.transit_gateway_attachments[
transit_gateway_attachment_id
].resource_id
self.resource_type = backend.transit_gateway_attachments[
transit_gateway_attachment_id
].resource_type
self.state = state
class TransitGatewayRelationsBackend(object):
def __init__(self):
self.transit_gateway_associations = {}
self.transit_gateway_propagations = {}
super(TransitGatewayRelationsBackend, self).__init__()
def associate_transit_gateway_route_table(
self, transit_gateway_attachment_id=None, transit_gateway_route_table_id=None
):
transit_gateway_association = TransitGatewayRelations(
self,
transit_gateway_attachment_id,
transit_gateway_route_table_id,
state="associated",
)
self.set_route_table_association(
transit_gateway_attachment_id, transit_gateway_route_table_id
)
self.set_attachment_association(
transit_gateway_attachment_id, transit_gateway_route_table_id
)
self.transit_gateway_associations[
transit_gateway_attachment_id
] = transit_gateway_association
return transit_gateway_association
def enable_transit_gateway_route_table_propagation(
self, transit_gateway_attachment_id=None, transit_gateway_route_table_id=None
):
transit_gateway_propagation = TransitGatewayRelations(
self,
transit_gateway_attachment_id,
transit_gateway_route_table_id,
state="enabled",
)
self.set_route_table_propagation(
transit_gateway_attachment_id, transit_gateway_route_table_id
)
self.set_attachment_propagation(
transit_gateway_attachment_id, transit_gateway_route_table_id
)
self.transit_gateway_propagations[
transit_gateway_attachment_id
] = transit_gateway_propagation
return transit_gateway_propagation
def disable_transit_gateway_route_table_propagation(
self, transit_gateway_attachment_id=None, transit_gateway_route_table_id=None
):
self.disable_route_table_propagation(
transit_gateway_route_table_id=transit_gateway_route_table_id
)
self.disable_attachment_propagation(
transit_gateway_attachment_id=transit_gateway_attachment_id
)
self.transit_gateway_propagations[
transit_gateway_attachment_id
].state = "disabled"
transit_gateway_propagation = self.transit_gateway_propagations.pop(
transit_gateway_attachment_id
)
return transit_gateway_propagation
class NatGateway(CloudFormationModel):
@ -6721,6 +6940,7 @@ class EC2Backend(
TransitGatewayBackend,
TransitGatewayRouteTableBackend,
TransitGatewayAttachmentBackend,
TransitGatewayRelationsBackend,
LaunchTemplateBackend,
IamInstanceProfileAssociationBackend,
):

View File

@ -41,6 +41,21 @@ class TransitGatewayAttachment(BaseResponse):
transit_gateway_vpc_attachments=transit_gateway_vpc_attachments
)
def modify_transit_gateway_vpc_attachment(self):
add_subnet_ids = self._get_multi_param("AddSubnetIds")
options = self._get_multi_param_dict("Options")
remove_subnet_ids = self._get_multi_param("RemoveSubnetIds")
transit_gateway_attachment_id = self._get_param("TransitGatewayAttachmentId")
transit_gateway_attachment = self.ec2_backend.modify_transit_gateway_vpc_attachment(
add_subnet_ids=add_subnet_ids,
options=options,
remove_subnet_ids=remove_subnet_ids,
transit_gateway_attachment_id=transit_gateway_attachment_id,
)
template = self.response_template(MODIFY_TRANSIT_GATEWAY_VPC_ATTACHMENTS)
return template.render(transit_gateway_attachment=transit_gateway_attachment)
def describe_transit_gateway_attachments(self):
transit_gateways_attachment_ids = self._get_multi_param(
"TransitGatewayAttachmentIds"
@ -55,6 +70,44 @@ class TransitGatewayAttachment(BaseResponse):
template = self.response_template(DESCRIBE_TRANSIT_GATEWAY_ATTACHMENTS)
return template.render(transit_gateway_attachments=transit_gateway_attachments)
def delete_transit_gateway_vpc_attachment(self):
transit_gateway_attachment_id = self._get_param("TransitGatewayAttachmentId")
transit_gateway_attachment = self.ec2_backend.delete_transit_gateway_vpc_attachment(
transit_gateway_attachment_id=transit_gateway_attachment_id
)
template = self.response_template(DELETE_TRANSIT_GATEWAY_VPC_ATTACHMENTS)
return template.render(transit_gateway_attachment=transit_gateway_attachment)
def associate_transit_gateway_route_table(self):
transit_gateway_attachment_id = self._get_param("TransitGatewayAttachmentId")
transit_gateway_route_table_id = self._get_param("TransitGatewayRouteTableId")
transit_gateway_association = self.ec2_backend.associate_transit_gateway_route_table(
transit_gateway_attachment_id=transit_gateway_attachment_id,
transit_gateway_route_table_id=transit_gateway_route_table_id,
)
template = self.response_template(TRANSIT_GATEWAY_ASSOCIATION)
return template.render(transit_gateway_association=transit_gateway_association)
def enable_transit_gateway_route_table_propagation(self):
transit_gateway_attachment_id = self._get_param("TransitGatewayAttachmentId")
transit_gateway_route_table_id = self._get_param("TransitGatewayRouteTableId")
transit_gateway_propagation = self.ec2_backend.enable_transit_gateway_route_table_propagation(
transit_gateway_attachment_id=transit_gateway_attachment_id,
transit_gateway_route_table_id=transit_gateway_route_table_id,
)
template = self.response_template(TRANSIT_GATEWAY_PROPAGATION)
return template.render(transit_gateway_propagation=transit_gateway_propagation)
def disable_transit_gateway_route_table_propagation(self):
transit_gateway_attachment_id = self._get_param("TransitGatewayAttachmentId")
transit_gateway_route_table_id = self._get_param("TransitGatewayRouteTableId")
transit_gateway_propagation = self.ec2_backend.disable_transit_gateway_route_table_propagation(
transit_gateway_attachment_id=transit_gateway_attachment_id,
transit_gateway_route_table_id=transit_gateway_route_table_id,
)
template = self.response_template(TRANSIT_GATEWAY_PROPAGATION)
return template.render(transit_gateway_propagation=transit_gateway_propagation)
CREATE_TRANSIT_GATEWAY_VPC_ATTACHMENT = """<CreateTransitGatewayVpcAttachmentResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>9b5766ac-2af6-4b92-9a8a-4d74ae46ae79</requestId>
@ -153,3 +206,91 @@ DESCRIBE_TRANSIT_GATEWAY_VPC_ATTACHMENTS = """<DescribeTransitGatewayVpcAttachme
</transitGatewayVpcAttachments>
</DescribeTransitGatewayVpcAttachmentsResponse>
"""
MODIFY_TRANSIT_GATEWAY_VPC_ATTACHMENTS = """<ModifyTransitGatewayVpcAttachmentResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>9b5766ac-2af6-4b92-9a8a-4d74ae46ae79</requestId>
<transitGatewayVpcAttachment>
<createTime>{{ transit_gateway_attachment.create_time }}</createTime>
<options>
<applianceModeSupport>{{ transit_gateway_attachment.options.ApplianceModeSupport }}</applianceModeSupport>
<dnsSupport>{{ transit_gateway_attachment.options.DnsSupport }}</dnsSupport>
<ipv6Support>{{ transit_gateway_attachment.options.Ipv6Support }}</ipv6Support>
</options>
<state>{{ transit_gateway_attachment.state }}</state>
<subnetIds>
{% for subnet_id in transit_gateway_attachment.subnet_ids %}
<item>{{ subnet_id }}</item>
{% endfor %}
</subnetIds>
<tagSet>
{% for tag in transit_gateway_attachment.get_tags() %}
<item>
<key>{{ tag.key }}</key>
<value>{{ tag.value }}</value>
</item>
{% endfor %}
</tagSet>
<transitGatewayAttachmentId>{{ transit_gateway_attachment.id }}</transitGatewayAttachmentId>
<transitGatewayId>{{ transit_gateway_attachment.transit_gateway_id }}</transitGatewayId>
<vpcId>{{ transit_gateway_attachment.vpc_id }}</vpcId>
<vpcOwnerId>{{ transit_gateway_attachment.resource_owner_id }}</vpcOwnerId>
</transitGatewayVpcAttachment>
</ModifyTransitGatewayVpcAttachmentResponse>"""
DELETE_TRANSIT_GATEWAY_VPC_ATTACHMENTS = """<DeleteTransitGatewayVpcAttachmentResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>9b5766ac-2af6-4b92-9a8a-4d74ae46ae79</requestId>
<transitGatewayVpcAttachment>
<createTime>{{ transit_gateway_attachment.create_time }}</createTime>
<options>
<applianceModeSupport>{{ transit_gateway_attachment.options.ApplianceModeSupport }}</applianceModeSupport>
<dnsSupport>{{ transit_gateway_attachment.options.DnsSupport }}</dnsSupport>
<ipv6Support>{{ transit_gateway_attachment.options.Ipv6Support }}</ipv6Support>
</options>
<state>{{ transit_gateway_attachment.state }}</state>
<subnetIds>
{% for subnet_id in transit_gateway_attachment.subnet_ids %}
<item>{{ subnet_id }}</item>
{% endfor %}
</subnetIds>
<tagSet>
{% for tag in transit_gateway_attachment.get_tags() %}
<item>
<key>{{ tag.key }}</key>
<value>{{ tag.value }}</value>
</item>
{% endfor %}
</tagSet>
<transitGatewayAttachmentId>{{ transit_gateway_attachment.id }}</transitGatewayAttachmentId>
<transitGatewayId>{{ transit_gateway_attachment.transit_gateway_id }}</transitGatewayId>
<vpcId>{{ transit_gateway_attachment.vpc_id }}</vpcId>
<vpcOwnerId>{{ transit_gateway_attachment.resource_owner_id }}</vpcOwnerId>
</transitGatewayVpcAttachment>
</DeleteTransitGatewayVpcAttachmentResponse>"""
TRANSIT_GATEWAY_ASSOCIATION = """<AssociateTransitGatewayRouteTableResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>86a597cf-93ec-44a3-9559-4641863642a5</requestId>
<association>
<resourceId>{{ transit_gateway_association.resource_id }}</resourceId>
<resourceType>{{ transit_gateway_association.resource_type }}</resourceType>
<state>{{ transit_gateway_association.state }}</state>
<transitGatewayAttachmentId>{{ transit_gateway_association.transit_gateway_attachment_id }}</transitGatewayAttachmentId>
<transitGatewayRouteTableId>{{ transit_gateway_association.transit_gateway_route_table_id }}</transitGatewayRouteTableId>
</association>
</AssociateTransitGatewayRouteTableResponse>
"""
TRANSIT_GATEWAY_PROPAGATION = """<EnableTransitGatewayRouteTablePropagationResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>c78427d4-e498-46ae-bc14-32841b16bff4</requestId>
<propagation>
<resourceId>{{ transit_gateway_propagation.resource_id }}</resourceId>
<resourceType>{{ transit_gateway_propagation.resource_type }}</resourceType>
<state>{{ transit_gateway_propagation.state }}</state>
<transitGatewayAttachmentId>{{ transit_gateway_propagation.transit_gateway_attachment_id }}</transitGatewayAttachmentId>
<transitGatewayRouteTableId>{{ transit_gateway_propagation.transit_gateway_route_table_id }}</transitGatewayRouteTableId>
</propagation>
</EnableTransitGatewayRouteTablePropagationResponse>
"""

View File

@ -20,11 +20,11 @@ class TransitGatewayRouteTable(BaseResponse):
def describe_transit_gateway_route_tables(self):
filters = filters_from_querystring(self.querystring)
transit_gateway_ids = (
transit_gateway_route_table_ids = (
self._get_multi_param("TransitGatewayRouteTableIds") or None
)
transit_gateway_route_tables = self.ec2_backend.get_all_transit_gateway_route_tables(
transit_gateway_ids, filters
transit_gateway_route_table_ids, filters
)
template = self.response_template(DESCRIBE_TRANSIT_GATEWAY_ROUTE_TABLE_RESPONSE)
return template.render(
@ -83,6 +83,32 @@ class TransitGatewayRouteTable(BaseResponse):
template = self.response_template(SEARCH_TRANSIT_GATEWAY_ROUTES_RESPONSE)
return template.render(transit_gateway_routes=transit_gateway_routes)
def get_transit_gateway_route_table_associations(self):
transit_gateway_route_table_id = self._get_param("TransitGatewayRouteTableId")
filters = filters_from_querystring(self.querystring)
transit_gateway_route_table_associations = self.ec2_backend.get_all_transit_gateway_route_table_associations(
transit_gateway_route_table_id, filters
)
template = self.response_template(
GET_TRANSIT_GATEWAY_ROUTE_TABLE_ASSOCIATIONS_RESPONSE
)
return template.render(
transit_gateway_route_table_associations=transit_gateway_route_table_associations
)
def get_transit_gateway_route_table_propagations(self):
transit_gateway_route_table_id = self._get_param("TransitGatewayRouteTableId")
filters = filters_from_querystring(self.querystring)
transit_gateway_route_table_propagations = self.ec2_backend.get_all_transit_gateway_route_table_propagations(
transit_gateway_route_table_id, filters
)
template = self.response_template(
GET_TRANSIT_GATEWAY_ROUTE_TABLE_PROPAGATIONS_RESPONSE
)
return template.render(
transit_gateway_route_table_propagations=transit_gateway_route_table_propagations
)
CREATE_TRANSIT_GATEWAY_ROUTE_TABLE_RESPONSE = """<CreateTransitGatewayRouteTableResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>3a495d25-08d4-466d-822e-477c9b1fc606</requestId>
@ -133,16 +159,12 @@ DESCRIBE_TRANSIT_GATEWAY_ROUTE_TABLE_RESPONSE = """<DescribeTransitGatewayRouteT
DELETE_TRANSIT_GATEWAY_ROUTE_TABLE_RESPONSE = """<DeleteTransitGatewayRouteTableResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>a9a07226-c7b1-4305-9934-0bcfc3ef1c5e</requestId>
<transitGatewayRouteTable>
{% for transit_gateway_route_table in transit_gateway_route_tables %}
<item>
<creationTime>{{ transit_gateway_route_table.create_time }}</creationTime>
<defaultAssociationRouteTable>{{ transit_gateway_route_table.default_association_route_table }}</defaultAssociationRouteTable>
<defaultPropagationRouteTable>{{ transit_gateway_route_table.default_propagation_route_table }}</defaultPropagationRouteTable>
<state>{{ transit_gateway_route_table.state }}</state>
<transitGatewayId>{{ transit_gateway_route_table.transit_gateway_id }}</transitGatewayId>
<transitGatewayRouteTableId>{{ transit_gateway_route_table.id }}</transitGatewayRouteTableId>
</item>
{% endfor %}
<creationTime>{{ transit_gateway_route_table.create_time }}</creationTime>
<defaultAssociationRouteTable>{{ transit_gateway_route_table.default_association_route_table }}</defaultAssociationRouteTable>
<defaultPropagationRouteTable>{{ transit_gateway_route_table.default_propagation_route_table }}</defaultPropagationRouteTable>
<state>{{ transit_gateway_route_table.state }}</state>
<transitGatewayId>{{ transit_gateway_route_table.transit_gateway_id }}</transitGatewayId>
<transitGatewayRouteTableId>{{ transit_gateway_route_table.id }}</transitGatewayRouteTableId>
</transitGatewayRouteTable>
</DeleteTransitGatewayRouteTableResponse>
"""
@ -152,9 +174,18 @@ CREATE_TRANSIT_GATEWAY_ROUTE_RESPONSE = """<?xml version="1.0" encoding="UTF-8"?
<CreateTransitGatewayRouteResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>072b02ce-df3a-4de6-a20b-6653ae4b91a4</requestId>
<route>
<destinationCidrBlock>{{ transit_gateway_route_table.routes[destination_cidr_block]['destinationCidrBlock'] }}</destinationCidrBlock>
<state>{{ transit_gateway_route_table.routes[destination_cidr_block]['state'] }}</state>
<type>{{ transit_gateway_route_table.routes[destination_cidr_block]['type'] }}</type>
<destinationCidrBlock>{{ transit_gateway_route_table.destinationCidrBlock }}</destinationCidrBlock>
<state>{{ transit_gateway_route_table.state }}</state>
<type>{{ transit_gateway_route_table.type }}</type>
<transitGatewayAttachments>
{% if transit_gateway_route_table.state != 'blackhole' and transit_gateway_route_table.transitGatewayAttachments %}
<item>
<resourceId>{{ transit_gateway_route_table.transitGatewayAttachments.resourceId }}</resourceId>
<resourceType>{{ transit_gateway_route_table.transitGatewayAttachments.resourceType }}</resourceType>
<transitGatewayAttachmentId>{{ transit_gateway_route_table.transitGatewayAttachments.transitGatewayAttachmentId }}</transitGatewayAttachmentId>
</item>
{% endif %}
</transitGatewayAttachments>
</route>
</CreateTransitGatewayRouteResponse>
"""
@ -163,9 +194,9 @@ DELETE_TRANSIT_GATEWAY_ROUTE_RESPONSE = """<?xml version="1.0" encoding="UTF-8"?
<DeleteTransitGatewayRouteResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>2109d5bb-f874-4f35-b419-4723792a638f</requestId>
<route>
<destinationCidrBlock>{{ transit_gateway_route_table.routes[destination_cidr_block]['destinationCidrBlock'] }}</destinationCidrBlock>
<state>{{ transit_gateway_route_table.routes[destination_cidr_block]['state'] }}</state>
<type>{{ transit_gateway_route_table.routes[destination_cidr_block]['type'] }}</type>
<destinationCidrBlock>{{ transit_gateway_route_table.routes[destination_cidr_block].destinationCidrBlock }}</destinationCidrBlock>
<state>{{ transit_gateway_route_table.routes[destination_cidr_block].state }}</state>
<type>{{ transit_gateway_route_table.routes[destination_cidr_block].type }}</type>
</route>
</DeleteTransitGatewayRouteResponse>
"""
@ -176,12 +207,49 @@ SEARCH_TRANSIT_GATEWAY_ROUTES_RESPONSE = """<?xml version="1.0" encoding="UTF-8"
<routeSet>
{% for route in transit_gateway_routes %}
<item>
<destinationCidrBlock>{{ route['destinationCidrBlock'] }}</destinationCidrBlock>
<state>{{ route['state'] }}</state>
<type>{{ route['type'] }}</type>
<destinationCidrBlock>{{ transit_gateway_routes[route].destinationCidrBlock }}</destinationCidrBlock>
<state>{{ transit_gateway_routes[route].state }}</state>
<type>{{ transit_gateway_routes[route].type }}</type>
{% if transit_gateway_routes[route].get('transitGatewayAttachments') %}
<transitGatewayAttachments>
<item>
<resourceId>{{ transit_gateway_routes[route].transitGatewayAttachments.resourceId }}</resourceId>
<resourceType>{{ transit_gateway_routes[route].transitGatewayAttachments.resourceType }}</resourceType>
<transitGatewayAttachmentId>{{ transit_gateway_routes[route].transitGatewayAttachments.transitGatewayAttachmentId }}</transitGatewayAttachmentId>
</item>
</transitGatewayAttachments>
{% endif %}
</item>
{% endfor %}
</routeSet>
<additionalRoutesAvailable>false</additionalRoutesAvailable>
</SearchTransitGatewayRoutesResponse>
"""
GET_TRANSIT_GATEWAY_ROUTE_TABLE_ASSOCIATIONS_RESPONSE = """<GetTransitGatewayRouteTableAssociationsResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>92fdc91d-c374-4217-b2b4-33f2fb0a2be7</requestId>
<associations>
{% for route_table in transit_gateway_route_table_associations %}
<item>
<resourceId>{{ route_table.route_table_association.resourceId }}</resourceId>
<resourceType>{{ route_table.route_table_association.resourceType }}</resourceType>
<state>{{ route_table.route_table_association.state }}</state>
<transitGatewayAttachmentId>{{ route_table.route_table_association.transitGatewayAttachmentId }}</transitGatewayAttachmentId>
</item>
{% endfor %}
</associations>
</GetTransitGatewayRouteTableAssociationsResponse>"""
GET_TRANSIT_GATEWAY_ROUTE_TABLE_PROPAGATIONS_RESPONSE = """<GetTransitGatewayRouteTablePropagationsResponse xmlns="http://ec2.amazonaws.com/doc/2016-11-15/">
<requestId>541bc42d-9ed9-4aef-a5f7-2ea32fbdec16</requestId>
<transitGatewayRouteTablePropagations>
{% for route_table in transit_gateway_route_table_propagations %}
<item>
<resourceId>{{ route_table.route_table_propagation.resourceId }}</resourceId>
<resourceType>{{ route_table.route_table_propagation.resourceType }}</resourceType>
<state>{{ route_table.route_table_propagation.state }}</state>
<transitGatewayAttachmentId>{{ route_table.route_table_propagation.transitGatewayAttachmentId }}</transitGatewayAttachmentId>
</item>
{% endfor %}
</transitGatewayRouteTablePropagations>
</GetTransitGatewayRouteTablePropagationsResponse>"""

View File

@ -14,6 +14,21 @@ class TransitGateways(BaseResponse):
transit_gateway = self.ec2_backend.create_transit_gateway(
description=description, options=options, tags=tags
)
# creating default route table
transit_gateway_route_table = self.ec2_backend.create_transit_gateway_route_table(
transit_gateway_id=transit_gateway.id,
tags={},
default_association_route_table=True,
default_propagation_route_table=True,
)
transit_gateway.options[
"AssociationDefaultRouteTableId"
] = transit_gateway_route_table.id
transit_gateway.options[
"PropagationDefaultRouteTableId"
] = transit_gateway_route_table.id
template = self.response_template(CREATE_TRANSIT_GATEWAY_RESPONSE)
return template.render(transit_gateway=transit_gateway)

View File

@ -34,3 +34,21 @@ def merge_multiple_dicts(*args):
for d in args:
result.update(d)
return result
def filter_resources(resources, filters, attr_pairs):
"""
Used to filter resources. Usually in get and describe apis.
"""
result = resources.copy()
for resource in resources:
for attrs in attr_pairs:
values = filters.get(attrs[0]) or None
if values:
instance = getattr(resource, attrs[1])
if (len(attrs) <= 2 and instance not in values) or (
len(attrs) == 3 and instance.get(attrs[2]) not in values
):
result.remove(resource)
break
return result

View File

@ -2,10 +2,7 @@ TestAccAWSEc2TransitGatewayDxGatewayAttachmentDataSource
TestAccAWSEc2TransitGatewayPeeringAttachment
TestAccAWSEc2TransitGatewayPeeringAttachmentAccepter
TestAccAWSEc2TransitGatewayPeeringAttachmentDataSource
TestAccAWSEc2TransitGatewayRoute
TestAccAWSEc2TransitGatewayRouteTableAssociation
TestAccAWSEc2TransitGatewayRouteTablePropagation
TestAccAWSEc2TransitGatewayVpcAttachment
TestAccAWSEc2TransitGatewayVpcAttachmentDataSource
TestAccAWSFms
TestAccAWSIAMRolePolicy

View File

@ -26,10 +26,18 @@ TestAccAWSEc2InstanceTypeOfferingDataSource
TestAccAWSEc2InstanceTypeOfferingsDataSource
TestAccAWSEc2Tag
TestAccAWSEc2TransitGateway
TestAccAWSEc2TransitGatewayRoute
TestAccAWSEc2TransitGatewayDataSource
TestAccAWSEc2TransitGatewayRouteTable
TestAccAWSEc2TransitGatewayRouteTableDataSource
TestAccAWSEc2TransitGatewayRouteTablePropagation
TestAccAWSEc2TransitGatewayVpcAttachment_basic
TestAccAWSEc2TransitGatewayVpcAttachment_disappears
TestAccAWSEc2TransitGatewayVpcAttachment_ApplianceModeSupport
TestAccAWSEc2TransitGatewayVpcAttachment_DnsSupport
TestAccAWSEc2TransitGatewayVpcAttachment_SharedTransitGateway
TestAccAWSEc2TransitGatewayVpcAttachmentAccepter
TestAccAWSEc2TransitGatewayVpcAttachmentDataSource
TestAccAWSEc2TransitGatewayVpnAttachmentDataSource
TestAccAWSElasticBeanstalkSolutionStackDataSource
TestAccAWSElbHostedZoneId

View File

@ -194,8 +194,7 @@ def test_create_transit_gateway_route_table():
table.should.have.key("Tags").equals([])
tables = ec2.describe_transit_gateway_route_tables()["TransitGatewayRouteTables"]
tables.should.have.length_of(1)
tables[0].should.equal(table)
tables.should.have.length_of(2)
@mock_ec2
@ -235,14 +234,16 @@ def test_delete_transit_gateway_route_table():
]
tables = ec2.describe_transit_gateway_route_tables()["TransitGatewayRouteTables"]
tables.should.have.length_of(1)
tables.should.have.length_of(2)
ec2.delete_transit_gateway_route_table(
table = ec2.delete_transit_gateway_route_table(
TransitGatewayRouteTableId=table["TransitGatewayRouteTableId"]
)
table["TransitGatewayRouteTable"].should.have.key("State").equals("deleted")
tables = ec2.describe_transit_gateway_route_tables()["TransitGatewayRouteTables"]
tables.should.have.length_of(0)
tables.should.have.length_of(2)
@mock_ec2
@ -278,7 +279,7 @@ def test_create_transit_gateway_route():
)["Route"]
route.should.have.key("DestinationCidrBlock").equal("0.0.0.0")
route.should.have.key("Type").equal("TODO")
route.should.have.key("Type").equal("static")
route.should.have.key("State").equal("active")
@ -299,7 +300,7 @@ def test_create_transit_gateway_route_as_blackhole():
)["Route"]
route.should.have.key("DestinationCidrBlock").equal("192.168.0.1")
route.should.have.key("Type").equal("TODO")
route.should.have.key("Type").equal("static")
route.should.have.key("State").equal("blackhole")
@ -329,7 +330,7 @@ def test_search_transit_gateway_routes_by_state():
)["Routes"]
routes.should.equal(
[{"DestinationCidrBlock": "192.168.0.0", "Type": "TODO", "State": "active"}]
[{"DestinationCidrBlock": "192.168.0.0", "Type": "static", "State": "active"}]
)
routes = ec2.search_transit_gateway_routes(
@ -338,7 +339,13 @@ def test_search_transit_gateway_routes_by_state():
)["Routes"]
routes.should.equal(
[{"DestinationCidrBlock": "192.168.0.1", "Type": "TODO", "State": "blackhole"}]
[
{
"DestinationCidrBlock": "192.168.0.1",
"Type": "static",
"State": "blackhole",
}
]
)
routes = ec2.search_transit_gateway_routes(
@ -371,7 +378,7 @@ def test_delete_transit_gateway_route():
)
response["Route"].should.equal(
{"DestinationCidrBlock": "192.168.0.0", "Type": "TODO", "State": "deleted"}
{"DestinationCidrBlock": "192.168.0.0", "Type": "static", "State": "deleted"}
)
routes = ec2.search_transit_gateway_routes(
@ -380,7 +387,7 @@ def test_delete_transit_gateway_route():
)["Routes"]
routes.should.equal(
[{"DestinationCidrBlock": "192.168.0.1", "Type": "TODO", "State": "active"}]
[{"DestinationCidrBlock": "192.168.0.1", "Type": "static", "State": "active"}]
)