Skip to content

Commit

Permalink
Support subnetwork IP CIDR range expansion (#945)
Browse files Browse the repository at this point in the history
* Vendor schema/helper/customdiff

* Support subnetwork IP CIDR range expansion

* Change wording
  • Loading branch information
rosbo authored Jan 17, 2018
1 parent 26c9343 commit c9826b1
Show file tree
Hide file tree
Showing 10 changed files with 358 additions and 11 deletions.
53 changes: 50 additions & 3 deletions google/resource_compute_subnetwork.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import (

"strings"

"github.com/apparentlymart/go-cidr/cidr"
"github.com/hashicorp/terraform/helper/customdiff"
"github.com/hashicorp/terraform/helper/schema"
computeBeta "google.golang.org/api/compute/v0.beta"
"google.golang.org/api/compute/v1"
"net"
"time"
)

Expand Down Expand Up @@ -37,9 +40,10 @@ func resourceComputeSubnetwork() *schema.Resource {

Schema: map[string]*schema.Schema{
"ip_cidr_range": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
Type: schema.TypeString,
Required: true,
ValidateFunc: validateIpCidrRange,
// ForceNew only if it shrinks the CIDR range, this is set in CustomizeDiff below.
},

"name": &schema.Schema{
Expand Down Expand Up @@ -113,6 +117,10 @@ func resourceComputeSubnetwork() *schema.Resource {
Computed: true,
},
},

CustomizeDiff: customdiff.All(
customdiff.ForceNewIfChange("ip_cidr_range", isShrinkageIpCidr),
),
}
}

Expand Down Expand Up @@ -279,6 +287,25 @@ func resourceComputeSubnetworkUpdate(d *schema.ResourceData, meta interface{}) e
d.SetPartial("private_ip_google_access")
}

if d.HasChange("ip_cidr_range") {
r := &compute.SubnetworksExpandIpCidrRangeRequest{
IpCidrRange: d.Get("ip_cidr_range").(string),
}

op, err := config.clientCompute.Subnetworks.ExpandIpCidrRange(project, region, d.Get("name").(string), r).Do()

if err != nil {
return fmt.Errorf("Error expanding the ip cidr range: %s", err)
}

err = computeSharedOperationWaitTime(config.clientCompute, op, project, int(d.Timeout(schema.TimeoutUpdate).Minutes()), "Expanding Subnetwork IP CIDR range")
if err != nil {
return err
}

d.SetPartial("ip_cidr_range")
}

if d.HasChange("secondary_ip_range") && computeApiVersion == v0beta {
v0BetaSubnetwork := &computeBeta.Subnetwork{
SecondaryIpRanges: expandSecondaryRangesV0Beta(d.Get("secondary_ip_range").([]interface{})),
Expand Down Expand Up @@ -415,3 +442,23 @@ func flattenSecondaryRangesV0Beta(secondaryRanges []*computeBeta.SubnetworkSecon
}
return secondaryRangesSchema
}

// Whether the IP CIDR change shrinks the block.
func isShrinkageIpCidr(old, new, _ interface{}) bool {
_, oldCidr, oldErr := net.ParseCIDR(old.(string))
_, newCidr, newErr := net.ParseCIDR(new.(string))

if oldErr != nil || newErr != nil {
// This should never happen. The ValidateFunc on the field ensures it.
return false
}

oldStart, oldEnd := cidr.AddressRange(oldCidr)

if newCidr.Contains(oldStart) && newCidr.Contains(oldEnd) {
// This is a CIDR range expansion, no need to ForceNew, we have an update method for it.
return false
}

return true
}
63 changes: 55 additions & 8 deletions google/resource_compute_subnetwork_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,44 @@ import (
"google.golang.org/api/compute/v1"
)

// Unit tests

func TestIsShrinkageIpCidr(t *testing.T) {
cases := map[string]struct {
Old, New string
Shrinkage bool
}{
"Expansion same network ip": {
Old: "10.0.0.0/24",
New: "10.0.0.0/16",
Shrinkage: false,
},
"Expansion different network ip": {
Old: "10.0.1.0/24",
New: "10.0.0.0/16",
Shrinkage: false,
},
"Shrinkage same network ip": {
Old: "10.0.0.0/16",
New: "10.0.0.0/24",
Shrinkage: true,
},
"Shrinkage different network ip": {
Old: "10.0.0.0/16",
New: "10.1.0.0/16",
Shrinkage: true,
},
}

for tn, tc := range cases {
if isShrinkageIpCidr(tc.Old, tc.New, nil) != tc.Shrinkage {
t.Errorf("%s failed: Shrinkage should be %t", tn, tc.Shrinkage)
}
}
}

// Acceptance tests

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

Expand Down Expand Up @@ -63,14 +101,23 @@ func TestAccComputeSubnetwork_update(t *testing.T) {
CheckDestroy: testAccCheckComputeSubnetworkDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeSubnetwork_update1(cnName, subnetworkName),
Config: testAccComputeSubnetwork_update1(cnName, "10.2.0.0/24", subnetworkName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSubnetworkExists(
"google_compute_subnetwork.network-with-private-google-access", &subnetwork),
),
},
resource.TestStep{
Config: testAccComputeSubnetwork_update2(cnName, subnetworkName),
// Expand IP CIDR range and update private_ip_google_access
Config: testAccComputeSubnetwork_update2(cnName, "10.2.0.0/16", subnetworkName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSubnetworkExists(
"google_compute_subnetwork.network-with-private-google-access", &subnetwork),
),
},
resource.TestStep{
// Shrink IP CIDR range and update private_ip_google_access
Config: testAccComputeSubnetwork_update2(cnName, "10.2.0.0/24", subnetworkName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSubnetworkExists(
"google_compute_subnetwork.network-with-private-google-access", &subnetwork),
Expand Down Expand Up @@ -234,7 +281,7 @@ resource "google_compute_subnetwork" "network-with-private-google-access" {
`, cnName, subnetwork1Name, subnetwork2Name, subnetwork3Name)
}

func testAccComputeSubnetwork_update1(cnName, subnetworkName string) string {
func testAccComputeSubnetwork_update1(cnName, cidrRange, subnetworkName string) string {
return fmt.Sprintf(`
resource "google_compute_network" "custom-test" {
name = "%s"
Expand All @@ -243,15 +290,15 @@ resource "google_compute_network" "custom-test" {
resource "google_compute_subnetwork" "network-with-private-google-access" {
name = "%s"
ip_cidr_range = "10.2.0.0/16"
ip_cidr_range = "%s"
region = "us-central1"
network = "${google_compute_network.custom-test.self_link}"
private_ip_google_access = true
}
`, cnName, subnetworkName)
`, cnName, subnetworkName, cidrRange)
}

func testAccComputeSubnetwork_update2(cnName, subnetworkName string) string {
func testAccComputeSubnetwork_update2(cnName, cidrRange, subnetworkName string) string {
return fmt.Sprintf(`
resource "google_compute_network" "custom-test" {
name = "%s"
Expand All @@ -260,11 +307,11 @@ resource "google_compute_network" "custom-test" {
resource "google_compute_subnetwork" "network-with-private-google-access" {
name = "%s"
ip_cidr_range = "10.2.0.0/16"
ip_cidr_range = "%s"
region = "us-central1"
network = "${google_compute_network.custom-test.self_link}"
}
`, cnName, subnetworkName)
`, cnName, subnetworkName, cidrRange)
}

func testAccComputeSubnetwork_secondaryIpRanges_update1(cnName, subnetworkName string) string {
Expand Down
8 changes: 8 additions & 0 deletions google/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,11 @@ func validateRFC1035Name(min, max int) schema.SchemaValidateFunc {

return validateRegexp(fmt.Sprintf("^"+RFC1035NameTemplate+"$", min-2, max-2))
}

func validateIpCidrRange(v interface{}, k string) (warnings []string, errors []error) {
_, _, err := net.ParseCIDR(v.(string))
if err != nil {
errors = append(errors, fmt.Errorf("%q is not a valid IP CIDR range: %s", k, err))
}
return
}
72 changes: 72 additions & 0 deletions vendor/github.com/hashicorp/terraform/helper/customdiff/compose.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions vendor/github.com/hashicorp/terraform/helper/customdiff/doc.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit c9826b1

Please sign in to comment.