From 4033642513ee61d04f0e4f15833425606139065f Mon Sep 17 00:00:00 2001 From: Dana Hoffman Date: Wed, 14 Feb 2018 15:19:56 -0500 Subject: [PATCH] add support for updating alias ips in instances --- google/resource_compute_instance.go | 54 +++++++++++++++++-- google/resource_compute_instance_test.go | 66 +++++++++++++++++++++--- 2 files changed, 107 insertions(+), 13 deletions(-) diff --git a/google/resource_compute_instance.go b/google/resource_compute_instance.go index f08a436b456..e38178d083d 100644 --- a/google/resource_compute_instance.go +++ b/google/resource_compute_instance.go @@ -371,20 +371,18 @@ func resourceComputeInstance() *schema.Resource { "alias_ip_range": &schema.Schema{ Type: schema.TypeList, + MaxItems: 1, Optional: true, - ForceNew: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "ip_cidr_range": &schema.Schema{ Type: schema.TypeString, Required: true, - ForceNew: true, DiffSuppressFunc: ipCidrRangeDiffSuppress, }, "subnetwork_range_name": &schema.Schema{ Type: schema.TypeString, Optional: true, - ForceNew: true, }, }, }, @@ -923,9 +921,11 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err return err } - instance, err := getInstance(config, d) + // Use beta api directly in order to read network_interface.fingerprint without having to put it in the schema. + // Change back to getInstance(config, d) once updating alias ips is GA. + instance, err := config.clientComputeBeta.Instances.Get(project, zone, d.Id()).Do() if err != nil { - return err + return handleNotFoundError(err, d, fmt.Sprintf("Instance %s", d.Get("name").(string))) } // Enable partial mode for the resource since it is possible @@ -1111,6 +1111,50 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err } } } + + if d.HasChange(prefix + ".alias_ip_range") { + rereadFingerprint := false + + // Alias IP ranges cannot be updated; they must be removed and then added. + if len(instNetworkInterface.AliasIpRanges) > 0 { + ni := &computeBeta.NetworkInterface{ + Fingerprint: instNetworkInterface.Fingerprint, + ForceSendFields: []string{"AliasIpRanges"}, + } + op, err := config.clientComputeBeta.Instances.UpdateNetworkInterface(project, zone, d.Id(), networkName, ni).Do() + if err != nil { + return errwrap.Wrapf("Error removing alias_ip_range: {{err}}", err) + } + opErr := computeSharedOperationWaitTime(config.clientCompute, op, project, int(d.Timeout(schema.TimeoutUpdate).Minutes()), "updaing alias ip ranges") + if opErr != nil { + return opErr + } + rereadFingerprint = true + } + + ranges := d.Get(prefix + ".alias_ip_range").([]interface{}) + if len(ranges) > 0 { + if rereadFingerprint { + instance, err = config.clientComputeBeta.Instances.Get(project, zone, d.Id()).Do() + if err != nil { + return err + } + instNetworkInterface = instance.NetworkInterfaces[i] + } + ni := &computeBeta.NetworkInterface{ + AliasIpRanges: expandAliasIpRanges(ranges), + Fingerprint: instNetworkInterface.Fingerprint, + } + op, err := config.clientComputeBeta.Instances.UpdateNetworkInterface(project, zone, d.Id(), networkName, ni).Do() + if err != nil { + return errwrap.Wrapf("Error adding alias_ip_range: {{err}}", err) + } + opErr := computeSharedOperationWaitTime(config.clientCompute, op, project, int(d.Timeout(schema.TimeoutUpdate).Minutes()), "updaing alias ip ranges") + if opErr != nil { + return opErr + } + } + } d.SetPartial("network_interface") } diff --git a/google/resource_compute_instance_test.go b/google/resource_compute_instance_test.go index 6c8edae5256..723396da1f9 100644 --- a/google/resource_compute_instance_test.go +++ b/google/resource_compute_instance_test.go @@ -983,6 +983,8 @@ func TestAccComputeInstance_secondaryAliasIpRange(t *testing.T) { var instance compute.Instance instanceName := fmt.Sprintf("terraform-test-%s", acctest.RandString(10)) + networkName := fmt.Sprintf("terraform-test-%s", acctest.RandString(10)) + subnetName := fmt.Sprintf("terraform-test-%s", acctest.RandString(10)) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -990,7 +992,7 @@ func TestAccComputeInstance_secondaryAliasIpRange(t *testing.T) { CheckDestroy: testAccCheckComputeInstanceDestroy, Steps: []resource.TestStep{ resource.TestStep{ - Config: testAccComputeInstance_secondaryAliasIpRange(instanceName), + Config: testAccComputeInstance_secondaryAliasIpRange(networkName, subnetName, instanceName), Check: resource.ComposeTestCheckFunc( testAccCheckComputeInstanceExists("google_compute_instance.foobar", &instance), testAccCheckComputeInstanceHasAliasIpRange(&instance, "inst-test-secondary", "172.16.0.0/24"), @@ -1001,6 +1003,18 @@ func TestAccComputeInstance_secondaryAliasIpRange(t *testing.T) { ImportState: true, ImportStateId: fmt.Sprintf("%s/%s/%s", getTestProjectFromEnv(), "us-east1-d", instanceName), }, + resource.TestStep{ + Config: testAccComputeInstance_secondaryAliasIpRangeUpdate(networkName, subnetName, instanceName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists("google_compute_instance.foobar", &instance), + testAccCheckComputeInstanceHasAliasIpRange(&instance, "", "10.0.1.0/24"), + ), + }, + resource.TestStep{ + ResourceName: "google_compute_instance.foobar", + ImportState: true, + ImportStateId: fmt.Sprintf("%s/%s/%s", getTestProjectFromEnv(), "us-east1-d", instanceName), + }, }, }) } @@ -2506,13 +2520,13 @@ resource "google_compute_instance" "foobar" { }`, instance) } -func testAccComputeInstance_secondaryAliasIpRange(instance string) string { +func testAccComputeInstance_secondaryAliasIpRange(network, subnet, instance string) string { return fmt.Sprintf(` resource "google_compute_network" "inst-test-network" { - name = "inst-test-network-%s" + name = "%s" } resource "google_compute_subnetwork" "inst-test-subnetwork" { - name = "inst-test-subnetwork-%s" + name = "%s" ip_cidr_range = "10.0.0.0/16" region = "us-east1" network = "${google_compute_network.inst-test-network.self_link}" @@ -2522,9 +2536,9 @@ resource "google_compute_subnetwork" "inst-test-subnetwork" { } } resource "google_compute_instance" "foobar" { - name = "%s" + name = "%s" machine_type = "n1-standard-1" - zone = "us-east1-d" + zone = "us-east1-d" boot_disk { initialize_params { @@ -2537,10 +2551,46 @@ resource "google_compute_instance" "foobar" { alias_ip_range { subnetwork_range_name = "${google_compute_subnetwork.inst-test-subnetwork.secondary_ip_range.0.range_name}" - ip_cidr_range = "172.16.0.0/24" + ip_cidr_range = "172.16.0.0/24" + } + } +}`, network, subnet, instance) +} + +func testAccComputeInstance_secondaryAliasIpRangeUpdate(network, subnet, instance string) string { + return fmt.Sprintf(` +resource "google_compute_network" "inst-test-network" { + name = "%s" +} +resource "google_compute_subnetwork" "inst-test-subnetwork" { + name = "%s" + ip_cidr_range = "10.0.0.0/16" + region = "us-east1" + network = "${google_compute_network.inst-test-network.self_link}" + secondary_ip_range { + range_name = "inst-test-secondary" + ip_cidr_range = "172.16.0.0/20" + } +} +resource "google_compute_instance" "foobar" { + name = "%s" + machine_type = "n1-standard-1" + zone = "us-east1-d" + + boot_disk { + initialize_params { + image = "debian-8-jessie-v20160803" + } + } + + network_interface { + subnetwork = "${google_compute_subnetwork.inst-test-subnetwork.self_link}" + + alias_ip_range { + ip_cidr_range = "10.0.1.0/24" } } -}`, acctest.RandString(10), acctest.RandString(10), instance) +}`, network, subnet, instance) } // Set fields that require stopping the instance: machine_type, min_cpu_platform, and service_account