Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#11206] Add BGP Peer Router Appliance instance argument #6874

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions mmv1/products/compute/api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
6 changes: 6 additions & 0 deletions mmv1/products/compute/terraform.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
104 changes: 104 additions & 0 deletions mmv1/templates/terraform/examples/router_peer_router_appliance.tf.erb
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.`,
},
Expand Down Expand Up @@ -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 = "";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only part I'm concerned about here. Why remove the interface if it's already marked Computed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TL;DR
The API automatically sets the redundant_interface field under an interface that interface has been set as redundant of another interface. Anyway, the API is not able to automatically clean up the redundant interface field, if the interface referenced in redundant_interface is removed.

Longer explanation with example:
Assume you create two interfaces. You insert the first one, then the other one.
On the second interface you set redundant_interface, referencing the one formerly created.
The API automatically sets redundant interface also on the first interface created, referencing the second one, so each interface is set as the redundant of the other. This is why I put Optional and Computed equal to true.
We now remove either the first or the second interface. The API is not automatically able to look for redundant interface fields in other interfaces on that router that reference the interface we're removing. As such, we've to look for it and remove it manually.

}
newIfaces = append(newIfaces, iface)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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" {
Expand Down