Implement in-place updates of secondary IP ranges (#811)

This commit is contained in:
koenw 2017-12-08 22:11:09 +01:00 committed by Vincent Roseberry
parent 13eb96cf6a
commit 4da0e984f6
2 changed files with 219 additions and 3 deletions

View File

@ -7,9 +7,17 @@ import (
"strings"
"github.com/hashicorp/terraform/helper/schema"
computeBeta "google.golang.org/api/compute/v0.beta"
"google.golang.org/api/compute/v1"
)
var (
SubnetworkBaseApiVersion = v1
SubnetworkVersionedFeatures = []Feature{
{Version: v0beta, Item: "secondary_ip_range"},
}
)
func resourceComputeSubnetwork() *schema.Resource {
return &schema.Resource{
Create: resourceComputeSubnetworkCreate,
@ -46,6 +54,11 @@ func resourceComputeSubnetwork() *schema.Resource {
ForceNew: true,
},
"fingerprint": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"gateway_address": &schema.Schema{
Type: schema.TypeString,
Computed: true,
@ -73,19 +86,16 @@ func resourceComputeSubnetwork() *schema.Resource {
"secondary_ip_range": &schema.Schema{
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"range_name": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validateGCPName,
},
"ip_cidr_range": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
},
},
@ -151,6 +161,11 @@ func resourceComputeSubnetworkCreate(d *schema.ResourceData, meta interface{}) e
}
func resourceComputeSubnetworkRead(d *schema.ResourceData, meta interface{}) error {
computeApiVersion := getComputeApiVersion(d, SubnetworkBaseApiVersion, SubnetworkVersionedFeatures)
if computeApiVersion == v0beta {
return resourceComputeSubnetworkReadV0Beta(d, meta)
}
config := meta.(*Config)
region, err := getRegion(d, config)
@ -184,7 +199,43 @@ func resourceComputeSubnetworkRead(d *schema.ResourceData, meta interface{}) err
return nil
}
func resourceComputeSubnetworkReadV0Beta(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
region, err := getRegion(d, config)
if err != nil {
return err
}
project, err := getProject(d, config)
if err != nil {
return err
}
name := d.Get("name").(string)
subnetwork, err := config.clientComputeBeta.Subnetworks.Get(project, region, name).Do()
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("Subnetwork %q", name))
}
d.Set("name", subnetwork.Name)
d.Set("ip_cidr_range", subnetwork.IpCidrRange)
d.Set("network", subnetwork.Network)
d.Set("description", subnetwork.Description)
d.Set("private_ip_google_access", subnetwork.PrivateIpGoogleAccess)
d.Set("gateway_address", subnetwork.GatewayAddress)
d.Set("secondary_ip_range", flattenSecondaryRangesV0Beta(subnetwork.SecondaryIpRanges))
d.Set("project", project)
d.Set("region", region)
d.Set("self_link", ConvertSelfLinkToV1(subnetwork.SelfLink))
d.Set("fingerprint", subnetwork.Fingerprint)
return nil
}
func resourceComputeSubnetworkUpdate(d *schema.ResourceData, meta interface{}) error {
computeApiVersion := getComputeApiVersion(d, SubnetworkBaseApiVersion, SubnetworkVersionedFeatures)
config := meta.(*Config)
region, err := getRegion(d, config)
@ -221,6 +272,26 @@ func resourceComputeSubnetworkUpdate(d *schema.ResourceData, meta interface{}) e
d.SetPartial("private_ip_google_access")
}
if d.HasChange("secondary_ip_range") && computeApiVersion == v0beta {
v0BetaSubnetwork := &computeBeta.Subnetwork{
SecondaryIpRanges: expandSecondaryRangesV0Beta(d.Get("secondary_ip_range").([]interface{})),
Fingerprint: d.Get("fingerprint").(string),
}
op, err := config.clientComputeBeta.Subnetworks.Patch(
project, region, d.Get("name").(string), v0BetaSubnetwork).Do()
if err != nil {
return fmt.Errorf("Error updating subnetwork SecondaryIpRanges: %s", err)
}
err = computeSharedOperationWait(config.clientCompute, op, project, "Updating Subnetwork SecondaryIpRanges")
if err != nil {
return err
}
d.SetPartial("secondary_ip_range")
}
d.Partial(false)
return resourceComputeSubnetworkRead(d, meta)
@ -298,6 +369,20 @@ func expandSecondaryRanges(configured []interface{}) []*compute.SubnetworkSecond
return secondaryRanges
}
func expandSecondaryRangesV0Beta(configured []interface{}) []*computeBeta.SubnetworkSecondaryRange {
secondaryRanges := make([]*computeBeta.SubnetworkSecondaryRange, 0, len(configured))
for _, raw := range configured {
data := raw.(map[string]interface{})
secondaryRange := computeBeta.SubnetworkSecondaryRange{
RangeName: data["range_name"].(string),
IpCidrRange: data["ip_cidr_range"].(string),
}
secondaryRanges = append(secondaryRanges, &secondaryRange)
}
return secondaryRanges
}
func flattenSecondaryRanges(secondaryRanges []*compute.SubnetworkSecondaryRange) []map[string]interface{} {
secondaryRangesSchema := make([]map[string]interface{}, 0, len(secondaryRanges))
for _, secondaryRange := range secondaryRanges {
@ -310,3 +395,16 @@ func flattenSecondaryRanges(secondaryRanges []*compute.SubnetworkSecondaryRange)
}
return secondaryRangesSchema
}
func flattenSecondaryRangesV0Beta(secondaryRanges []*computeBeta.SubnetworkSecondaryRange) []map[string]interface{} {
secondaryRangesSchema := make([]map[string]interface{}, 0, len(secondaryRanges))
for _, secondaryRange := range secondaryRanges {
data := map[string]interface{}{
"range_name": secondaryRange.RangeName,
"ip_cidr_range": secondaryRange.IpCidrRange,
}
secondaryRangesSchema = append(secondaryRangesSchema, data)
}
return secondaryRangesSchema
}

View File

@ -74,6 +74,46 @@ func TestAccComputeSubnetwork_update(t *testing.T) {
}
}
func TestAccComputeSubnetwork_secondaryIpRangesUpdate(t *testing.T) {
t.Parallel()
var subnetwork compute.Subnetwork
cnName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
subnetworkName := fmt.Sprintf("tf-test-%s", acctest.RandString(10))
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSubnetworkDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccComputeSubnetwork_secondaryIpRanges_update1(cnName, subnetworkName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSubnetworkExists("google_compute_subnetwork.network-with-private-secondary-ip-ranges", &subnetwork),
testAccCheckComputeSubnetworkHasSecondaryIpRange(&subnetwork, "tf-test-secondary-range-update1", "192.168.10.0/24"),
),
},
resource.TestStep{
Config: testAccComputeSubnetwork_secondaryIpRanges_update2(cnName, subnetworkName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSubnetworkExists("google_compute_subnetwork.network-with-private-secondary-ip-ranges", &subnetwork),
testAccCheckComputeSubnetworkHasSecondaryIpRange(&subnetwork, "tf-test-secondary-range-update1", "192.168.10.0/24"),
testAccCheckComputeSubnetworkHasSecondaryIpRange(&subnetwork, "tf-test-secondary-range-update2", "192.168.11.0/24"),
),
},
resource.TestStep{
Config: testAccComputeSubnetwork_secondaryIpRanges_update3(cnName, subnetworkName),
Check: resource.ComposeTestCheckFunc(
testAccCheckComputeSubnetworkExists("google_compute_subnetwork.network-with-private-secondary-ip-ranges", &subnetwork),
testAccCheckComputeSubnetworkHasSecondaryIpRange(&subnetwork, "tf-test-secondary-range-update1", "192.168.10.0/24"),
testAccCheckComputeSubnetworkHasNotSecondaryIpRange(&subnetwork, "tf-test-secondary-range-update2", "192.168.11.0/24"),
),
},
},
})
}
func TestAccComputeSubnetwork_secondaryIpRanges(t *testing.T) {
t.Parallel()
@ -162,6 +202,20 @@ func testAccCheckComputeSubnetworkHasSecondaryIpRange(subnetwork *compute.Subnet
}
}
func testAccCheckComputeSubnetworkHasNotSecondaryIpRange(subnetwork *compute.Subnetwork, rangeName, ipCidrRange string) resource.TestCheckFunc {
return func(s *terraform.State) error {
for _, secondaryRange := range subnetwork.SecondaryIpRanges {
if secondaryRange.RangeName == rangeName {
if secondaryRange.IpCidrRange == ipCidrRange {
return fmt.Errorf("Secondary range %s has the wrong ip_cidr_range. Expected %s, got %s", rangeName, ipCidrRange, secondaryRange.IpCidrRange)
}
}
}
return nil
}
}
func testAccComputeSubnetwork_basic(cnName, subnetwork1Name, subnetwork2Name, subnetwork3Name string) string {
return fmt.Sprintf(`
resource "google_compute_network" "custom-test" {
@ -246,3 +300,67 @@ resource "google_compute_subnetwork" "network-with-private-secondary-ip-range" {
}
`, cnName, subnetworkName)
}
func testAccComputeSubnetwork_secondaryIpRanges_update1(cnName, subnetworkName string) string {
return fmt.Sprintf(`
resource "google_compute_network" "custom-test" {
name = "%s"
auto_create_subnetworks = false
}
resource "google_compute_subnetwork" "network-with-private-secondary-ip-ranges" {
name = "%s"
ip_cidr_range = "10.2.0.0/16"
region = "us-central1"
network = "${google_compute_network.custom-test.self_link}"
secondary_ip_range {
range_name = "tf-test-secondary-range-update1"
ip_cidr_range = "192.168.10.0/24"
}
}
`, cnName, subnetworkName)
}
func testAccComputeSubnetwork_secondaryIpRanges_update2(cnName, subnetworkName string) string {
return fmt.Sprintf(`
resource "google_compute_network" "custom-test" {
name = "%s"
auto_create_subnetworks = false
}
resource "google_compute_subnetwork" "network-with-private-secondary-ip-ranges" {
name = "%s"
ip_cidr_range = "10.2.0.0/16"
region = "us-central1"
network = "${google_compute_network.custom-test.self_link}"
secondary_ip_range {
range_name = "tf-test-secondary-range-update1"
ip_cidr_range = "192.168.10.0/24"
}
secondary_ip_range {
range_name = "tf-test-secondary-range-update2"
ip_cidr_range = "192.168.11.0/24"
},
}
`, cnName, subnetworkName)
}
func testAccComputeSubnetwork_secondaryIpRanges_update3(cnName, subnetworkName string) string {
return fmt.Sprintf(`
resource "google_compute_network" "custom-test" {
name = "%s"
auto_create_subnetworks = false
}
resource "google_compute_subnetwork" "network-with-private-secondary-ip-ranges" {
name = "%s"
ip_cidr_range = "10.2.0.0/16"
region = "us-central1"
network = "${google_compute_network.custom-test.self_link}"
secondary_ip_range {
range_name = "tf-test-secondary-range-update1"
ip_cidr_range = "192.168.10.0/24"
}
}
`, cnName, subnetworkName)
}