Repository: getmoto/moto (Python)

Issue:
DescribeTransitGatewayAttachments Returns Placeholder Value for an Attachment's Associated TGW RTB
When retrieving information on a TGW attachment using the DescribeTransitGatewayAttachments API, the _transitGatewayRouteTableId_ field  in the response — used to signify the TGW RTB associated with the attachment — always returns a placeholder value of _tgw-rtb-0b36edb9b88f0d5e3_. It seems that the AssociateTransitGatewayRouteTable API is correctly creating associations, but the DescribeTransitGatewayAttachments is not retrieving the record of RTB association that has been created.

The line where this placeholder is defined: https://github.com/getmoto/moto/blob/e280e92dcfd207f2d95dba88bbd7d71407a6a793/moto/ec2/responses/transit_gateway_attachments.py#L245

Ideally, DescribeTransitGatewayAttachments could be changed to return the ID of the associated TGW RTB (if one exists). If a placeholder must be used, it would be more user friendly if a clear placeholder value was returned, rather than _tgw-rtb-0b36edb9b88f0d5e3_ which seems like a legitimate TGW RTB ID.





Fix (patch):
diff --git a/moto/ec2/exceptions.py b/moto/ec2/exceptions.py
index 14e6b09bd5cd..aae503f13e34 100644
--- a/moto/ec2/exceptions.py
+++ b/moto/ec2/exceptions.py
@@ -196,7 +196,7 @@ class InvalidCustomerGatewayIdError(EC2ClientError):
     def __init__(self, customer_gateway_id: str):
         super().__init__(
             "InvalidCustomerGatewayID.NotFound",
-            f"The customer gateway ID '{customer_gateway_id}' does not exist",
+            f"The customerGateway ID '{customer_gateway_id}' does not exist",
         )
 
 
@@ -860,6 +860,14 @@ def __init__(self, carrier_gateway_id: str):
         )
 
 
+class InvalidTransitGatewayID(EC2ClientError):
+    def __init__(self, transit_gateway_id: str):
+        super().__init__(
+            "InvalidTransitGatewayID.NotFound",
+            f"The transitGateway ID '{transit_gateway_id}' does not exist",
+        )
+
+
 class NoLoadBalancersProvided(EC2ClientError):
     def __init__(self) -> None:
         super().__init__(
diff --git a/moto/ec2/models/vpn_connections.py b/moto/ec2/models/vpn_connections.py
index e4604d41076c..ab3742e43c25 100644
--- a/moto/ec2/models/vpn_connections.py
+++ b/moto/ec2/models/vpn_connections.py
@@ -1,6 +1,10 @@
 from typing import Any, Dict, List, Optional
 
-from ..exceptions import InvalidVpnConnectionIdError
+from ..exceptions import (
+    InvalidParameterValue,
+    InvalidTransitGatewayID,
+    InvalidVpnConnectionIdError,
+)
 from ..utils import generic_filter, random_vpn_connection_id
 from .core import TaggedEC2Resource
 
@@ -45,12 +49,20 @@ def create_vpn_connection(
         customer_gateway_id: str,
         vpn_gateway_id: Optional[str] = None,
         transit_gateway_id: Optional[str] = None,
-        static_routes_only: Optional[bool] = None,
         tags: Optional[Dict[str, str]] = None,
     ) -> VPNConnection:
+        if vpn_gateway_id and transit_gateway_id:
+            # From the docs (parentheses mine):
+            # Creates a VPN connection between an existing (virtual private gateway or transit gateway) and a customer gateway
+            raise InvalidParameterValue(
+                "The request must not contain both parameter vpnGatewayId and transitGatewayId"
+            )
+        # Validate Gateways exist
+        self.get_customer_gateway(customer_gateway_id=customer_gateway_id)  # type: ignore[attr-defined]
+        if transit_gateway_id and transit_gateway_id not in self.transit_gateways:  # type: ignore[attr-defined]
+            raise InvalidTransitGatewayID(transit_gateway_id)
+
         vpn_connection_id = random_vpn_connection_id()
-        if static_routes_only:
-            pass
         vpn_connection = VPNConnection(
             self,
             vpn_connection_id=vpn_connection_id,
diff --git a/moto/ec2/responses/vpn_connections.py b/moto/ec2/responses/vpn_connections.py
index f45de76a43ee..5e998d2a1040 100644
--- a/moto/ec2/responses/vpn_connections.py
+++ b/moto/ec2/responses/vpn_connections.py
@@ -12,14 +12,12 @@ def create_vpn_connection(self) -> str:
         cgw_id = self._get_param("CustomerGatewayId")
         vgw_id = self._get_param("VpnGatewayId")
         tgw_id = self._get_param("TransitGatewayId")
-        static_routes = self._get_param("StaticRoutesOnly")
         tags = add_tag_specification(self._get_multi_param("TagSpecification"))
         vpn_connection = self.ec2_backend.create_vpn_connection(
             vpn_conn_type,
             cgw_id,
             vpn_gateway_id=vgw_id,
             transit_gateway_id=tgw_id,
-            static_routes_only=static_routes,
             tags=tags,
         )
         if vpn_connection.transit_gateway_id: