From 9cd691714ca037caeb58b78bac877d15a9536881 Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Wed, 30 Jun 2021 19:05:46 +0000 Subject: [PATCH] Add `advanced_machine_features` to GCE Instances (#4849) * add advance_machine_features Co-authored-by: upodroid * fix doc typo * fix typos and remove computed schema * make one of nested fields required * remove erroneous typo in expand functions Signed-off-by: Modular Magician --- .changelog/4849.txt | 3 + google-beta/compute_instance_helpers.go | 2 - google-beta/resource_compute_instance.go | 61 ++++++++++++- google-beta/resource_compute_instance_test.go | 91 ++++++++++++++++++- ...esource_gke_hub_feature_membership_test.go | 2 +- website/docs/r/compute_instance.html.markdown | 8 ++ .../r/compute_instance_template.html.markdown | 4 +- 7 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 .changelog/4849.txt diff --git a/.changelog/4849.txt b/.changelog/4849.txt new file mode 100644 index 0000000000..5f08ce4313 --- /dev/null +++ b/.changelog/4849.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +compute: added `advanced_machine_features` to `google_compute_instance` +``` diff --git a/google-beta/compute_instance_helpers.go b/google-beta/compute_instance_helpers.go index 0761a0bac5..b1e94c9a3a 100644 --- a/google-beta/compute_instance_helpers.go +++ b/google-beta/compute_instance_helpers.go @@ -331,7 +331,6 @@ func expandConfidentialInstanceConfig(d TerraformResourceData) *computeBeta.Conf prefix := "confidential_instance_config.0" return &computeBeta.ConfidentialInstanceConfig{ EnableConfidentialCompute: d.Get(prefix + ".enable_confidential_compute").(bool), - ForceSendFields: []string{"EnableSecureBoot"}, } } @@ -354,7 +353,6 @@ func expandAdvancedMachineFeatures(d TerraformResourceData) *computeBeta.Advance return &computeBeta.AdvancedMachineFeatures{ EnableNestedVirtualization: d.Get(prefix + ".enable_nested_virtualization").(bool), ThreadsPerCore: int64(d.Get(prefix + ".threads_per_core").(int)), - // ForceSendFields: []string{"EnableSecureBoot"}, } } diff --git a/google-beta/resource_compute_instance.go b/google-beta/resource_compute_instance.go index a5b0a3c81b..9e776c1349 100644 --- a/google-beta/resource_compute_instance.go +++ b/google-beta/resource_compute_instance.go @@ -658,6 +658,28 @@ func resourceComputeInstance() *schema.Resource { }, }, }, + "advanced_machine_features": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Description: `Controls for advanced machine-related behavior features.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "enable_nested_virtualization": { + Type: schema.TypeBool, + Optional: true, + AtLeastOneOf: []string{"advanced_machine_features.0.enable_nested_virtualization","advanced_machine_features.0.threads_per_core"} + Description: `Whether to enable nested virtualization or not.`, + }, + "threads_per_core": { + Type: schema.TypeInt, + Optional: true, + AtLeastOneOf: []string{"advanced_machine_features.0.enable_nested_virtualization","advanced_machine_features.0.threads_per_core"} + Description: `The number of threads per physical core. To disable simultaneous multithreading (SMT) set this to 1. If unset, the maximum number of threads supported per core by the underlying processor is assumed.`, + }, + }, + }, + }, "confidential_instance_config": { Type: schema.TypeList, MaxItems: 1, @@ -946,6 +968,7 @@ func expandComputeInstance(project string, d *schema.ResourceData, config *Confi Hostname: d.Get("hostname").(string), ForceSendFields: []string{"CanIpForward", "DeletionProtection"}, ConfidentialInstanceConfig: expandConfidentialInstanceConfig(d), + AdvancedMachineFeatures: expandAdvancedMachineFeatures(d), ShieldedInstanceConfig: expandShieldedVmConfigs(d), DisplayDevice: expandDisplayDevice(d), ResourcePolicies: convertStringArr(d.Get("resource_policies").([]interface{})), @@ -1305,6 +1328,9 @@ func resourceComputeInstanceRead(d *schema.ResourceData, meta interface{}) error if err := d.Set("confidential_instance_config", flattenConfidentialInstanceConfig(instance.ConfidentialInstanceConfig)); err != nil { return fmt.Errorf("Error setting confidential_instance_config: %s", err) } + if err := d.Set("advanced_machine_features", flattenAdvancedMachineFeatures(instance.AdvancedMachineFeatures)); err != nil { + return fmt.Errorf("Error setting advanced_machine_config: %s", err) + } if d.Get("desired_status") != "" { if err := d.Set("desired_status", instance.Status); err != nil { return fmt.Errorf("Error setting desired_status: %s", err) @@ -1709,7 +1735,7 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err } } - needToStopInstanceBeforeUpdating := scopesChange || d.HasChange("service_account.0.email") || d.HasChange("machine_type") || d.HasChange("min_cpu_platform") || d.HasChange("enable_display") || d.HasChange("shielded_instance_config") || len(updatesToNIWhileStopped) > 0 || bootRequiredSchedulingChange + needToStopInstanceBeforeUpdating := scopesChange || d.HasChange("service_account.0.email") || d.HasChange("machine_type") || d.HasChange("min_cpu_platform") || d.HasChange("enable_display") || d.HasChange("shielded_instance_config") || len(updatesToNIWhileStopped) > 0 || bootRequiredSchedulingChange || d.HasChange("advanced_machine_features") if d.HasChange("desired_status") && !needToStopInstanceBeforeUpdating { desiredStatus := d.Get("desired_status").(string) @@ -1744,7 +1770,7 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err if statusBeforeUpdate == "RUNNING" && desiredStatus != "TERMINATED" && !d.Get("allow_stopping_for_update").(bool) { return fmt.Errorf("Changing the machine_type, min_cpu_platform, service_account, enable_display, shielded_instance_config, scheduling.node_affinities " + - "or network_interface.[#d].(network/subnetwork/subnetwork_project) on a started instance requires stopping it. " + + "or network_interface.[#d].(network/subnetwork/subnetwork_project) or advanced_machine_config on a started instance requires stopping it. " + "To acknowledge this, please set allow_stopping_for_update = true in your config. " + "You can also stop it by setting desired_status = \"TERMINATED\", but the instance will not be restarted after the update.") } @@ -1868,6 +1894,37 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err } } + if d.HasChange("advanced_machine_features") { + err = retry( + func() error { + // retrieve up-to-date instance from the API in case several updates hit simultaneously. instances + // sometimes but not always share metadata fingerprints. + instance, err := config.NewComputeBetaClient(userAgent).Instances.Get(project, zone, instance.Name).Do() + if err != nil { + return fmt.Errorf("Error retrieving instance: %s", err) + } + + instance.AdvancedMachineFeatures = expandAdvancedMachineFeatures(d) + + op, err := config.NewComputeBetaClient(userAgent).Instances.Update(project, zone, instance.Name, instance).Do() + if err != nil { + return fmt.Errorf("Error updating instance: %s", err) + } + + opErr := computeOperationWaitTime(config, op, project, "advanced_machine_features to update", userAgent, d.Timeout(schema.TimeoutUpdate)) + if opErr != nil { + return opErr + } + + return nil + }, + ) + + if err != nil { + return err + } + } + // If the instance stops it can invalidate the fingerprint for network interface. // refresh the instance to get a new fingerprint if len(updatesToNIWhileStopped) > 0 { diff --git a/google-beta/resource_compute_instance_test.go b/google-beta/resource_compute_instance_test.go index c5bfd3ce39..1b90325d12 100644 --- a/google-beta/resource_compute_instance_test.go +++ b/google-beta/resource_compute_instance_test.go @@ -924,6 +924,37 @@ func TestAccComputeInstance_scheduling(t *testing.T) { }) } +func TestAccComputeInstance_advancedMachineFeatures(t *testing.T) { + t.Parallel() + + var instance compute.Instance + var instanceName = fmt.Sprintf("tf-test-%s", randString(t, 10)) + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeInstance_advancedMachineFeatures(instanceName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists( + t, "google_compute_instance.foobar", &instance), + ), + }, + computeInstanceImportStep("us-central1-a", instanceName, []string{"allow_stopping_for_update"}), + { + Config: testAccComputeInstance_advancedMachineFeaturesUpdated(instanceName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists( + t, "google_compute_instance.foobar", &instance), + ), + }, + computeInstanceImportStep("us-central1-a", instanceName, []string{"allow_stopping_for_update"}), + }, + }) +} + func TestAccComputeInstance_soleTenantNodeAffinities(t *testing.T) { t.Parallel() @@ -1678,7 +1709,7 @@ func TestAccComputeInstance_updateRunning_desiredStatusRunning_allowStoppingForU }) } -const errorAllowStoppingMsg = "Changing the machine_type, min_cpu_platform, service_account, enable_display, shielded_instance_config, scheduling.node_affinities or network_interface.\\[#d\\].\\(network/subnetwork/subnetwork_project\\) on a started instance requires stopping it. To acknowledge this, please set allow_stopping_for_update = true in your config. You can also stop it by setting desired_status = \"TERMINATED\", but the instance will not be restarted after the update." +const errorAllowStoppingMsg = "Changing the machine_type, min_cpu_platform, service_account, enable_display, shielded_instance_config, scheduling.node_affinities, network_interface.\\[#d\\].\\(network/subnetwork/subnetwork_project\\) or advanced_machine_config on a started instance requires stopping it. To acknowledge this, please set allow_stopping_for_update = true in your config. You can also stop it by setting desired_status = \"TERMINATED\", but the instance will not be restarted after the update." func TestAccComputeInstance_updateRunning_desiredStatusNotSet_notAllowStoppingForUpdate(t *testing.T) { t.Parallel() @@ -4241,6 +4272,64 @@ resource "google_compute_instance" "foobar" { `, instance) } +func testAccComputeInstance_advancedMachineFeatures(instance string) string { + return fmt.Sprintf(` +data "google_compute_image" "my_image" { + family = "debian-10" + project = "debian-cloud" +} + +resource "google_compute_instance" "foobar" { + name = "%s" + machine_type = "n1-standard-2" // Nested Virt isn't supported on E2 and N2Ds https://cloud.google.com/compute/docs/instances/nested-virtualization/overview#restrictions and https://cloud.google.com/compute/docs/instances/disabling-smt#limitations + zone = "us-central1-a" + + boot_disk { + initialize_params { + image = data.google_compute_image.my_image.self_link + } + } + + network_interface { + network = "default" + } + + allow_stopping_for_update = true + +} +`, instance) +} + +func testAccComputeInstance_advancedMachineFeaturesUpdated(instance string) string { + return fmt.Sprintf(` +data "google_compute_image" "my_image" { + family = "debian-10" + project = "debian-cloud" +} + +resource "google_compute_instance" "foobar" { + name = "%s" + machine_type = "n1-standard-2" // Nested Virt isn't supported on E2 and N2Ds https://cloud.google.com/compute/docs/instances/nested-virtualization/overview#restrictions and https://cloud.google.com/compute/docs/instances/disabling-smt#limitations + zone = "us-central1-a" + + boot_disk { + initialize_params { + image = data.google_compute_image.my_image.self_link + } + } + + network_interface { + network = "default" + } + advanced_machine_features { + threads_per_core = 1 + enable_nested_virtualization = true + } + allow_stopping_for_update = true +} +`, instance) +} + func testAccComputeInstance_subnet_auto(suffix, instance string) string { return fmt.Sprintf(` data "google_compute_image" "my_image" { diff --git a/google-beta/resource_gke_hub_feature_membership_test.go b/google-beta/resource_gke_hub_feature_membership_test.go index 9e1f2ea64d..32fa84c196 100644 --- a/google-beta/resource_gke_hub_feature_membership_test.go +++ b/google-beta/resource_gke_hub_feature_membership_test.go @@ -5,7 +5,7 @@ import ( "fmt" "testing" - "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" + dcl "github.com/GoogleCloudPlatform/declarative-resource-client-library/dcl" gkehub "github.com/GoogleCloudPlatform/declarative-resource-client-library/services/google/gkehub/beta" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" diff --git a/website/docs/r/compute_instance.html.markdown b/website/docs/r/compute_instance.html.markdown index 7f28800d50..fdc7869885 100644 --- a/website/docs/r/compute_instance.html.markdown +++ b/website/docs/r/compute_instance.html.markdown @@ -176,6 +176,8 @@ The following arguments are supported: * `confidential_instance_config` (Optional) - Enable [Confidential Mode](https://cloud.google.com/compute/confidential-vm/docs/about-cvm) on this VM. +* `advanced_machine_config` (Optional) - Configure Nested Virtualisation and Simultaneous Hyper Threading on this VM. + * `network_performance_config` (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html) Configures network performance settings for the instance. Structure is documented below. **Note**: [`machine_type`](#machine_type) must be a [supported type](https://cloud.google.com/compute/docs/networking/configure-vm-with-high-bandwidth-configuration), @@ -380,6 +382,12 @@ The `confidential_instance_config` block supports: * `enable_confidential_compute` (Optional) Defines whether the instance should have confidential compute enabled. [`on_host_maintenance`](#on_host_maintenance) has to be set to TERMINATE or this will fail to create the VM. +The `advanced_machine_features` block supports: + +* `enable_nested_virtualization` (Optional) Defines whether the instance should have [nested virtualization](#on_host_maintenance) enabled. Defaults to false. + +* `threads_per_core` (Optional) he number of threads per physical core. To disable [simultaneous multithreading (SMT)](https://cloud.google.com/compute/docs/instances/disabling-smt) set this to 1. + The `reservation_affinity` block supports: * `type` - (Required) The type of reservation from which this instance can consume resources. diff --git a/website/docs/r/compute_instance_template.html.markdown b/website/docs/r/compute_instance_template.html.markdown index 9bb64b080a..c3abf4b467 100644 --- a/website/docs/r/compute_instance_template.html.markdown +++ b/website/docs/r/compute_instance_template.html.markdown @@ -282,7 +282,7 @@ The following arguments are supported: * `confidential_instance_config` (Optional) - Enable [Confidential Mode](https://cloud.google.com/compute/confidential-vm/docs/about-cvm) on this VM. -* `advanced_machine_features` (Optional) - Configure Nested Virtualisation and Simultaneous Hyper Threading on this VM. +* `advanced_machine_features` (Optional) - Configure Nested Virtualisation and Simultaneous Hyper Threading on this VM. The `disk` block supports: @@ -477,7 +477,7 @@ The `network_performance_config` block supports: The `advanced_machine_features` block supports: -* `enable_nested_virtualization` (Optional) Defines whether the instance should have [nested virtualization](#on_host_maintenance) enabled. Defaults to false. +* `enable_nested_virtualization` (Optional) Defines whether the instance should have [nested virtualization](#on_host_maintenance) enabled. Defaults to false. * `threads_per_core` (Optional) he number of threads per physical core. To disable [simultaneous multithreading (SMT)](https://cloud.google.com/compute/docs/instances/disabling-smt) set this to 1.