diff --git a/go.sum b/go.sum index 544f244c..207d132c 100644 --- a/go.sum +++ b/go.sum @@ -121,6 +121,7 @@ github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASu github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/googleapis/gax-go v2.0.0+incompatible h1:j0GKcs05QVmm7yesiZq2+9cxHkNK9YM6zKx4D2qucQU= github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= github.com/googleapis/gax-go/v2 v2.0.3 h1:siORttZ36U2R/WjiJuDz8znElWBiAlO9rVt+mqJt0Cc= github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= diff --git a/google/resource_compute_instance.go b/google/resource_compute_instance.go index 5611cbb7..af5f610d 100644 --- a/google/resource_compute_instance.go +++ b/google/resource_compute_instance.go @@ -370,10 +370,11 @@ func resourceComputeInstance() *schema.Resource { }, "guest_accelerator": { - Type: schema.TypeList, - Optional: true, - Computed: true, - ForceNew: true, + Type: schema.TypeList, + Optional: true, + Computed: true, + ForceNew: true, + ConfigMode: schema.SchemaConfigModeAttr, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "count": { diff --git a/google/resource_compute_instance_from_template.go b/google/resource_compute_instance_from_template.go index 471bda75..ba9ef26e 100644 --- a/google/resource_compute_instance_from_template.go +++ b/google/resource_compute_instance_from_template.go @@ -37,6 +37,17 @@ func computeInstanceFromTemplateSchema() map[string]*schema.Schema { s[field].Optional = true } + // schema.SchemaConfigModeAttr allows these fields to be removed in Terraform 0.12. + // Passing field_name = [] in this mode differentiates between an intentionally empty + // block vs an ignored computed block. + nic := s["network_interface"].Elem.(*schema.Resource) + nic.Schema["alias_ip_range"].ConfigMode = schema.SchemaConfigModeAttr + nic.Schema["access_config"].ConfigMode = schema.SchemaConfigModeAttr + + for _, field := range []string{"attached_disk", "guest_accelerator", "service_account", "scratch_disk"} { + s[field].ConfigMode = schema.SchemaConfigModeAttr + } + // Remove deprecated/removed fields that are never d.Set. We can't // programatically remove all of them, because some of them still have d.Set // calls. diff --git a/google/resource_compute_instance_from_template_test.go b/google/resource_compute_instance_from_template_test.go index aad76d32..bc7ebf38 100644 --- a/google/resource_compute_instance_from_template_test.go +++ b/google/resource_compute_instance_from_template_test.go @@ -125,6 +125,50 @@ func TestAccComputeInstanceFromTemplate_overrideScratchDisk(t *testing.T) { }) } +func TestAccComputeInstanceFromTemplate_012_removableFields(t *testing.T) { + t.Parallel() + + var instance compute.Instance + instanceName := fmt.Sprintf("terraform-test-%s", acctest.RandString(10)) + templateName := fmt.Sprintf("terraform-test-%s", acctest.RandString(10)) + resourceName := "google_compute_instance_from_template.inst" + + // First config is a basic instance from template, second tests the empty list syntax + config1 := testAccComputeInstanceFromTemplate_012_removableFieldsTpl(templateName) + + testAccComputeInstanceFromTemplate_012_removableFields1(instanceName) + config2 := testAccComputeInstanceFromTemplate_012_removableFieldsTpl(templateName) + + testAccComputeInstanceFromTemplate_012_removableFields2(instanceName) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeInstanceFromTemplateDestroy, + Steps: []resource.TestStep{ + { + Config: config1, + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists(resourceName, &instance), + + resource.TestCheckResourceAttr(resourceName, "service_account.#", "1"), + resource.TestCheckResourceAttr(resourceName, "service_account.0.scopes.#", "3"), + ), + }, + { + Config: config2, + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists(resourceName, &instance), + + // Check that fields were able to be removed + resource.TestCheckResourceAttr(resourceName, "service_account.#", "0"), + resource.TestCheckResourceAttr(resourceName, "scratch_disk.#", "0"), + resource.TestCheckResourceAttr(resourceName, "attached_disk.#", "0"), + resource.TestCheckResourceAttr(resourceName, "network_interface.0.alias_ip_range.#", "0"), + ), + }, + }, + }) +} + func testAccCheckComputeInstanceFromTemplateDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) @@ -390,3 +434,81 @@ resource "google_compute_instance_from_template" "inst" { } `, templateDisk, overrideDisk, template, instance) } + +func testAccComputeInstanceFromTemplate_012_removableFieldsTpl(template string) string { + + return fmt.Sprintf(` +data "google_compute_image" "my_image" { + family = "debian-9" + project = "debian-cloud" +} + +resource "google_compute_instance_template" "foobar" { + name = "%s" + machine_type = "n1-standard-1" + + disk { + source_image = "${data.google_compute_image.my_image.self_link}" + auto_delete = true + disk_size_gb = 20 + boot = true + } + + network_interface { + network = "default" + } + + metadata = { + foo = "bar" + } + + service_account { + scopes = ["userinfo-email", "compute-ro", "storage-ro"] + } + + can_ip_forward = true +} +`, template) +} + +func testAccComputeInstanceFromTemplate_012_removableFields1(instance string) string { + return fmt.Sprintf(` +resource "google_compute_instance_from_template" "inst" { + name = "%s" + zone = "us-central1-a" + + allow_stopping_for_update = true + + source_instance_template = "${google_compute_instance_template.foobar.self_link}" +} +`, instance) +} + +func testAccComputeInstanceFromTemplate_012_removableFields2(instance string) string { + return fmt.Sprintf(` +resource "google_compute_instance_from_template" "inst" { + name = "%s" + zone = "us-central1-a" + + allow_stopping_for_update = true + + source_instance_template = "${google_compute_instance_template.foobar.self_link}" + + // Overrides + network_interface { + alias_ip_range = [] + } + + service_account = [] + + scratch_disk = [] + + attached_disk = [] + + timeouts { + create = "10m" + update = "10m" + } +} +`, instance) +} diff --git a/google/resource_compute_subnetwork.go b/google/resource_compute_subnetwork.go index 12dc63ca..bb3786cf 100644 --- a/google/resource_compute_subnetwork.go +++ b/google/resource_compute_subnetwork.go @@ -117,6 +117,7 @@ func resourceComputeSubnetwork() *schema.Resource { }, "secondary_ip_range": { Type: schema.TypeList, + Computed: true, Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ diff --git a/website/docs/r/compute_instance_from_template.html.markdown b/website/docs/r/compute_instance_from_template.html.markdown index 10fba707..4c11b090 100644 --- a/website/docs/r/compute_instance_from_template.html.markdown +++ b/website/docs/r/compute_instance_from_template.html.markdown @@ -76,6 +76,14 @@ In addition to these, all arguments from `google_compute_instance` are supported as a way to override the properties in the template. All exported attributes from `google_compute_instance` are likewise exported here. +To support removal of Optional/Computed fields in Terraform 0.12 the following fields +are marked [Attributes as Blocks](/docs/configuration/attr-as-blocks.html): +* `attached_disk` +* `guest_accelerator` +* `service_account` +* `scratch_disk` +* `network_interface.alias_ip_range` +* `network_interface.access_config` ## Timeouts