From 24a7f9871b1c51e405388456d4792d348263e59c Mon Sep 17 00:00:00 2001 From: The Magician Date: Tue, 23 Jan 2024 14:53:02 -0800 Subject: [PATCH] Add `readiness_checks` to `google_workstations_workstation_config` (#9841) (#6895) * feat: add `readiness_checks` to Workstation Config * chore: set path and change port to port 80 * Update WorkstationConfig.yaml * chore: make readiness checks arguments required * chore: add readiness checks to basic example * LRevert "chore: add readiness checks to basic example" This reverts commit e8d3ec37c649d86bf03fa978003d07f22caf8d7b. --------- [upstream:7ca983b9aa12655a93b7e9683ddc25ed1bd972ae] Signed-off-by: Modular Magician --- .changelog/9841.txt | 3 + ...esource_workstations_workstation_config.go | 115 ++++++++++++++++++ ...ce_workstations_workstation_config_test.go | 77 ++++++++++++ ...kstations_workstation_config.html.markdown | 15 +++ 4 files changed, 210 insertions(+) create mode 100644 .changelog/9841.txt diff --git a/.changelog/9841.txt b/.changelog/9841.txt new file mode 100644 index 0000000000..d0ff75c7ea --- /dev/null +++ b/.changelog/9841.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +workstations: added `readiness_checks` argument block to `google_workstations_workstation_config` resource (beta) +``` diff --git a/google-beta/services/workstations/resource_workstations_workstation_config.go b/google-beta/services/workstations/resource_workstations_workstation_config.go index e6c723c48f..530e2c9276 100644 --- a/google-beta/services/workstations/resource_workstations_workstation_config.go +++ b/google-beta/services/workstations/resource_workstations_workstation_config.go @@ -388,6 +388,25 @@ Valid values are '10', '50', '100', '200', '500', or '1000'. Defaults to '200'. }, }, }, + "readiness_checks": { + Type: schema.TypeList, + Optional: true, + Description: `Readiness checks to be performed on a workstation.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "path": { + Type: schema.TypeString, + Required: true, + Description: `Path to which the request should be sent.`, + }, + "port": { + Type: schema.TypeInt, + Required: true, + Description: `Port to which the request should be sent.`, + }, + }, + }, + }, "replica_zones": { Type: schema.TypeList, Computed: true, @@ -557,6 +576,12 @@ func resourceWorkstationsWorkstationConfigCreate(d *schema.ResourceData, meta in } else if v, ok := d.GetOkExists("encryption_key"); !tpgresource.IsEmptyValue(reflect.ValueOf(encryptionKeyProp)) && (ok || !reflect.DeepEqual(v, encryptionKeyProp)) { obj["encryptionKey"] = encryptionKeyProp } + readinessChecksProp, err := expandWorkstationsWorkstationConfigReadinessChecks(d.Get("readiness_checks"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("readiness_checks"); !tpgresource.IsEmptyValue(reflect.ValueOf(readinessChecksProp)) && (ok || !reflect.DeepEqual(v, readinessChecksProp)) { + obj["readinessChecks"] = readinessChecksProp + } disableTcpConnectionsProp, err := expandWorkstationsWorkstationConfigDisableTcpConnections(d.Get("disable_tcp_connections"), d, config) if err != nil { return err @@ -712,6 +737,9 @@ func resourceWorkstationsWorkstationConfigRead(d *schema.ResourceData, meta inte if err := d.Set("encryption_key", flattenWorkstationsWorkstationConfigEncryptionKey(res["encryptionKey"], d, config)); err != nil { return fmt.Errorf("Error reading WorkstationConfig: %s", err) } + if err := d.Set("readiness_checks", flattenWorkstationsWorkstationConfigReadinessChecks(res["readinessChecks"], d, config)); err != nil { + return fmt.Errorf("Error reading WorkstationConfig: %s", err) + } if err := d.Set("degraded", flattenWorkstationsWorkstationConfigDegraded(res["degraded"], d, config)); err != nil { return fmt.Errorf("Error reading WorkstationConfig: %s", err) } @@ -798,6 +826,12 @@ func resourceWorkstationsWorkstationConfigUpdate(d *schema.ResourceData, meta in } else if v, ok := d.GetOkExists("container"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, containerProp)) { obj["container"] = containerProp } + readinessChecksProp, err := expandWorkstationsWorkstationConfigReadinessChecks(d.Get("readiness_checks"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("readiness_checks"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, readinessChecksProp)) { + obj["readinessChecks"] = readinessChecksProp + } disableTcpConnectionsProp, err := expandWorkstationsWorkstationConfigDisableTcpConnections(d.Get("disable_tcp_connections"), d, config) if err != nil { return err @@ -872,6 +906,10 @@ func resourceWorkstationsWorkstationConfigUpdate(d *schema.ResourceData, meta in "container.runAsUser") } + if d.HasChange("readiness_checks") { + updateMask = append(updateMask, "readinessChecks") + } + if d.HasChange("disable_tcp_connections") { updateMask = append(updateMask, "disableTcpConnections") } @@ -1408,6 +1446,46 @@ func flattenWorkstationsWorkstationConfigEncryptionKeyKmsKeyServiceAccount(v int return v } +func flattenWorkstationsWorkstationConfigReadinessChecks(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "path": flattenWorkstationsWorkstationConfigReadinessChecksPath(original["path"], d, config), + "port": flattenWorkstationsWorkstationConfigReadinessChecksPort(original["port"], d, config), + }) + } + return transformed +} +func flattenWorkstationsWorkstationConfigReadinessChecksPath(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenWorkstationsWorkstationConfigReadinessChecksPort(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + func flattenWorkstationsWorkstationConfigDegraded(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { return v } @@ -1972,6 +2050,43 @@ func expandWorkstationsWorkstationConfigEncryptionKeyKmsKeyServiceAccount(v inte return v, nil } +func expandWorkstationsWorkstationConfigReadinessChecks(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedPath, err := expandWorkstationsWorkstationConfigReadinessChecksPath(original["path"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPath); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["path"] = transformedPath + } + + transformedPort, err := expandWorkstationsWorkstationConfigReadinessChecksPort(original["port"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPort); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["port"] = transformedPort + } + + req = append(req, transformed) + } + return req, nil +} + +func expandWorkstationsWorkstationConfigReadinessChecksPath(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandWorkstationsWorkstationConfigReadinessChecksPort(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + func expandWorkstationsWorkstationConfigDisableTcpConnections(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } diff --git a/google-beta/services/workstations/resource_workstations_workstation_config_test.go b/google-beta/services/workstations/resource_workstations_workstation_config_test.go index 627f51dd01..ff13566723 100644 --- a/google-beta/services/workstations/resource_workstations_workstation_config_test.go +++ b/google-beta/services/workstations/resource_workstations_workstation_config_test.go @@ -371,6 +371,83 @@ func testAccWorkstationsWorkstationConfig_disableTcpConnections(context map[stri `, context) } +func TestAccWorkstationsWorkstationConfig_readinessChecks(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + CheckDestroy: testAccCheckWorkstationsWorkstationConfigDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccWorkstationsWorkstationConfig_readinessChecks(context), + }, + { + ResourceName: "google_workstations_workstation_cluster.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"etag"}, + }, + }, + }) +} + +func testAccWorkstationsWorkstationConfig_readinessChecks(context map[string]interface{}) string { + return acctest.Nprintf(` + resource "google_compute_network" "default" { + provider = google-beta + name = "tf-test-workstation-cluster%{random_suffix}" + auto_create_subnetworks = false + } + + resource "google_compute_subnetwork" "default" { + provider = google-beta + name = "tf-test-workstation-cluster%{random_suffix}" + ip_cidr_range = "10.0.0.0/24" + region = "us-central1" + network = google_compute_network.default.name + } + + resource "google_workstations_workstation_cluster" "default" { + provider = google-beta + workstation_cluster_id = "tf-test-workstation-cluster%{random_suffix}" + network = google_compute_network.default.id + subnetwork = google_compute_subnetwork.default.id + location = "us-central1" + } + + resource "google_service_account" "default" { + provider = google-beta + + account_id = "tf-test-my-account%{random_suffix}" + display_name = "Service Account" + } + + resource "google_workstations_workstation_config" "default" { + provider = google-beta + workstation_config_id = "tf-test-workstation-config%{random_suffix}" + workstation_cluster_id = google_workstations_workstation_cluster.default.workstation_cluster_id + location = "us-central1" + + readiness_checks { + path = "/" + port = 80 + } + + host { + gce_instance { + service_account = google_service_account.default.email + service_account_scopes = ["https://www.googleapis.com/auth/cloud-platform"] + } + } + } +`, context) +} + func TestAccWorkstationsWorkstationConfig_update(t *testing.T) { t.Parallel() diff --git a/website/docs/r/workstations_workstation_config.html.markdown b/website/docs/r/workstations_workstation_config.html.markdown index 4030d99332..4ac92fbe00 100644 --- a/website/docs/r/workstations_workstation_config.html.markdown +++ b/website/docs/r/workstations_workstation_config.html.markdown @@ -573,6 +573,11 @@ The following arguments are supported: If the encryption key is revoked, the workstation session will automatically be stopped within 7 hours. Structure is [documented below](#nested_encryption_key). +* `readiness_checks` - + (Optional) + Readiness checks to be performed on a workstation. + Structure is [documented below](#nested_readiness_checks). + * `disable_tcp_connections` - (Optional) Disables support for plain TCP connections in the workstation. By default the service supports TCP connections via a websocket relay. Setting this option to true disables that relay, which prevents the usage of services that require plain tcp connections, such as ssh. When enabled, all communication must occur over https or wss. @@ -743,6 +748,16 @@ The following arguments are supported: (Required) The service account to use with the specified KMS key. +The `readiness_checks` block supports: + +* `path` - + (Required) + Path to which the request should be sent. + +* `port` - + (Required) + Port to which the request should be sent. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are exported: