forked from hashicorp/terraform-provider-google
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new resource
google_compute_network_peering
(hashicorp#259)
- Loading branch information
Showing
5 changed files
with
380 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
package google | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"regexp" | ||
"sort" | ||
|
||
"github.com/hashicorp/terraform/helper/schema" | ||
"google.golang.org/api/compute/v1" | ||
"google.golang.org/api/googleapi" | ||
) | ||
|
||
const peerNetworkLinkRegex = "projects/(" + ProjectRegex + ")/global/networks/((?:[a-z](?:[-a-z0-9]*[a-z0-9])?))$" | ||
|
||
func resourceComputeNetworkPeering() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceComputeNetworkPeeringCreate, | ||
Read: resourceComputeNetworkPeeringRead, | ||
Delete: resourceComputeNetworkPeeringDelete, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"name": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateFunc: validateGCPName, | ||
}, | ||
"network": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateFunc: validateRegexp(peerNetworkLinkRegex), | ||
DiffSuppressFunc: compareSelfLinkRelativePaths, | ||
}, | ||
"peer_network": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
ValidateFunc: validateRegexp(peerNetworkLinkRegex), | ||
DiffSuppressFunc: compareSelfLinkRelativePaths, | ||
}, | ||
"auto_create_routes": &schema.Schema{ | ||
Type: schema.TypeBool, | ||
ForceNew: true, | ||
Optional: true, | ||
Default: true, | ||
}, | ||
"state": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"state_details": &schema.Schema{ | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceComputeNetworkPeeringCreate(d *schema.ResourceData, meta interface{}) error { | ||
config := meta.(*Config) | ||
|
||
project, err := getProject(d, config) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
networkLink := d.Get("network").(string) | ||
networkName := getNameFromNetworkLink(networkLink) | ||
|
||
request := &compute.NetworksAddPeeringRequest{ | ||
Name: d.Get("name").(string), | ||
PeerNetwork: d.Get("peer_network").(string), | ||
AutoCreateRoutes: d.Get("auto_create_routes").(bool), | ||
} | ||
|
||
addOp, err := config.clientCompute.Networks.AddPeering(project, networkName, request).Do() | ||
if err != nil { | ||
return fmt.Errorf("Error adding network peering: %s", err) | ||
} | ||
|
||
err = computeOperationWait(config, addOp, project, "Adding Network Peering") | ||
if err != nil { | ||
return err | ||
} | ||
|
||
d.SetId(fmt.Sprintf("%s/%s", networkName, d.Get("name").(string))) | ||
|
||
return resourceComputeNetworkPeeringRead(d, meta) | ||
} | ||
|
||
func resourceComputeNetworkPeeringRead(d *schema.ResourceData, meta interface{}) error { | ||
config := meta.(*Config) | ||
|
||
project, err := getProject(d, config) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
peeringName := d.Get("name").(string) | ||
networkLink := d.Get("network").(string) | ||
networkName := getNameFromNetworkLink(networkLink) | ||
|
||
network, err := config.clientCompute.Networks.Get(project, networkName).Do() | ||
if err != nil { | ||
return handleNotFoundError(err, d, fmt.Sprintf("Network %q", networkName)) | ||
} | ||
|
||
peering := findPeeringFromNetwork(network, peeringName) | ||
if peering == nil { | ||
log.Printf("[WARN] Removing network peering %s from network %s because it's gone", peeringName, networkName) | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
d.Set("peer_network", peering.Network) | ||
d.Set("auto_create_routes", peering.AutoCreateRoutes) | ||
d.Set("state", peering.State) | ||
d.Set("state_details", peering.StateDetails) | ||
|
||
return nil | ||
} | ||
|
||
func resourceComputeNetworkPeeringDelete(d *schema.ResourceData, meta interface{}) error { | ||
config := meta.(*Config) | ||
|
||
// Remove the `network` to `peer_network` peering | ||
project, err := getProject(d, config) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
name := d.Get("name").(string) | ||
networkLink := d.Get("network").(string) | ||
peerNetworkLink := d.Get("peer_network").(string) | ||
networkName := getNameFromNetworkLink(networkLink) | ||
peerNetworkName := getNameFromNetworkLink(peerNetworkLink) | ||
|
||
request := &compute.NetworksRemovePeeringRequest{ | ||
Name: name, | ||
} | ||
|
||
// Only one delete peering operation at a time can be performed inside any peered VPCs. | ||
peeringLockName := getNetworkPeeringLockName(networkName, peerNetworkName) | ||
mutexKV.Lock(peeringLockName) | ||
defer mutexKV.Unlock(peeringLockName) | ||
|
||
removeOp, err := config.clientCompute.Networks.RemovePeering(project, networkName, request).Do() | ||
if err != nil { | ||
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { | ||
log.Printf("[WARN] Peering `%s` already removed from network `%s`", name, networkName) | ||
} else { | ||
return fmt.Errorf("Error removing peering `%s` from network `%s`: %s", name, networkName, err) | ||
} | ||
} else { | ||
err = computeOperationWait(config, removeOp, project, "Removing Network Peering") | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func findPeeringFromNetwork(network *compute.Network, peeringName string) *compute.NetworkPeering { | ||
for _, p := range network.Peerings { | ||
if p.Name == peeringName { | ||
return p | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func getNameFromNetworkLink(network string) string { | ||
r := regexp.MustCompile(peerNetworkLinkRegex) | ||
|
||
m := r.FindStringSubmatch(network) | ||
return m[2] | ||
} | ||
|
||
func getNetworkPeeringLockName(networkName, peerNetworkName string) string { | ||
// Whether you delete the peering from network A to B or the one from B to A, they | ||
// cannot happen at the same time. | ||
networks := []string{networkName, peerNetworkName} | ||
sort.Strings(networks) | ||
|
||
return fmt.Sprintf("network_peering/%s/%s", networks[0], networks[1]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package google | ||
|
||
import ( | ||
"fmt" | ||
"github.com/hashicorp/terraform/helper/acctest" | ||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
"google.golang.org/api/compute/v1" | ||
"strings" | ||
"testing" | ||
) | ||
|
||
func TestAccComputeNetworkPeering_basic(t *testing.T) { | ||
var peering compute.NetworkPeering | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccComputeNetworkPeeringDestroy, | ||
Steps: []resource.TestStep{ | ||
resource.TestStep{ | ||
Config: testAccComputeNetworkPeering_basic, | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckComputeNetworkPeeringExist("google_compute_network_peering.foo", &peering), | ||
testAccCheckComputeNetworkPeeringAutoCreateRoutes(true, &peering), | ||
testAccCheckComputeNetworkPeeringExist("google_compute_network_peering.bar", &peering), | ||
testAccCheckComputeNetworkPeeringAutoCreateRoutes(true, &peering), | ||
), | ||
}, | ||
}, | ||
}) | ||
|
||
} | ||
|
||
func testAccComputeNetworkPeeringDestroy(s *terraform.State) error { | ||
config := testAccProvider.Meta().(*Config) | ||
|
||
for _, rs := range s.RootModule().Resources { | ||
if rs.Type != "google_compute_network_peering" { | ||
continue | ||
} | ||
|
||
_, err := config.clientCompute.Networks.Get( | ||
config.Project, rs.Primary.ID).Do() | ||
if err == nil { | ||
return fmt.Errorf("Network peering still exists") | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func testAccCheckComputeNetworkPeeringExist(n string, peering *compute.NetworkPeering) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
rs, ok := s.RootModule().Resources[n] | ||
if !ok { | ||
return fmt.Errorf("Not found: %s", n) | ||
} | ||
|
||
if rs.Primary.ID == "" { | ||
return fmt.Errorf("No ID is set") | ||
} | ||
|
||
config := testAccProvider.Meta().(*Config) | ||
|
||
parts := strings.Split(rs.Primary.ID, "/") | ||
if len(parts) != 2 { | ||
return fmt.Errorf("Invalid network peering identifier: %s", rs.Primary.ID) | ||
} | ||
|
||
networkName, peeringName := parts[0], parts[1] | ||
|
||
network, err := config.clientCompute.Networks.Get(config.Project, networkName).Do() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
found := findPeeringFromNetwork(network, peeringName) | ||
if found == nil { | ||
return fmt.Errorf("Network peering '%s' not found in network '%s'", peeringName, network.Name) | ||
} | ||
*peering = *found | ||
|
||
return nil | ||
} | ||
} | ||
|
||
func testAccCheckComputeNetworkPeeringAutoCreateRoutes(v bool, peering *compute.NetworkPeering) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
if peering.AutoCreateRoutes != v { | ||
return fmt.Errorf("should AutoCreateRoutes set to %t", v) | ||
} | ||
|
||
return nil | ||
} | ||
} | ||
|
||
var testAccComputeNetworkPeering_basic = fmt.Sprintf(` | ||
resource "google_compute_network" "network1" { | ||
name = "network-test-1-%s" | ||
auto_create_subnetworks = false | ||
} | ||
resource "google_compute_network" "network2" { | ||
name = "network-test-2-%s" | ||
auto_create_subnetworks = false | ||
} | ||
resource "google_compute_network_peering" "foo" { | ||
name = "peering-test-1-%s" | ||
network = "${google_compute_network.network1.self_link}" | ||
peer_network = "${google_compute_network.network2.self_link}" | ||
} | ||
resource "google_compute_network_peering" "bar" { | ||
name = "peering-test-2-%s" | ||
auto_create_routes = true | ||
network = "${google_compute_network.network2.self_link}" | ||
peer_network = "${google_compute_network.network1.self_link}" | ||
} | ||
`, acctest.RandString(10), acctest.RandString(10), acctest.RandString(10), acctest.RandString(10)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
--- | ||
layout: "google" | ||
page_title: "Google: google_compute_network_peering" | ||
sidebar_current: "docs-google-compute-network-peering" | ||
description: |- | ||
Manages a network peering within GCE. | ||
--- | ||
|
||
# google\_compute\_network\_peering | ||
|
||
Manages a network peering within GCE. For more information see | ||
[the official documentation](https://cloud.google.com/compute/docs/vpc/vpc-peering) | ||
and | ||
[API](https://cloud.google.com/compute/docs/reference/latest/networks). | ||
|
||
~> **Note:** Both network must create a peering with each other for the peering to be functional. | ||
|
||
~> **Note:** Subnets IP ranges across peered VPC networks cannot overlap. | ||
|
||
## Example Usage | ||
|
||
```hcl | ||
resource "google_compute_network_peering" "peering1" { | ||
name = "peering1" | ||
network = "${google_compute_network.default.self_link}" | ||
peer_network = "${google_compute_network.other.self_link}" | ||
} | ||
resource "google_compute_network_peering" "peering2" { | ||
name = "peering2" | ||
network = "${google_compute_network.other.self_link}" | ||
peer_network = "${google_compute_network.default.self_link}" | ||
} | ||
resource "google_compute_network" "default" { | ||
name = "foobar" | ||
auto_create_subnetworks = "false" | ||
} | ||
resource "google_compute_network" "other" { | ||
name = "other" | ||
auto_create_subnetworks = "false" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The following arguments are supported: | ||
|
||
* `name` - (Required) Name of the peering. | ||
|
||
* `network` - (Required) Resource link of the network to add a peering to. | ||
|
||
* `peer_network` - (Required) Resource link of the peer network. | ||
|
||
* `auto_create_routes` - (Optional) If set to `true`, the routes between the two networks will | ||
be created and managed automatically. Defaults to `true`. | ||
|
||
## Attributes Reference | ||
|
||
In addition to the arguments listed above, the following computed attributes are | ||
exported: | ||
|
||
* `state` - State for the peering. | ||
|
||
* `state_details` - Details about the current state of the peering. |