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

Add interconnect_attachment to router_interface #3715

Merged
merged 1 commit into from
May 24, 2019
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
48 changes: 39 additions & 9 deletions google/resource_compute_router_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ func resourceComputeRouterInterface() *schema.Resource {
State: resourceComputeRouterInterfaceImportState,
},

CustomizeDiff: routerInterfaceDiffOneOfCheck,

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Expand All @@ -33,11 +35,18 @@ func resourceComputeRouterInterface() *schema.Resource {
},
"vpn_tunnel": {
Type: schema.TypeString,
Required: true,
ConflictsWith: []string{"interconnect_attachment"},
Optional: true,
ForceNew: true,
DiffSuppressFunc: linkDiffSuppress,
},
"interconnect_attachment": {
Type: schema.TypeString,
ConflictsWith: []string{"vpn_tunnel"},
Optional: true,
ForceNew: true,
DiffSuppressFunc: linkDiffSuppress,
},

"ip_range": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -102,16 +111,26 @@ func resourceComputeRouterInterfaceCreate(d *schema.ResourceData, meta interface
}
}

vpnTunnel, err := getVpnTunnelLink(config, project, region, d.Get("vpn_tunnel").(string))
if err != nil {
return err
iface := &compute.RouterInterface{Name: ifaceName}

if ipVal, ok := d.GetOk("ip_range"); ok {
iface.IpRange = ipVal.(string)
}

iface := &compute.RouterInterface{Name: ifaceName,
LinkedVpnTunnel: vpnTunnel}
if vpnVal, ok := d.GetOk("vpn_tunnel"); ok {
vpnTunnel, err := getVpnTunnelLink(config, project, region, vpnVal.(string))
if err != nil {
return err
}
iface.LinkedVpnTunnel = vpnTunnel
}

if v, ok := d.GetOk("ip_range"); ok {
iface.IpRange = v.(string)
if icVal, ok := d.GetOk("interconnect_attachment"); ok {
interconnectAttachment, err := getInterconnectAttachmentLink(config, project, region, icVal.(string))
if err != nil {
return err
}
iface.LinkedInterconnectAttachment = interconnectAttachment
}

log.Printf("[INFO] Adding interface %s", ifaceName)
Expand Down Expand Up @@ -170,6 +189,7 @@ func resourceComputeRouterInterfaceRead(d *schema.ResourceData, meta interface{}
if iface.Name == ifaceName {
d.SetId(fmt.Sprintf("%s/%s/%s", region, routerName, ifaceName))
d.Set("vpn_tunnel", iface.LinkedVpnTunnel)
d.Set("interconnect_attachment", iface.LinkedInterconnectAttachment)
d.Set("ip_range", iface.IpRange)
d.Set("region", region)
d.Set("project", project)
Expand Down Expand Up @@ -271,3 +291,13 @@ func resourceComputeRouterInterfaceImportState(d *schema.ResourceData, meta inte

return []*schema.ResourceData{d}, nil
}

func routerInterfaceDiffOneOfCheck(d *schema.ResourceDiff, meta interface{}) error {
_, ipOk := d.GetOk("ip_range")
_, vpnOk := d.GetOk("vpn_tunnel")
_, icOk := d.GetOk("interconnect_attachment")
if !(ipOk || vpnOk || icOk) {
return fmt.Errorf("Each interface requires one linked resource or an ip range, or both.")
}
return nil
}
97 changes: 86 additions & 11 deletions google/resource_compute_router_interface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,29 @@ func TestAccComputeRouterInterface_basic(t *testing.T) {
})
}

func TestAccComputeRouterInterface_withTunnel(t *testing.T) {
t.Parallel()

testId := acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeRouterInterfaceDestroy,
Steps: []resource.TestStep{
{
Config: testAccComputeRouterInterfaceWithTunnel(testId),
Check: testAccCheckComputeRouterInterfaceExists(
"google_compute_router_interface.foobar"),
},
{
ResourceName: "google_compute_router_interface.foobar",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccCheckComputeRouterInterfaceDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)

Expand Down Expand Up @@ -208,25 +231,70 @@ func testAccComputeRouterInterfaceBasic(testId string) string {
asn = 64514
}
}
resource "google_compute_vpn_tunnel" "foobar" {
name = "router-interface-test-%s"
region = "${google_compute_forwarding_rule.foobar_udp4500.region}"
target_vpn_gateway = "${google_compute_vpn_gateway.foobar.self_link}"
shared_secret = "unguessable"
peer_ip = "8.8.8.8"
router = "${google_compute_router.foobar.name}"
}
resource "google_compute_router_interface" "foobar" {
name = "router-interface-test-%s"
router = "${google_compute_router.foobar.name}"
region = "${google_compute_router.foobar.region}"
ip_range = "169.254.3.1/30"
vpn_tunnel = "${google_compute_vpn_tunnel.foobar.name}"
}
`, testId, testId, testId, testId, testId, testId, testId, testId, testId, testId)
`, testId, testId, testId, testId, testId, testId, testId, testId, testId)
}

func testAccComputeRouterInterfaceKeepRouter(testId string) string {
return fmt.Sprintf(`
resource "google_compute_network" "foobar" {
name = "router-interface-test-%s"
}
resource "google_compute_subnetwork" "foobar" {
name = "router-interface-test-subnetwork-%s"
network = "${google_compute_network.foobar.self_link}"
ip_cidr_range = "10.0.0.0/16"
region = "us-central1"
}
resource "google_compute_address" "foobar" {
name = "router-interface-test-%s"
region = "${google_compute_subnetwork.foobar.region}"
}
resource "google_compute_vpn_gateway" "foobar" {
name = "router-interface-test-%s"
network = "${google_compute_network.foobar.self_link}"
region = "${google_compute_subnetwork.foobar.region}"
}
resource "google_compute_forwarding_rule" "foobar_esp" {
name = "router-interface-test-%s-1"
region = "${google_compute_vpn_gateway.foobar.region}"
ip_protocol = "ESP"
ip_address = "${google_compute_address.foobar.address}"
target = "${google_compute_vpn_gateway.foobar.self_link}"
}
resource "google_compute_forwarding_rule" "foobar_udp500" {
name = "router-interface-test-%s-2"
region = "${google_compute_forwarding_rule.foobar_esp.region}"
ip_protocol = "UDP"
port_range = "500-500"
ip_address = "${google_compute_address.foobar.address}"
target = "${google_compute_vpn_gateway.foobar.self_link}"
}
resource "google_compute_forwarding_rule" "foobar_udp4500" {
name = "router-interface-test-%s-3"
region = "${google_compute_forwarding_rule.foobar_udp500.region}"
ip_protocol = "UDP"
port_range = "4500-4500"
ip_address = "${google_compute_address.foobar.address}"
target = "${google_compute_vpn_gateway.foobar.self_link}"
}
resource "google_compute_router" "foobar"{
name = "router-interface-test-%s"
region = "${google_compute_forwarding_rule.foobar_udp500.region}"
network = "${google_compute_network.foobar.self_link}"
bgp {
asn = 64514
}
}
`, testId, testId, testId, testId, testId, testId, testId, testId)
}

func testAccComputeRouterInterfaceWithTunnel(testId string) string {
return fmt.Sprintf(`
resource "google_compute_network" "foobar" {
name = "router-interface-test-%s"
Expand Down Expand Up @@ -285,5 +353,12 @@ func testAccComputeRouterInterfaceKeepRouter(testId string) string {
peer_ip = "8.8.8.8"
router = "${google_compute_router.foobar.name}"
}
`, testId, testId, testId, testId, testId, testId, testId, testId, testId)
resource "google_compute_router_interface" "foobar" {
name = "router-interface-test-%s"
router = "${google_compute_router.foobar.name}"
region = "${google_compute_router.foobar.region}"
ip_range = "169.254.3.1/30"
vpn_tunnel = "${google_compute_vpn_tunnel.foobar.name}"
}
`, testId, testId, testId, testId, testId, testId, testId, testId, testId, testId)
}
2 changes: 1 addition & 1 deletion google/resource_compute_vpn_tunnel.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ var invalidPeerAddrs = []struct {
}

func getVpnTunnelLink(config *Config, project string, region string, tunnel string) (string, error) {
if !strings.HasPrefix(tunnel, "https://www.googleapis.com/compute/") {
if !strings.Contains(tunnel, "/") {
// Tunnel value provided is just the name, lookup the tunnel SelfLink
tunnelData, err := config.clientCompute.VpnTunnels.Get(
project, region, tunnel).Do()
Expand Down
13 changes: 13 additions & 0 deletions google/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,3 +466,16 @@ func paginatedListRequest(baseUrl string, config *Config, flattener func(map[str

return ls, nil
}

func getInterconnectAttachmentLink(config *Config, project, region, ic string) (string, error) {
if !strings.Contains(ic, "/") {
icData, err := config.clientCompute.InterconnectAttachments.Get(
project, region, ic).Do()
if err != nil {
return "", fmt.Errorf("Error reading interconnect attachment: %s", err)
}
ic = icData.SelfLink
}

return ic, nil
}
14 changes: 12 additions & 2 deletions website/docs/r/compute_router_interface.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,24 @@ The following arguments are supported:
* `router` - (Required) The name of the router this interface will be attached to.
Changing this forces a new interface to be created.

* `vpn_tunnel` - (Required) The name or resource link to the VPN tunnel this
interface will be linked to. Changing this forces a new interface to be created.
In addition to the above required fields, a router interface must have specified
either `ip_range` or exactly one of `vpn_tunnel` or `interconnect_attachment`,
or both.

- - -

* `ip_range` - (Optional) IP address and range of the interface. The IP range must be
in the RFC3927 link-local IP space. Changing this forces a new interface to be created.

* `vpn_tunnel` - (Optional) The name or resource link to the VPN tunnel this
interface will be linked to. Changing this forces a new interface to be created. Only
one of `vpn_tunnel` and `interconnect_attachment` can be specified.

* `interconnect_attachment` - (Optional) The name or resource link to the
VLAN interconnect for this interface. Changing this forces a new interface to
be created. Only one of `vpn_tunnel` and `interconnect_attachment` can be
specified.

* `project` - (Optional) The ID of the project in which this interface's router belongs. If it
is not provided, the provider project is used. Changing this forces a new interface to be created.

Expand Down