diff --git a/mmv1/products/compute/api.yaml b/mmv1/products/compute/api.yaml index e20ac2f11f9b..c9585a4b5a27 100644 --- a/mmv1/products/compute/api.yaml +++ b/mmv1/products/compute/api.yaml @@ -14401,6 +14401,15 @@ objects: If set to true, the peer connection can be established with routing information. The default is true. default_value: true + - !ruby/object:Api::Type::ResourceRef + name: 'routerApplianceInstance' + resource: 'Instance' + imports: 'selfLink' + description: | + The URI of the VM instance that is used as third-party router appliances + such as Next Gen Firewalls, Virtual Routers, or Router Appliances. + The VM instance must be located in zones contained in the same region as + this Cloud Router. The VM instance is the peer side of the BGP session. - !ruby/object:Api::Resource name: 'SecurityPolicy' kind: 'compute#securityPolicy' diff --git a/mmv1/products/compute/terraform.yaml b/mmv1/products/compute/terraform.yaml index 7c2b13c088d9..5933bc541001 100644 --- a/mmv1/products/compute/terraform.yaml +++ b/mmv1/products/compute/terraform.yaml @@ -2726,6 +2726,12 @@ overrides: !ruby/object:Overrides::ResourceOverrides vars: router_name: "my-router" peer_name: "my-router-peer" + - !ruby/object:Provider::Terraform::Examples + name: "router_peer_router_appliance" + primary_resource_id: "peer" + vars: + router_name: "my-router" + peer_name: "my-router-peer" properties: advertiseMode: !ruby/object:Overrides::Terraform::PropertyOverride custom_flatten: 'templates/terraform/custom_flatten/default_if_empty.erb' diff --git a/mmv1/templates/terraform/examples/router_peer_router_appliance.tf.erb b/mmv1/templates/terraform/examples/router_peer_router_appliance.tf.erb new file mode 100644 index 000000000000..d194c4154cc6 --- /dev/null +++ b/mmv1/templates/terraform/examples/router_peer_router_appliance.tf.erb @@ -0,0 +1,104 @@ +resource "google_compute_network" "network" { + name = "<%= ctx[:vars]['router_name'] %>-net" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "subnetwork" { + name = "<%= ctx[:vars]['router_name'] %>-sub" + network = google_compute_network.network.self_link + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" +} + +resource "google_compute_address" "addr_intf" { + name = "<%= ctx[:vars]['router_name'] %>-addr-intf" + region = google_compute_subnetwork.subnetwork.region + subnetwork = google_compute_subnetwork.subnetwork.id + address_type = "INTERNAL" +} + +resource "google_compute_address" "addr_intf_redundant" { + name = "<%= ctx[:vars]['router_name'] %>-addr-intf-red" + region = google_compute_subnetwork.subnetwork.region + subnetwork = google_compute_subnetwork.subnetwork.id + address_type = "INTERNAL" +} + +resource "google_compute_address" "addr_peer" { + name = "<%= ctx[:vars]['router_name'] %>-addr-peer" + region = google_compute_subnetwork.subnetwork.region + subnetwork = google_compute_subnetwork.subnetwork.id + address_type = "INTERNAL" +} + +resource "google_compute_instance" "instance" { + name = "router-appliance" + zone = "us-central1-a" + machine_type = "e2-medium" + can_ip_forward = true + + boot_disk { + initialize_params { + image = "debian-cloud/debian-11" + } + } + + network_interface { + network_ip = google_compute_address.addr_peer.address + subnetwork = google_compute_subnetwork.subnetwork.self_link + } +} + +resource "google_network_connectivity_hub" "hub" { + name = "<%= ctx[:vars]['router_name'] %>-hub" +} + +resource "google_network_connectivity_spoke" "spoke" { + name = "<%= ctx[:vars]['router_name'] %>-spoke" + location = google_compute_subnetwork.subnetwork.region + hub = google_network_connectivity_hub.hub.id + + linked_router_appliance_instances { + instances { + virtual_machine = google_compute_instance.instance.self_link + ip_address = google_compute_address.addr_peer.address + } + site_to_site_data_transfer = false + } +} + +resource "google_compute_router" "router" { + name = "<%= ctx[:vars]['router_name'] %>-router" + region = google_compute_subnetwork.subnetwork.region + network = google_compute_network.network.self_link + bgp { + asn = 64514 + } +} + +resource "google_compute_router_interface" "interface_redundant" { + name = "<%= ctx[:vars]['router_name'] %>-intf-red" + region = google_compute_router.router.region + router = google_compute_router.router.name + subnetwork = google_compute_subnetwork.subnetwork.self_link + private_ip_address = google_compute_address.addr_intf_redundant.address +} + +resource "google_compute_router_interface" "interface" { + name = "<%= ctx[:vars]['router_name'] %>-intf" + region = google_compute_router.router.region + router = google_compute_router.router.name + subnetwork = google_compute_subnetwork.subnetwork.self_link + private_ip_address = google_compute_address.addr_intf.address + redundant_interface = google_compute_router_interface.interface_redundant.name +} + +resource "google_compute_router_peer" "peer" { + name = "<%= ctx[:vars]['peer_name'] %>" + router = google_compute_router.router.name + region = google_compute_router.router.region + interface = google_compute_router_interface.interface.name + router_appliance_instance = google_compute_instance.instance.self_link + peer_asn = 65513 + peer_ip_address = google_compute_address.addr_peer.address +} diff --git a/mmv1/third_party/terraform/resources/resource_compute_router_interface.go.erb b/mmv1/third_party/terraform/resources/resource_compute_router_interface.go.erb index d3b657220787..27f7904e9963 100644 --- a/mmv1/third_party/terraform/resources/resource_compute_router_interface.go.erb +++ b/mmv1/third_party/terraform/resources/resource_compute_router_interface.go.erb @@ -104,6 +104,7 @@ func resourceComputeRouterInterface() *schema.Resource { "redundant_interface": { Type: schema.TypeString, Optional: true, + Computed: true, ForceNew: true, Description: `The name of the interface that is redundant to this interface. Changing this forces a new interface to be created.`, }, @@ -328,6 +329,11 @@ func resourceComputeRouterInterfaceDelete(d *schema.ResourceData, meta interface ifaceFound = true continue } else { + // If this is a redundant interface, + // remove its reference from other interfaces as well + if iface.RedundantInterface == ifaceName { + iface.RedundantInterface = ""; + } newIfaces = append(newIfaces, iface) } } diff --git a/mmv1/third_party/terraform/tests/resource_compute_router_bgp_peer_test.go b/mmv1/third_party/terraform/tests/resource_compute_router_bgp_peer_test.go index 2693bae8905a..f5818f137746 100644 --- a/mmv1/third_party/terraform/tests/resource_compute_router_bgp_peer_test.go +++ b/mmv1/third_party/terraform/tests/resource_compute_router_bgp_peer_test.go @@ -155,6 +155,29 @@ func TestAccComputeRouterPeer_bfd(t *testing.T) { }) } +func TestAccComputeRouterPeer_routerApplianceInstance(t *testing.T) { + t.Parallel() + + routerName := fmt.Sprintf("tf-test-router-%s", randString(t, 10)) + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeRouterPeerDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeRouterPeerRouterApplianceInstance(routerName), + Check: testAccCheckComputeRouterPeerExists( + t, "google_compute_router_peer.foobar"), + }, + { + ResourceName: "google_compute_router_peer.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckComputeRouterPeerDestroyProducer(t *testing.T) func(s *terraform.State) error { return func(s *terraform.State) error { config := googleProviderConfig(t) @@ -493,6 +516,115 @@ resource "google_compute_router_peer" "foobar" { `, routerName, routerName, routerName, routerName, routerName, routerName, routerName, routerName, routerName) } +func testAccComputeRouterPeerRouterApplianceInstance(routerName string) string { + return fmt.Sprintf(` +resource "google_compute_network" "foobar" { + name = "%s-net" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "foobar" { + name = "%s-sub" + network = google_compute_network.foobar.self_link + ip_cidr_range = "10.0.0.0/16" + region = "us-central1" +} + +resource "google_compute_address" "addr_intf" { + name = "%s-addr-intf" + region = google_compute_subnetwork.foobar.region + subnetwork = google_compute_subnetwork.foobar.id + address_type = "INTERNAL" +} + +resource "google_compute_address" "addr_intf_red" { + name = "%s-addr-intf-red" + region = google_compute_subnetwork.foobar.region + subnetwork = google_compute_subnetwork.foobar.id + address_type = "INTERNAL" +} + +resource "google_compute_address" "addr_peer" { + name = "%s-addr-peer" + region = google_compute_subnetwork.foobar.region + subnetwork = google_compute_subnetwork.foobar.id + address_type = "INTERNAL" +} + +resource "google_compute_instance" "foobar" { + name = "%s-vm" + machine_type = "e2-medium" + zone = "us-central1-a" + can_ip_forward = true + + boot_disk { + initialize_params { + image = "debian-cloud/debian-11" + } + } + + network_interface { + network_ip = google_compute_address.addr_peer.address + subnetwork = google_compute_subnetwork.foobar.self_link + } +} + +resource "google_network_connectivity_hub" "foobar" { + name = "%s-hub" +} + +resource "google_network_connectivity_spoke" "foobar" { + name = "%s-spoke" + location = google_compute_subnetwork.foobar.region + hub = google_network_connectivity_hub.foobar.id + + linked_router_appliance_instances { + instances { + virtual_machine = google_compute_instance.foobar.self_link + ip_address = google_compute_address.addr_peer.address + } + site_to_site_data_transfer = false + } +} + +resource "google_compute_router" "foobar" { + name = "%s-ra" + region = google_compute_subnetwork.foobar.region + network = google_compute_network.foobar.self_link + bgp { + asn = 64514 + } +} + +resource "google_compute_router_interface" "foobar_redundant" { + name = "%s-intf-red" + region = google_compute_router.foobar.region + router = google_compute_router.foobar.name + subnetwork = google_compute_subnetwork.foobar.self_link + private_ip_address = google_compute_address.addr_intf_red.address +} + +resource "google_compute_router_interface" "foobar" { + name = "%s-intf" + region = google_compute_router.foobar.region + router = google_compute_router.foobar.name + subnetwork = google_compute_subnetwork.foobar.self_link + private_ip_address = google_compute_address.addr_intf.address + redundant_interface = google_compute_router_interface.foobar_redundant.name +} + +resource "google_compute_router_peer" "foobar" { + name = "%s-peer" + router = google_compute_router.foobar.name + region = google_compute_router.foobar.region + peer_ip_address = google_compute_address.addr_peer.address + peer_asn = 65515 + interface = google_compute_router_interface.foobar.name + router_appliance_instance = google_compute_instance.foobar.self_link +} +`, routerName, routerName, routerName, routerName, routerName, routerName, routerName, routerName, routerName, routerName, routerName, routerName) +} + func testAccComputeRouterPeerAdvertiseModeUpdate(routerName string) string { return fmt.Sprintf(` resource "google_compute_network" "foobar" {