From 18666fbc36225b39c6c35756bbd0d71a5da661fc Mon Sep 17 00:00:00 2001 From: kkram01 Date: Wed, 14 Feb 2024 01:36:29 +0530 Subject: [PATCH 01/77] add featureregistry field support for featureview (#9967) --- .../FeatureOnlineStoreFeatureview.yaml | 38 +++ ...estore_featureview_feature_registry.tf.erb | 93 ++++++ ...i_feature_online_store_featureview_test.go | 288 ++++++++++++++++++ 3 files changed, 419 insertions(+) create mode 100644 mmv1/templates/terraform/examples/vertex_ai_featureonlinestore_featureview_feature_registry.tf.erb diff --git a/mmv1/products/vertexai/FeatureOnlineStoreFeatureview.yaml b/mmv1/products/vertexai/FeatureOnlineStoreFeatureview.yaml index de319a0b83f4..ef350a823964 100644 --- a/mmv1/products/vertexai/FeatureOnlineStoreFeatureview.yaml +++ b/mmv1/products/vertexai/FeatureOnlineStoreFeatureview.yaml @@ -55,6 +55,11 @@ examples: primary_resource_id: 'featureview' vars: name: 'example_feature_view' + - !ruby/object:Provider::Terraform::Examples + name: 'vertex_ai_featureonlinestore_featureview_feature_registry' + primary_resource_id: 'featureview_featureregistry' + vars: + name: 'example_feature_view_feature_registry' - !ruby/object:Provider::Terraform::Examples name: 'vertex_ai_featureonlinestore_featureview_with_vector_search' primary_resource_id: 'featureview_vector_search' @@ -112,6 +117,9 @@ properties: name: 'bigQuerySource' description: | Configures how data is supposed to be extracted from a BigQuery source to be loaded onto the FeatureOnlineStore. + exactly_one_of: + - big_query_source + - feature_registry_source properties: - !ruby/object:Api::Type::String name: 'uri' @@ -124,10 +132,40 @@ properties: description: | Columns to construct entityId / row keys. Start by supporting 1 only. item_type: Api::Type::String + - !ruby/object:Api::Type::NestedObject + name: 'featureRegistrySource' + conflicts: + - vector_search_config + exactly_one_of: + - big_query_source + - feature_registry_source + description: | + Configures the features from a Feature Registry source that need to be loaded onto the FeatureOnlineStore. + properties: + - !ruby/object:Api::Type::Array + name: 'featureGroups' + required: true + description: | + List of features that need to be synced to Online Store. + item_type: !ruby/object:Api::Type::NestedObject + properties: + - !ruby/object:Api::Type::String + name: 'featureGroupId' + required: true + description: | + Identifier of the feature group. + - !ruby/object:Api::Type::Array + name: featureIds + required: true + description: | + Identifiers of features under the feature group. + item_type: Api::Type::String - !ruby/object:Api::Type::NestedObject name: 'vectorSearchConfig' description: | Configuration for vector search. It contains the required configurations to create an index from source data, so that approximate nearest neighbor (a.k.a ANN) algorithms search can be performed during online serving. + conflicts: + - feature_registry_source immutable: true min_version: beta properties: diff --git a/mmv1/templates/terraform/examples/vertex_ai_featureonlinestore_featureview_feature_registry.tf.erb b/mmv1/templates/terraform/examples/vertex_ai_featureonlinestore_featureview_feature_registry.tf.erb new file mode 100644 index 000000000000..e82ea2a0c104 --- /dev/null +++ b/mmv1/templates/terraform/examples/vertex_ai_featureonlinestore_featureview_feature_registry.tf.erb @@ -0,0 +1,93 @@ +resource "google_vertex_ai_feature_online_store" "featureonlinestore" { + name = "<%= ctx[:vars]['name'] %>" + labels = { + foo = "bar" + } + region = "us-central1" + bigtable { + auto_scaling { + min_node_count = 1 + max_node_count = 2 + cpu_utilization_target = 80 + } + } +} + +resource "google_bigquery_dataset" "sample_dataset" { + dataset_id = "<%= ctx[:vars]['name'] %>" + friendly_name = "test" + description = "This is a test description" + location = "US" +} + +resource "google_bigquery_table" "sample_table" { + deletion_protection = false + dataset_id = google_bigquery_dataset.sample_dataset.dataset_id + table_id = "<%= ctx[:vars]['name'] %>" + + schema = <", + "type": "STRING", + "mode": "NULLABLE" + }, + { + "name": "feature_timestamp", + "type": "TIMESTAMP", + "mode": "NULLABLE" + } +] +EOF +} + +resource "google_vertex_ai_feature_group" "sample_feature_group" { + name = "<%= ctx[:vars]['name'] %>" + description = "A sample feature group" + region = "us-central1" + labels = { + label-one = "value-one" + } + big_query { + big_query_source { + # The source table must have a column named 'feature_timestamp' of type TIMESTAMP. + input_uri = "bq://${google_bigquery_table.sample_table.project}.${google_bigquery_table.sample_table.dataset_id}.${google_bigquery_table.sample_table.table_id}" + } + entity_id_columns = ["feature_id"] + } +} + + + +resource "google_vertex_ai_feature_group_feature" "sample_feature" { + name = "<%= ctx[:vars]['name'] %>" + region = "us-central1" + feature_group = google_vertex_ai_feature_group.sample_feature_group.name + description = "A sample feature" + labels = { + label-one = "value-one" + } +} + + +resource "google_vertex_ai_feature_online_store_featureview" "<%= ctx[:primary_resource_id] %>" { + name = "<%= ctx[:vars]['name'] %>" + region = "us-central1" + feature_online_store = google_vertex_ai_feature_online_store.featureonlinestore.name + sync_config { + cron = "0 0 * * *" + } + feature_registry_source { + + feature_groups { + feature_group_id = google_vertex_ai_feature_group.sample_feature_group.name + feature_ids = [google_vertex_ai_feature_group_feature.sample_feature.name] + } + } +} + diff --git a/mmv1/third_party/terraform/services/vertexai/resource_vertex_ai_feature_online_store_featureview_test.go b/mmv1/third_party/terraform/services/vertexai/resource_vertex_ai_feature_online_store_featureview_test.go index 87d69f45c9fb..4c3eb97c736f 100644 --- a/mmv1/third_party/terraform/services/vertexai/resource_vertex_ai_feature_online_store_featureview_test.go +++ b/mmv1/third_party/terraform/services/vertexai/resource_vertex_ai_feature_online_store_featureview_test.go @@ -198,3 +198,291 @@ func testAccVertexAIFeatureOnlineStoreFeatureview_vertexAiFeatureonlinestoreFeat } `, context) } + +func TestAccVertexAIFeatureOnlineStoreFeatureview_vertexAiFeatureonlinestoreFeatureview_featureRegistry_updated(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.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckVertexAIFeatureOnlineStoreFeatureviewDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccVertexAIFeatureOnlineStoreFeatureview_vertexAiFeatureonlinestoreFeatureview_featureRegistry_basic(context), + }, + { + ResourceName: "google_vertex_ai_feature_online_store_featureview.featureregistry_featureview", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "etag", "feature_online_store", "labels", "terraform_labels"}, + }, + { + Config: testAccVertexAIFeatureOnlineStoreFeatureview_vertexAiFeatureonlinestoreFeatureview_featureRegistry_update(context), + }, + { + ResourceName: "google_vertex_ai_feature_online_store_featureview.featureregistry_featureview", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "feature_online_store", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccVertexAIFeatureOnlineStoreFeatureview_vertexAiFeatureonlinestoreFeatureview_featureRegistry_basic(context map[string]interface{}) string { + return acctest.Nprintf(` + resource "google_vertex_ai_feature_online_store" "featureregistry_featureonlinestore" { + name = "tf_test_featureonlinestore%{random_suffix}" + labels = { + foo = "bar" + } + region = "us-central1" + bigtable { + auto_scaling { + min_node_count = 1 + max_node_count = 2 + cpu_utilization_target = 80 + } + } + } + + resource "google_bigquery_dataset" "featureregistry-tf-test-dataset" { + + dataset_id = "tf_test_dataset1_featureview%{random_suffix}" + friendly_name = "test" + description = "This is a test description" + location = "US" + } + + resource "google_bigquery_table" "sample_table" { + deletion_protection = false + + dataset_id = google_bigquery_dataset.featureregistry-tf-test-dataset.dataset_id + table_id = "tf_test_bq_table%{random_suffix}" + schema = < Date: Wed, 14 Feb 2024 02:32:45 +0530 Subject: [PATCH 02/77] Posture1 (#9976) * fix display name format * fix expression field --------- Co-authored-by: Sneha Prasad --- mmv1/products/securityposture/posture.yaml | 4 ++-- .../examples/securityposture_posture_basic.tf.erb | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/mmv1/products/securityposture/posture.yaml b/mmv1/products/securityposture/posture.yaml index 993ada901fd7..6737b42a7a25 100644 --- a/mmv1/products/securityposture/posture.yaml +++ b/mmv1/products/securityposture/posture.yaml @@ -231,7 +231,7 @@ properties: If `true`, then the policy is enforced. If `false`, then any configuration is acceptable. This field can be set only in policies for boolean constraints. - !ruby/object:Api::Type::NestedObject - name: 'expr' + name: 'condition' description: | Represents a textual expression in the Common Expression Language (CEL) syntax. CEL is a C-like expression language. This page details the objects and attributes that are used to the build the CEL expressions for @@ -348,7 +348,7 @@ properties: If `true`, then the policy is enforced. If `false`, then any configuration is acceptable. This field can be set only in policies for boolean constraints. - !ruby/object:Api::Type::NestedObject - name: 'expr' + name: 'condition' description: | Represents a textual expression in the Common Expression Language (CEL) syntax. CEL is a C-like expression language. This page details the objects and attributes that are used to the build the CEL expressions for diff --git a/mmv1/templates/terraform/examples/securityposture_posture_basic.tf.erb b/mmv1/templates/terraform/examples/securityposture_posture_basic.tf.erb index 5d865222aa4e..9101034c48c2 100644 --- a/mmv1/templates/terraform/examples/securityposture_posture_basic.tf.erb +++ b/mmv1/templates/terraform/examples/securityposture_posture_basic.tf.erb @@ -14,6 +14,11 @@ resource "google_securityposture_posture" "<%= ctx[:primary_resource_id] %>"{ canned_constraint_id = "storage.uniformBucketLevelAccess" policy_rules { enforce = true + condition { + description = "condition description" + expression = "resource.matchTag('org_id/tag_key_short_name,'tag_value_short_name')" + title = "a CEL condition" + } } } } @@ -33,6 +38,11 @@ resource "google_securityposture_posture" "<%= ctx[:primary_resource_id] %>"{ } policy_rules { enforce = true + condition { + description = "condition description" + expression = "resource.matchTagId('tagKeys/key_id','tagValues/value_id')" + title = "a CEL condition" + } } } } From a81b0c649289b24114c3481128d903027fecc1d4 Mon Sep 17 00:00:00 2001 From: Nidhi <36001038+nidhi0710@users.noreply.github.com> Date: Tue, 13 Feb 2024 21:04:19 +0000 Subject: [PATCH 03/77] Adding support for reject_duplicate_message flag while creating hl7v2store (#9977) --- mmv1/products/healthcare/Hl7V2Store.yaml | 6 ++++++ .../terraform/examples/healthcare_hl7_v2_store_basic.tf.erb | 1 + .../healthcare/resource_healthcare_hl7_v2_store_test.go.erb | 1 + 3 files changed, 8 insertions(+) diff --git a/mmv1/products/healthcare/Hl7V2Store.yaml b/mmv1/products/healthcare/Hl7V2Store.yaml index 2c395e9a1338..b923d404a489 100644 --- a/mmv1/products/healthcare/Hl7V2Store.yaml +++ b/mmv1/products/healthcare/Hl7V2Store.yaml @@ -73,6 +73,12 @@ properties: ** Changing this property may recreate the Hl7v2 store (removing all data) ** required: true immutable: true + - !ruby/object:Api::Type::Boolean + name: rejectDuplicateMessage + required: false + default_value: false + description: | + Determines whether duplicate messages are allowed. - !ruby/object:Api::Type::NestedObject name: parserConfig required: false diff --git a/mmv1/templates/terraform/examples/healthcare_hl7_v2_store_basic.tf.erb b/mmv1/templates/terraform/examples/healthcare_hl7_v2_store_basic.tf.erb index 42460e90eec3..a75931fd02ae 100644 --- a/mmv1/templates/terraform/examples/healthcare_hl7_v2_store_basic.tf.erb +++ b/mmv1/templates/terraform/examples/healthcare_hl7_v2_store_basic.tf.erb @@ -1,6 +1,7 @@ resource "google_healthcare_hl7_v2_store" "store" { name = "<%= ctx[:vars]['hl7_v2_store_name'] %>" dataset = google_healthcare_dataset.dataset.id + reject_duplicate_message = true notification_configs { pubsub_topic = google_pubsub_topic.topic.id diff --git a/mmv1/third_party/terraform/services/healthcare/resource_healthcare_hl7_v2_store_test.go.erb b/mmv1/third_party/terraform/services/healthcare/resource_healthcare_hl7_v2_store_test.go.erb index aec48d059681..4491a090fb29 100644 --- a/mmv1/third_party/terraform/services/healthcare/resource_healthcare_hl7_v2_store_test.go.erb +++ b/mmv1/third_party/terraform/services/healthcare/resource_healthcare_hl7_v2_store_test.go.erb @@ -162,6 +162,7 @@ func testGoogleHealthcareHl7V2Store_basic(hl7_v2StoreName, datasetName string) s resource "google_healthcare_hl7_v2_store" "default" { name = "%s" dataset = google_healthcare_dataset.dataset.id + reject_duplicate_message = true } resource "google_healthcare_dataset" "dataset" { From 18072d2b0665b0182e8bcd677fc1d0ca75693507 Mon Sep 17 00:00:00 2001 From: bcreddy-gcp <123543489+bcreddy-gcp@users.noreply.github.com> Date: Wed, 14 Feb 2024 02:39:33 +0530 Subject: [PATCH 04/77] =?UTF-8?q?Make=20notebooks=20wait=20for=20active=20?= =?UTF-8?q?state=20and=20enable=20stopping/starting=20ins=E2=80=A6=20(#997?= =?UTF-8?q?1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Make notebooks wait for active state and enable stopping/starting instances using the desired_state field * ignore update_time --- mmv1/products/notebooks/Instance.yaml | 22 +++++ .../terraform/constants/notebooks_instance.go | 53 ++++++++++++ .../notebook_instance_basic_stopped.tf.erb | 10 +++ .../examples/notebook_instance_full.tf.erb | 1 + .../post_create/notebooks_instance.go.erb | 13 +++ .../post_update/notebooks_instance.go.erb | 21 +++++ ...ource_notebooks_instance_state_test.go.erb | 85 +++++++++++++++++++ 7 files changed, 205 insertions(+) create mode 100644 mmv1/templates/terraform/examples/notebook_instance_basic_stopped.tf.erb create mode 100644 mmv1/templates/terraform/post_create/notebooks_instance.go.erb create mode 100644 mmv1/templates/terraform/post_update/notebooks_instance.go.erb create mode 100644 mmv1/third_party/terraform/services/notebooks/resource_notebooks_instance_state_test.go.erb diff --git a/mmv1/products/notebooks/Instance.yaml b/mmv1/products/notebooks/Instance.yaml index b770e0489040..1e0ad5c49374 100644 --- a/mmv1/products/notebooks/Instance.yaml +++ b/mmv1/products/notebooks/Instance.yaml @@ -55,6 +55,17 @@ examples: region_override: 'us-west1-a' vars: instance_name: 'notebooks-instance' + - !ruby/object:Provider::Terraform::Examples + name: 'notebook_instance_basic_stopped' + primary_resource_id: 'instance' + primary_resource_name: "fmt.Sprintf(\"tf-test-notebooks-instance%s\", + context[\"\ + random_suffix\"])" + region_override: 'us-west1-a' + vars: + instance_name: 'notebooks-instance' + ignore_read_extra: + - 'desired_state' - !ruby/object:Provider::Terraform::Examples name: 'notebook_instance_basic_container' primary_resource_id: 'instance' @@ -87,9 +98,20 @@ examples: key_name: 'acctest.BootstrapKMSKeyInLocation(t, "global").CryptoKey.Name' test_env_vars: service_account: :SERVICE_ACCT +virtual_fields: + - !ruby/object:Api::Type::Enum + name: desired_state + description: | + Desired state of the Notebook Instance. Set this field to `ACTIVE` to start the Instance, and `STOPPED` to stop the Instance. + values: + - :ACTIVE + - :STOPPED + default_value: :ACTIVE custom_code: !ruby/object:Provider::Terraform::CustomCode constants: templates/terraform/constants/notebooks_instance.go update_encoder: templates/terraform/update_encoder/notebooks_instance.go + post_create: templates/terraform/post_create/notebooks_instance.go.erb + post_update: templates/terraform/post_update/notebooks_instance.go.erb state_upgraders: true schema_version: 1 parameters: diff --git a/mmv1/templates/terraform/constants/notebooks_instance.go b/mmv1/templates/terraform/constants/notebooks_instance.go index 5d376547fe83..230d2aece282 100644 --- a/mmv1/templates/terraform/constants/notebooks_instance.go +++ b/mmv1/templates/terraform/constants/notebooks_instance.go @@ -33,3 +33,56 @@ func NotebooksInstanceKmsDiffSuppress(_, old, new string, _ *schema.ResourceData } return false } + +<% unless compiler == "terraformgoogleconversion-codegen" -%> +// waitForNotebooksInstanceActive waits for an Notebook instance to become "ACTIVE" +func waitForNotebooksInstanceActive(d *schema.ResourceData, config *transport_tpg.Config, timeout time.Duration) error { + return resource.Retry(timeout, func() *resource.RetryError { + if err := resourceNotebooksInstanceRead(d, config); err != nil { + return resource.NonRetryableError(err) + } + + name := d.Get("name").(string) + state := d.Get("state").(string) + if state == "ACTIVE" { + log.Printf("[DEBUG] Notebook Instance %q has state %q.", name, state) + return nil + } else { + return resource.RetryableError(fmt.Errorf("Notebook Instance %q has state %q. Waiting for ACTIVE state", name, state)) + } + + }) +} +<% end -%> + +func modifyNotebooksInstanceState(config *transport_tpg.Config, d *schema.ResourceData, project string, billingProject string, userAgent string, state string) (map[string]interface{}, error) { + url, err := tpgresource.ReplaceVars(d, config, "{{NotebooksBasePath}}projects/{{project}}/locations/{{location}}/instances/{{name}}:"+state) + if err != nil { + return nil, err + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + }) + if err != nil { + return nil, fmt.Errorf("Unable to %q google_notebooks_instance %q: %s", state, d.Id(), err) + } + return res, nil +} + +<% unless compiler == "terraformgoogleconversion-codegen" -%> +func waitForNotebooksOperation(config *transport_tpg.Config, d *schema.ResourceData, project string, billingProject string, userAgent string, response map[string]interface{}) error { + var opRes map[string]interface{} + err := NotebooksOperationWaitTimeWithResponse( + config, response, &opRes, project, "Modifying Notebook Instance state", userAgent, + d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + return nil +} +<% end -%> diff --git a/mmv1/templates/terraform/examples/notebook_instance_basic_stopped.tf.erb b/mmv1/templates/terraform/examples/notebook_instance_basic_stopped.tf.erb new file mode 100644 index 000000000000..41130bcca3ef --- /dev/null +++ b/mmv1/templates/terraform/examples/notebook_instance_basic_stopped.tf.erb @@ -0,0 +1,10 @@ +resource "google_notebooks_instance" "<%= ctx[:primary_resource_id] %>" { + name = "<%= ctx[:vars]["instance_name"] %>" + location = "us-west1-a" + machine_type = "e2-medium" + vm_image { + project = "deeplearning-platform-release" + image_family = "tf-latest-cpu" + } + desired_state = "STOPPED" +} diff --git a/mmv1/templates/terraform/examples/notebook_instance_full.tf.erb b/mmv1/templates/terraform/examples/notebook_instance_full.tf.erb index 0137529b0d1a..31f2af55ca3c 100644 --- a/mmv1/templates/terraform/examples/notebook_instance_full.tf.erb +++ b/mmv1/templates/terraform/examples/notebook_instance_full.tf.erb @@ -36,6 +36,7 @@ resource "google_notebooks_instance" "<%= ctx[:primary_resource_id] %>" { ] disk_encryption = "CMEK" kms_key = "<%= ctx[:vars]['key_name'] %>" + desired_state = "ACTIVE" } data "google_compute_network" "my_network" { diff --git a/mmv1/templates/terraform/post_create/notebooks_instance.go.erb b/mmv1/templates/terraform/post_create/notebooks_instance.go.erb new file mode 100644 index 000000000000..a70d7cb313a5 --- /dev/null +++ b/mmv1/templates/terraform/post_create/notebooks_instance.go.erb @@ -0,0 +1,13 @@ +if err := waitForNotebooksInstanceActive(d, config, d.Timeout(schema.TimeoutCreate) - time.Minute); err != nil { + return fmt.Errorf("Notebook instance %q did not reach ACTIVE state: %q", d.Get("name").(string), err) +} + +if p, ok := d.GetOk("desired_state"); ok && p.(string) == "STOPPED" { + dRes, err := modifyNotebooksInstanceState(config, d, project, billingProject, userAgent, "stop") + if err != nil { + return err + } + if err := waitForNotebooksOperation(config, d, project, billingProject, userAgent, dRes); err != nil { + return fmt.Errorf("Error stopping Notebook Instance: %s", err) + } +} diff --git a/mmv1/templates/terraform/post_update/notebooks_instance.go.erb b/mmv1/templates/terraform/post_update/notebooks_instance.go.erb new file mode 100644 index 000000000000..819cff2d1dd2 --- /dev/null +++ b/mmv1/templates/terraform/post_update/notebooks_instance.go.erb @@ -0,0 +1,21 @@ +name := d.Get("name").(string) +state := d.Get("state").(string) +desired_state := d.Get("desired_state").(string) + +if state != desired_state { + verb := "start" + if desired_state == "STOPPED" { + verb = "stop" + } + pRes, err := modifyNotebooksInstanceState(config, d, project, billingProject, userAgent, verb) + if err != nil { + return err + } + + if err := waitForNotebooksOperation(config, d, project, billingProject, userAgent, pRes); err != nil { + return fmt.Errorf("Error waiting to modify Notebook Instance state: %s", err) + } + +} else { + log.Printf("[DEBUG] Notebook Instance %q has state %q.", name, state) +} diff --git a/mmv1/third_party/terraform/services/notebooks/resource_notebooks_instance_state_test.go.erb b/mmv1/third_party/terraform/services/notebooks/resource_notebooks_instance_state_test.go.erb new file mode 100644 index 000000000000..ff99d9c7cc31 --- /dev/null +++ b/mmv1/third_party/terraform/services/notebooks/resource_notebooks_instance_state_test.go.erb @@ -0,0 +1,85 @@ +<% autogen_exception -%> +package notebooks_test + +<% unless version == 'ga' %> +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccNotebooksInstance_state(t *testing.T) { + t.Parallel() + + prefix := fmt.Sprintf("%d", acctest.RandInt(t)) + name := fmt.Sprintf("tf-%s", prefix) + + acctest.VcrTest(t, resource.TestCase{ + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccNotebooksInstance_basic_active(name), + }, + { + ResourceName: "google_notebooks_instance.test", + ImportState: true, + ImportStateVerify: true, + ExpectNonEmptyPlan: true, + ImportStateVerifyIgnore: []string{"container_image", "metadata", "vm_image","desired_state", "update_time"}, + }, + { + Config: testAccNotebooksInstance_basic_stopped(name), + }, + { + ResourceName: "google_notebooks_instance.test", + ImportState: true, + ImportStateVerify: true, + ExpectNonEmptyPlan: true, + ImportStateVerifyIgnore: []string{"container_image", "metadata", "vm_image","desired_state", "update_time"}, + }, + { + Config: testAccNotebooksInstance_basic_active(name), + }, + { + ResourceName: "google_notebooks_instance.test", + ImportState: true, + ImportStateVerify: true, + ExpectNonEmptyPlan: true, + ImportStateVerifyIgnore: []string{"container_image", "metadata", "vm_image","desired_state", "update_time"}, + }, + }, + }) +} + +func testAccNotebooksInstance_basic_active(name string) string { + return fmt.Sprintf(` +resource "google_notebooks_instance" "test" { + name = "%s" + location = "us-west1-a" + machine_type = "e2-medium" + vm_image { + project = "deeplearning-platform-release" + image_family = "tf-latest-cpu" + } + desired_state = "ACTIVE" +} +`, name) +} + +func testAccNotebooksInstance_basic_stopped(name string) string { + return fmt.Sprintf(` +resource "google_notebooks_instance" "test" { + name = "%s" + location = "us-west1-a" + machine_type = "e2-medium" + vm_image { + project = "deeplearning-platform-release" + image_family = "tf-latest-cpu" + } + desired_state = "STOPPED" +} +`, name) +} +<% end -%> From 1d3073d06c8e650a1afd7de552bbf457ea2a972f Mon Sep 17 00:00:00 2001 From: bcreddy-gcp <123543489+bcreddy-gcp@users.noreply.github.com> Date: Wed, 14 Feb 2024 02:48:10 +0530 Subject: [PATCH 05/77] Add desired state to workbench instances. (#9945) * add labels to runtime update test * Add desired_state for workbench instances * fix(tgc): Fixing the if block for existingConverterAsset and add test case (#9914) * Add sweepers for vertex_dataset, vertex_tensorboard and vertex_metadataStore (#9911) * Make acctest use bootstrapped KMS key, instead of making new key that resembles a shared key (#9926) * Refactor the TeamCity config to define all projects, across GA, Beta, and VCR testing (#9837) * Replace contents of .teamcity/ with new refactored config files * Remove remaining automation for generating service lists automatically * Remove copyright headers, as they're added during generation process * Update header comments on .teamcity files * Make VCR testing compatible with TeamCity agent * Update GA + Beta service lists to match the currrent provider * Fix whitespace * Update default TEST ENV value for VCR builds * Add chmod commands to handling of creds file * Update pre- and post-VCR steps to echo out more information about their actions * Rename `generated` folder to `inputs` * Update header comments on .teamcity files * Refactor how VCR recording buid configurations are made * Fix comment on MM VCR build * Update VCR post step to fail if no cassettes are produced by the tests before * Whitespace changes * Fix how teamcity files are copied to the downstreams * Change how VCR build configs are named * remove newlines * Fix defect in post VCR build steps * Refactor labelling that indicates automated vs ad hoc builds * Make VCR builds be triggered to indicate VCR_MODE * Add first version of TeamCity documentation! * Add contents section to PERFORMING_TASKS_IN_TEAMCITY.md * Move details about DSL into technical README, away from process doc * Make the .teamcity folder only propogate to the TPG repo, and no longer be in the TPGB repo * Ensure all TeamCity files are being copied to the downstream repo * Move echo command to after `BRANCH_NAME` ENV declared * Update VCR steps to look for fixtures files inside beta folder * Update mmv1/third_party/terraform/.teamcity/components/builds/vcr_build_steps.kt Co-authored-by: Shuya Ma <87669292+shuyama1@users.noreply.github.com> * Update mmv1/third_party/terraform/.teamcity/CONTRIBUTION_GUIDE.md Co-authored-by: Stephen Lewis (Burrows) --------- Co-authored-by: Shuya Ma <87669292+shuyama1@users.noreply.github.com> Co-authored-by: Stephen Lewis (Burrows) * [#15779] Add google_network_security_firewall_endpoint resource (#9813) * [#15779] Add google_network_security_firewall_endpoint resource * Fix yaml linting * Removing unused fields from yaml * Fixing tests * Fixes per comments --------- Co-authored-by: Luca Prete * enhancement: Allow overriding the Billing Project for google_cloud_asset_resources_search_all (#9935) * enhancement: Allow overriding the Billing Project for cloud_asset_resources_search_all * chore: Fixed indentation * Add firebaseappcheck to service package lists (#9937) * Enable CRONs in TeamCity (#9938) * Set CRONs for 4am UTC * Enable CRONs * Update enrolled_teams.yml (#9939) * add NickElliot to vacation reviewers (#9942) * Update membership.go * Update membership.go * fix lint issues * fix conversion compilation * Remove Runtime example * Add back kms flatten * change encryption to CMEK to test for KMS * Try using a global KMS key * kms key location to us-central1 * remove service account in full example * Adding back service account into full test --------- Co-authored-by: Iris Chen <10179943+iyabchen@users.noreply.github.com> Co-authored-by: hao-nan-li <100219545+hao-nan-li@users.noreply.github.com> Co-authored-by: Sarah French <15078782+SarahFrench@users.noreply.github.com> Co-authored-by: Shuya Ma <87669292+shuyama1@users.noreply.github.com> Co-authored-by: Stephen Lewis (Burrows) Co-authored-by: Luca Prete Co-authored-by: Luca Prete Co-authored-by: Koen van Zuijlen <8818390+kvanzuijlen@users.noreply.github.com> Co-authored-by: Ryan Oaks Co-authored-by: Nick Elliot --- mmv1/products/workbench/Instance.yaml | 27 ++++++---- .../terraform/constants/workbench_instance.go | 39 ++++++++++++++ ...stance_boot_disk_encryption_flatten.go.erb | 17 ------ ...ench_instance_boot_disk_kms_flatten.go.erb | 17 ------ ...stance_data_disk_encryption_flatten.go.erb | 17 ------ ...ench_instance_data_disk_kms_flatten.go.erb | 17 ------ .../examples/workbench_instance_full.tf.erb | 6 ++- ... workbench_instance_labels_stopped.tf.erb} | 2 + .../post_create/workbench_instance.go.erb | 10 ++++ .../post_update/workbench_instance.go.erb | 33 ++++-------- .../pre_update/workbench_instance.go.erb | 29 ++-------- ...> resource_workbench_instance_test.go.erb} | 54 +++++++++++++++++++ 12 files changed, 139 insertions(+), 129 deletions(-) delete mode 100644 mmv1/templates/terraform/custom_flatten/workbench_instance_boot_disk_encryption_flatten.go.erb delete mode 100644 mmv1/templates/terraform/custom_flatten/workbench_instance_boot_disk_kms_flatten.go.erb delete mode 100644 mmv1/templates/terraform/custom_flatten/workbench_instance_data_disk_encryption_flatten.go.erb delete mode 100644 mmv1/templates/terraform/custom_flatten/workbench_instance_data_disk_kms_flatten.go.erb rename mmv1/templates/terraform/examples/{workbench_instance_labels.tf.erb => workbench_instance_labels_stopped.tf.erb} (93%) rename mmv1/third_party/terraform/services/workbench/{resource_workbench_instance_gpu_test.go.erb => resource_workbench_instance_test.go.erb} (80%) diff --git a/mmv1/products/workbench/Instance.yaml b/mmv1/products/workbench/Instance.yaml index b0b2b08e8d43..8575e8be652f 100644 --- a/mmv1/products/workbench/Instance.yaml +++ b/mmv1/products/workbench/Instance.yaml @@ -55,7 +55,7 @@ examples: ignore_read_extra: - 'gce_setup.0.vm_image' - !ruby/object:Provider::Terraform::Examples - name: 'workbench_instance_labels' + name: 'workbench_instance_labels_stopped' primary_resource_id: 'instance' primary_resource_name: "fmt.Sprintf(\"tf-test-workbench-instance%s\", context[\"\ @@ -66,6 +66,8 @@ examples: network_name: 'wbi-test-default' test_env_vars: service_account: :SERVICE_ACCT + ignore_read_extra: + - 'desired_state' - !ruby/object:Provider::Terraform::Examples name: 'workbench_instance_full' primary_resource_id: 'instance' @@ -83,15 +85,20 @@ examples: service_account: :SERVICE_ACCT ignore_read_extra: - 'gce_setup.0.vm_image' - - 'gce_setup.0.boot_disk.0.disk_encryption' - 'gce_setup.0.boot_disk.0.disk_type' - - 'gce_setup.0.boot_disk.0.kms_key' - - 'gce_setup.0.data_disks.0.disk_encryption' - 'gce_setup.0.data_disks.0.disk_type' - - 'gce_setup.0.data_disks.0.kms_key' timeouts: !ruby/object:Api::Timeouts insert_minutes: 10 update_minutes: 20 +virtual_fields: + - !ruby/object:Api::Type::Enum + name: desired_state + description: | + Desired state of the Workbench Instance. Set this field to `ACTIVE` to start the Instance, and `STOPPED` to stop the Instance. + values: + - :ACTIVE + - :STOPPED + default_value: :ACTIVE custom_code: !ruby/object:Provider::Terraform::CustomCode constants: templates/terraform/constants/workbench_instance.go post_create: templates/terraform/post_create/workbench_instance.go.erb @@ -231,7 +238,6 @@ properties: - !ruby/object:Api::Type::Enum name: diskEncryption default_from_api: true - custom_flatten: templates/terraform/custom_flatten/workbench_instance_boot_disk_encryption_flatten.go.erb values: - GMEK - CMEK @@ -242,11 +248,11 @@ properties: - !ruby/object:Api::Type::String name: kmsKey description: | - 'Optional. Input only. The KMS key used to encrypt the disks, only + 'Optional. The KMS key used to encrypt the disks, only applicable if disk_encryption is CMEK. Format: `projects/{project_id}/locations/{location}/keyRings/{key_ring_id}/cryptoKeys/{key_id}` Learn more about using your own encryption keys.' immutable: true - custom_flatten: templates/terraform/custom_flatten/workbench_instance_boot_disk_kms_flatten.go.erb + diff_suppress_func: WorkbenchInstanceKmsDiffSuppress - !ruby/object:Api::Type::Array name: dataDisks description: Data disks attached to the VM instance. Currently supports only one data disk. @@ -276,7 +282,6 @@ properties: - !ruby/object:Api::Type::Enum name: diskEncryption default_from_api: true - custom_flatten: templates/terraform/custom_flatten/workbench_instance_data_disk_encryption_flatten.go.erb values: - GMEK - CMEK @@ -287,11 +292,11 @@ properties: - !ruby/object:Api::Type::String name: kmsKey description: | - 'Optional. Input only. The KMS key used to encrypt the disks, + 'Optional. The KMS key used to encrypt the disks, only applicable if disk_encryption is CMEK. Format: `projects/{project_id}/locations/{location}/keyRings/{key_ring_id}/cryptoKeys/{key_id}` Learn more about using your own encryption keys.' immutable: true - custom_flatten: templates/terraform/custom_flatten/workbench_instance_data_disk_kms_flatten.go.erb + diff_suppress_func: WorkbenchInstanceKmsDiffSuppress description: | Optional. Data disks attached to the VM instance. Currently supports only one data disk. diff --git a/mmv1/templates/terraform/constants/workbench_instance.go b/mmv1/templates/terraform/constants/workbench_instance.go index 6ae6d20dca67..4462c0e5baa7 100644 --- a/mmv1/templates/terraform/constants/workbench_instance.go +++ b/mmv1/templates/terraform/constants/workbench_instance.go @@ -140,3 +140,42 @@ func waitForWorkbenchInstanceActive(d *schema.ResourceData, config *transport_tp }) } <% end -%> + +func modifyWorkbenchInstanceState(config *transport_tpg.Config, d *schema.ResourceData, project string, billingProject string, userAgent string, state string) (map[string]interface{}, error) { + url, err := tpgresource.ReplaceVars(d, config, "{{WorkbenchBasePath}}projects/{{project}}/locations/{{location}}/instances/{{name}}:"+state) + if err != nil { + return nil, err + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + }) + if err != nil { + return nil, fmt.Errorf("Unable to %q google_workbench_instance %q: %s", state, d.Id(), err) + } + return res, nil +} + +func WorkbenchInstanceKmsDiffSuppress(_, old, new string, _ *schema.ResourceData) bool { + if strings.HasPrefix(old, new) { + return true + } + return false +} + +<% unless compiler == "terraformgoogleconversion-codegen" -%> +func waitForWorkbenchOperation(config *transport_tpg.Config, d *schema.ResourceData, project string, billingProject string, userAgent string, response map[string]interface{}) error { + var opRes map[string]interface{} + err := WorkbenchOperationWaitTimeWithResponse( + config, response, &opRes, project, "Modifying Workbench Instance state", userAgent, + d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return err + } + return nil +} +<% end -%> diff --git a/mmv1/templates/terraform/custom_flatten/workbench_instance_boot_disk_encryption_flatten.go.erb b/mmv1/templates/terraform/custom_flatten/workbench_instance_boot_disk_encryption_flatten.go.erb deleted file mode 100644 index eb44d9657f33..000000000000 --- a/mmv1/templates/terraform/custom_flatten/workbench_instance_boot_disk_encryption_flatten.go.erb +++ /dev/null @@ -1,17 +0,0 @@ -<%# The license inside this block applies to this file. - # Copyright 2023 Google Inc. - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. --%> -func flatten<%= prefix -%><%= titlelize_property(property) -%>(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { - return d.Get("gce_setup.0.boot_disk.0.disk_encryption") -} diff --git a/mmv1/templates/terraform/custom_flatten/workbench_instance_boot_disk_kms_flatten.go.erb b/mmv1/templates/terraform/custom_flatten/workbench_instance_boot_disk_kms_flatten.go.erb deleted file mode 100644 index 70c27a7661e2..000000000000 --- a/mmv1/templates/terraform/custom_flatten/workbench_instance_boot_disk_kms_flatten.go.erb +++ /dev/null @@ -1,17 +0,0 @@ -<%# The license inside this block applies to this file. - # Copyright 2023 Google Inc. - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. --%> -func flatten<%= prefix -%><%= titlelize_property(property) -%>(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { - return d.Get("gce_setup.0.boot_disk.0.kms_key") -} diff --git a/mmv1/templates/terraform/custom_flatten/workbench_instance_data_disk_encryption_flatten.go.erb b/mmv1/templates/terraform/custom_flatten/workbench_instance_data_disk_encryption_flatten.go.erb deleted file mode 100644 index d93558a3db76..000000000000 --- a/mmv1/templates/terraform/custom_flatten/workbench_instance_data_disk_encryption_flatten.go.erb +++ /dev/null @@ -1,17 +0,0 @@ -<%# The license inside this block applies to this file. - # Copyright 2023 Google Inc. - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. --%> -func flatten<%= prefix -%><%= titlelize_property(property) -%>(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { - return d.Get("gce_setup.0.data_disks.0.disk_encryption") -} diff --git a/mmv1/templates/terraform/custom_flatten/workbench_instance_data_disk_kms_flatten.go.erb b/mmv1/templates/terraform/custom_flatten/workbench_instance_data_disk_kms_flatten.go.erb deleted file mode 100644 index b6a7b9649db0..000000000000 --- a/mmv1/templates/terraform/custom_flatten/workbench_instance_data_disk_kms_flatten.go.erb +++ /dev/null @@ -1,17 +0,0 @@ -<%# The license inside this block applies to this file. - # Copyright 2023 Google Inc. - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. --%> -func flatten<%= prefix -%><%= titlelize_property(property) -%>(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { - return d.Get("gce_setup.0.data_disks.0.kms_key") -} diff --git a/mmv1/templates/terraform/examples/workbench_instance_full.tf.erb b/mmv1/templates/terraform/examples/workbench_instance_full.tf.erb index 2ec579cba8dc..270f73d23abc 100644 --- a/mmv1/templates/terraform/examples/workbench_instance_full.tf.erb +++ b/mmv1/templates/terraform/examples/workbench_instance_full.tf.erb @@ -30,14 +30,14 @@ resource "google_workbench_instance" "<%= ctx[:primary_resource_id] %>" { boot_disk { disk_size_gb = 310 disk_type = "PD_SSD" - disk_encryption = "GMEK" + disk_encryption = "CMEK" kms_key = "<%= ctx[:vars]['key_name'] %>" } data_disks { disk_size_gb = 330 disk_type = "PD_SSD" - disk_encryption = "GMEK" + disk_encryption = "CMEK" kms_key = "<%= ctx[:vars]['key_name'] %>" } @@ -65,4 +65,6 @@ resource "google_workbench_instance" "<%= ctx[:primary_resource_id] %>" { k = "val" } + desired_state = "ACTIVE" + } diff --git a/mmv1/templates/terraform/examples/workbench_instance_labels.tf.erb b/mmv1/templates/terraform/examples/workbench_instance_labels_stopped.tf.erb similarity index 93% rename from mmv1/templates/terraform/examples/workbench_instance_labels.tf.erb rename to mmv1/templates/terraform/examples/workbench_instance_labels_stopped.tf.erb index 3a0d9afda853..78e6c11ce6b7 100644 --- a/mmv1/templates/terraform/examples/workbench_instance_labels.tf.erb +++ b/mmv1/templates/terraform/examples/workbench_instance_labels_stopped.tf.erb @@ -21,4 +21,6 @@ resource "google_workbench_instance" "<%= ctx[:primary_resource_id] %>" { k = "val" } + desired_state = "STOPPED" + } diff --git a/mmv1/templates/terraform/post_create/workbench_instance.go.erb b/mmv1/templates/terraform/post_create/workbench_instance.go.erb index e3a968e4a6b2..25128f95f821 100644 --- a/mmv1/templates/terraform/post_create/workbench_instance.go.erb +++ b/mmv1/templates/terraform/post_create/workbench_instance.go.erb @@ -1,3 +1,13 @@ if err := waitForWorkbenchInstanceActive(d, config, d.Timeout(schema.TimeoutCreate) - time.Minute); err != nil { return fmt.Errorf("Workbench instance %q did not reach ACTIVE state: %q", d.Get("name").(string), err) } + +if p, ok := d.GetOk("desired_state"); ok && p.(string) == "STOPPED" { + dRes, err := modifyWorkbenchInstanceState(config, d, project, billingProject, userAgent, "stop") + if err != nil { + return err + } + if err := waitForWorkbenchOperation(config, d, project, billingProject, userAgent, dRes); err != nil { + return fmt.Errorf("Error stopping Workbench Instance: %s", err) + } +} diff --git a/mmv1/templates/terraform/post_update/workbench_instance.go.erb b/mmv1/templates/terraform/post_update/workbench_instance.go.erb index fa994a3aacb4..cd216f018387 100644 --- a/mmv1/templates/terraform/post_update/workbench_instance.go.erb +++ b/mmv1/templates/terraform/post_update/workbench_instance.go.erb @@ -1,33 +1,18 @@ state := d.Get("state").(string) +desired_state := d.Get("desired_state").(string) -if state != "ACTIVE" { - startURL, err := tpgresource.ReplaceVars(d, config, "{{WorkbenchBasePath}}projects/{{project}}/locations/{{location}}/instances/{{name}}:start") - if err != nil { - return err +if state != desired_state { + verb := "start" + if desired_state == "STOPPED" { + verb = "stop" } - - log.Printf("[DEBUG] Starting Workbench Instance: %q", name) - - emptyReqBody := make(map[string]interface{}) - - pRes, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ - Config: config, - Method: "POST", - Project: billingProject, - RawURL: startURL, - UserAgent: userAgent, - Body: emptyReqBody, - }) + pRes, err := modifyWorkbenchInstanceState(config, d, project, billingProject, userAgent, verb) if err != nil { - return fmt.Errorf("Error Starting Workbench Instance: %s", err) + return err } - var opResp map[string]interface{} - err = WorkbenchOperationWaitTimeWithResponse( - config, pRes, &opResp, project, "Starting Workbench Instance", userAgent, - d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return fmt.Errorf("Error waiting to start Workbench Instance: %s", err) + if err := waitForWorkbenchOperation(config, d, project, billingProject, userAgent, pRes); err != nil { + return fmt.Errorf("Error waiting to modify Workbench Instance state: %s", err) } } else { diff --git a/mmv1/templates/terraform/pre_update/workbench_instance.go.erb b/mmv1/templates/terraform/pre_update/workbench_instance.go.erb index 2b33205942a7..71ef1d976501 100644 --- a/mmv1/templates/terraform/pre_update/workbench_instance.go.erb +++ b/mmv1/templates/terraform/pre_update/workbench_instance.go.erb @@ -1,34 +1,15 @@ name := d.Get("name").(string) if d.HasChange("gce_setup.0.machine_type") || d.HasChange("gce_setup.0.accelerator_configs") { state := d.Get("state").(string) - if state != "STOPPED" { - stopURL, err := tpgresource.ReplaceVars(d, config, "{{WorkbenchBasePath}}projects/{{project}}/locations/{{location}}/instances/{{name}}:stop") - if err != nil { - return err - } - - log.Printf("[DEBUG] Stopping Workbench Instance: %q", name) - - emptyReqBody := make(map[string]interface{}) - dRes, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ - Config: config, - Method: "POST", - Project: billingProject, - RawURL: stopURL, - UserAgent: userAgent, - Body: emptyReqBody, - }) + if state != "STOPPED" { + dRes, err := modifyWorkbenchInstanceState(config, d, project, billingProject, userAgent, "stop") if err != nil { - return fmt.Errorf("Error Stopping Workbench Instance: %s", err) + return err } - var opRes map[string]interface{} - err = WorkbenchOperationWaitTimeWithResponse( - config, dRes, &opRes, project, "Stopping Workbench Instance", userAgent, - d.Timeout(schema.TimeoutUpdate)) - if err != nil { - return fmt.Errorf("Error waiting to stop Workbench Instance: %s", err) + if err := waitForWorkbenchOperation(config, d, project, billingProject, userAgent, dRes); err != nil { + return fmt.Errorf("Error stopping Workbench Instance: %s", err) } } else { diff --git a/mmv1/third_party/terraform/services/workbench/resource_workbench_instance_gpu_test.go.erb b/mmv1/third_party/terraform/services/workbench/resource_workbench_instance_test.go.erb similarity index 80% rename from mmv1/third_party/terraform/services/workbench/resource_workbench_instance_gpu_test.go.erb rename to mmv1/third_party/terraform/services/workbench/resource_workbench_instance_test.go.erb index c1914881b2a6..42f21d425404 100644 --- a/mmv1/third_party/terraform/services/workbench/resource_workbench_instance_gpu_test.go.erb +++ b/mmv1/third_party/terraform/services/workbench/resource_workbench_instance_test.go.erb @@ -270,3 +270,57 @@ resource "google_workbench_instance" "instance" { } `, context) } + +func TestAccWorkbenchInstance_updateState(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.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccWorkbenchInstance_basic(context), + }, + { + ResourceName: "google_workbench_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels","desired_state"}, + }, + { + Config: testAccWorkbenchInstance_updateState(context), + }, + { + ResourceName: "google_workbench_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels","desired_state"}, + }, + { + Config: testAccWorkbenchInstance_basic(context), + }, + { + ResourceName: "google_workbench_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels","desired_state"}, + }, + }, + }) +} + +func testAccWorkbenchInstance_updateState(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_workbench_instance" "instance" { + name = "tf-test-workbench-instance%{random_suffix}" + location = "us-central1-a" + + desired_state = "STOPPED" + +} +`, context) +} From 379d462fa7096c0f4789fc9e75463320603b14e2 Mon Sep 17 00:00:00 2001 From: Sarah French <15078782+SarahFrench@users.noreply.github.com> Date: Tue, 13 Feb 2024 21:19:50 +0000 Subject: [PATCH 06/77] Promote `user_ip_request_headers` field on `google_compute_security_policy` resource to GA (#9872) --- .../resource_compute_security_policy.go.erb | 16 ---------------- .../resource_compute_security_policy_test.go.erb | 7 ------- .../docs/r/compute_security_policy.html.markdown | 2 +- 3 files changed, 1 insertion(+), 24 deletions(-) diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_security_policy.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_security_policy.go.erb index 59db357b97a6..2222dd74ab0d 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_security_policy.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_security_policy.go.erb @@ -5,9 +5,7 @@ import ( "context" "fmt" "log" -<% unless version == 'ga' -%> "strings" -<% end -%> "time" @@ -466,14 +464,12 @@ func ResourceComputeSecurityPolicy() *schema.Resource { ValidateFunc: validation.StringInSlice([]string{"NORMAL", "VERBOSE"}, false), Description: `Logging level. Supported values include: "NORMAL", "VERBOSE".`, }, - <% unless version == 'ga' -%> "user_ip_request_headers": { Type: schema.TypeSet, Optional: true, Description: `An optional list of case-insensitive request header names to use for resolving the callers client IP address.`, Elem: &schema.Schema{Type: schema.TypeString}, }, - <% end -%> }, }, }, @@ -742,9 +738,7 @@ func resourceComputeSecurityPolicyUpdate(d *schema.ResourceData, meta interface{ Fingerprint: d.Get("fingerprint").(string), } - <% unless version == 'ga' -%> updateMask := []string{} - <% end -%> if d.HasChange("type") { securityPolicy.Type = d.Get("type").(string) @@ -759,13 +753,11 @@ func resourceComputeSecurityPolicyUpdate(d *schema.ResourceData, meta interface{ if d.HasChange("advanced_options_config") { securityPolicy.AdvancedOptionsConfig = expandSecurityPolicyAdvancedOptionsConfig(d.Get("advanced_options_config").([]interface{})) securityPolicy.ForceSendFields = append(securityPolicy.ForceSendFields, "AdvancedOptionsConfig", "advancedOptionsConfig.jsonParsing", "advancedOptionsConfig.jsonCustomConfig", "advancedOptionsConfig.logLevel") - <% unless version == 'ga' -%> securityPolicy.ForceSendFields = append(securityPolicy.ForceSendFields, "advanceOptionConfig.userIpRequestHeaders") if len(securityPolicy.AdvancedOptionsConfig.UserIpRequestHeaders) == 0 { // to clean this list we must send the updateMask of this field on the request. updateMask = append(updateMask, "advanced_options_config.user_ip_request_headers") } - <% end -%> } if d.HasChange("adaptive_protection_config") { @@ -784,11 +776,7 @@ func resourceComputeSecurityPolicyUpdate(d *schema.ResourceData, meta interface{ if len(securityPolicy.ForceSendFields) > 0 { client := config.NewComputeClient(userAgent) - <% if version == 'ga' -%> - op, err := client.SecurityPolicies.Patch(project, sp, securityPolicy).Do() - <% else -%> op, err := client.SecurityPolicies.Patch(project, sp, securityPolicy).UpdateMask(strings.Join(updateMask, ",")).Do() - <% end -%> if err != nil { return errwrap.Wrapf(fmt.Sprintf("Error updating SecurityPolicy %q: {{err}}", sp), err) @@ -1230,9 +1218,7 @@ func expandSecurityPolicyAdvancedOptionsConfig(configured []interface{}) *comput JsonParsing: data["json_parsing"].(string), JsonCustomConfig: expandSecurityPolicyAdvancedOptionsConfigJsonCustomConfig(data["json_custom_config"].([]interface{})), LogLevel: data["log_level"].(string), - <% unless version == 'ga' -%> UserIpRequestHeaders: tpgresource.ConvertStringArr(data["user_ip_request_headers"].(*schema.Set).List()), - <% end %> } } @@ -1245,9 +1231,7 @@ func flattenSecurityPolicyAdvancedOptionsConfig(conf *compute.SecurityPolicyAdva "json_parsing": conf.JsonParsing, "json_custom_config": flattenSecurityPolicyAdvancedOptionsConfigJsonCustomConfig(conf.JsonCustomConfig), "log_level": conf.LogLevel, - <% unless version == 'ga' -%> "user_ip_request_headers": schema.NewSet(schema.HashString, tpgresource.ConvertStringArrToInterface(conf.UserIpRequestHeaders)), - <% end -%> } return []map[string]interface{}{data} diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_security_policy_test.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_security_policy_test.go.erb index b3dcaac75f47..310985e5536e 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_security_policy_test.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_security_policy_test.go.erb @@ -189,7 +189,6 @@ func TestAccComputeSecurityPolicy_withAdvancedOptionsConfig(t *testing.T) { ImportState: true, ImportStateVerify: true, }, - <% unless version == 'ga' -%> { Config: testAccComputeSecurityPolicy_withAdvancedOptionsConfig_update(spName), }, @@ -216,7 +215,6 @@ func TestAccComputeSecurityPolicy_withAdvancedOptionsConfig(t *testing.T) { ImportState: true, ImportStateVerify: true, }, - <% end -%> { Config: testAccComputeSecurityPolicy_basic(spName), }, @@ -1108,19 +1106,15 @@ resource "google_compute_security_policy" "policy" { ] } log_level = "VERBOSE" - <% unless version == 'ga' -%> user_ip_request_headers = [ "True-Client-IP", "x-custom-ip" ] - <% end -%> - } } `, spName) } -<% unless version == 'ga' -%> func testAccComputeSecurityPolicy_withAdvancedOptionsConfig_update(spName string) string { return fmt.Sprintf(` resource "google_compute_security_policy" "policy" { @@ -1189,7 +1183,6 @@ resource "google_compute_security_policy" "policy" { } `, spName) } -<% end -%> func testAccComputeSecurityPolicy_withAdaptiveProtection(spName string) string { return fmt.Sprintf(` diff --git a/mmv1/third_party/terraform/website/docs/r/compute_security_policy.html.markdown b/mmv1/third_party/terraform/website/docs/r/compute_security_policy.html.markdown index 98af03c92186..92d2b5ab5b4f 100644 --- a/mmv1/third_party/terraform/website/docs/r/compute_security_policy.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/compute_security_policy.html.markdown @@ -204,7 +204,7 @@ The following arguments are supported: * `NORMAL` - Normal log level. * `VERBOSE` - Verbose log level. -* `user_ip_request_headers` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) An optional list of case-insensitive request header names to use for resolving the callers client IP address. +* `user_ip_request_headers` - (Optional) An optional list of case-insensitive request header names to use for resolving the callers client IP address. The `json_custom_config` block supports: From 781b533bfe7e9f0bff3cf31eaff212fe7f3c4575 Mon Sep 17 00:00:00 2001 From: Alex Coomans Date: Tue, 13 Feb 2024 18:32:32 -0600 Subject: [PATCH 07/77] Expose version_id on google_cloudfunctions_function (#9969) --- .../cloudfunctions/resource_cloudfunctions_function.go | 8 ++++++++ .../resource_cloudfunctions_function_test.go.erb | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function.go b/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function.go index ac86bac73dbf..b6d3d77906e2 100644 --- a/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function.go +++ b/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function.go @@ -490,6 +490,11 @@ func ResourceCloudFunctionsFunction() *schema.Resource { Computed: true, Description: `Describes the current stage of a deployment.`, }, + "version_id": { + Type: schema.TypeString, + Computed: true, + Description: `The version identifier of the Cloud Function. Each deployment attempt results in a new version of a function being created.`, + }, }, UseJSONNumber: true, } @@ -786,6 +791,9 @@ func resourceCloudFunctionsRead(d *schema.ResourceData, meta interface{}) error if err := d.Set("project", cloudFuncId.Project); err != nil { return fmt.Errorf("Error setting project: %s", err) } + if err := d.Set("version_id", strconv.FormatInt(function.VersionId, 10)); err != nil { + return fmt.Errorf("Error setting version_id: %s", err) + } return nil } diff --git a/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function_test.go.erb b/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function_test.go.erb index 0c2be3a3a1a3..61a267c0fcd8 100644 --- a/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function_test.go.erb +++ b/mmv1/third_party/terraform/services/cloudfunctions/resource_cloudfunctions_function_test.go.erb @@ -71,6 +71,8 @@ func TestAccCloudFunctionsFunction_basic(t *testing.T) { "entry_point", "helloGET"), resource.TestCheckResourceAttr(funcResourceName, "trigger_http", "true"), + resource.TestCheckResourceAttr(funcResourceName, + "version_id", "1"), testAccCloudFunctionsFunctionHasLabel("my-label", "my-label-value", &function), testAccCloudFunctionsFunctionHasEnvironmentVariable("TEST_ENV_VARIABLE", "test-env-variable-value", &function), @@ -110,6 +112,8 @@ func TestAccCloudFunctionsFunction_update(t *testing.T) { t, funcResourceName, &function), resource.TestCheckResourceAttr(funcResourceName, "available_memory_mb", "128"), + resource.TestCheckResourceAttr(funcResourceName, + "version_id", "1"), testAccCloudFunctionsFunctionHasLabel("my-label", "my-label-value", &function), ), }, @@ -138,6 +142,8 @@ func TestAccCloudFunctionsFunction_update(t *testing.T) { "min_instances", "5"), resource.TestCheckResourceAttr(funcResourceName, "ingress_settings", "ALLOW_ALL"), + resource.TestCheckResourceAttr(funcResourceName, + "version_id", "2"), testAccCloudFunctionsFunctionHasLabel("my-label", "my-updated-label-value", &function), testAccCloudFunctionsFunctionHasLabel("a-new-label", "a-new-label-value", &function), testAccCloudFunctionsFunctionHasEnvironmentVariable("TEST_ENV_VARIABLE", From 27496964e8867a39253ac536b2fc480624a6e574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20=27Cherit=27=20Sz=C3=B3stak?= Date: Wed, 14 Feb 2024 17:34:42 +0100 Subject: [PATCH 08/77] Fix documentation notes for google_compute_instance_group, google_compute_instance_group_membership and google_compute_region_network_endpoint resources (#9981) --- mmv1/products/compute/InstanceGroup.yaml | 2 +- mmv1/products/compute/InstanceGroupMembership.yaml | 4 ++-- mmv1/products/compute/RegionNetworkEndpoint.yaml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mmv1/products/compute/InstanceGroup.yaml b/mmv1/products/compute/InstanceGroup.yaml index e9504d021b87..59abe5b63864 100644 --- a/mmv1/products/compute/InstanceGroup.yaml +++ b/mmv1/products/compute/InstanceGroup.yaml @@ -59,7 +59,7 @@ parameters: and will not be deleted. Only the full identifier of the instance will be returned. - **NOTE** If a user will be recreating instances under the same name + !> **WARNING** If a user will be recreating instances under the same name (eg. via `terraform taint`), please consider adding instances to an instance group via the `instance_group_membership` resource, along side the `update_triggered_by` lifecycle method with an instance's ID. diff --git a/mmv1/products/compute/InstanceGroupMembership.yaml b/mmv1/products/compute/InstanceGroupMembership.yaml index 414b0846cb83..f41938f17bb8 100644 --- a/mmv1/products/compute/InstanceGroupMembership.yaml +++ b/mmv1/products/compute/InstanceGroupMembership.yaml @@ -18,11 +18,11 @@ base_url: 'projects/{{project}}/zones/{{zone}}/instanceGroups/{{instance_group}} description: | Represents the Instance membership to the Instance Group. - **NOTE** You can use this resource instead of the `instances` field in the + -> **NOTE** You can use this resource instead of the `instances` field in the `google_compute_instance_group`, however it's not recommended to use it alongside this field. It might cause inconsistencies, as they can end up competing over control. - **NOTE** This resource has been added to avoid a situation, where after + -> **NOTE** This resource has been added to avoid a situation, where after Instance is recreated, it's removed from Instance Group and it's needed to perform `apply` twice. To avoid situations like this, please use this resource with the lifecycle `update_triggered_by` method, with the passed Instance's ID. diff --git a/mmv1/products/compute/RegionNetworkEndpoint.yaml b/mmv1/products/compute/RegionNetworkEndpoint.yaml index cf4f49b6c5d2..81d31f7e1f6e 100644 --- a/mmv1/products/compute/RegionNetworkEndpoint.yaml +++ b/mmv1/products/compute/RegionNetworkEndpoint.yaml @@ -19,7 +19,7 @@ description: | A Region network endpoint represents a IP address/FQDN and port combination that is part of a specific network endpoint group (NEG). - **NOTE**: Network endpoints cannot be created outside of a network endpoint group. + ~> **NOTE**: Network endpoints cannot be created outside of a network endpoint group. immutable: true create_verb: :POST create_url: projects/{{project}}/regions/{{region}}/networkEndpointGroups/{{region_network_endpoint_group}}/attachNetworkEndpoints From 5efc7e75cf620159e09d3fe75ed339d41bd6f86a Mon Sep 17 00:00:00 2001 From: Sarah French <15078782+SarahFrench@users.noreply.github.com> Date: Wed, 14 Feb 2024 16:39:35 +0000 Subject: [PATCH 09/77] Add BBBmau to reviewer rotation (#9929) --- .ci/magician/github/membership.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/magician/github/membership.go b/.ci/magician/github/membership.go index 0f41990a121c..c6a8349fb0bb 100644 --- a/.ci/magician/github/membership.go +++ b/.ci/magician/github/membership.go @@ -39,11 +39,11 @@ var ( "trodge", "hao-nan-li", "NickElliot", + "BBBmau", } // This is for new team members who are onboarding trustedContributors = []string{ - "BBBmau", } // This is for reviewers who are "on vacation": will not receive new review assignments but will still receive re-requests for assigned PRs. From eba7c66d9cfb4ca509a3bbb723fd33ad42b299b5 Mon Sep 17 00:00:00 2001 From: Riley Karson Date: Wed, 14 Feb 2024 11:39:06 -0800 Subject: [PATCH 10/77] Add tf-test- prefix to gkehub2 tests (#9524) --- .../gkehub2/resource_gke_hub_membership_binding_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mmv1/third_party/terraform/services/gkehub2/resource_gke_hub_membership_binding_test.go b/mmv1/third_party/terraform/services/gkehub2/resource_gke_hub_membership_binding_test.go index e70ad26785a7..92cd069eb444 100644 --- a/mmv1/third_party/terraform/services/gkehub2/resource_gke_hub_membership_binding_test.go +++ b/mmv1/third_party/terraform/services/gkehub2/resource_gke_hub_membership_binding_test.go @@ -49,7 +49,7 @@ func TestAccGKEHub2MembershipBinding_gkehubMembershipBindingBasicExample_update( func testAccGKEHub2MembershipBinding_gkehubMembershipBindingBasicExample_basic(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_container_cluster" "primary" { - name = "basiccluster%{random_suffix}" + name = "tf-test-basic-cluster%{random_suffix}" location = "us-central1-a" initial_node_count = 1 deletion_protection = false @@ -93,7 +93,7 @@ resource "google_gke_hub_membership_binding" "example" { func testAccGKEHub2MembershipBinding_gkehubMembershipBindingBasicExample_update(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_container_cluster" "primary" { - name = "basiccluster%{random_suffix}" + name = "tf-test-basic-cluster%{random_suffix}" location = "us-central1-a" initial_node_count = 1 deletion_protection = false From 5a6abe3f97dc5a97e206c0d2cddfdf7f82cdd0c8 Mon Sep 17 00:00:00 2001 From: Lingkai Shen Date: Wed, 14 Feb 2024 14:41:38 -0500 Subject: [PATCH 11/77] AppAttest and PlayIntegrity for App Check (#9970) * AppAttest and PlayIntegrity for App Check * use camelCase for updateMask for consistency * Enhance examples to use precondition checks --- .../firebaseappcheck/AppAttestConfig.yaml | 89 +++++++++++++++++++ .../firebaseappcheck/PlayIntegrityConfig.yaml | 83 +++++++++++++++++ ...se_app_check_app_attest_config_full.tf.erb | 28 ++++++ ...app_check_app_attest_config_minimal.tf.erb | 27 ++++++ ...pp_check_play_integrity_config_full.tf.erb | 29 ++++++ ...check_play_integrity_config_minimal.tf.erb | 28 ++++++ ...rebase_app_check_app_attest_config_test.go | 59 ++++++++++++ ...se_app_check_play_integrity_config_test.go | 58 ++++++++++++ 8 files changed, 401 insertions(+) create mode 100644 mmv1/products/firebaseappcheck/AppAttestConfig.yaml create mode 100644 mmv1/products/firebaseappcheck/PlayIntegrityConfig.yaml create mode 100644 mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_full.tf.erb create mode 100644 mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_minimal.tf.erb create mode 100644 mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_full.tf.erb create mode 100644 mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_minimal.tf.erb create mode 100644 mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_test.go create mode 100644 mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_test.go diff --git a/mmv1/products/firebaseappcheck/AppAttestConfig.yaml b/mmv1/products/firebaseappcheck/AppAttestConfig.yaml new file mode 100644 index 000000000000..025e59fbcca9 --- /dev/null +++ b/mmv1/products/firebaseappcheck/AppAttestConfig.yaml @@ -0,0 +1,89 @@ +# Copyright 2024 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +!ruby/object:Api::Resource +name: "AppAttestConfig" +base_url: projects/{{project}}/apps/{{app_id}}/appAttestConfig +self_link: projects/{{project}}/apps/{{app_id}}/appAttestConfig +create_url: projects/{{project}}/apps/{{app_id}}/appAttestConfig?updateMask=tokenTtl +create_verb: :PATCH +update_verb: :PATCH +update_mask: true +skip_delete: true +description: | + An app's App Attest configuration object. Note that the Team ID registered with your + app is used as part of the validation process. Make sure your `google_firebase_apple_app` has a team_id present. +references: !ruby/object:Api::Resource::ReferenceLinks + guides: + "Official Documentation": "https://firebase.google.com/docs/app-check" + api: "https://firebase.google.com/docs/reference/appcheck/rest/v1/projects.apps.appAttestConfig" +import_format: + [ + "projects/{{project}}/apps/{{app_id}}/appAttestConfig", + "{{project}}/{{app_id}}", + "{{app_id}}", + ] +examples: + - !ruby/object:Provider::Terraform::Examples + name: "firebase_app_check_app_attest_config_minimal" + # Need the time_sleep resource + pull_external: true + primary_resource_id: "default" + vars: + team_id: "9987654321" + bundle_id: "bundle.id.appattest" + test_vars_overrides: + # Don't add random suffix + team_id: '"9987654321"' + test_env_vars: + project_id: :PROJECT_NAME + - !ruby/object:Provider::Terraform::Examples + name: "firebase_app_check_app_attest_config_full" + # Need the time_sleep resource + pull_external: true + primary_resource_id: "default" + vars: + team_id: "9987654321" + bundle_id: "bundle.id.appattest" + token_ttl: "7200s" + test_vars_overrides: + # Don't add random suffix + team_id: '"9987654321"' + token_ttl: '"7200s"' + test_env_vars: + project_id: :PROJECT_NAME +parameters: + - !ruby/object:Api::Type::String + name: app_id + description: | + The ID of an + [Apple App](https://firebase.google.com/docs/reference/firebase-management/rest/v1beta1/projects.iosApps#IosApp.FIELDS.app_id). + required: true + immutable: true + url_param_only: true +properties: + - !ruby/object:Api::Type::String + name: name + description: | + The relative resource name of the App Attest configuration object + output: true + pattern: projects/{{project}}/apps/{{app_id}}/appAttestConfig + - !ruby/object:Api::Type::String + name: tokenTtl + description: | + Specifies the duration for which App Check tokens exchanged from App Attest artifacts will be valid. + If unset, a default value of 1 hour is assumed. Must be between 30 minutes and 7 days, inclusive. + + A duration in seconds with up to nine fractional digits, ending with 's'. Example: "3.5s". + default_from_api: true diff --git a/mmv1/products/firebaseappcheck/PlayIntegrityConfig.yaml b/mmv1/products/firebaseappcheck/PlayIntegrityConfig.yaml new file mode 100644 index 000000000000..7631e64d1a4b --- /dev/null +++ b/mmv1/products/firebaseappcheck/PlayIntegrityConfig.yaml @@ -0,0 +1,83 @@ +# Copyright 2024 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +!ruby/object:Api::Resource +name: "PlayIntegrityConfig" +base_url: projects/{{project}}/apps/{{app_id}}/playIntegrityConfig +self_link: projects/{{project}}/apps/{{app_id}}/playIntegrityConfig +create_url: projects/{{project}}/apps/{{app_id}}/playIntegrityConfig?updateMask=tokenTtl +create_verb: :PATCH +update_verb: :PATCH +update_mask: true +skip_delete: true +description: | + An app's Play Integrity configuration object. Note that your registered SHA-256 certificate fingerprints are used to validate tokens issued by the Play Integrity API. + Make sure your `google_firebase_android_app` has at least one `sha256_hashes` present. +references: !ruby/object:Api::Resource::ReferenceLinks + guides: + "Official Documentation": "https://firebase.google.com/docs/app-check" + api: "https://firebase.google.com/docs/reference/appcheck/rest/v1/projects.apps.playIntegrityConfig" +import_format: + [ + "projects/{{project}}/apps/{{app_id}}/playIntegrityConfig", + "{{project}}/{{app_id}}", + "{{app_id}}", + ] +examples: + - !ruby/object:Provider::Terraform::Examples + name: "firebase_app_check_play_integrity_config_minimal" + # Need the time_sleep resource + pull_external: true + primary_resource_id: "default" + vars: + package_name: "package.name.playintegrity" + test_env_vars: + project_id: :PROJECT_NAME + - !ruby/object:Provider::Terraform::Examples + name: "firebase_app_check_play_integrity_config_full" + # Need the time_sleep resource + pull_external: true + primary_resource_id: "default" + vars: + package_name: "package.name.playintegrity" + token_ttl: "7200s" + test_vars_overrides: + # Don't add random suffix + token_ttl: '"7200s"' + test_env_vars: + project_id: :PROJECT_NAME +parameters: + - !ruby/object:Api::Type::String + name: app_id + description: | + The ID of an + [Android App](https://firebase.google.com/docs/reference/firebase-management/rest/v1beta1/projects.androidApps#AndroidApp.FIELDS.app_id). + required: true + immutable: true + url_param_only: true +properties: + - !ruby/object:Api::Type::String + name: name + description: | + The relative resource name of the Play Integrity configuration object + output: true + pattern: projects/{{project}}/apps/{{app_id}}/playIntegrityConfig + - !ruby/object:Api::Type::String + name: tokenTtl + description: | + Specifies the duration for which App Check tokens exchanged from Play Integrity artifacts will be valid. + If unset, a default value of 1 hour is assumed. Must be between 30 minutes and 7 days, inclusive. + + A duration in seconds with up to nine fractional digits, ending with 's'. Example: "3.5s". + default_from_api: true diff --git a/mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_full.tf.erb b/mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_full.tf.erb new file mode 100644 index 000000000000..134ecacfc5f8 --- /dev/null +++ b/mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_full.tf.erb @@ -0,0 +1,28 @@ +resource "google_firebase_apple_app" "default" { + project = "<%= ctx[:test_env_vars]['project_id'] %>" + display_name = "Apple app" + bundle_id = "<%= ctx[:vars]['bundle_id'] %>" + team_id = "<%= ctx[:vars]['team_id'] %>" +} + +# It takes a while for App Check to recognize the new app +# If your app already exists, you don't have to wait 30 seconds. +resource "time_sleep" "wait_30s" { + depends_on = [google_firebase_apple_app.default] + create_duration = "30s" +} + +resource "google_firebase_app_check_app_attest_config" "default" { + project = "<%= ctx[:test_env_vars]['project_id'] %>" + app_id = google_firebase_apple_app.default.app_id + token_ttl = "<%= ctx[:vars]['token_ttl'] %>" + + depends_on = [time_sleep.wait_30s] + + lifecycle { + precondition { + condition = google_firebase_apple_app.default.team_id != "" + error_message = "Provide a Team ID on the Apple App to use App Check" + } + } +} diff --git a/mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_minimal.tf.erb b/mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_minimal.tf.erb new file mode 100644 index 000000000000..a25a7f2d698f --- /dev/null +++ b/mmv1/templates/terraform/examples/firebase_app_check_app_attest_config_minimal.tf.erb @@ -0,0 +1,27 @@ +resource "google_firebase_apple_app" "default" { + project = "<%= ctx[:test_env_vars]['project_id'] %>" + display_name = "Apple app" + bundle_id = "<%= ctx[:vars]['bundle_id'] %>" + team_id = "<%= ctx[:vars]['team_id'] %>" +} + +# It takes a while for App Check to recognize the new app +# If your app already exists, you don't have to wait 30 seconds. +resource "time_sleep" "wait_30s" { + depends_on = [google_firebase_apple_app.default] + create_duration = "30s" +} + +resource "google_firebase_app_check_app_attest_config" "default" { + project = "<%= ctx[:test_env_vars]['project_id'] %>" + app_id = google_firebase_apple_app.default.app_id + + depends_on = [time_sleep.wait_30s] + + lifecycle { + precondition { + condition = google_firebase_apple_app.default.team_id != "" + error_message = "Provide a Team ID on the Apple App to use App Check" + } + } +} diff --git a/mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_full.tf.erb b/mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_full.tf.erb new file mode 100644 index 000000000000..78559763e319 --- /dev/null +++ b/mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_full.tf.erb @@ -0,0 +1,29 @@ +resource "google_firebase_android_app" "default" { + project = "<%= ctx[:test_env_vars]['project_id'] %>" + display_name = "Play Integrity app" + package_name = "<%= ctx[:vars]['package_name'] %>" + sha1_hashes = ["2145bdf698b8715039bd0e83f2069bed435ac21c"] + sha256_hashes = ["2145bdf698b8715039bd0e83f2069bed435ac21ca1b2c3d4e5f6123456789abc"] +} + +# It takes a while for App Check to recognize the new app +# If your app already exists, you don't have to wait 30 seconds. +resource "time_sleep" "wait_30s" { + depends_on = [google_firebase_android_app.default] + create_duration = "30s" +} + +resource "google_firebase_app_check_play_integrity_config" "default" { + project = "<%= ctx[:test_env_vars]['project_id'] %>" + app_id = google_firebase_android_app.default.app_id + token_ttl = "<%= ctx[:vars]['token_ttl'] %>" + + depends_on = [time_sleep.wait_30s] + + lifecycle { + precondition { + condition = length(google_firebase_android_app.default.sha256_hashes) > 0 + error_message = "Provide a SHA-256 certificate on the Android App to use App Check" + } + } +} diff --git a/mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_minimal.tf.erb b/mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_minimal.tf.erb new file mode 100644 index 000000000000..4aacde367414 --- /dev/null +++ b/mmv1/templates/terraform/examples/firebase_app_check_play_integrity_config_minimal.tf.erb @@ -0,0 +1,28 @@ +resource "google_firebase_android_app" "default" { + project = "<%= ctx[:test_env_vars]['project_id'] %>" + display_name = "Play Integrity app" + package_name = "<%= ctx[:vars]['package_name'] %>" + sha1_hashes = ["2145bdf698b8715039bd0e83f2069bed435ac21c"] + sha256_hashes = ["2145bdf698b8715039bd0e83f2069bed435ac21ca1b2c3d4e5f6123456789abc"] +} + +# It takes a while for App Check to recognize the new app +# If your app already exists, you don't have to wait 30 seconds. +resource "time_sleep" "wait_30s" { + depends_on = [google_firebase_android_app.default] + create_duration = "30s" +} + +resource "google_firebase_app_check_play_integrity_config" "default" { + project = "<%= ctx[:test_env_vars]['project_id'] %>" + app_id = google_firebase_android_app.default.app_id + + depends_on = [time_sleep.wait_30s] + + lifecycle { + precondition { + condition = length(google_firebase_android_app.default.sha256_hashes) > 0 + error_message = "Provide a SHA-256 certificate on the Android App to use App Check" + } + } +} diff --git a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_test.go b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_test.go new file mode 100644 index 000000000000..a1b05b852feb --- /dev/null +++ b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_app_attest_config_test.go @@ -0,0 +1,59 @@ +package firebaseappcheck_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccFirebaseAppCheckAppAttestConfig_firebaseAppCheckAppAttestConfigUpdate(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_id": envvar.GetTestProjectFromEnv(), + "team_id": "9987654321", + "random_suffix": acctest.RandString(t, 10), + "token_ttl": "7200s", + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccFirebaseAppCheckAppAttestConfig_firebaseAppCheckAppAttestConfigMinimalExample(context), + }, + { + ResourceName: "google_firebase_app_check_app_attest_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + { + Config: testAccFirebaseAppCheckAppAttestConfig_firebaseAppCheckAppAttestConfigFullExample(context), + }, + { + ResourceName: "google_firebase_app_check_app_attest_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + { + Config: testAccFirebaseAppCheckAppAttestConfig_firebaseAppCheckAppAttestConfigMinimalExample(context), + }, + { + ResourceName: "google_firebase_app_check_app_attest_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + }, + }) +} diff --git a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_test.go b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_test.go new file mode 100644 index 000000000000..c97df9fd1fab --- /dev/null +++ b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_play_integrity_config_test.go @@ -0,0 +1,58 @@ +package firebaseappcheck_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccFirebaseAppCheckPlayIntegrityConfig_firebaseAppCheckPlayIntegrityConfigUpdate(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_id": envvar.GetTestProjectFromEnv(), + "random_suffix": acctest.RandString(t, 10), + "token_ttl": "7200s", + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccFirebaseAppCheckPlayIntegrityConfig_firebaseAppCheckPlayIntegrityConfigMinimalExample(context), + }, + { + ResourceName: "google_firebase_app_check_play_integrity_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + { + Config: testAccFirebaseAppCheckPlayIntegrityConfig_firebaseAppCheckPlayIntegrityConfigFullExample(context), + }, + { + ResourceName: "google_firebase_app_check_play_integrity_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + { + Config: testAccFirebaseAppCheckPlayIntegrityConfig_firebaseAppCheckPlayIntegrityConfigMinimalExample(context), + }, + { + ResourceName: "google_firebase_app_check_play_integrity_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + }, + }) +} From 56fb584e20f40c371728bd5cbc1f4f5c41a0228b Mon Sep 17 00:00:00 2001 From: Lingkai Shen Date: Thu, 15 Feb 2024 12:29:45 -0500 Subject: [PATCH 12/77] Use a different service name for TestAccFirebaseAppCheckServiceConfig_firebaseAppCheckServiceConfigUpdate (#9961) --- .../resource_firebase_app_check_service_config_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_service_config_test.go b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_service_config_test.go index 2ea26c572329..aba5a807434f 100644 --- a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_service_config_test.go +++ b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_service_config_test.go @@ -14,7 +14,7 @@ func TestAccFirebaseAppCheckServiceConfig_firebaseAppCheckServiceConfigUpdate(t context := map[string]interface{}{ "project_id": envvar.GetTestProjectFromEnv(), - "service_id": "firestore.googleapis.com", + "service_id": "identitytoolkit.googleapis.com", "random_suffix": acctest.RandString(t, 10), } From e06ba191ab8745caadcf97e85a096201b79c3fb2 Mon Sep 17 00:00:00 2001 From: Sam Levenick Date: Thu, 15 Feb 2024 14:11:46 -0500 Subject: [PATCH 13/77] Add Preference Set resource (#9698) * Add Preference Set * YAML lint * YAML lint * YAML lint * YAML lint * Add full test * Full test added * Reordering * PR review --- .../migrationcenter/PreferenceSet.yaml | 206 ++++++++++++++++++ .../examples/preference_set_basic.tf.erb | 13 ++ .../examples/preference_set_full.tf.erb | 35 +++ ...ce_migration_center_preference_set_test.go | 88 ++++++++ 4 files changed, 342 insertions(+) create mode 100644 mmv1/products/migrationcenter/PreferenceSet.yaml create mode 100644 mmv1/templates/terraform/examples/preference_set_basic.tf.erb create mode 100644 mmv1/templates/terraform/examples/preference_set_full.tf.erb create mode 100644 mmv1/third_party/terraform/services/migrationcenter/resource_migration_center_preference_set_test.go diff --git a/mmv1/products/migrationcenter/PreferenceSet.yaml b/mmv1/products/migrationcenter/PreferenceSet.yaml new file mode 100644 index 000000000000..9232294c71e5 --- /dev/null +++ b/mmv1/products/migrationcenter/PreferenceSet.yaml @@ -0,0 +1,206 @@ +# Copyright 2023 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- !ruby/object:Api::Resource +base_url: projects/{{project}}/locations/{{location}}/preferenceSets +create_url: projects/{{project}}/locations/{{location}}/preferenceSets?preferenceSetId={{preference_set_id}} +self_link: projects/{{project}}/locations/{{location}}/preferenceSets/{{preference_set_id}} +id_format: projects/{{project}}/locations/{{location}}/preferenceSets/{{preference_set_id}} +import_format: + - projects/{{project}}/locations/{{location}}/preferenceSets/{{preference_set_id}} +name: PreferenceSet +description: Manages the PreferenceSet resource. +update_verb: :PATCH +update_mask: true +autogen_async: true +references: !ruby/object:Api::Resource::ReferenceLinks + guides: + 'Managing Migration Preferences': 'https://cloud.google.com/migration-center/docs/migration-preferences' + api: 'https://cloud.google.com/migration-center/docs/reference/rest/v1' +examples: + - !ruby/object:Provider::Terraform::Examples + name: 'preference_set_basic' + primary_resource_id: 'default' + vars: + set_name: 'preference-set-test' + - !ruby/object:Provider::Terraform::Examples + name: 'preference_set_full' + primary_resource_id: 'default' + vars: + set_name: 'preference-set-test' +properties: + - !ruby/object:Api::Type::String + name: name + description: 'Output only. Name of the preference set. ' + output: true + - !ruby/object:Api::Type::String + name: createTime + description: 'Output only. The timestamp when the preference set was created. ' + output: true + - !ruby/object:Api::Type::String + name: updateTime + description: 'Output only. The timestamp when the preference set was last updated. ' + output: true + - !ruby/object:Api::Type::String + name: displayName + description: 'User-friendly display name. Maximum length is 63 characters. ' + - !ruby/object:Api::Type::String + name: description + description: 'A description of the preference set. ' + - !ruby/object:Api::Type::NestedObject + name: virtualMachinePreferences + description: 'VirtualMachinePreferences enables you to create sets of assumptions, + for example, a geographical location and pricing track, for your migrated virtual + machines. The set of preferences influence recommendations for migrating virtual + machine assets. ' + properties: + - !ruby/object:Api::Type::String + name: targetProduct + description: "Target product for assets using this preference set. Specify either + target product or business goal, but not both. \n Possible values:\n COMPUTE_MIGRATION_TARGET_PRODUCT_UNSPECIFIED\nCOMPUTE_MIGRATION_TARGET_PRODUCT_COMPUTE_ENGINE\nCOMPUTE_MIGRATION_TARGET_PRODUCT_VMWARE_ENGINE\nCOMPUTE_MIGRATION_TARGET_PRODUCT_SOLE_TENANCY" + - !ruby/object:Api::Type::NestedObject + name: regionPreferences + description: 'The user preferences relating to target regions. ' + properties: + - !ruby/object:Api::Type::Array + name: preferredRegions + item_type: Api::Type::String + description: 'A list of preferred regions, ordered by the most preferred region + first. Set only valid Google Cloud region names. See https://cloud.google.com/compute/docs/regions-zones + for available regions. ' + - !ruby/object:Api::Type::String + name: commitmentPlan + description: "Commitment plan to consider when calculating costs for virtual machine + insights and recommendations. If you are unsure which value to set, a 3 year + commitment plan is often a good value to start with. \n Possible values:\n COMMITMENT_PLAN_UNSPECIFIED\nCOMMITMENT_PLAN_NONE\nCOMMITMENT_PLAN_ONE_YEAR\nCOMMITMENT_PLAN_THREE_YEARS" + - !ruby/object:Api::Type::String + name: sizingOptimizationStrategy + description: "Sizing optimization strategy specifies the preferred strategy used + when extrapolating usage data to calculate insights and recommendations for + a virtual machine. If you are unsure which value to set, a moderate sizing optimization + strategy is often a good value to start with. \n Possible values:\n SIZING_OPTIMIZATION_STRATEGY_UNSPECIFIED\nSIZING_OPTIMIZATION_STRATEGY_SAME_AS_SOURCE\nSIZING_OPTIMIZATION_STRATEGY_MODERATE\nSIZING_OPTIMIZATION_STRATEGY_AGGRESSIVE" + - !ruby/object:Api::Type::NestedObject + name: computeEnginePreferences + description: 'The user preferences relating to Compute Engine target platform. ' + properties: + - !ruby/object:Api::Type::NestedObject + name: machinePreferences + description: 'The type of machines to consider when calculating virtual machine + migration insights and recommendations. Not all machine types are available + in all zones and regions. ' + properties: + - !ruby/object:Api::Type::Array + name: allowedMachineSeries + item_type: !ruby/object:Api::Type::NestedObject + properties: + - !ruby/object:Api::Type::String + name: code + description: 'Code to identify a Compute Engine machine series. Consult + https://cloud.google.com/compute/docs/machine-resource#machine_type_comparison + for more details on the available series. ' + description: 'Compute Engine machine series to consider for insights and recommendations. + If empty, no restriction is applied on the machine series. ' + - !ruby/object:Api::Type::String + name: licenseType + description: "License type to consider when calculating costs for virtual machine + insights and recommendations. If unspecified, costs are calculated based on + the default licensing plan. \n Possible values:\n LICENSE_TYPE_UNSPECIFIED\nLICENSE_TYPE_DEFAULT\nLICENSE_TYPE_BRING_YOUR_OWN_LICENSE" + - !ruby/object:Api::Type::NestedObject + name: vmwareEnginePreferences + description: 'The user preferences relating to Google Cloud VMware Engine target + platform. ' + properties: + - !ruby/object:Api::Type::Double + name: cpuOvercommitRatio + description: 'CPU overcommit ratio. Acceptable values are between 1.0 and 8.0, + with 0.1 increment. ' + - !ruby/object:Api::Type::Double + name: memoryOvercommitRatio + description: 'Memory overcommit ratio. Acceptable values are 1.0, 1.25, 1.5, + 1.75 and 2.0. ' + - !ruby/object:Api::Type::Double + name: storageDeduplicationCompressionRatio + description: 'The Deduplication and Compression ratio is based on the logical + (Used Before) space required to store data before applying deduplication and + compression, in relation to the physical (Used After) space required after + applying deduplication and compression. Specifically, the ratio is the Used + Before space divided by the Used After space. For example, if the Used Before + space is 3 GB, but the physical Used After space is 1 GB, the deduplication + and compression ratio is 3x. Acceptable values are between 1.0 and 4.0. ' + - !ruby/object:Api::Type::String + name: commitmentPlan + description: "Commitment plan to consider when calculating costs for virtual + machine insights and recommendations. If you are unsure which value to set, + a 3 year commitment plan is often a good value to start with. \n Possible + values:\n COMMITMENT_PLAN_UNSPECIFIED\nON_DEMAND\nCOMMITMENT_1_YEAR_MONTHLY_PAYMENTS\nCOMMITMENT_3_YEAR_MONTHLY_PAYMENTS\nCOMMITMENT_1_YEAR_UPFRONT_PAYMENT\nCOMMITMENT_3_YEAR_UPFRONT_PAYMENT" + - !ruby/object:Api::Type::NestedObject + name: soleTenancyPreferences + description: 'Preferences concerning Sole Tenancy nodes and VMs. ' + properties: + - !ruby/object:Api::Type::Double + name: cpuOvercommitRatio + description: 'CPU overcommit ratio. Acceptable values are between 1.0 and 2.0 + inclusive. ' + - !ruby/object:Api::Type::String + name: hostMaintenancePolicy + description: "Sole Tenancy nodes maintenance policy. \n Possible values:\n HOST_MAINTENANCE_POLICY_UNSPECIFIED\nHOST_MAINTENANCE_POLICY_DEFAULT\nHOST_MAINTENANCE_POLICY_RESTART_IN_PLACE\nHOST_MAINTENANCE_POLICY_MIGRATE_WITHIN_NODE_GROUP" + - !ruby/object:Api::Type::String + name: commitmentPlan + description: "Commitment plan to consider when calculating costs for virtual + machine insights and recommendations. If you are unsure which value to set, + a 3 year commitment plan is often a good value to start with. \n Possible + values:\n COMMITMENT_PLAN_UNSPECIFIED\nON_DEMAND\nCOMMITMENT_1_YEAR\nCOMMITMENT_3_YEAR" + - !ruby/object:Api::Type::Array + name: nodeTypes + item_type: !ruby/object:Api::Type::NestedObject + properties: + - !ruby/object:Api::Type::String + name: nodeName + description: 'Name of the Sole Tenant node. Consult https://cloud.google.com/compute/docs/nodes/sole-tenant-nodes ' + description: 'A list of sole tenant node types. An empty list means that all + possible node types will be considered. ' +parameters: + - !ruby/object:Api::Type::String + name: location + description: 'Part of `parent`. See documentation of `projectsId`. ' + url_param_only: true + required: true + immutable: true + - !ruby/object:Api::Type::String + name: preferenceSetId + description: 'Required. User specified ID for the preference set. It will become + the last component of the preference set name. The ID must be unique within the + project, must conform with RFC-1034, is restricted to lower-cased letters, and + has a maximum length of 63 characters. The ID must match the regular expression + `[a-z]([a-z0-9-]{0,61}[a-z0-9])?`. ' + url_param_only: true + required: true + immutable: true +async: !ruby/object:Api::OpAsync + operation: !ruby/object:Api::OpAsync::Operation + path: name + base_url: "{{op_id}}" + wait_ms: 1000 + timeouts: + result: !ruby/object:Api::OpAsync::Result + path: response + resource_inside_response: true + status: !ruby/object:Api::OpAsync::Status + path: done + complete: true + allowed: + - true + - false + error: !ruby/object:Api::OpAsync::Error + path: error + message: message diff --git a/mmv1/templates/terraform/examples/preference_set_basic.tf.erb b/mmv1/templates/terraform/examples/preference_set_basic.tf.erb new file mode 100644 index 000000000000..ebe5c10263fa --- /dev/null +++ b/mmv1/templates/terraform/examples/preference_set_basic.tf.erb @@ -0,0 +1,13 @@ +resource "google_migration_center_preference_set" "<%= ctx[:primary_resource_id] %>" { + location = "us-central1" + preference_set_id = "<%= ctx[:vars]['set_name'] %>" + description = "Terraform integration test description" + display_name = "Terraform integration test display" + virtual_machine_preferences { + vmware_engine_preferences { + cpu_overcommit_ratio = 1.5 + } + sizing_optimization_strategy = "SIZING_OPTIMIZATION_STRATEGY_SAME_AS_SOURCE" + target_product = "COMPUTE_MIGRATION_TARGET_PRODUCT_COMPUTE_ENGINE" + } +} diff --git a/mmv1/templates/terraform/examples/preference_set_full.tf.erb b/mmv1/templates/terraform/examples/preference_set_full.tf.erb new file mode 100644 index 000000000000..61acf00f5540 --- /dev/null +++ b/mmv1/templates/terraform/examples/preference_set_full.tf.erb @@ -0,0 +1,35 @@ +resource "google_migration_center_preference_set" "<%= ctx[:primary_resource_id] %>" { + location = "us-central1" + preference_set_id = "<%= ctx[:vars]['set_name'] %>" + description = "Terraform integration test description" + display_name = "Terraform integration test display" + virtual_machine_preferences { + vmware_engine_preferences { + cpu_overcommit_ratio = 1.5 + storage_deduplication_compression_ratio = 1.3 + commitment_plan = "ON_DEMAND" + } + sizing_optimization_strategy = "SIZING_OPTIMIZATION_STRATEGY_SAME_AS_SOURCE" + target_product = "COMPUTE_MIGRATION_TARGET_PRODUCT_COMPUTE_ENGINE" + commitment_plan = "COMMITMENT_PLAN_ONE_YEAR" + region_preferences { + preferred_regions = ["us-central1"] + } + sole_tenancy_preferences { + commitment_plan = "ON_DEMAND" + cpu_overcommit_ratio = 1.2 + host_maintenance_policy = "HOST_MAINTENANCE_POLICY_DEFAULT" + node_types { + node_name = "tf-test" + } + } + compute_engine_preferences { + license_type = "LICENSE_TYPE_BRING_YOUR_OWN_LICENSE" + machine_preferences { + allowed_machine_series { + code = "C3" + } + } + } + } +} diff --git a/mmv1/third_party/terraform/services/migrationcenter/resource_migration_center_preference_set_test.go b/mmv1/third_party/terraform/services/migrationcenter/resource_migration_center_preference_set_test.go new file mode 100644 index 000000000000..739265f52527 --- /dev/null +++ b/mmv1/third_party/terraform/services/migrationcenter/resource_migration_center_preference_set_test.go @@ -0,0 +1,88 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This file is automatically generated by Magic Modules and manual +// changes will be clobbered when the file is regenerated. +// +// Please read more about how to change this file in +// .github/CONTRIBUTING.md. +// +// ---------------------------------------------------------------------------- + +package migrationcenter_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccMigrationCenterPreferenceSet_preferenceSetUpdate(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.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckMigrationCenterPreferenceSetDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccMigrationCenterPreferenceSet_preferenceSetStart(context), + }, + { + ResourceName: "google_migration_center_preference_set.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "preference_set_id"}, + }, + }, + }) +} + +func testAccMigrationCenterPreferenceSet_preferenceSetStart(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_migration_center_preference_set" "default" { + location = "us-central1" + preference_set_id = "tf-test-preference-set-test%{random_suffix}" + description = "Terraform integration test description" + display_name = "Terraform integration test display" + virtual_machine_preferences { + vmware_engine_preferences { + cpu_overcommit_ratio = 1.5 + memory_overcommit_ratio = 2.0 + } + sizing_optimization_strategy = "SIZING_OPTIMIZATION_STRATEGY_SAME_AS_SOURCE" + } +} +`, context) +} + +func testAccMigrationCenterPreferenceSet_preferenceSetUpdate(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_migration_center_preference_set" "default" { + location = "us-central1" + preference_set_id = "tf-test-preference-set-test%{random_suffix}" + description = "Terraform integration test updated description" + display_name = "Terraform integration test updated display" + virtual_machine_preferences { + vmware_engine_preferences { + cpu_overcommit_ratio = 1.4 + } + sizing_optimization_strategy = "SIZING_OPTIMIZATION_STRATEGY_MODERATE" + commitment_plan = "COMMITMENT_PLAN_ONE_YEAR" + preferred_regions = ["us-central1"] + } +} +`, context) +} From cacc4c83118fad13081315d45ddeefbc5e297ca9 Mon Sep 17 00:00:00 2001 From: Luca Prete Date: Thu, 15 Feb 2024 20:17:19 +0100 Subject: [PATCH 14/77] [#16607] Fix: support iamMember (i.e. for WIF ids) in big query datasets (#9948) Co-authored-by: Luca Prete --- .../services/bigquery/iam_bigquery_dataset.go | 9 ++- ...source_bigquery_dataset_iam_member_test.go | 71 +++++++++++++++++-- .../terraform/tpgiamresource/iam.go.erb | 5 ++ .../docs/r/bigquery_dataset_iam.html.markdown | 9 +-- 4 files changed, 78 insertions(+), 16 deletions(-) diff --git a/mmv1/third_party/terraform/services/bigquery/iam_bigquery_dataset.go b/mmv1/third_party/terraform/services/bigquery/iam_bigquery_dataset.go index f6966ac4d2d2..740da92602ad 100644 --- a/mmv1/third_party/terraform/services/bigquery/iam_bigquery_dataset.go +++ b/mmv1/third_party/terraform/services/bigquery/iam_bigquery_dataset.go @@ -214,7 +214,6 @@ func iamMemberToAccess(member string) (string, string, error) { if strings.HasPrefix(member, "deleted:") { return "", "", fmt.Errorf("BigQuery Dataset IAM member is deleted: %s", member) } - pieces := strings.SplitN(member, ":", 2) if len(pieces) > 1 { switch pieces[0] { @@ -222,19 +221,19 @@ func iamMemberToAccess(member string) (string, string, error) { return "groupByEmail", pieces[1], nil case "domain": return "domain", pieces[1], nil + case "iamMember": + return "iamMember", pieces[1], nil case "user": return "userByEmail", pieces[1], nil case "serviceAccount": return "userByEmail", pieces[1], nil - default: - return "", "", fmt.Errorf("Failed to parse BigQuery Dataset IAM member type: %s", member) } } if member == "projectOwners" || member == "projectReaders" || member == "projectWriters" || member == "allAuthenticatedUsers" { // These are special BigQuery Dataset permissions return "specialGroup", member, nil } - return "iamMember", member, nil + return "", "", fmt.Errorf("Failed to parse BigQuery Dataset IAM member type: %s", member) } func accessToIamMember(access map[string]interface{}) (string, error) { @@ -249,7 +248,7 @@ func accessToIamMember(access map[string]interface{}) (string, error) { return member.(string), nil } if member, ok := access["iamMember"]; ok { - return member.(string), nil + return fmt.Sprintf("iamMember:%s", member.(string)), nil } if _, ok := access["view"]; ok { // view does not map to an IAM member, use access instead diff --git a/mmv1/third_party/terraform/services/bigquery/resource_bigquery_dataset_iam_member_test.go b/mmv1/third_party/terraform/services/bigquery/resource_bigquery_dataset_iam_member_test.go index d138457f702d..0ab43e371d9d 100644 --- a/mmv1/third_party/terraform/services/bigquery/resource_bigquery_dataset_iam_member_test.go +++ b/mmv1/third_party/terraform/services/bigquery/resource_bigquery_dataset_iam_member_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-provider-google/google/envvar" ) -func TestAccBigqueryDatasetIamMember_basic(t *testing.T) { +func TestAccBigqueryDatasetIamMember_serviceAccount(t *testing.T) { t.Parallel() datasetID := fmt.Sprintf("tf_test_%s", acctest.RandString(t, 10)) @@ -25,27 +25,55 @@ func TestAccBigqueryDatasetIamMember_basic(t *testing.T) { ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), Steps: []resource.TestStep{ { - Config: testAccBigqueryDatasetIamMember_basic(datasetID, saID), + Config: testAccBigqueryDatasetIamMember_serviceAccount(datasetID, saID), Check: testAccCheckBigQueryDatasetAccessPresent(t, "google_bigquery_dataset.dataset", expected), }, { // Destroy step instead of CheckDestroy so we can check the access is removed without deleting the dataset - Config: testAccBigqueryDatasetIamMember_destroy(datasetID, "dataset"), + Config: testAccBigqueryDatasetIamMember_destroy(datasetID), Check: testAccCheckBigQueryDatasetAccessAbsent(t, "google_bigquery_dataset.dataset", expected), }, }, }) } -func testAccBigqueryDatasetIamMember_destroy(datasetID, rs string) string { +func TestAccBigqueryDatasetIamMember_iamMember(t *testing.T) { + t.Parallel() + + datasetID := fmt.Sprintf("tf_test_%s", acctest.RandString(t, 10)) + wifIDs := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + + expected := map[string]interface{}{ + "role": "roles/viewer", + "iamMember": fmt.Sprintf("principal://iam.googleapis.com/projects/%s/locations/global/workloadIdentityPools/%s/subject/test", envvar.GetTestProjectNumberFromEnv(), wifIDs), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccBigqueryDatasetIamMember_iamMember(datasetID, wifIDs), + Check: testAccCheckBigQueryDatasetAccessPresent(t, "google_bigquery_dataset.dataset", expected), + }, + { + // Destroy step instead of CheckDestroy so we can check the access is removed without deleting the dataset + Config: testAccBigqueryDatasetIamMember_destroy(datasetID), + Check: testAccCheckBigQueryDatasetAccessAbsent(t, "google_bigquery_dataset.dataset", expected), + }, + }, + }) +} + +func testAccBigqueryDatasetIamMember_destroy(datasetID string) string { return fmt.Sprintf(` -resource "google_bigquery_dataset" "%s" { +resource "google_bigquery_dataset" "dataset" { dataset_id = "%s" } -`, rs, datasetID) +`, datasetID) } -func testAccBigqueryDatasetIamMember_basic(datasetID, saID string) string { +func testAccBigqueryDatasetIamMember_serviceAccount(datasetID, saID string) string { return fmt.Sprintf(` resource "google_bigquery_dataset_iam_member" "access" { dataset_id = google_bigquery_dataset.dataset.dataset_id @@ -62,3 +90,32 @@ resource "google_service_account" "bqviewer" { } `, datasetID, saID) } + +func testAccBigqueryDatasetIamMember_iamMember(datasetID, wifIDs string) string { + return fmt.Sprintf(` +resource "google_bigquery_dataset_iam_member" "access" { + dataset_id = google_bigquery_dataset.dataset.dataset_id + role = "roles/viewer" + member = "iamMember:principal://iam.googleapis.com/${google_iam_workload_identity_pool.wif_pool.name}/subject/test" +} + +resource "google_bigquery_dataset" "dataset" { + dataset_id = "%s" +} + +resource "google_iam_workload_identity_pool" "wif_pool" { + workload_identity_pool_id = "%s" +} + +resource "google_iam_workload_identity_pool_provider" "wif_provider" { + workload_identity_pool_id = google_iam_workload_identity_pool.wif_pool.workload_identity_pool_id + workload_identity_pool_provider_id = "%s" + attribute_mapping = { + "google.subject" = "assertion.sub" + } + oidc { + issuer_uri = "https://issuer-uri.com" + } +} +`, datasetID, wifIDs, wifIDs) +} diff --git a/mmv1/third_party/terraform/tpgiamresource/iam.go.erb b/mmv1/third_party/terraform/tpgiamresource/iam.go.erb index 6dcb6c1ba8f7..ce9fce404baf 100644 --- a/mmv1/third_party/terraform/tpgiamresource/iam.go.erb +++ b/mmv1/third_party/terraform/tpgiamresource/iam.go.erb @@ -274,6 +274,11 @@ func normalizeIamMemberCasing(member string) string { if len(pieces) > 2 && !iamMemberIsCaseSensitive(strings.TrimPrefix(member, "deleted:")) { pieces[2] = strings.ToLower(pieces[2]) } + } else if strings.HasPrefix(member, "iamMember:") { + pieces = strings.SplitN(member, ":", 3) + if len(pieces) > 2 && !iamMemberIsCaseSensitive(strings.TrimPrefix(member, "iamMember:")) { + pieces[2] = strings.ToLower(pieces[2]) + } } else if !iamMemberIsCaseSensitive(member) { pieces = strings.SplitN(member, ":", 2) if len(pieces) > 1 { diff --git a/mmv1/third_party/terraform/website/docs/r/bigquery_dataset_iam.html.markdown b/mmv1/third_party/terraform/website/docs/r/bigquery_dataset_iam.html.markdown index e911137bdfae..4702defcded5 100644 --- a/mmv1/third_party/terraform/website/docs/r/bigquery_dataset_iam.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/bigquery_dataset_iam.html.markdown @@ -86,12 +86,13 @@ The following arguments are supported: * `member/members` - (Required) Identities that will be granted the privilege in `role`. Each entry can have one of the following values: - * **allUsers**: A special identifier that represents anyone who is on the internet; with or without a Google account. * **allAuthenticatedUsers**: A special identifier that represents anyone who is authenticated with a Google account or a service account. - * **user:{emailid}**: An email address that represents a specific Google account. For example, alice@gmail.com or joe@example.com. - * **serviceAccount:{emailid}**: An email address that represents a service account. For example, my-other-app@appspot.gserviceaccount.com. - * **group:{emailid}**: An email address that represents a Google group. For example, admins@example.com. + * **allUsers**: A special identifier that represents anyone who is on the internet; with or without a Google account. * **domain:{domain}**: A G Suite domain (primary, instead of alias) name that represents all the users of that domain. For example, google.com or example.com. + * **group:{emailid}**: An email address that represents a Google group. For example, admins@example.com. + * **iamMember:{principal}**: Some other type of member that appears in the IAM Policy but isn't a user, group, domain, or special group. This is used for example for workload/workforce federated identities (principal, principalSet). + * **serviceAccount:{emailid}**: An email address that represents a service account. For example, my-other-app@appspot.gserviceaccount.com. + * **user:{emailid}**: An email address that represents a specific Google account. For example, alice@gmail.com or joe@example.com. * `role` - (Required) The role that should be applied. Only one `google_bigquery_dataset_iam_binding` can be used per role. Note that custom roles must be of the format From 125391685be1c603329ca249f5d233c21396effa Mon Sep 17 00:00:00 2001 From: Thomas Rodgers Date: Thu, 15 Feb 2024 13:13:40 -0800 Subject: [PATCH 15/77] Fix issues with vcr status and logs (#9987) * Fix issues with vcr status and logs * Report success if recording succeeds, not replaying after recording --- .ci/magician/cmd/test_terraform_vcr.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.ci/magician/cmd/test_terraform_vcr.go b/.ci/magician/cmd/test_terraform_vcr.go index 99ca6cd74a81..2749ddd586c0 100644 --- a/.ci/magician/cmd/test_terraform_vcr.go +++ b/.ci/magician/cmd/test_terraform_vcr.go @@ -168,6 +168,8 @@ Affected tests: ` + fmt.Sprintf("`%d`", len(replayingResult.FailedTests)) + ` recordingResult, recordingErr := vt.RunParallel(vcr.Recording, provider.Beta, testDirs, replayingResult.FailedTests) if recordingErr != nil { testState = "failure" + } else { + testState = "success" } if err := vt.UploadCassettes("ci-vcr-cassettes", prNumber, provider.Beta); err != nil { @@ -200,7 +202,7 @@ Affected tests: ` + fmt.Sprintf("`%d`", len(replayingResult.FailedTests)) + ` testState = "failure" } - if err := vt.UploadLogs("ci-vcr-logs", prNumber, buildID, true, false, vcr.Recording, provider.Beta); err != nil { + if err := vt.UploadLogs("ci-vcr-logs", prNumber, buildID, true, true, vcr.Replaying, provider.Beta); err != nil { fmt.Println("Error uploading recording logs: ", err) os.Exit(1) } From 44e139bad1261704549ac95150b5b666ff790528 Mon Sep 17 00:00:00 2001 From: Oliver Krause <3621164+okrause@users.noreply.github.com> Date: Thu, 15 Feb 2024 22:52:06 +0100 Subject: [PATCH 16/77] Netapp volumes: Add restoreParameters (#9918) * Add force delete to delete volumes with nested snapshots * few cleanups * Make virtual field verifies happy * Minor test improvements * Remove ignore_read for deletion_policy * Fix typos in snapRestore comment * Adding missing fields state, StateDetails, backupConfig * BackupConfig is work in progress * Implemented restoreParameters - added parameters state and state_details. Needs discussion if they are to be included. Currently they are deactivated - added restore_parameters. - added test for restore_parameters.source_snapshot - adding a test for restore_parameters.sourceBackup required currently non-existing backup resoruce and would have long runtime - renamed the example file to follow format of other peer resources * More improvements on restore_parameters * Comment cleanups * Remove backupConfig support for now. * Fix small typos * - Adding state, state_details and create_time fields - make backup_config parameters "exactly_one_of" - some work on backup_config, but still disabled - added tests for backup_config, but still disabled - made tests more compact by removing resources and fields which did their job earlier but aren't required later anymore. * convert tabs to spaces in test resource blocks * remove backupConfig. Will PR later --- mmv1/products/netapp/volume.yaml | 69 ++- ...asic.tf.erb => netapp_volume_basic.tf.erb} | 0 .../netapp/resource_netapp_volume_test.go | 506 ++++++++++-------- 3 files changed, 336 insertions(+), 239 deletions(-) rename mmv1/templates/terraform/examples/{volume_basic.tf.erb => netapp_volume_basic.tf.erb} (100%) diff --git a/mmv1/products/netapp/volume.yaml b/mmv1/products/netapp/volume.yaml index 4f617b3ab27c..698f8ab4906b 100644 --- a/mmv1/products/netapp/volume.yaml +++ b/mmv1/products/netapp/volume.yaml @@ -53,7 +53,7 @@ parameters: url_param_only: true examples: - !ruby/object:Provider::Terraform::Examples - name: 'volume_basic' + name: 'netapp_volume_basic' primary_resource_id: 'test_volume' vars: volume_name: 'test-volume' @@ -64,6 +64,30 @@ examples: test_vars_overrides: network_name: 'acctest.BootstrapSharedServiceNetworkingConnection(t, "gcnv-network-config-1", acctest.ServiceNetworkWithParentService("netapp.servicenetworking.goog"))' properties: + - !ruby/object:Api::Type::Enum + name: 'state' + description: | + State of the volume. + values: + - STATE_UNSPECIFIED + - READY + - CREATING + - DELETING + - UPDATING + - RESTORING + - DISABLED + - ERROR + output: true + - !ruby/object:Api::Type::String + name: 'stateDetails' + description: | + State details of the volume. + output: true + - !ruby/object:Api::Type::String + name: 'createTime' + description: | + Create time of the volume. A timestamp in RFC3339 UTC "Zulu" format. Examples: "2023-06-22T09:13:01.617Z". + output: true - !ruby/object:Api::Type::String name: 'shareName' description: | @@ -205,11 +229,11 @@ properties: name: 'description' description: | An optional description of this resource. - # Use of snapReserve is depricated. We don't expose it intentially. + # Use of snapReserve is deprecated. Here as a comment to express intention. # - !ruby/object:Api::Type::Integer # name: 'snapReserve' # description: | - # Snap_reserve specifies percentage of volume storage reserved for snapshot storage. Default is 0 percent. Use is deprecated. + # `snap_reserve` specifies percentage of volume storage reserved for snapshot storage. Default is 0 percent. Use is deprecated. - !ruby/object:Api::Type::Boolean name: 'snapshotDirectory' description: | @@ -245,6 +269,34 @@ properties: description: | Reports the resource name of the Active Directory policy being used. Inherited from storage pool. output: true + - !ruby/object:Api::Type::NestedObject + name: 'restoreParameters' + description: |- + Used to create this volume from a snapshot (= cloning) or an backup. + immutable: true + # This parameter is only used at CREATE. READs will omit it. + ignore_read: true + properties: + - !ruby/object:Api::Type::String + name: 'sourceSnapshot' + description: |- + Full name of the snapshot to use for creating this volume. + `source_snapshot` and `source_backup` cannot be used simultaneously. + Format: `projects/{{project}}/locations/{{location}}/volumes/{{volume}}/snapshots/{{snapshot}}`. + exactly_one_of: + - restore_parameters.0.source_backup + - restore_parameters.0.source_snapshot + immutable: true + - !ruby/object:Api::Type::String + name: 'sourceBackup' + description: |- + Full name of the snapshot to use for creating this volume. + `source_snapshot` and `source_backup` cannot be used simultaneously. + Format: `projects/{{project}}/locations/{{location}}/backupVaults/{{backupVaultId}}/backups/{{backup}}`. + exactly_one_of: + - restore_parameters.0.source_backup + - restore_parameters.0.source_snapshot + immutable: true - !ruby/object:Api::Type::String name: 'kmsConfig' description: | @@ -405,17 +457,6 @@ properties: description: |- Set the day or days of the month to make a snapshot (1-31). Accepts a comma separated number of days. Defaults to '1'. default_value: '1' -# This is disabled until we have support for backup resource and can test it. -# - !ruby/object:Api::Type::NestedObject -# name: restoreParameters -# description: Specifies the source information to create a volume from. -# immutable: true -# properties: -# - !ruby/object:Api::Type::String -# name: 'sourceSnapshot' -# description: |- -# Full name of the snapshot resource. Format: `projects/{{project}}/locations/{{location}}/volumes/{{volume}}/snapshots/{{snapshot}}`. -# required: true virtual_fields: - !ruby/object:Api::Type::Enum name: 'deletion_policy' diff --git a/mmv1/templates/terraform/examples/volume_basic.tf.erb b/mmv1/templates/terraform/examples/netapp_volume_basic.tf.erb similarity index 100% rename from mmv1/templates/terraform/examples/volume_basic.tf.erb rename to mmv1/templates/terraform/examples/netapp_volume_basic.tf.erb diff --git a/mmv1/third_party/terraform/services/netapp/resource_netapp_volume_test.go b/mmv1/third_party/terraform/services/netapp/resource_netapp_volume_test.go index 386e29eb7f42..81574ec62d00 100644 --- a/mmv1/third_party/terraform/services/netapp/resource_netapp_volume_test.go +++ b/mmv1/third_party/terraform/services/netapp/resource_netapp_volume_test.go @@ -1,20 +1,6 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -// ---------------------------------------------------------------------------- -// -// *** AUTO GENERATED CODE *** Type: MMv1 *** -// -// ---------------------------------------------------------------------------- -// -// This file is automatically generated by Magic Modules and manual -// changes will be clobbered when the file is regenerated. -// -// Please read more about how to change this file in -// .github/CONTRIBUTING.md. -// -// ---------------------------------------------------------------------------- - package netapp_test import ( @@ -25,7 +11,7 @@ import ( "github.com/hashicorp/terraform-provider-google/google/acctest" ) -func TestAccNetappVolume_volumeBasicExample_update(t *testing.T) { +func TestAccNetappVolume_netappVolumeBasicExample_update(t *testing.T) { t.Parallel() context := map[string]interface{}{ @@ -45,7 +31,7 @@ func TestAccNetappVolume_volumeBasicExample_update(t *testing.T) { ResourceName: "google_netapp_volume.test_volume", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "name", "labels", "terraform_labels", "deletion_policy"}, + ImportStateVerifyIgnore: []string{"restore_parameters", "location", "name", "deletion_policy", "labels", "terraform_labels"}, }, { Config: testAccNetappVolume_volumeBasicExample_full(context), }, @@ -53,7 +39,7 @@ func TestAccNetappVolume_volumeBasicExample_update(t *testing.T) { ResourceName: "google_netapp_volume.test_volume", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "name", "labels", "terraform_labels", "deletion_policy"}, + ImportStateVerifyIgnore: []string{"restore_parameters", "location", "name", "deletion_policy", "labels", "terraform_labels"}, }, { Config: testAccNetappVolume_volumeBasicExample_update(context), @@ -62,7 +48,7 @@ func TestAccNetappVolume_volumeBasicExample_update(t *testing.T) { ResourceName: "google_netapp_volume.test_volume", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "name", "labels", "terraform_labels", "deletion_policy"}, + ImportStateVerifyIgnore: []string{"restore_parameters", "location", "name", "deletion_policy", "labels", "terraform_labels"}, }, { Config: testAccNetappVolume_volumeBasicExample_updatesnapshot(context), @@ -71,7 +57,16 @@ func TestAccNetappVolume_volumeBasicExample_update(t *testing.T) { ResourceName: "google_netapp_volume.test_volume", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "name", "labels", "terraform_labels", "deletion_policy"}, + ImportStateVerifyIgnore: []string{"restore_parameters", "location", "name", "deletion_policy", "labels", "terraform_labels"}, + }, + { + Config: testAccNetappVolume_volumeBasicExample_createclonevolume(context), + }, + { + ResourceName: "google_netapp_volume.test_volume_clone", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"restore_parameters", "location", "name", "deletion_policy", "labels", "terraform_labels"}, }, }, }) @@ -80,24 +75,24 @@ func TestAccNetappVolume_volumeBasicExample_update(t *testing.T) { func testAccNetappVolume_volumeBasicExample_basic(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_netapp_storage_pool" "default" { - name = "tf-test-test-pool%{random_suffix}" - location = "us-west2" - service_level = "PREMIUM" - capacity_gib = "2048" - network = data.google_compute_network.default.id + name = "tf-test-test-pool%{random_suffix}" + location = "us-west2" + service_level = "PREMIUM" + capacity_gib = "2048" + network = data.google_compute_network.default.id } resource "google_netapp_volume" "test_volume" { - location = "us-west2" - name = "tf-test-test-volume%{random_suffix}" - capacity_gib = "100" - share_name = "tf-test-test-volume%{random_suffix}" - storage_pool = google_netapp_storage_pool.default.name - protocols = ["NFSV3"] + location = "us-west2" + name = "tf-test-test-volume%{random_suffix}" + capacity_gib = "100" + share_name = "tf-test-test-volume%{random_suffix}" + storage_pool = google_netapp_storage_pool.default.name + protocols = ["NFSV3"] } data "google_compute_network" "default" { - name = "%{network_name}" + name = "%{network_name}" } `, context) } @@ -105,237 +100,298 @@ data "google_compute_network" "default" { func testAccNetappVolume_volumeBasicExample_full(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_netapp_storage_pool" "default" { - name = "tf-test-test-pool%{random_suffix}" - location = "us-west2" - service_level = "PREMIUM" - capacity_gib = "2048" - network = data.google_compute_network.default.id + name = "tf-test-test-pool%{random_suffix}" + location = "us-west2" + service_level = "PREMIUM" + capacity_gib = "2048" + network = data.google_compute_network.default.id } - + resource "google_netapp_storage_pool" "default2" { - name = "tf-test-pool%{random_suffix}" - location = "us-west2" - service_level = "EXTREME" - capacity_gib = "2048" - network = data.google_compute_network.default.id + name = "tf-test-pool%{random_suffix}" + location = "us-west2" + service_level = "EXTREME" + capacity_gib = "2048" + network = data.google_compute_network.default.id } - + resource "google_netapp_volume" "test_volume" { - location = "us-west2" - name = "tf-test-test-volume%{random_suffix}" - capacity_gib = "100" - share_name = "tf-test-test-volume%{random_suffix}" - storage_pool = google_netapp_storage_pool.default.name - protocols = ["NFSV3"] - smb_settings = [] - unix_permissions = "0770" - labels = { - key= "test" - value= "pool" - } - description = "This is a test description" - snapshot_directory = false - security_style = "UNIX" - kerberos_enabled = false - export_policy { - rules { - access_type = "READ_ONLY" - allowed_clients = "0.0.0.0/0" - has_root_access = "false" - kerberos5_read_only = false - kerberos5_read_write = false - kerberos5i_read_only = false - kerberos5i_read_write = false - kerberos5p_read_only = false - kerberos5p_read_write = false - nfsv3 = true - nfsv4 = false - } - rules { - access_type = "READ_WRITE" - allowed_clients = "10.2.3.4,10.2.3.5" - has_root_access = "true" - kerberos5_read_only = false - kerberos5_read_write = false - kerberos5i_read_only = false - kerberos5i_read_write = false - kerberos5p_read_only = false - kerberos5p_read_write = false - nfsv3 = true - nfsv4 = false - } - } - restricted_actions = [] - snapshot_policy { - daily_schedule { - snapshots_to_keep = 2 - } - enabled = true - hourly_schedule { - snapshots_to_keep = 2 - } - monthly_schedule { - snapshots_to_keep = 4 - } - weekly_schedule { - snapshots_to_keep = 2 - } - } + location = "us-west2" + name = "tf-test-test-volume%{random_suffix}" + capacity_gib = "100" + share_name = "tf-test-test-volume%{random_suffix}" + storage_pool = google_netapp_storage_pool.default.name + protocols = ["NFSV3"] + smb_settings = [] + unix_permissions = "0770" + labels = { + key= "test" + value= "pool" + } + description = "This is a test description" + snapshot_directory = false + security_style = "UNIX" + kerberos_enabled = false + export_policy { + rules { + access_type = "READ_ONLY" + allowed_clients = "0.0.0.0/0" + has_root_access = "false" + kerberos5_read_only = false + kerberos5_read_write = false + kerberos5i_read_only = false + kerberos5i_read_write = false + kerberos5p_read_only = false + kerberos5p_read_write = false + nfsv3 = true + nfsv4 = false + } + rules { + access_type = "READ_WRITE" + allowed_clients = "10.2.3.4,10.2.3.5" + has_root_access = "true" + kerberos5_read_only = false + kerberos5_read_write = false + kerberos5i_read_only = false + kerberos5i_read_write = false + kerberos5p_read_only = false + kerberos5p_read_write = false + nfsv3 = true + nfsv4 = false + } + } + restricted_actions = [] + snapshot_policy { + daily_schedule { + snapshots_to_keep = 2 + } + enabled = true + hourly_schedule { + snapshots_to_keep = 2 + } + monthly_schedule { + snapshots_to_keep = 4 + } + weekly_schedule { + snapshots_to_keep = 2 + } + } } data "google_compute_network" "default" { - name = "%{network_name}" + name = "%{network_name}" } `, context) } func testAccNetappVolume_volumeBasicExample_update(context map[string]interface{}) string { return acctest.Nprintf(` - resource "google_netapp_storage_pool" "default" { - name = "tf-test-test-pool%{random_suffix}" - location = "us-west2" - service_level = "PREMIUM" - capacity_gib = "2048" - network = data.google_compute_network.default.id + name = "tf-test-test-pool%{random_suffix}" + location = "us-west2" + service_level = "PREMIUM" + capacity_gib = "2048" + network = data.google_compute_network.default.id } - + resource "google_netapp_storage_pool" "default2" { - name = "tf-test-pool%{random_suffix}" - location = "us-west2" - service_level = "EXTREME" - capacity_gib = "2048" - network = data.google_compute_network.default.id + name = "tf-test-pool%{random_suffix}" + location = "us-west2" + service_level = "EXTREME" + capacity_gib = "2048" + network = data.google_compute_network.default.id } resource "google_netapp_volume" "test_volume" { - location = "us-west2" - name = "tf-test-test-volume%{random_suffix}" - capacity_gib = "200" - share_name = "tf-test-test-volume%{random_suffix}" - storage_pool = google_netapp_storage_pool.default2.name - protocols = ["NFSV3"] - smb_settings = [] - unix_permissions = "0740" - labels = {} - description = "" - snapshot_directory = true - security_style = "UNIX" - kerberos_enabled = false - export_policy { - rules { - access_type = "READ_WRITE" - allowed_clients = "0.0.0.0/0" - has_root_access = "true" - kerberos5_read_only = false - kerberos5_read_write = false - kerberos5i_read_only = false - kerberos5i_read_write = false - kerberos5p_read_only = false - kerberos5p_read_write = false - nfsv3 = true - nfsv4 = false - } - } - restricted_actions = ["DELETE"] - snapshot_policy { - enabled = true - daily_schedule { - hour = 1 - minute = 2 - snapshots_to_keep = 1 - } - hourly_schedule { - minute = 10 - snapshots_to_keep = 1 - } - monthly_schedule { - days_of_month = "2" - hour = 3 - minute = 4 - snapshots_to_keep = 1 - } - weekly_schedule { - day = "Monday" - hour = 5 - minute = 6 - snapshots_to_keep = 1 - } - } + location = "us-west2" + name = "tf-test-test-volume%{random_suffix}" + capacity_gib = "200" + share_name = "tf-test-test-volume%{random_suffix}" + storage_pool = google_netapp_storage_pool.default2.name + protocols = ["NFSV3"] + smb_settings = [] + unix_permissions = "0740" + labels = {} + description = "" + snapshot_directory = true + security_style = "UNIX" + kerberos_enabled = false + export_policy { + rules { + access_type = "READ_WRITE" + allowed_clients = "0.0.0.0/0" + has_root_access = "true" + kerberos5_read_only = false + kerberos5_read_write = false + kerberos5i_read_only = false + kerberos5i_read_write = false + kerberos5p_read_only = false + kerberos5p_read_write = false + nfsv3 = true + nfsv4 = false + } + } + # Delete protection only gets active after an NFS client mounts. + # Setting it here is save, volume can still be deleted. + deletion_policy = "FORCE" + snapshot_policy { + enabled = true + daily_schedule { + hour = 1 + minute = 2 + snapshots_to_keep = 1 + } + hourly_schedule { + minute = 10 + snapshots_to_keep = 1 + } + monthly_schedule { + days_of_month = "2" + hour = 3 + minute = 4 + snapshots_to_keep = 1 + } + weekly_schedule { + day = "Monday" + hour = 5 + minute = 6 + snapshots_to_keep = 1 + } + } } data "google_compute_network" "default" { - name = "%{network_name}" + name = "%{network_name}" } `, context) } func testAccNetappVolume_volumeBasicExample_updatesnapshot(context map[string]interface{}) string { return acctest.Nprintf(` +resource "google_netapp_storage_pool" "default2" { + name = "tf-test-pool%{random_suffix}" + location = "us-west2" + service_level = "EXTREME" + capacity_gib = "2048" + network = data.google_compute_network.default.id +} + +resource "google_netapp_volume" "test_volume" { + location = "us-west2" + name = "tf-test-test-volume%{random_suffix}" + capacity_gib = "200" + share_name = "tf-test-test-volume%{random_suffix}" + storage_pool = google_netapp_storage_pool.default2.name + protocols = ["NFSV3"] + smb_settings = [] + unix_permissions = "0740" + labels = {} + description = "" + snapshot_directory = true + security_style = "UNIX" + kerberos_enabled = false + export_policy { + rules { + access_type = "READ_WRITE" + allowed_clients = "0.0.0.0/0" + has_root_access = "true" + kerberos5_read_only = false + kerberos5_read_write = false + kerberos5i_read_only = false + kerberos5i_read_write = false + kerberos5p_read_only = false + kerberos5p_read_write = false + nfsv3 = true + nfsv4 = false + } + } + # Delete protection only gets active after an NFS client mounts. + # Setting it here is save, volume can still be deleted. + restricted_actions = ["DELETE"] + deletion_policy = "FORCE" +} -resource "google_netapp_storage_pool" "default" { - name = "tf-test-test-pool%{random_suffix}" - location = "us-west2" - service_level = "PREMIUM" - capacity_gib = "2048" - network = data.google_compute_network.default.id +resource "google_netapp_volume_snapshot" "test-snapshot" { + depends_on = [google_netapp_volume.test_volume] + location = google_netapp_volume.test_volume.location + volume_name = google_netapp_volume.test_volume.name + name = "test-snapshot" +} + +data "google_compute_network" "default" { + name = "%{network_name}" +} + `, context) } - + +// Tests creating a new volume (clone) from a snapshot created from existing volume +func testAccNetappVolume_volumeBasicExample_createclonevolume(context map[string]interface{}) string { + return acctest.Nprintf(` resource "google_netapp_storage_pool" "default2" { - name = "tf-test-pool%{random_suffix}" - location = "us-west2" - service_level = "EXTREME" - capacity_gib = "2048" - network = data.google_compute_network.default.id + name = "tf-test-pool%{random_suffix}" + location = "us-west2" + service_level = "EXTREME" + capacity_gib = "2048" + network = data.google_compute_network.default.id } - + resource "google_netapp_volume" "test_volume" { - location = "us-west2" - name = "tf-test-test-volume%{random_suffix}" - capacity_gib = "200" - share_name = "tf-test-test-volume%{random_suffix}" - storage_pool = google_netapp_storage_pool.default2.name - protocols = ["NFSV3"] - smb_settings = [] - unix_permissions = "0740" - labels = {} - description = "" - snapshot_directory = true - security_style = "UNIX" - kerberos_enabled = false - export_policy { - rules { - access_type = "READ_WRITE" - allowed_clients = "0.0.0.0/0" - has_root_access = "true" - kerberos5_read_only = false - kerberos5_read_write = false - kerberos5i_read_only = false - kerberos5i_read_write = false - kerberos5p_read_only = false - kerberos5p_read_write = false - nfsv3 = true - nfsv4 = false - } - } - # Delete protection only gets active after an NFS client mounts. - # Setting it here is save, volume can still be deleted. - restricted_actions = ["DELETE"] - deletion_policy = "FORCE" + location = "us-west2" + name = "tf-test-test-volume%{random_suffix}" + capacity_gib = "200" + share_name = "tf-test-test-volume%{random_suffix}" + storage_pool = google_netapp_storage_pool.default2.name + protocols = ["NFSV3"] + smb_settings = [] + unix_permissions = "0740" + labels = {} + description = "" + snapshot_directory = true + security_style = "UNIX" + kerberos_enabled = false + export_policy { + rules { + access_type = "READ_WRITE" + allowed_clients = "0.0.0.0/0" + has_root_access = "true" + kerberos5_read_only = false + kerberos5_read_write = false + kerberos5i_read_only = false + kerberos5i_read_write = false + kerberos5p_read_only = false + kerberos5p_read_write = false + nfsv3 = true + nfsv4 = false + } + } + # Delete protection only gets active after an NFS client mounts. + # Setting it here is save, volume can still be deleted. + restricted_actions = ["DELETE"] + deletion_policy = "FORCE" } -# Add the following snapshot block to the test as soon as snapshot resoruce -# is added to the provider. It will make the test cleanup require -# deletion_policy = "FORCE" on the volume for successful delete. -# resource "google_netapp_volumesnapshot" "test-snapshot" { -# depends_on = [google_netapp_volume.test_volume] -# location = google_netapp_volume.test_volume.location -# volume_name = google_netapp_volume.test_volume.name -# name = "test-snapshot%{random_suffix}" -# } +resource "google_netapp_volume_snapshot" "test-snapshot" { + depends_on = [google_netapp_volume.test_volume] + location = google_netapp_volume.test_volume.location + volume_name = google_netapp_volume.test_volume.name + name = "test-snapshot" +} + +resource "google_netapp_volume" "test_volume_clone" { + location = "us-west2" + name = "tf-test-test-volume-clone%{random_suffix}" + capacity_gib = "200" + share_name = "tf-test-test-volume-clone%{random_suffix}" + storage_pool = google_netapp_storage_pool.default2.name + protocols = ["NFSV3"] + deletion_policy = "FORCE" + restore_parameters { + source_snapshot = google_netapp_volume_snapshot.test-snapshot.id + } +} data "google_compute_network" "default" { - name = "%{network_name}" + name = "%{network_name}" } `, context) } From a7be02a81382c71ab5647986ef63b01c795da7cb Mon Sep 17 00:00:00 2001 From: Timofey Yushchenko Date: Thu, 15 Feb 2024 23:08:44 +0100 Subject: [PATCH 17/77] Fix updating NIC stack type for google compute instance (#9983) Co-authored-by: Timofey Yushchenko --- .../compute/resource_compute_instance.go.erb | 19 ++++- .../resource_compute_instance_test.go.erb | 74 +++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.erb index 97069c02ca59..3fb7c963acf1 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.erb @@ -444,7 +444,7 @@ func ResourceComputeInstance() *schema.Resource { "ipv6_access_config": { Type: schema.TypeList, - Optional: true, + Optional: true, Description: `An array of IPv6 access configurations for this interface. Currently, only one IPv6 access config, DIRECT_IPV6, is supported. If there is no ipv6AccessConfig specified, then this instance will have no external IPv6 Internet access.`, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ @@ -2067,6 +2067,23 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err } } + if !updateDuringStop && d.HasChange(prefix+".stack_type") { + + networkInterfacePatchObj := &compute.NetworkInterface{ + StackType: d.Get(prefix+".stack_type").(string), + Fingerprint: instNetworkInterface.Fingerprint, + } + updateCall := config.NewComputeClient(userAgent).Instances.UpdateNetworkInterface(project, zone, instance.Name, networkName, networkInterfacePatchObj).Do + op, err := updateCall() + if err != nil { + return errwrap.Wrapf("Error updating network interface: {{err}}", err) + } + opErr := ComputeOperationWaitTime(config, op, project, "network interface to update", userAgent, d.Timeout(schema.TimeoutUpdate)) + if opErr != nil { + return opErr + } + } + if !updateDuringStop && d.HasChange(prefix+".ipv6_address") { networkInterfacePatchObj := &compute.NetworkInterface{ diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_test.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_instance_test.go.erb index c86796109098..bbed47e387b2 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance_test.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_test.go.erb @@ -3279,6 +3279,33 @@ func TestAccComputeInstance_NetworkAttachmentUpdate(t *testing.T) { } <% end %> +func TestAccComputeInstance_NicStackTypeUpdate(t *testing.T) { + t.Parallel() + suffix := acctest.RandString(t, 10) + envRegion := envvar.GetTestRegionFromEnv() + instanceName := fmt.Sprintf("tf-test-compute-instance-%s", suffix) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeInstance_nicStackTypeUpdate(suffix, envRegion, "IPV4_ONLY", instanceName), + }, + computeInstanceImportStep("us-central1-a", instanceName, []string{"allow_stopping_for_update"}), + { + Config: testAccComputeInstance_nicStackTypeUpdate(suffix, envRegion, "IPV4_IPV6", instanceName), + }, + computeInstanceImportStep("us-central1-a", instanceName, []string{"allow_stopping_for_update"}), + { + Config: testAccComputeInstance_nicStackTypeUpdate(suffix, envRegion, "IPV4_ONLY", instanceName), + }, + computeInstanceImportStep("us-central1-a", instanceName, []string{"allow_stopping_for_update"}), + }, + }) +} + func testAccCheckComputeInstanceDestroyProducer(t *testing.T) func(s *terraform.State) error { return func(s *terraform.State) error { config := acctest.GoogleProviderConfig(t) @@ -8964,3 +8991,50 @@ resource "google_compute_instance" "foobar" { } <% end %> +func testAccComputeInstance_nicStackTypeUpdate(suffix, region, stack_type, instance string) string { + return fmt.Sprintf(` +data "google_compute_image" "my_image" { + family = "debian-11" + project = "debian-cloud" +} + +resource "google_compute_network" "net" { + name = "tf-test-network-%s" + enable_ula_internal_ipv6 = true + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "subnet-ipv6" { + region = "%s" + name = "tf-test-subnet-ip6-%s" + ip_cidr_range = "10.0.0.0/22" + purpose = "PRIVATE" + stack_type = "IPV4_IPV6" + ipv6_access_type = "INTERNAL" + network = google_compute_network.net.id +} + +resource "google_compute_instance" "foobar" { + name = "%s" + machine_type = "e2-medium" + zone = "%s-a" + tags = ["foo", "bar"] + + boot_disk { + initialize_params { + image = data.google_compute_image.my_image.self_link + } + } + + network_interface { + network = google_compute_network.net.self_link + subnetwork = google_compute_subnetwork.subnet-ipv6.self_link + stack_type = "%s" + } + + metadata = { + foo = "bar" + } +} +`, suffix, region, suffix, instance, region, stack_type) +} From 5c294ad788a678bcc4685aff0eb8ee07cdb6a1d4 Mon Sep 17 00:00:00 2001 From: "Stephen Lewis (Burrows)" Date: Thu, 15 Feb 2024 15:05:04 -0800 Subject: [PATCH 18/77] Separated review requests into a github action (#9992) * Separated review requests into a github action * Removed CODEOWNERS --- .ci/magician/cmd/membership_checker.go | 35 ------ .ci/magician/cmd/membership_checker_test.go | 60 +--------- .ci/magician/cmd/request_reviewer.go | 102 +++++++++++++++++ .ci/magician/cmd/request_reviewer_test.go | 103 ++++++++++++++++++ .../github/REVIEWER_ASSIGNMENT_COMMENT.md | 2 +- .ci/magician/github/membership.go | 19 ++-- .ci/magician/github/reviewer_assignment.go | 10 +- .../github/reviewer_assignment_test.go | 19 +--- .github/workflows/request-reviewer.yml | 38 +++++++ CODEOWNERS | 1 - 10 files changed, 263 insertions(+), 126 deletions(-) create mode 100644 .ci/magician/cmd/request_reviewer.go create mode 100644 .ci/magician/cmd/request_reviewer_test.go create mode 100644 .github/workflows/request-reviewer.yml diff --git a/.ci/magician/cmd/membership_checker.go b/.ci/magician/cmd/membership_checker.go index bc37d0c7234d..4af9c95b81bc 100644 --- a/.ci/magician/cmd/membership_checker.go +++ b/.ci/magician/cmd/membership_checker.go @@ -97,41 +97,6 @@ func execMembershipChecker(prNumber, commitSha, branchName, headRepoUrl, headBra authorUserType := gh.GetUserType(author) trusted := authorUserType == github.CoreContributorUserType || authorUserType == github.GooglerUserType - if authorUserType != github.CoreContributorUserType { - fmt.Println("Not core contributor - assigning reviewer") - - requestedReviewers, err := gh.GetPullRequestRequestedReviewers(prNumber) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - previousReviewers, err := gh.GetPullRequestPreviousReviewers(prNumber) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - reviewersToRequest, newPrimaryReviewer := github.ChooseCoreReviewers(requestedReviewers, previousReviewers) - - for _, reviewer := range reviewersToRequest { - err = gh.RequestPullRequestReviewer(prNumber, reviewer) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - } - - if newPrimaryReviewer != "" { - comment := github.FormatReviewerComment(newPrimaryReviewer, authorUserType, trusted) - err = gh.PostComment(prNumber, comment) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - } - } - // auto_run(contributor-membership-checker) will be run on every commit or /gcbrun: // only triggers builds for trusted users if trusted { diff --git a/.ci/magician/cmd/membership_checker_test.go b/.ci/magician/cmd/membership_checker_test.go index 93b3805d29f4..a3a40b4b89bd 100644 --- a/.ci/magician/cmd/membership_checker_test.go +++ b/.ci/magician/cmd/membership_checker_test.go @@ -18,7 +18,6 @@ package cmd import ( "magician/github" "reflect" - "regexp" "testing" ) @@ -78,20 +77,7 @@ func TestExecMembershipChecker_GooglerFlow(t *testing.T) { execMembershipChecker("pr1", "sha1", "branch1", "url1", "head1", "base1", gh, cb) - method := "RequestPullRequestReviewer" - if calls, ok := gh.calledMethods[method]; !ok { - t.Fatal("Review wasn't requested for googler") - } else if len(calls) != 1 { - t.Fatalf("Wrong number of calls for %s, got %d, expected 1", method, len(calls)) - } else if params := calls[0]; len(params) != 2 { - t.Fatalf("Wrong number of params for %s, got %d, expected 2", method, len(params)) - } else if param := params[0]; param != "pr1" { - t.Fatalf("Wrong first param for %s, got %v, expected pr1", method, param) - } else if param := params[1]; !github.IsTeamReviewer(param.(string)) { - t.Fatalf("Wrong second param for %s, got %v, expected a team reviewer", method, param) - } - - method = "TriggerMMPresubmitRuns" + method := "TriggerMMPresubmitRuns" expected := [][]any{{"sha1", map[string]string{"BRANCH_NAME": "branch1", "_BASE_BRANCH": "base1", "_HEAD_BRANCH": "head1", "_HEAD_REPO_URL": "url1", "_PR_NUMBER": "pr1"}}} if calls, ok := cb.calledMethods[method]; !ok { t.Fatal("Presubmit runs not triggered for googler") @@ -126,20 +112,7 @@ func TestExecMembershipChecker_AmbiguousUserFlow(t *testing.T) { execMembershipChecker("pr1", "sha1", "branch1", "url1", "head1", "base1", gh, cb) - method := "RequestPullRequestReviewer" - if calls, ok := gh.calledMethods[method]; !ok { - t.Fatal("Review wasn't requested for ambiguous user") - } else if len(calls) != 1 { - t.Fatalf("Wrong number of calls for %s, got %d, expected 1", method, len(calls)) - } else if params := calls[0]; len(params) != 2 { - t.Fatalf("Wrong number of params for %s, got %d, expected 2", method, len(params)) - } else if param := params[0]; param != "pr1" { - t.Fatalf("Wrong first param for %s, got %v, expected pr1", method, param) - } else if param := params[1]; !github.IsTeamReviewer(param.(string)) { - t.Fatalf("Wrong second param for %s, got %v, expected a team reviewer", method, param) - } - - method = "AddLabel" + method := "AddLabel" expected := [][]any{{"pr1", "awaiting-approval"}} if calls, ok := gh.calledMethods[method]; !ok { t.Fatal("Label wasn't posted to pull request") @@ -181,33 +154,4 @@ func TestExecMembershipChecker_CommentForNewPrimaryReviewer(t *testing.T) { } execMembershipChecker("pr1", "sha1", "branch1", "url1", "head1", "base1", gh, cb) - - method := "RequestPullRequestReviewer" - if calls, ok := gh.calledMethods[method]; !ok { - t.Fatal("Review wasn't requested for googler") - } else if len(calls) != 1 { - t.Fatalf("Wrong number of calls for %s, got %d, expected 1", method, len(calls)) - } else if params := calls[0]; len(params) != 2 { - t.Fatalf("Wrong number of params for %s, got %d, expected 2", method, len(params)) - } else if param := params[0]; param != "pr1" { - t.Fatalf("Wrong first param for %s, got %v, expected pr1", method, param) - } else if param := params[1]; !github.IsTeamReviewer(param.(string)) { - t.Fatalf("Wrong second param for %s, got %v, expected a team reviewer", method, param) - } - - method = "PostComment" - reviewerExp := regexp.MustCompile(`@(.*?),`) - if calls, ok := gh.calledMethods[method]; !ok { - t.Fatal("Comment wasn't posted stating user status") - } else if len(calls) != 1 { - t.Fatalf("Wrong number of calls for %s, got %d, expected 1", method, len(calls)) - } else if params := calls[0]; len(params) != 2 { - t.Fatalf("Wrong number of params for %s, got %d, expected 2", method, len(params)) - } else if param := params[0]; param != "pr1" { - t.Fatalf("Wrong first param for %s, got %v, expected pr1", method, param) - } else if param, ok := params[1].(string); !ok { - t.Fatalf("Got non-string second param for %s", method) - } else if submatches := reviewerExp.FindStringSubmatch(param); len(submatches) != 2 || !github.IsTeamReviewer(submatches[1]) { - t.Fatalf("%s called without a team reviewer (found %v) in the comment: %s", method, submatches, param) - } } diff --git a/.ci/magician/cmd/request_reviewer.go b/.ci/magician/cmd/request_reviewer.go new file mode 100644 index 000000000000..b5deed4e828e --- /dev/null +++ b/.ci/magician/cmd/request_reviewer.go @@ -0,0 +1,102 @@ +/* +* Copyright 2024 Google LLC. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. + */ +package cmd + +import ( + "fmt" + "magician/github" + "os" + + "github.com/spf13/cobra" +) + +// requestReviewerCmd represents the requestReviewer command +var requestReviewerCmd = &cobra.Command{ + Use: "request-reviewer", + Short: "Assigns and re-requests reviewers", + Long: `This command automatically requests (or re-requests) core contributor reviews for a PR based on whether the user is a core contributor. + + The command expects the following pull request details as arguments: + 1. PR Number + 2. Commit SHA + 3. Branch Name + 4. Head Repo URL + 5. Head Branch + 6. Base Branch + + It then performs the following operations: + 1. Determines the author of the pull request + 2. If the author is not a core contributor: + a. Identifies the initially requested reviewer and those who previously reviewed this PR. + b. Determines and requests reviewers based on the above. + c. As appropriate, posts a welcome comment on the PR. + `, + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + prNumber := args[0] + fmt.Println("PR Number: ", prNumber) + gh := github.NewClient() + execRequestReviewer(prNumber, gh) + }, +} + +func execRequestReviewer(prNumber string, gh GithubClient) { + pullRequest, err := gh.GetPullRequest(prNumber) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + author := pullRequest.User.Login + if !github.IsCoreContributor(author) { + fmt.Println("Not core contributor - assigning reviewer") + + requestedReviewers, err := gh.GetPullRequestRequestedReviewers(prNumber) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + previousReviewers, err := gh.GetPullRequestPreviousReviewers(prNumber) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + reviewersToRequest, newPrimaryReviewer := github.ChooseCoreReviewers(requestedReviewers, previousReviewers) + + for _, reviewer := range reviewersToRequest { + err = gh.RequestPullRequestReviewer(prNumber, reviewer) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + } + + if newPrimaryReviewer != "" { + comment := github.FormatReviewerComment(newPrimaryReviewer) + err = gh.PostComment(prNumber, comment) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + } + } +} + +func init() { + rootCmd.AddCommand(requestReviewerCmd) +} diff --git a/.ci/magician/cmd/request_reviewer_test.go b/.ci/magician/cmd/request_reviewer_test.go new file mode 100644 index 000000000000..d3daa08960f4 --- /dev/null +++ b/.ci/magician/cmd/request_reviewer_test.go @@ -0,0 +1,103 @@ +/* +* Copyright 2024 Google LLC. All Rights Reserved. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. + */ + +package cmd + +import ( + "github.com/stretchr/testify/assert" + "magician/github" + "testing" +) + +func TestExecRequestReviewer(t *testing.T) { + availableReviewers := github.AvailableReviewers() + cases := map[string]struct { + pullRequest github.PullRequest + requestedReviewers []string + previousReviewers []string + teamMembers map[string][]string + expectSpecificReviewers []string + expectReviewersFromList []string + }{ + "core contributor author doesn't get a new reviewer, re-request, or comment with no previous reviewers": { + pullRequest: github.PullRequest{ + User: github.User{Login: availableReviewers[0]}, + }, + expectSpecificReviewers: []string{}, + }, + "core contributor author doesn't get a new reviewer, re-request, or comment with previous reviewers": { + pullRequest: github.PullRequest{ + User: github.User{Login: availableReviewers[0]}, + }, + previousReviewers: []string{availableReviewers[1]}, + expectSpecificReviewers: []string{}, + }, + "non-core-contributor author gets a new reviewer with no previous reviewers": { + pullRequest: github.PullRequest{ + User: github.User{Login: "author"}, + }, + expectReviewersFromList: availableReviewers, + }, + "non-core-contributor author doesn't get a new reviewer (but does get re-request) with previous reviewers": { + pullRequest: github.PullRequest{ + User: github.User{Login: "author"}, + }, + previousReviewers: []string{availableReviewers[1], "author2", availableReviewers[2]}, + expectSpecificReviewers: []string{availableReviewers[1], availableReviewers[2]}, + }, + "non-core-contributor author doesn't get a new reviewer or a re-request with already-requested reviewers": { + pullRequest: github.PullRequest{ + User: github.User{Login: "author"}, + }, + requestedReviewers: []string{availableReviewers[1], "author2", availableReviewers[2]}, + expectSpecificReviewers: []string{}, + }, + } + for tn, tc := range cases { + t.Run(tn, func(t *testing.T) { + requestedReviewers := []github.User{} + for _, login := range tc.requestedReviewers { + requestedReviewers = append(requestedReviewers, github.User{Login: login}) + } + previousReviewers := []github.User{} + for _, login := range tc.previousReviewers { + previousReviewers = append(previousReviewers, github.User{Login: login}) + } + gh := &mockGithub{ + pullRequest: tc.pullRequest, + requestedReviewers: requestedReviewers, + previousReviewers: previousReviewers, + calledMethods: make(map[string][][]any), + } + + execRequestReviewer("1", gh) + + actualReviewers := []string{} + for _, args := range gh.calledMethods["RequestPullRequestReviewer"] { + actualReviewers = append(actualReviewers, args[1].(string)) + } + + if tc.expectSpecificReviewers != nil { + assert.ElementsMatch(t, tc.expectSpecificReviewers, actualReviewers) + } + if tc.expectReviewersFromList != nil { + for _, reviewer := range actualReviewers { + assert.Contains(t, tc.expectReviewersFromList, reviewer) + } + } + }) + } +} diff --git a/.ci/magician/github/REVIEWER_ASSIGNMENT_COMMENT.md b/.ci/magician/github/REVIEWER_ASSIGNMENT_COMMENT.md index 09d5bfc62936..2678f295947d 100644 --- a/.ci/magician/github/REVIEWER_ASSIGNMENT_COMMENT.md +++ b/.ci/magician/github/REVIEWER_ASSIGNMENT_COMMENT.md @@ -1,4 +1,4 @@ -Hello! I am a robot. It looks like you are a: {{if eq .authorUserType "Community Contributor"}}Community Contributor{{else}}~Community Contributor~{{end}} {{if eq .authorUserType "Googler"}}Googler{{else}}~Googler~{{end}} {{if eq .authorUserType "Core Contributor"}}Core Contributor{{else}}~Core Contributor~{{end}}. {{if .trusted}}Tests will run automatically.{{else}}Tests will require approval to run.{{end}} +Hello! I am a robot. Tests will require approval from a repository maintainer to run. @{{.reviewer}}, a repository maintainer, has been assigned to review your changes. If you have not received review feedback within 2 business days, please leave a comment on this PR asking them to take a look. diff --git a/.ci/magician/github/membership.go b/.ci/magician/github/membership.go index c6a8349fb0bb..fd151935d98b 100644 --- a/.ci/magician/github/membership.go +++ b/.ci/magician/github/membership.go @@ -43,8 +43,7 @@ var ( } // This is for new team members who are onboarding - trustedContributors = []string{ - } + trustedContributors = []string{} // This is for reviewers who are "on vacation": will not receive new review assignments but will still receive re-requests for assigned PRs. onVacationReviewers = []string{ @@ -74,8 +73,8 @@ func (ut UserType) String() string { } func (gh *Client) GetUserType(user string) UserType { - if isTeamMember(user, gh.token) { - fmt.Println("User is a team member") + if IsCoreContributor(user) { + fmt.Println("User is a core contributor") return CoreContributorUserType } @@ -93,11 +92,11 @@ func (gh *Client) GetUserType(user string) UserType { } // Check if a user is team member to not request a random reviewer -func isTeamMember(author, githubToken string) bool { - return slices.Contains(reviewerRotation, author) || slices.Contains(trustedContributors, author) +func IsCoreContributor(user string) bool { + return slices.Contains(reviewerRotation, user) || slices.Contains(trustedContributors, user) } -func IsTeamReviewer(reviewer string) bool { +func IsCoreReviewer(reviewer string) bool { return slices.Contains(reviewerRotation, reviewer) } @@ -112,8 +111,12 @@ func isOrgMember(author, org, githubToken string) bool { } func GetRandomReviewer() string { - availableReviewers := utils.Removes(reviewerRotation, onVacationReviewers) + availableReviewers := AvailableReviewers() rand.Seed(time.Now().UnixNano()) reviewer := availableReviewers[rand.Intn(len(availableReviewers))] return reviewer } + +func AvailableReviewers() []string { + return utils.Removes(reviewerRotation, onVacationReviewers) +} diff --git a/.ci/magician/github/reviewer_assignment.go b/.ci/magician/github/reviewer_assignment.go index 23651a15b1a0..d06415bab810 100644 --- a/.ci/magician/github/reviewer_assignment.go +++ b/.ci/magician/github/reviewer_assignment.go @@ -34,14 +34,14 @@ func ChooseCoreReviewers(requestedReviewers, previousReviewers []User) (reviewer newPrimaryReviewer = "" for _, reviewer := range requestedReviewers { - if IsTeamReviewer(reviewer.Login) { + if IsCoreReviewer(reviewer.Login) { hasPrimaryReviewer = true break } } for _, reviewer := range previousReviewers { - if IsTeamReviewer(reviewer.Login) { + if IsCoreReviewer(reviewer.Login) { hasPrimaryReviewer = true reviewersToRequest = append(reviewersToRequest, reviewer.Login) } @@ -55,16 +55,14 @@ func ChooseCoreReviewers(requestedReviewers, previousReviewers []User) (reviewer return reviewersToRequest, newPrimaryReviewer } -func FormatReviewerComment(newPrimaryReviewer string, authorUserType UserType, trusted bool) string { +func FormatReviewerComment(newPrimaryReviewer string) string { tmpl, err := template.New("REVIEWER_ASSIGNMENT_COMMENT.md").Parse(reviewerAssignmentComment) if err != nil { panic(fmt.Sprintf("Unable to parse REVIEWER_ASSIGNMENT_COMMENT.md: %s", err)) } sb := new(strings.Builder) tmpl.Execute(sb, map[string]any{ - "reviewer": newPrimaryReviewer, - "authorUserType": authorUserType.String(), - "trusted": trusted, + "reviewer": newPrimaryReviewer, }) return sb.String() } diff --git a/.ci/magician/github/reviewer_assignment_test.go b/.ci/magician/github/reviewer_assignment_test.go index 252fc4d61186..6247891fd7db 100644 --- a/.ci/magician/github/reviewer_assignment_test.go +++ b/.ci/magician/github/reviewer_assignment_test.go @@ -127,27 +127,12 @@ func TestFormatReviewerComment(t *testing.T) { tc := tc t.Run(tn, func(t *testing.T) { t.Parallel() - comment := FormatReviewerComment(tc.Reviewer, tc.AuthorUserType, tc.Trusted) + comment := FormatReviewerComment(tc.Reviewer) t.Log(comment) if !strings.Contains(comment, fmt.Sprintf("@%s", tc.Reviewer)) { t.Errorf("wanted comment to contain @%s; does not.", tc.Reviewer) } - if !strings.Contains(comment, tc.AuthorUserType.String()) { - t.Errorf("wanted comment to contain user type (%s); does not.", tc.AuthorUserType.String()) - } - if strings.Contains(comment, fmt.Sprintf("~%s~", tc.AuthorUserType.String())) { - t.Errorf("wanted user type (%s) in comment to not be crossed out, but it is", tc.AuthorUserType.String()) - } - for _, ut := range []UserType{CommunityUserType, GooglerUserType, CoreContributorUserType} { - if ut != tc.AuthorUserType && !strings.Contains(comment, fmt.Sprintf("~%s~", ut.String())) { - t.Errorf("wanted other user type (%s) in comment to be crossed out, but it is not", ut) - } - } - - if tc.Trusted && !strings.Contains(comment, "Tests will run automatically") { - t.Errorf("wanted comment to say tests will run automatically; does not") - } - if !tc.Trusted && !strings.Contains(comment, "Tests will require approval") { + if !strings.Contains(comment, "Tests will require approval") { t.Errorf("wanted comment to say tests will require approval; does not") } }) diff --git a/.github/workflows/request-reviewer.yml b/.github/workflows/request-reviewer.yml new file mode 100644 index 000000000000..56bc1a126220 --- /dev/null +++ b/.github/workflows/request-reviewer.yml @@ -0,0 +1,38 @@ +name: request-reviewer + +permissions: read-all + +on: + pull_request_target: + types: + - edited + - opened + - ready_for_review + - reopened + - synchronize + branches: + - 'main' + - 'FEATURE-BRANCH-*' + +jobs: + request-review: + if: github.event.pull_request.draft == false + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: '^1.20' + - name: Build magician + run: | + cd .ci/magician + go build . + - name: Request reviewer + permissions: + pull-requests: write + run: .ci/magician request-reviewer ${{ github.event.pull_request.number }} + diff --git a/CODEOWNERS b/CODEOWNERS index 5528c7612e1b..e69de29bb2d1 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +0,0 @@ -* @GoogleCloudPlatform/terraform-team From b8b1a940bd477a539feb3148026d756bcb5ef302 Mon Sep 17 00:00:00 2001 From: "Stephen Lewis (Burrows)" Date: Thu, 15 Feb 2024 15:39:19 -0800 Subject: [PATCH 19/77] Corrected request-reviewer permissions to be at the job level (#9995) Step-level permissions are not actually a thing. https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idpermissions --- .github/workflows/request-reviewer.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/request-reviewer.yml b/.github/workflows/request-reviewer.yml index 56bc1a126220..87159d06e52d 100644 --- a/.github/workflows/request-reviewer.yml +++ b/.github/workflows/request-reviewer.yml @@ -18,6 +18,8 @@ jobs: request-review: if: github.event.pull_request.draft == false runs-on: ubuntu-latest + permissions: + pull-requests: write steps: - name: Checkout Repository uses: actions/checkout@v4 @@ -32,7 +34,5 @@ jobs: cd .ci/magician go build . - name: Request reviewer - permissions: - pull-requests: write run: .ci/magician request-reviewer ${{ github.event.pull_request.number }} From cddaf2f52ba09f5d313acee49ec07c01756090e3 Mon Sep 17 00:00:00 2001 From: "Stephen Lewis (Burrows)" Date: Thu, 15 Feb 2024 16:07:43 -0800 Subject: [PATCH 20/77] Fixed path to magician binary (#9996) Also removed unnecessary clone of entire history and resolved node version warning --- .github/workflows/request-reviewer.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/request-reviewer.yml b/.github/workflows/request-reviewer.yml index 87159d06e52d..59f360596b0b 100644 --- a/.github/workflows/request-reviewer.yml +++ b/.github/workflows/request-reviewer.yml @@ -23,16 +23,16 @@ jobs: steps: - name: Checkout Repository uses: actions/checkout@v4 - with: - fetch-depth: 0 - name: Set up Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v5 with: go-version: '^1.20' + # Disable caching for now due to issues with large provider dependency caches + cache: false - name: Build magician run: | cd .ci/magician go build . - name: Request reviewer - run: .ci/magician request-reviewer ${{ github.event.pull_request.number }} + run: .ci/magician/magician request-reviewer ${{ github.event.pull_request.number }} From 95916e9456acc5e3735ecae0575cacbccc7a6206 Mon Sep 17 00:00:00 2001 From: "Stephen Lewis (Burrows)" Date: Thu, 15 Feb 2024 16:17:18 -0800 Subject: [PATCH 21/77] Added missing GITHUB_TOKEN env var (#9997) --- .github/workflows/request-reviewer.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/request-reviewer.yml b/.github/workflows/request-reviewer.yml index 59f360596b0b..2831ec975caa 100644 --- a/.github/workflows/request-reviewer.yml +++ b/.github/workflows/request-reviewer.yml @@ -20,6 +20,8 @@ jobs: runs-on: ubuntu-latest permissions: pull-requests: write + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Checkout Repository uses: actions/checkout@v4 From 0c871aae7350de3dcf693d33a0d9bcd382f9ca2f Mon Sep 17 00:00:00 2001 From: Sarah French <15078782+SarahFrench@users.noreply.github.com> Date: Fri, 16 Feb 2024 13:34:28 +0000 Subject: [PATCH 22/77] Add GHA to run TeamCity config tests on PRs editing `.teamcity` (#9954) * Add GHA to run TeamCity config tests on PRs editing `.teamcity` * Push failing test to check GHA detects it * Remove intentionally failing test --- .github/workflows/teamcity-pr-checks.yml | 46 ++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .github/workflows/teamcity-pr-checks.yml diff --git a/.github/workflows/teamcity-pr-checks.yml b/.github/workflows/teamcity-pr-checks.yml new file mode 100644 index 000000000000..bea371247b07 --- /dev/null +++ b/.github/workflows/teamcity-pr-checks.yml @@ -0,0 +1,46 @@ +name: TeamCity Configuration Tests +permissions: read-all + +on: + workflow_dispatch: + pull_request: + paths: + - '.github/workflows/teamcity-pr-checks.yml' + - 'mmv1/third_party/terraform/!.teamcity' + + +jobs: + teamcity-config-tests: + runs-on: ubuntu-22.04 + steps: + - name: Checkout Repository + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + fetch-depth: 0 + + - name: Setup Java + uses: actions/setup-java@387ac29b308b003ca37ba93a6cab5eb57c8f5f93 # v4.0.0 + with: + distribution: zulu + java-version: 17 + java-package: jdk + + - name: Cache Maven files + uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + with: + path: ~/.m2/repository + key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} + restore-keys: | + ${{ runner.os }}-maven- + + - name: Download TeamCity Tools + run : | + cd mmv1/third_party/terraform/.teamcity + make tools + + # Running the tests twice ensures that the tests are discovered and run + - name: Run TeamCity Tests + run : | + cd mmv1/third_party/terraform/.teamcity + make test + make test \ No newline at end of file From 8c99637f3dda5efde734c02861e13e98e54bf4b1 Mon Sep 17 00:00:00 2001 From: askubis Date: Fri, 16 Feb 2024 15:53:39 +0100 Subject: [PATCH 23/77] additional fixes for stateful ips (#9965) --- .../compute/resource_compute_instance_group_manager.go.erb | 7 ------- .../resource_compute_region_instance_group_manager.go.erb | 7 ------- ...ource_compute_region_instance_group_manager_test.go.erb | 2 -- 3 files changed, 16 deletions(-) diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager.go.erb index 3dc61dfc1d17..d61f2457be99 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager.go.erb @@ -904,17 +904,10 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte } <% end -%> - <% unless version == "ga" -%> if d.HasChange("stateful_internal_ip") || d.HasChange("stateful_external_ip") || d.HasChange("stateful_disk") { updatedManager.StatefulPolicy = expandStatefulPolicy(d) change = true } - <% else -%> - if d.HasChange("stateful_disk") { - updatedManager.StatefulPolicy = expandStatefulPolicy(d) - change = true - } - <% end -%> if d.HasChange("list_managed_instances_results") { updatedManager.ListManagedInstancesResults = d.Get("list_managed_instances_results").(string) diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager.go.erb index 871dd0314275..8530b1e3e6b5 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager.go.erb @@ -847,17 +847,10 @@ func resourceComputeRegionInstanceGroupManagerUpdate(d *schema.ResourceData, met change = true } - <% unless version == "ga" -%> if d.HasChange("stateful_internal_ip") || d.HasChange("stateful_external_ip") || d.HasChange("stateful_disk") { updatedManager.StatefulPolicy = expandStatefulPolicy(d) change = true } - <% else -%> - if d.HasChange("stateful_disk") { - updatedManager.StatefulPolicy = expandStatefulPolicy(d) - change = true - } - <% end -%> <% unless version == "ga" -%> if d.HasChange("all_instances_config") { diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager_test.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager_test.go.erb index 85416a6ebdcb..a5470d09b032 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager_test.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager_test.go.erb @@ -323,8 +323,6 @@ func TestAccRegionInstanceGroupManager_distributionPolicy(t *testing.T) { } func TestAccRegionInstanceGroupManager_stateful(t *testing.T) { - // TODO: Flaky test due to ordering of IPs https://github.com/hashicorp/terraform-provider-google/issues/13430 - t.Skip() t.Parallel() template := fmt.Sprintf("tf-test-rigm-%s", acctest.RandString(t, 10)) From e0bbf633015085939f30ddec84a8af18b2e36f43 Mon Sep 17 00:00:00 2001 From: Sarah French <15078782+SarahFrench@users.noreply.github.com> Date: Fri, 16 Feb 2024 17:26:04 +0000 Subject: [PATCH 24/77] Fix path in TeamCity GHA (#10003) --- .github/workflows/teamcity-pr-checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/teamcity-pr-checks.yml b/.github/workflows/teamcity-pr-checks.yml index bea371247b07..6a576185e912 100644 --- a/.github/workflows/teamcity-pr-checks.yml +++ b/.github/workflows/teamcity-pr-checks.yml @@ -6,7 +6,7 @@ on: pull_request: paths: - '.github/workflows/teamcity-pr-checks.yml' - - 'mmv1/third_party/terraform/!.teamcity' + - 'mmv1/third_party/terraform/.teamcity/**' jobs: From 04ddc21dd5f7cb400b14a5746042c6d0dfeea889 Mon Sep 17 00:00:00 2001 From: Niek Khasuntsev Date: Fri, 16 Feb 2024 19:08:01 +0100 Subject: [PATCH 25/77] Add custom domain configuration for Looker (#9936) * Add custom domain configuration for Looker * Add test case * Fix test * Add small change in test to include domain * Simplify domain state output --- mmv1/products/looker/Instance.yaml | 24 +++++++++++++++++++ .../looker_instance_custom_domain.tf.erb | 12 ++++++++++ 2 files changed, 36 insertions(+) create mode 100644 mmv1/templates/terraform/examples/looker_instance_custom_domain.tf.erb diff --git a/mmv1/products/looker/Instance.yaml b/mmv1/products/looker/Instance.yaml index 38b871deb18e..be77445ddd7a 100644 --- a/mmv1/products/looker/Instance.yaml +++ b/mmv1/products/looker/Instance.yaml @@ -73,6 +73,14 @@ examples: kms_key_name: 'acctest.BootstrapKMSKeyInLocation(t, "us-central1").CryptoKey.Name' network_name: 'acctest.BootstrapSharedServiceNetworkingConnection(t, "looker-vpc-network-1", acctest.ServiceNetworkWithPrefixLength(20))' skip_docs: true + - !ruby/object:Provider::Terraform::Examples + name: 'looker_instance_custom_domain' + primary_resource_id: 'looker-instance' + vars: + instance_name: 'my-instance' + client_id: 'my-client-id' + client_secret: 'my-client-secret' + custom_domain: 'my-custom-domain' parameters: - !ruby/object:Api::Type::String name: 'region' @@ -416,3 +424,19 @@ properties: description: | Number of additional Developer Users to allocate to the Looker Instance. # UserMetadata Object - End + # CustomDomain Object + - !ruby/object:Api::Type::NestedObject + name: customDomain + description: | + Custom domain settings for a Looker instance. + properties: + - !ruby/object:Api::Type::String + name: 'domain' + description: | + Domain name + - !ruby/object:Api::Type::String + name: 'state' + description: | + Status of the custom domain. + output: true + # CustomDomain Object - End diff --git a/mmv1/templates/terraform/examples/looker_instance_custom_domain.tf.erb b/mmv1/templates/terraform/examples/looker_instance_custom_domain.tf.erb new file mode 100644 index 000000000000..1a69e027ad91 --- /dev/null +++ b/mmv1/templates/terraform/examples/looker_instance_custom_domain.tf.erb @@ -0,0 +1,12 @@ +resource "google_looker_instance" "<%= ctx[:primary_resource_id] %>" { + name = "<%= ctx[:vars]["instance_name"] %>" + platform_edition = "LOOKER_CORE_STANDARD" + region = "us-central1" + oauth_config { + client_id = "<%= ctx[:vars]["client_id"] %>" + client_secret = "<%= ctx[:vars]["client_secret"] %>" + } + custom_domain { + domain = "<%= ctx[:vars]["custom_domain"] %>.com" + } +} From a3f44ceebc7028ed7cde9c07e59e3afeb941593a Mon Sep 17 00:00:00 2001 From: Daniel Randell Date: Fri, 16 Feb 2024 18:56:32 +0000 Subject: [PATCH 26/77] Fix doc typos (#10002) --- mmv1/products/integrationconnectors/Connection.yaml | 2 +- .../examples/scc_event_threat_detection_custom_module.tf.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mmv1/products/integrationconnectors/Connection.yaml b/mmv1/products/integrationconnectors/Connection.yaml index 51baae956ad3..cde9925b86dd 100644 --- a/mmv1/products/integrationconnectors/Connection.yaml +++ b/mmv1/products/integrationconnectors/Connection.yaml @@ -927,7 +927,7 @@ properties: - !ruby/object:Api::Type::NestedObject name: "connectorVersionInfraConfig" description: | - This cofiguration provides infra configs like rate limit threshold which need to be configurable for every connector version. + This configuration provides infra configs like rate limit threshold which need to be configurable for every connector version. output: true properties: - !ruby/object:Api::Type::String diff --git a/mmv1/templates/terraform/examples/scc_event_threat_detection_custom_module.tf.erb b/mmv1/templates/terraform/examples/scc_event_threat_detection_custom_module.tf.erb index 34bb64ac066f..8f7c08b49f8c 100644 --- a/mmv1/templates/terraform/examples/scc_event_threat_detection_custom_module.tf.erb +++ b/mmv1/templates/terraform/examples/scc_event_threat_detection_custom_module.tf.erb @@ -4,7 +4,7 @@ resource "google_scc_event_threat_detection_custom_module" "<%= ctx[:primary_res enablement_state = "ENABLED" type = "<%= ctx[:vars]['type'] %>" description = "My Event Threat Detection Custom Module" - cofig = jsonencode({ + config = jsonencode({ "metadata": { "severity": "LOW", "description": "Flagged by Forcepoint as malicious", From 69bbb46e4dbb743bf2507999a503f16f551f2c5b Mon Sep 17 00:00:00 2001 From: Sneha Prasad <32434989+snpd25@users.noreply.github.com> Date: Sat, 17 Feb 2024 00:38:36 +0530 Subject: [PATCH 27/77] make poilcy sets and policies required field. (#10001) Co-authored-by: Sneha Prasad --- mmv1/products/securityposture/posture.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mmv1/products/securityposture/posture.yaml b/mmv1/products/securityposture/posture.yaml index 6737b42a7a25..cc1882c4d055 100644 --- a/mmv1/products/securityposture/posture.yaml +++ b/mmv1/products/securityposture/posture.yaml @@ -120,6 +120,7 @@ properties: output: true - !ruby/object:Api::Type::Array name: 'policySets' + required: true description: | List of policy sets for the posture. item_type: !ruby/object:Api::Type::NestedObject @@ -141,6 +142,7 @@ properties: name: 'policies' description: | List of security policy + required: true item_type: !ruby/object:Api::Type::NestedObject name: 'Policy' description: | From a7354eb4d6297c135758b28f7a130e8a6b52878a Mon Sep 17 00:00:00 2001 From: bryan0515 <14116199+bryan0515@users.noreply.github.com> Date: Fri, 16 Feb 2024 12:13:16 -0800 Subject: [PATCH 28/77] Temporary fix TestAccIapAppEngineServiceIamBindingGenerated tests (#10000) --- .../terraform/examples/iap_app_engine_service.tf.erb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mmv1/templates/terraform/examples/iap_app_engine_service.tf.erb b/mmv1/templates/terraform/examples/iap_app_engine_service.tf.erb index 6727559e4325..37f79449f02b 100644 --- a/mmv1/templates/terraform/examples/iap_app_engine_service.tf.erb +++ b/mmv1/templates/terraform/examples/iap_app_engine_service.tf.erb @@ -39,6 +39,10 @@ resource "google_app_engine_standard_app_version" "version" { runtime = "nodejs10" noop_on_destroy = true + // TODO: Removed basic scaling once automatic_scaling refresh behavior is fixed. + basic_scaling { + max_instances = 5 + } entrypoint { shell = "node ./app.js" } From 3577ce32d9754ee0da8b2c23a4c732ae455ad98f Mon Sep 17 00:00:00 2001 From: jiayimeow <136068086+jiayimeow@users.noreply.github.com> Date: Fri, 16 Feb 2024 12:51:44 -0800 Subject: [PATCH 29/77] Add two output-only fields (`membership_id`, `membership_location`) under google_container_cluster.fleet (#9974) * add 2 output only fields under resource_container_cluster.fleet * fix format * fix format * fix format * fix format * fix format * fix format * fix format * fix format * fix format * update documentation * update documentation * update documentation * update documentation * fix --- .../resource_container_cluster.go.erb | 61 +++++++++++++------ .../docs/r/container_cluster.html.markdown | 4 ++ 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/mmv1/third_party/terraform/services/container/resource_container_cluster.go.erb b/mmv1/third_party/terraform/services/container/resource_container_cluster.go.erb index 356a5b58ec6d..0ab9a425f653 100644 --- a/mmv1/third_party/terraform/services/container/resource_container_cluster.go.erb +++ b/mmv1/third_party/terraform/services/container/resource_container_cluster.go.erb @@ -2069,16 +2069,26 @@ func ResourceContainerCluster() *schema.Resource { Optional: true, Description: `The Fleet host project of the cluster.`, }, - "membership": { - Type: schema.TypeString, - Computed: true, - Description: `Full resource name of the registered fleet membership of the cluster.`, - }, - "pre_registered": { - Type: schema.TypeBool, - Computed: true, - Description: `Whether the cluster has been registered via the fleet API.`, - }, + "membership": { + Type: schema.TypeString, + Computed: true, + Description: `Full resource name of the registered fleet membership of the cluster.`, + }, + "pre_registered": { + Type: schema.TypeBool, + Computed: true, + Description: `Whether the cluster has been registered via the fleet API.`, + }, + "membership_id": { + Type: schema.TypeString, + Computed: true, + Description: `Short name of the fleet membership, for example "member-1".`, + }, + "membership_location": { + Type: schema.TypeString, + Computed: true, + Description: `Location of the fleet membership, for example "us-central1".`, + }, }, }, }, @@ -6108,16 +6118,27 @@ func flattenGatewayApiConfig(c *container.GatewayAPIConfig) []map[string]interfa } func flattenFleet(c *container.Fleet) []map[string]interface{} { - if c == nil { - return nil - } - return []map[string]interface{}{ - { - "project": c.Project, - "membership": c.Membership, - "pre_registered": c.PreRegistered, - }, - } + if c == nil { + return nil + } + + // Parse membership_id and membership_location from full membership name. + var membership_id, membership_location string + membershipRE := regexp.MustCompile(`^(//[a-zA-Z0-9\.\-]+)?/?projects/([^/]+)/locations/([a-zA-Z0-9\-]+)/memberships/([^/]+)$`) + if match := membershipRE.FindStringSubmatch(c.Membership); match != nil { + membership_id = match[4] + membership_location = match[3] + } + + return []map[string]interface{}{ + { + "project": c.Project, + "membership": c.Membership, + "membership_id": membership_id, + "membership_location": membership_location, + "pre_registered": c.PreRegistered, + }, + } } func flattenEnableK8sBetaApis(c *container.K8sBetaAPIConfig) []map[string]interface{} { diff --git a/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown b/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown index d35c3df76919..46fafb9df471 100644 --- a/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown @@ -1348,6 +1348,10 @@ exported: * `fleet.0.membership` - The resource name of the fleet Membership resource associated to this cluster with format `//gkehub.googleapis.com/projects/{{project}}/locations/{{location}}/memberships/{{name}}`. See the official doc for [fleet management](https://cloud.google.com/kubernetes-engine/docs/fleets-overview). +* `fleet.0.membership_id` - The short name of the fleet membership, extracted from `fleet.0.membership`. You can use this field to configure `membership_id` under [google_gkehub_feature_membership](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/gke_hub_feature_membership). + +* `fleet.0.membership_location` - The location of the fleet membership, extracted from `fleet.0.membership`. You can use this field to configure `membership_location` under [google_gkehub_feature_membership](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/gke_hub_feature_membership). + ## Timeouts This resource provides the following From 25d06fee267f69dfaf8dc323a95997fbf869b1c1 Mon Sep 17 00:00:00 2001 From: bcreddy-gcp <123543489+bcreddy-gcp@users.noreply.github.com> Date: Sat, 17 Feb 2024 02:58:06 +0530 Subject: [PATCH 30/77] shielded instance config for Workbench instances (#9622) * shielded instance config for Workbench instances * Add test to double apply --- mmv1/products/workbench/Instance.yaml | 30 +++ .../examples/workbench_instance_full.tf.erb | 6 + .../workbench_instance_labels_stopped.tf.erb | 6 + .../pre_update/workbench_instance.go.erb | 5 +- ...bench_instance_shielded_config_test.go.erb | 189 ++++++++++++++++++ .../resource_workbench_instance_test.go.erb | 12 ++ 6 files changed, 247 insertions(+), 1 deletion(-) create mode 100644 mmv1/third_party/terraform/services/workbench/resource_workbench_instance_shielded_config_test.go.erb diff --git a/mmv1/products/workbench/Instance.yaml b/mmv1/products/workbench/Instance.yaml index 8575e8be652f..1c0faeab3958 100644 --- a/mmv1/products/workbench/Instance.yaml +++ b/mmv1/products/workbench/Instance.yaml @@ -156,6 +156,36 @@ properties: use accelerators, make sure that your configuration has [enough vCPUs and memory to support the `machine_type` you have selected](https://cloud.google.com/compute/docs/gpus/#gpus-list). Currently supports only one accelerator configuration. + - !ruby/object:Api::Type::NestedObject + name: shieldedInstanceConfig + default_from_api: true + allow_empty_object: true + send_empty_value: true + description: | + A set of Shielded Instance options. See [Images using supported Shielded + VM features](https://cloud.google.com/compute/docs/instances/modifying-shielded-vm). + Not all combinations are valid. + properties: + - !ruby/object:Api::Type::Boolean + name: enableSecureBoot + description: | + Optional. Defines whether the VM instance has Secure Boot enabled. + Secure Boot helps ensure that the system only runs authentic software by verifying + the digital signature of all boot components, and halting the boot process + if signature verification fails. Disabled by default. + - !ruby/object:Api::Type::Boolean + name: enableVtpm + description: | + Optional. Defines whether the VM instance has the vTPM enabled. + Enabled by default. + - !ruby/object:Api::Type::Boolean + name: enableIntegrityMonitoring + description: | + Optional. Defines whether the VM instance has integrity monitoring + enabled. Enables monitoring and attestation of the boot integrity of the VM + instance. The attestation is performed against the integrity policy baseline. + This baseline is initially derived from the implicitly trusted boot image + when the VM instance is created. Enabled by default. - !ruby/object:Api::Type::Array name: serviceAccounts description: | diff --git a/mmv1/templates/terraform/examples/workbench_instance_full.tf.erb b/mmv1/templates/terraform/examples/workbench_instance_full.tf.erb index 270f73d23abc..dd1122901e18 100644 --- a/mmv1/templates/terraform/examples/workbench_instance_full.tf.erb +++ b/mmv1/templates/terraform/examples/workbench_instance_full.tf.erb @@ -21,6 +21,12 @@ resource "google_workbench_instance" "<%= ctx[:primary_resource_id] %>" { core_count = 1 } + shielded_instance_config { + enable_secure_boot = true + enable_vtpm = true + enable_integrity_monitoring = true + } + disable_public_ip = false service_accounts { diff --git a/mmv1/templates/terraform/examples/workbench_instance_labels_stopped.tf.erb b/mmv1/templates/terraform/examples/workbench_instance_labels_stopped.tf.erb index 78e6c11ce6b7..151053d0ef49 100644 --- a/mmv1/templates/terraform/examples/workbench_instance_labels_stopped.tf.erb +++ b/mmv1/templates/terraform/examples/workbench_instance_labels_stopped.tf.erb @@ -5,6 +5,12 @@ resource "google_workbench_instance" "<%= ctx[:primary_resource_id] %>" { gce_setup { machine_type = "e2-standard-4" + shielded_instance_config { + enable_secure_boot = false + enable_vtpm = false + enable_integrity_monitoring = false + } + service_accounts { email = "<%= ctx[:test_env_vars]["service_account"] %>" } diff --git a/mmv1/templates/terraform/pre_update/workbench_instance.go.erb b/mmv1/templates/terraform/pre_update/workbench_instance.go.erb index 71ef1d976501..847a0bcd1311 100644 --- a/mmv1/templates/terraform/pre_update/workbench_instance.go.erb +++ b/mmv1/templates/terraform/pre_update/workbench_instance.go.erb @@ -1,5 +1,5 @@ name := d.Get("name").(string) -if d.HasChange("gce_setup.0.machine_type") || d.HasChange("gce_setup.0.accelerator_configs") { +if d.HasChange("gce_setup.0.machine_type") || d.HasChange("gce_setup.0.accelerator_configs") || d.HasChange("gce_setup.0.shielded_instance_config"){ state := d.Get("state").(string) if state != "STOPPED" { @@ -28,6 +28,9 @@ if d.HasChange("gce_setup.0.machine_type") { if d.HasChange("gce_setup.0.accelerator_configs") { newUpdateMask = append(newUpdateMask, "gce_setup.accelerator_configs") } +if d.HasChange("gce_setup.0.shielded_instance_config") { + newUpdateMask = append(newUpdateMask, "gce_setup.shielded_instance_config") +} if d.HasChange("gce_setup.0.metadata") { newUpdateMask = append(newUpdateMask, "gceSetup.metadata") } diff --git a/mmv1/third_party/terraform/services/workbench/resource_workbench_instance_shielded_config_test.go.erb b/mmv1/third_party/terraform/services/workbench/resource_workbench_instance_shielded_config_test.go.erb new file mode 100644 index 000000000000..22fd838d2e46 --- /dev/null +++ b/mmv1/third_party/terraform/services/workbench/resource_workbench_instance_shielded_config_test.go.erb @@ -0,0 +1,189 @@ +<% autogen_exception -%> +package workbench_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccWorkbenchInstance_shielded_config_update(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.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccWorkbenchInstance_shielded_config_false(context), + }, + { + ResourceName: "google_workbench_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels"}, + }, + { + Config: testAccWorkbenchInstance_shielded_config_true(context), + }, + { + ResourceName: "google_workbench_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels"}, + }, + }, + }) +} + +func TestAccWorkbenchInstance_shielded_config_remove(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.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccWorkbenchInstance_shielded_config_true(context), + }, + { + ResourceName: "google_workbench_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels"}, + }, + { + Config: testAccWorkbenchInstance_shielded_config_none(context), + }, + { + ResourceName: "google_workbench_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels"}, + }, + }, + }) +} + +func TestAccWorkbenchInstance_shielded_config_double_apply(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.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccWorkbenchInstance_shielded_config_none(context), + }, + { + ResourceName: "google_workbench_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels"}, + }, + { + Config: testAccWorkbenchInstance_shielded_config_none(context), + }, + { + ResourceName: "google_workbench_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels"}, + }, + { + Config: testAccWorkbenchInstance_shielded_config_false(context), + }, + { + ResourceName: "google_workbench_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels"}, + }, + { + Config: testAccWorkbenchInstance_shielded_config_false(context), + }, + { + ResourceName: "google_workbench_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels"}, + }, + { + Config: testAccWorkbenchInstance_shielded_config_true(context), + }, + { + ResourceName: "google_workbench_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels"}, + }, + { + Config: testAccWorkbenchInstance_shielded_config_true(context), + }, + { + ResourceName: "google_workbench_instance.instance", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "instance_owners", "location", "instance_id", "request_id", "labels", "terraform_labels"}, + }, + }, + }) +} + +func testAccWorkbenchInstance_shielded_config_true(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_workbench_instance" "instance" { + name = "tf-test-workbench-instance%{random_suffix}" + location = "us-central1-a" + + gce_setup { + shielded_instance_config { + enable_secure_boot = true + enable_vtpm = true + enable_integrity_monitoring = true + } + } +} +`, context) +} + +func testAccWorkbenchInstance_shielded_config_false(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_workbench_instance" "instance" { + name = "tf-test-workbench-instance%{random_suffix}" + location = "us-central1-a" + + gce_setup { + shielded_instance_config { + enable_secure_boot = false + enable_vtpm = false + enable_integrity_monitoring = false + } + } + +} +`, context) +} + +func testAccWorkbenchInstance_shielded_config_none(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_workbench_instance" "instance" { + name = "tf-test-workbench-instance%{random_suffix}" + location = "us-central1-a" +} +`, context) +} diff --git a/mmv1/third_party/terraform/services/workbench/resource_workbench_instance_test.go.erb b/mmv1/third_party/terraform/services/workbench/resource_workbench_instance_test.go.erb index 42f21d425404..8fbff0b8f080 100644 --- a/mmv1/third_party/terraform/services/workbench/resource_workbench_instance_test.go.erb +++ b/mmv1/third_party/terraform/services/workbench/resource_workbench_instance_test.go.erb @@ -65,6 +65,12 @@ resource "google_workbench_instance" "instance" { core_count = 1 } + shielded_instance_config { + enable_secure_boot = false + enable_vtpm = true + enable_integrity_monitoring = false + } + metadata = { terraform = "true" } @@ -143,6 +149,12 @@ resource "google_workbench_instance" "instance" { core_count = 1 } + shielded_instance_config { + enable_secure_boot = false + enable_vtpm = true + enable_integrity_monitoring = false + } + } labels = { From aa4dd138e3c2d6a5e5234c496a864808e065cfea Mon Sep 17 00:00:00 2001 From: hao-nan-li <100219545+hao-nan-li@users.noreply.github.com> Date: Fri, 16 Feb 2024 13:43:14 -0800 Subject: [PATCH 31/77] Add comment to skip_sweeper for datacatalog_taxonomy (#9924) * Add comment to skip_sweeper for datacatalog_taxonomy * Update comment for skip_sweeper --- mmv1/products/datacatalog/Taxonomy.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/mmv1/products/datacatalog/Taxonomy.yaml b/mmv1/products/datacatalog/Taxonomy.yaml index 8fa5bf8c9b7b..c472fd415119 100644 --- a/mmv1/products/datacatalog/Taxonomy.yaml +++ b/mmv1/products/datacatalog/Taxonomy.yaml @@ -23,6 +23,7 @@ references: !ruby/object:Api::Resource::ReferenceLinks guides: 'Official Documentation': https://cloud.google.com/data-catalog/docs api: https://cloud.google.com/data-catalog/docs/reference/rest/v1/projects.locations.taxonomies +# Skip sweeper as this resource name is autogenerated from the API, thus the sweeper runs on the display_name field. Handwritten sweeper added #9908. skip_sweeper: true iam_policy: !ruby/object:Api::Resource::IamPolicy skip_import_test: true From ef763566fb57f8eb571e4ccf3983b62649211d32 Mon Sep 17 00:00:00 2001 From: Sarah French <15078782+SarahFrench@users.noreply.github.com> Date: Tue, 20 Feb 2024 16:02:15 +0000 Subject: [PATCH 32/77] Stop acceptance test deleting in-use service account (#10010) --- ...workstations_workstation_config_test.go.erb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/mmv1/third_party/terraform/services/workstations/resource_workstations_workstation_config_test.go.erb b/mmv1/third_party/terraform/services/workstations/resource_workstations_workstation_config_test.go.erb index d927fb6b72f5..72565a7f5219 100644 --- a/mmv1/third_party/terraform/services/workstations/resource_workstations_workstation_config_test.go.erb +++ b/mmv1/third_party/terraform/services/workstations/resource_workstations_workstation_config_test.go.erb @@ -675,6 +675,15 @@ resource "google_workstations_workstation_cluster" "default" { location = "us-central1" } +# No longer explicitly used in google_workstations_workstation_config resource block below, but the +# service account needs to keep existing to allow the field to default from the API without error +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}" @@ -729,6 +738,15 @@ resource "google_workstations_workstation_cluster" "default" { location = "us-central1" } +# No longer explicitly used in google_workstations_workstation_config resource block below, but the +# service account needs to keep existing to allow the field to default from the API without error +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}" From 41f37f5046bb8a495bcd77a2ee3a6f65c9828f5c Mon Sep 17 00:00:00 2001 From: bcreddy-gcp <123543489+bcreddy-gcp@users.noreply.github.com> Date: Tue, 20 Feb 2024 22:43:12 +0530 Subject: [PATCH 33/77] Notebook instances output tags by default (#10006) --- mmv1/products/notebooks/Instance.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/mmv1/products/notebooks/Instance.yaml b/mmv1/products/notebooks/Instance.yaml index 1e0ad5c49374..b5fb92b0c1b1 100644 --- a/mmv1/products/notebooks/Instance.yaml +++ b/mmv1/products/notebooks/Instance.yaml @@ -392,6 +392,7 @@ properties: description: | The Compute Engine tags to add to instance. item_type: Api::Type::String + default_from_api: true - !ruby/object:Api::Type::KeyValuePairs name: 'metadata' description: | From 4b1359dd28df86080ac35ed9cfc4c20f14ae5e68 Mon Sep 17 00:00:00 2001 From: Mike Senn Date: Tue, 20 Feb 2024 12:34:45 -0500 Subject: [PATCH 34/77] Patch 14 (#10008) * Add link to Service-orientation This article tried to link to Wikipedia, but the wasn't actually a link. I think this change conveys its intention. * Update GenericService.yaml --- mmv1/products/monitoring/GenericService.yaml | 3 ++- mmv1/products/monitoring/Service.yaml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/mmv1/products/monitoring/GenericService.yaml b/mmv1/products/monitoring/GenericService.yaml index be972bbca23d..142af9e431dd 100644 --- a/mmv1/products/monitoring/GenericService.yaml +++ b/mmv1/products/monitoring/GenericService.yaml @@ -20,13 +20,14 @@ update_verb: :PATCH update_mask: true description: | A Service is a discrete, autonomous, and network-accessible unit, - designed to solve an individual concern (Wikipedia). In Cloud Monitoring, + designed to solve an individual concern. In Cloud Monitoring, a Service acts as the root resource under which operational aspects of the service are accessible references: !ruby/object:Api::Resource::ReferenceLinks guides: 'Service Monitoring': 'https://cloud.google.com/monitoring/service-monitoring' 'Monitoring API Documentation': 'https://cloud.google.com/monitoring/api/v3/' + 'Service-orientation on Wikipedia': 'https://en.wikipedia.org/wiki/Service-orientation' api: 'https://cloud.google.com/monitoring/api/ref_v3/rest/v3/services' legacy_name: 'google_monitoring_service' id_format: 'projects/{{project}}/services/{{service_id}}' diff --git a/mmv1/products/monitoring/Service.yaml b/mmv1/products/monitoring/Service.yaml index 4624cafcd416..a204ba56ef68 100644 --- a/mmv1/products/monitoring/Service.yaml +++ b/mmv1/products/monitoring/Service.yaml @@ -20,13 +20,14 @@ update_verb: :PATCH update_mask: true description: | A Service is a discrete, autonomous, and network-accessible unit, - designed to solve an individual concern (Wikipedia). In Cloud Monitoring, + designed to solve an individual concern. In Cloud Monitoring, a Service acts as the root resource under which operational aspects of the service are accessible references: !ruby/object:Api::Resource::ReferenceLinks guides: 'Service Monitoring': 'https://cloud.google.com/monitoring/service-monitoring' 'Monitoring API Documentation': 'https://cloud.google.com/monitoring/api/v3/' + 'Service-orientation on Wikipedia': 'https://en.wikipedia.org/wiki/Service-orientation' api: 'https://cloud.google.com/monitoring/api/ref_v3/rest/v3/services' legacy_name: 'google_monitoring_custom_service' id_format: '{{name}}' From aeba6c4947923df75d25ce0ec3e710b6d0140b48 Mon Sep 17 00:00:00 2001 From: bcreddy-gcp <123543489+bcreddy-gcp@users.noreply.github.com> Date: Wed, 21 Feb 2024 00:18:21 +0530 Subject: [PATCH 35/77] Add support for custom containers for workbench instances (#9973) * Add support for custom containers for workbench instances * Use conflicts instead of exactly_one_of for backward compatibility --- mmv1/products/workbench/Instance.yaml | 28 +++++++++++++++++++ .../workbench_instance_basic_container.tf.erb | 11 ++++++++ 2 files changed, 39 insertions(+) create mode 100644 mmv1/templates/terraform/examples/workbench_instance_basic_container.tf.erb diff --git a/mmv1/products/workbench/Instance.yaml b/mmv1/products/workbench/Instance.yaml index 1c0faeab3958..7b3e0d2b47c0 100644 --- a/mmv1/products/workbench/Instance.yaml +++ b/mmv1/products/workbench/Instance.yaml @@ -43,6 +43,15 @@ examples: region_override: 'us-west1-a' vars: instance_name: 'workbench-instance' + - !ruby/object:Provider::Terraform::Examples + name: 'workbench_instance_basic_container' + primary_resource_id: 'instance' + primary_resource_name: "fmt.Sprintf(\"tf-test-workbench-instance%s\", + context[\"\ + random_suffix\"])" + region_override: 'us-west1-a' + vars: + instance_name: 'workbench-instance' - !ruby/object:Provider::Terraform::Examples name: 'workbench_instance_basic_gpu' primary_resource_id: 'instance' @@ -213,6 +222,8 @@ properties: name: vmImage custom_flatten: templates/terraform/custom_flatten/workbench_instance_vm_image_flatten.go.erb default_from_api: true + conflicts: + - gce_setup.0.container_image immutable: true description: | Definition of a custom Compute Engine virtual machine image for starting @@ -240,6 +251,23 @@ properties: exactly_one_of: - vm_image.0.name - vm_image.0.family + - !ruby/object:Api::Type::NestedObject + name: containerImage + conflicts: + - gce_setup.0.vm_image + description: | + Use a container image to start the workbench instance. + properties: + - !ruby/object:Api::Type::String + name: 'repository' + description: | + The path to the container image repository. + For example: gcr.io/{project_id}/{imageName} + required: true + - !ruby/object:Api::Type::String + name: 'tag' + description: | + The tag of the container image. If not specified, this defaults to the latest tag. - !ruby/object:Api::Type::NestedObject name: bootDisk default_from_api: true diff --git a/mmv1/templates/terraform/examples/workbench_instance_basic_container.tf.erb b/mmv1/templates/terraform/examples/workbench_instance_basic_container.tf.erb new file mode 100644 index 000000000000..55ba370ffee1 --- /dev/null +++ b/mmv1/templates/terraform/examples/workbench_instance_basic_container.tf.erb @@ -0,0 +1,11 @@ +resource "google_workbench_instance" "<%= ctx[:primary_resource_id] %>" { + name = "<%= ctx[:vars]['instance_name'] %>" + location = "us-west1-a" + + gce_setup { + container_image { + repository = "us-docker.pkg.dev/deeplearning-platform-release/gcr.io/base-cu113.py310" + tag = "latest" + } + } +} From 5ddf4406a2fdb1f18a3cdf35872a9f7d072c5b7e Mon Sep 17 00:00:00 2001 From: Lingkai Shen Date: Tue, 20 Feb 2024 14:32:36 -0500 Subject: [PATCH 36/77] App Check reCAPTCHA V3 and reCAPTCHA Enterprise providers (#9991) * App check debug token * Use api_name and identity to wire up debugTokenId * App Check * update mask --- .../RecaptchaEnterpriseConfig.yaml | 81 +++++++++++++++++ .../firebaseappcheck/RecaptchaV3Config.yaml | 87 +++++++++++++++++++ ...k_recaptcha_enterprise_config_basic.tf.erb | 20 +++++ ...app_check_recaptcha_v3_config_basic.tf.erb | 20 +++++ ..._check_recaptcha_enterprise_config_test.go | 57 ++++++++++++ ...base_app_check_recaptcha_v3_config_test.go | 57 ++++++++++++ 6 files changed, 322 insertions(+) create mode 100644 mmv1/products/firebaseappcheck/RecaptchaEnterpriseConfig.yaml create mode 100644 mmv1/products/firebaseappcheck/RecaptchaV3Config.yaml create mode 100644 mmv1/templates/terraform/examples/firebase_app_check_recaptcha_enterprise_config_basic.tf.erb create mode 100644 mmv1/templates/terraform/examples/firebase_app_check_recaptcha_v3_config_basic.tf.erb create mode 100644 mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_enterprise_config_test.go create mode 100644 mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_v3_config_test.go diff --git a/mmv1/products/firebaseappcheck/RecaptchaEnterpriseConfig.yaml b/mmv1/products/firebaseappcheck/RecaptchaEnterpriseConfig.yaml new file mode 100644 index 000000000000..a103c5dfb226 --- /dev/null +++ b/mmv1/products/firebaseappcheck/RecaptchaEnterpriseConfig.yaml @@ -0,0 +1,81 @@ +# Copyright 2024 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +!ruby/object:Api::Resource +name: "RecaptchaEnterpriseConfig" +base_url: projects/{{project}}/apps/{{app_id}}/recaptchaEnterpriseConfig +self_link: projects/{{project}}/apps/{{app_id}}/recaptchaEnterpriseConfig +create_url: projects/{{project}}/apps/{{app_id}}/recaptchaEnterpriseConfig?updateMask=tokenTtl,siteKey +create_verb: :PATCH +update_verb: :PATCH +update_mask: true +skip_delete: true +description: | + An app's reCAPTCHA Enterprise configuration object. +references: !ruby/object:Api::Resource::ReferenceLinks + guides: + "Official Documentation": "https://firebase.google.com/docs/app-check" + api: "https://firebase.google.com/docs/reference/appcheck/rest/v1/projects.apps.recaptchaEnterpriseConfig" +import_format: + [ + "projects/{{project}}/apps/{{app_id}}/recaptchaEnterpriseConfig", + "{{project}}/{{app_id}}", + "{{app_id}}", + ] +examples: + - !ruby/object:Provider::Terraform::Examples + name: "firebase_app_check_recaptcha_enterprise_config_basic" + # Need the time_sleep resource + pull_external: true + primary_resource_id: "default" + vars: + token_ttl: "7200s" + # A valid key, but is actually unusable + site_key: "6LdpMXIpAAAAANkwWQPgEdjEhal7ugkH9RK9ytuw" + test_vars_overrides: + # Don't add random suffix + token_ttl: '"7200s"' + site_key: '"6LdpMXIpAAAAANkwWQPgEdjEhal7ugkH9RK9ytuw"' + test_env_vars: + project_id: :PROJECT_NAME +parameters: + - !ruby/object:Api::Type::String + name: app_id + description: | + The ID of an + [Web App](https://firebase.google.com/docs/reference/firebase-management/rest/v1beta1/projects.webApps#WebApp.FIELDS.app_id). + required: true + immutable: true + url_param_only: true +properties: + - !ruby/object:Api::Type::String + name: name + description: | + The relative resource name of the reCAPTCHA Enterprise configuration object + output: true + - !ruby/object:Api::Type::String + name: tokenTtl + description: | + Specifies the duration for which App Check tokens exchanged from reCAPTCHA Enterprise artifacts will be valid. + If unset, a default value of 1 hour is assumed. Must be between 30 minutes and 7 days, inclusive. + + A duration in seconds with up to nine fractional digits, ending with 's'. Example: "3.5s". + default_from_api: true + - !ruby/object:Api::Type::String + name: siteKey + description: | + The score-based site key created in reCAPTCHA Enterprise used to invoke reCAPTCHA and generate the reCAPTCHA tokens for your application. + + **Important**: This is not the siteSecret (as it is in reCAPTCHA v3), but rather your score-based reCAPTCHA Enterprise site key. + required: true diff --git a/mmv1/products/firebaseappcheck/RecaptchaV3Config.yaml b/mmv1/products/firebaseappcheck/RecaptchaV3Config.yaml new file mode 100644 index 000000000000..1e42c4796246 --- /dev/null +++ b/mmv1/products/firebaseappcheck/RecaptchaV3Config.yaml @@ -0,0 +1,87 @@ +# Copyright 2024 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +!ruby/object:Api::Resource +name: "RecaptchaV3Config" +base_url: projects/{{project}}/apps/{{app_id}}/recaptchaV3Config +self_link: projects/{{project}}/apps/{{app_id}}/recaptchaV3Config +create_url: projects/{{project}}/apps/{{app_id}}/recaptchaV3Config?updateMask=tokenTtl,siteSecret +create_verb: :PATCH +update_verb: :PATCH +update_mask: true +skip_delete: true +description: | + An app's reCAPTCHA V3 configuration object. +references: !ruby/object:Api::Resource::ReferenceLinks + guides: + "Official Documentation": "https://firebase.google.com/docs/app-check" + api: "https://firebase.google.com/docs/reference/appcheck/rest/v1/projects.apps.recaptchaV3Config" +import_format: + [ + "projects/{{project}}/apps/{{app_id}}/recaptchaV3Config", + "{{project}}/{{app_id}}", + "{{app_id}}", + ] +examples: + - !ruby/object:Provider::Terraform::Examples + name: "firebase_app_check_recaptcha_v3_config_basic" + # Need the time_sleep resource + pull_external: true + primary_resource_id: "default" + vars: + token_ttl: "7200s" + # A valid secret, but is actually unusable + site_secret: "6Lf9YnQpAAAAAC3-MHmdAllTbPwTZxpUw5d34YzX" + test_vars_overrides: + # Don't add random suffix + token_ttl: '"7200s"' + site_secret: '"6Lf9YnQpAAAAAC3-MHmdAllTbPwTZxpUw5d34YzX"' + test_env_vars: + project_id: :PROJECT_NAME +parameters: + - !ruby/object:Api::Type::String + name: app_id + description: | + The ID of an + [Web App](https://firebase.google.com/docs/reference/firebase-management/rest/v1beta1/projects.webApps#WebApp.FIELDS.app_id). + required: true + immutable: true + url_param_only: true +properties: + - !ruby/object:Api::Type::String + name: name + description: | + The relative resource name of the reCAPTCHA V3 configuration object + output: true + - !ruby/object:Api::Type::String + name: tokenTtl + description: | + Specifies the duration for which App Check tokens exchanged from reCAPTCHA V3 artifacts will be valid. + If unset, a default value of 1 hour is assumed. Must be between 30 minutes and 7 days, inclusive. + + A duration in seconds with up to nine fractional digits, ending with 's'. Example: "3.5s". + default_from_api: true + - !ruby/object:Api::Type::String + name: siteSecret + description: | + The site secret used to identify your service for reCAPTCHA v3 verification. + For security reasons, this field will never be populated in any response. + required: true + sensitive: true + ignore_read: true + - !ruby/object:Api::Type::Boolean + name: siteSecretSet + description: | + Whether the siteSecret was previously set. Since we will never return the siteSecret field, this field is the only way to find out whether it was previously set. + output: true diff --git a/mmv1/templates/terraform/examples/firebase_app_check_recaptcha_enterprise_config_basic.tf.erb b/mmv1/templates/terraform/examples/firebase_app_check_recaptcha_enterprise_config_basic.tf.erb new file mode 100644 index 000000000000..806dfe37a16d --- /dev/null +++ b/mmv1/templates/terraform/examples/firebase_app_check_recaptcha_enterprise_config_basic.tf.erb @@ -0,0 +1,20 @@ +resource "google_firebase_web_app" "default" { + project = "<%= ctx[:test_env_vars]['project_id'] %>" + display_name = "Web App for reCAPTCHA Enterprise" +} + +# It takes a while for App Check to recognize the new app +# If your app already exists, you don't have to wait 30 seconds. +resource "time_sleep" "wait_30s" { + depends_on = [google_firebase_web_app.default] + create_duration = "30s" +} + +resource "google_firebase_app_check_recaptcha_enterprise_config" "default" { + project = "<%= ctx[:test_env_vars]['project_id'] %>" + app_id = google_firebase_web_app.default.app_id + site_key = "<%= ctx[:vars]['site_key'] %>" + token_ttl = "<%= ctx[:vars]['token_ttl'] %>" + + depends_on = [time_sleep.wait_30s] +} diff --git a/mmv1/templates/terraform/examples/firebase_app_check_recaptcha_v3_config_basic.tf.erb b/mmv1/templates/terraform/examples/firebase_app_check_recaptcha_v3_config_basic.tf.erb new file mode 100644 index 000000000000..4b4c88b7ddd7 --- /dev/null +++ b/mmv1/templates/terraform/examples/firebase_app_check_recaptcha_v3_config_basic.tf.erb @@ -0,0 +1,20 @@ +resource "google_firebase_web_app" "default" { + project = "<%= ctx[:test_env_vars]['project_id'] %>" + display_name = "Web App for reCAPTCHA V3" +} + +# It takes a while for App Check to recognize the new app +# If your app already exists, you don't have to wait 30 seconds. +resource "time_sleep" "wait_30s" { + depends_on = [google_firebase_web_app.default] + create_duration = "30s" +} + +resource "google_firebase_app_check_recaptcha_v3_config" "default" { + project = "<%= ctx[:test_env_vars]['project_id'] %>" + app_id = google_firebase_web_app.default.app_id + site_secret = "<%= ctx[:vars]['site_secret'] %>" + token_ttl = "<%= ctx[:vars]['token_ttl'] %>" + + depends_on = [time_sleep.wait_30s] +} diff --git a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_enterprise_config_test.go b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_enterprise_config_test.go new file mode 100644 index 000000000000..6d0a91601ea7 --- /dev/null +++ b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_enterprise_config_test.go @@ -0,0 +1,57 @@ +package firebaseappcheck_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccFirebaseAppCheckRecaptchaEnterpriseConfig_firebaseAppCheckRecaptchaEnterpriseConfigUpdate(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_id": envvar.GetTestProjectFromEnv(), + "token_ttl": "7200s", + "site_key": "6LdpMXIpAAAAANkwWQPgEdjEhal7ugkH9RK9ytuw", + "random_suffix": acctest.RandString(t, 10), + } + + contextUpdated := map[string]interface{}{ + "project_id": envvar.GetTestProjectFromEnv(), + "token_ttl": "3800s", + "site_key": "7LdpMXIpAAAAANkwWQPgEdjEhal7ugkH9RK9ytuw", + "random_suffix": context["random_suffix"], + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccFirebaseAppCheckRecaptchaEnterpriseConfig_firebaseAppCheckRecaptchaEnterpriseConfigBasicExample(context), + }, + { + ResourceName: "google_firebase_app_check_recaptcha_enterprise_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + { + Config: testAccFirebaseAppCheckRecaptchaEnterpriseConfig_firebaseAppCheckRecaptchaEnterpriseConfigBasicExample(contextUpdated), + }, + { + ResourceName: "google_firebase_app_check_recaptcha_enterprise_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"app_id"}, + }, + }, + }) +} diff --git a/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_v3_config_test.go b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_v3_config_test.go new file mode 100644 index 000000000000..961215b8f63e --- /dev/null +++ b/mmv1/third_party/terraform/services/firebaseappcheck/resource_firebase_app_check_recaptcha_v3_config_test.go @@ -0,0 +1,57 @@ +package firebaseappcheck_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccFirebaseAppCheckRecaptchaV3Config_firebaseAppCheckRecaptchaV3ConfigUpdate(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "project_id": envvar.GetTestProjectFromEnv(), + "token_ttl": "7200s", + "site_secret": "6Lf9YnQpAAAAAC3-MHmdAllTbPwTZxpUw5d34YzX", + "random_suffix": acctest.RandString(t, 10), + } + + contextUpdated := map[string]interface{}{ + "project_id": envvar.GetTestProjectFromEnv(), + "token_ttl": "3800s", + "site_secret": "7Lf9YnQpAAAAAC3-MHmdAllTbPwTZxpUw5d34YzX", + "random_suffix": context["random_suffix"], + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + "time": {}, + }, + Steps: []resource.TestStep{ + { + Config: testAccFirebaseAppCheckRecaptchaV3Config_firebaseAppCheckRecaptchaV3ConfigBasicExample(context), + }, + { + ResourceName: "google_firebase_app_check_recaptcha_v3_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"site_secret", "app_id"}, + }, + { + Config: testAccFirebaseAppCheckRecaptchaV3Config_firebaseAppCheckRecaptchaV3ConfigBasicExample(contextUpdated), + }, + { + ResourceName: "google_firebase_app_check_recaptcha_v3_config.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"site_secret", "app_id"}, + }, + }, + }) +} From a9f2961f319e3803d6b0afadf465c686ac618692 Mon Sep 17 00:00:00 2001 From: Shuya Ma <87669292+shuyama1@users.noreply.github.com> Date: Tue, 20 Feb 2024 11:38:42 -0800 Subject: [PATCH 37/77] Removed GH token from VCR nightly job (#10015) --- .ci/gcb-vcr-nightly.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.ci/gcb-vcr-nightly.yml b/.ci/gcb-vcr-nightly.yml index 5906d404d11f..fb3bbf8663c3 100644 --- a/.ci/gcb-vcr-nightly.yml +++ b/.ci/gcb-vcr-nightly.yml @@ -3,7 +3,7 @@ steps: - name: 'gcr.io/graphite-docker-images/go-plus' id: gcb-vcr-nightly entrypoint: '/workspace/.ci/scripts/go-plus/vcr-cassette-update/vcr_cassette_update.sh' - secretEnv: ["GITHUB_TOKEN", "GOOGLE_BILLING_ACCOUNT", "GOOGLE_CUST_ID", "GOOGLE_FIRESTORE_PROJECT", "GOOGLE_IDENTITY_USER", "GOOGLE_MASTER_BILLING_ACCOUNT", "GOOGLE_ORG", "GOOGLE_ORG_2", "GOOGLE_ORG_DOMAIN", "GOOGLE_PROJECT", "GOOGLE_PROJECT_NUMBER", "GOOGLE_SERVICE_ACCOUNT", "SA_KEY", "GOOGLE_PUBLIC_AVERTISED_PREFIX_DESCRIPTION", "GOOGLE_TPU_V2_VM_RUNTIME_VERSION"] + secretEnv: ["GOOGLE_BILLING_ACCOUNT", "GOOGLE_CUST_ID", "GOOGLE_FIRESTORE_PROJECT", "GOOGLE_IDENTITY_USER", "GOOGLE_MASTER_BILLING_ACCOUNT", "GOOGLE_ORG", "GOOGLE_ORG_2", "GOOGLE_ORG_DOMAIN", "GOOGLE_PROJECT", "GOOGLE_PROJECT_NUMBER", "GOOGLE_SERVICE_ACCOUNT", "SA_KEY", "GOOGLE_PUBLIC_AVERTISED_PREFIX_DESCRIPTION", "GOOGLE_TPU_V2_VM_RUNTIME_VERSION"] args: - $BUILD_ID @@ -15,8 +15,6 @@ options: logsBucket: 'gs://cloudbuild-vcr-nightly-logs' availableSecrets: secretManager: - - versionName: projects/673497134629/secrets/github-magician-token/versions/latest - env: GITHUB_TOKEN - versionName: projects/673497134629/secrets/ci-test-billing-account/versions/latest env: GOOGLE_BILLING_ACCOUNT - versionName: projects/673497134629/secrets/ci-test-cust-id/versions/latest From 02e719917fd193513b3e580493a2df4e051cafc9 Mon Sep 17 00:00:00 2001 From: Deepak Kumar <21131061+kumadee@users.noreply.github.com> Date: Tue, 20 Feb 2024 20:53:34 +0100 Subject: [PATCH 38/77] fixes: permadiff issue if event trigger region is not specified (#9989) * fixes: permadiff issue if event trigger region is not specified - fixes https://github.com/hashicorp/terraform-provider-google/issues/17161 * chore: Updated cloudfunction2 test with no explicit trigger_region --- mmv1/products/cloudfunctions2/Function.yaml | 1 + .../terraform/examples/cloudfunctions2_basic_gcs.tf.erb | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/mmv1/products/cloudfunctions2/Function.yaml b/mmv1/products/cloudfunctions2/Function.yaml index a094196586fc..71fd0ef07e87 100644 --- a/mmv1/products/cloudfunctions2/Function.yaml +++ b/mmv1/products/cloudfunctions2/Function.yaml @@ -594,6 +594,7 @@ properties: events originating in this region. It can be the same region as the function, a different region or multi-region, or the global region. If not provided, defaults to the same region as the function. + default_from_api: true - !ruby/object:Api::Type::String name: 'eventType' description: 'Required. The type of event to observe.' diff --git a/mmv1/templates/terraform/examples/cloudfunctions2_basic_gcs.tf.erb b/mmv1/templates/terraform/examples/cloudfunctions2_basic_gcs.tf.erb index 8dd602fc4c5f..00a11528241d 100644 --- a/mmv1/templates/terraform/examples/cloudfunctions2_basic_gcs.tf.erb +++ b/mmv1/templates/terraform/examples/cloudfunctions2_basic_gcs.tf.erb @@ -91,7 +91,6 @@ resource "google_cloudfunctions2_function" "<%= ctx[:primary_resource_id] %>" { } event_trigger { - trigger_region = "us-central1" # The trigger must be in the same location as the bucket event_type = "google.cloud.storage.object.v1.finalized" retry_policy = "RETRY_POLICY_RETRY" service_account_email = google_service_account.account.email From f25a214012dc398a6c1a07531a7ae85e049aa538 Mon Sep 17 00:00:00 2001 From: Riley Karson Date: Tue, 20 Feb 2024 15:38:56 -0800 Subject: [PATCH 39/77] Fix GKE front matter, bad field docs (#10018) * Fix GKE front matter, bad field docs * Update container_cluster.html.markdown --- .../docs/r/container_cluster.html.markdown | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown b/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown index 46fafb9df471..b7713ba6d51c 100644 --- a/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown @@ -6,22 +6,21 @@ description: |- # google\_container\_cluster --> Visit the [Provision a GKE Cluster (Google Cloud)](https://learn.hashicorp.com/tutorials/terraform/gke?in=terraform/kubernetes&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) Learn tutorial to learn how to provision and interact -with a GKE cluster. +Manages a Google Kubernetes Engine (GKE) cluster. --> See the [Using GKE with Terraform](/docs/providers/google/guides/using_gke_with_terraform.html) -guide for more information about using GKE with Terraform. +To get more information about GKE clusters, see: + * [The API reference](https://cloud.google.com/kubernetes-engine/docs/reference/rest/v1beta1/projects.locations.clusters) + * How-to guides + * [GKE overview](https://cloud.google.com/kubernetes-engine/docs/concepts/kubernetes-engine-overview) + * [About cluster configuration choices](https://cloud.google.com/kubernetes-engine/docs/concepts/types-of-clusters) + * Terraform guidance + * [Using GKE with Terraform](/docs/providers/google/guides/using_gke_with_terraform.html) + * [Provision a GKE Cluster (Google Cloud) Learn tutorial](https://learn.hashicorp.com/tutorials/terraform/gke?in=terraform/kubernetes&utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS) -Manages a Google Kubernetes Engine (GKE) cluster. For more information see -[the official documentation](https://cloud.google.com/container-engine/docs/clusters) -and [the API reference](https://cloud.google.com/kubernetes-engine/docs/reference/rest/v1beta1/projects.locations.clusters). +-> On version 5.0.0+ of the provider, you must explicitly set `deletion_protection = false` +and run `terraform apply` to write the field to state in order to destroy a cluster. --> **Note**: On version 5.0.0+ of the provider, you must explicitly set `deletion_protection=false` -(and run `terraform apply` to write the field to state) in order to destroy a cluster. -It is recommended to not set this field (or set it to true) until you're ready to destroy. - -~> **Warning:** All arguments and attributes, including basic auth username and -passwords as well as certificate outputs will be stored in the raw state as +~> All arguments and attributes (including certificate outputs) will be stored in the raw state as plaintext. [Read more about sensitive data in state](https://www.terraform.io/language/state/sensitive-data). ## Example Usage - with a separately managed node pool (recommended) @@ -1111,6 +1110,8 @@ subnet. See [Private Cluster Limitations](https://cloud.google.com/kubernetes-en for more details. This field only applies to private clusters, when `enable_private_nodes` is `true`. +* `private_endpoint_subnetwork` - (Optional) Subnetwork in cluster's network where master's endpoint will be provisioned. + * `master_global_access_config` (Optional) - Controls cluster master global access settings. If unset, Terraform will no longer manage this field and will not modify the previously-set value. Structure is [documented below](#nested_master_global_access_config). @@ -1121,8 +1122,6 @@ In addition, the `private_cluster_config` allows access to the following read-on * `private_endpoint` - The internal IP address of this cluster's master endpoint. -* `private_endpoint_subnetwork` - Subnetwork in cluster's network where master's endpoint will be provisioned. - * `public_endpoint` - The external IP address of this cluster's master endpoint. !> The Google provider is unable to validate certain configurations of From 3e85823b9bda72a1910ef6eabdf0b64ca6211de5 Mon Sep 17 00:00:00 2001 From: Max Portocarrero CI&T <105444618+maxi-cit@users.noreply.github.com> Date: Wed, 21 Feb 2024 11:21:15 -0500 Subject: [PATCH 40/77] added default value for minPortsPerVM field at "google_compute_router_nat" (#9712) * added default value for statis allocation * setting the default from API --- mmv1/products/compute/RouterNat.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mmv1/products/compute/RouterNat.yaml b/mmv1/products/compute/RouterNat.yaml index 9b0d414391a1..fef5eb3398c2 100644 --- a/mmv1/products/compute/RouterNat.yaml +++ b/mmv1/products/compute/RouterNat.yaml @@ -236,7 +236,8 @@ properties: - !ruby/object:Api::Type::Integer name: minPortsPerVm description: | - Minimum number of ports allocated to a VM from this NAT. + Minimum number of ports allocated to a VM from this NAT. Defaults to 64 for static port allocation and 32 dynamic port allocation if not set. + default_from_api: true - !ruby/object:Api::Type::Integer name: maxPortsPerVm description: | From 7369959626ffc0ecea935a3210fdf46a90517bfb Mon Sep 17 00:00:00 2001 From: Mauricio Alvarez Leon <65101411+BBBmau@users.noreply.github.com> Date: Wed, 21 Feb 2024 08:34:41 -0800 Subject: [PATCH 41/77] add newline removal bash command in guidelines (#9734) --- .../terraform/website/docs/guides/getting_started.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmv1/third_party/terraform/website/docs/guides/getting_started.html.markdown b/mmv1/third_party/terraform/website/docs/guides/getting_started.html.markdown index 4559a54f224a..a329a71258e7 100644 --- a/mmv1/third_party/terraform/website/docs/guides/getting_started.html.markdown +++ b/mmv1/third_party/terraform/website/docs/guides/getting_started.html.markdown @@ -182,7 +182,7 @@ quota or billing issues which don't seem to apply to you, you may want to set ### Using Terraform Cloud as the Backend You need to use a different [environment variable](https://www.terraform.io/docs/cloud/workspaces/variables.html) name to store your credentials in Terraform Cloud. 1. Create an environment variable called `GOOGLE_CREDENTIALS` in your Terraform Cloud workspace. -2. Remove the newline characters from your JSON key file and then paste the credentials into the environment variable value field. +2. Remove the newline characters from your JSON key file and then paste the credentials into the environment variable value field. (Running `cat CREDENTIALS.json | tr -s '\n' ' '` will remove newline characters from your JSON key file) 3. Mark the variable as **Sensitive** and click **Save variable**. All runs within the workspace will use the `GOOGLE_CREDENTIALS` variable to authenticate with Google Cloud Platform. From 6675072e699fd4f3f445d83ae3469d091116c224 Mon Sep 17 00:00:00 2001 From: Sarah French <15078782+SarahFrench@users.noreply.github.com> Date: Wed, 21 Feb 2024 17:55:56 +0000 Subject: [PATCH 42/77] Update hashicorp/terraform-plugin-framework, hashicorp/terraform-plugin-mux, hashicorp/terraform-plugin-sdk/v2 (#10009) --- mmv1/third_party/terraform/go.mod.erb | 40 ++--- mmv1/third_party/terraform/go.sum | 202 ++++++++++---------------- 2 files changed, 100 insertions(+), 142 deletions(-) diff --git a/mmv1/third_party/terraform/go.mod.erb b/mmv1/third_party/terraform/go.mod.erb index b75cb3b55059..0d5943fb44fc 100644 --- a/mmv1/third_party/terraform/go.mod.erb +++ b/mmv1/third_party/terraform/go.mod.erb @@ -1,5 +1,6 @@ <% autogen_exception -%> module github.com/hashicorp/terraform-provider-google + go 1.20 require ( @@ -15,12 +16,12 @@ require ( github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-version v1.6.0 - github.com/hashicorp/terraform-plugin-framework v1.1.1 + github.com/hashicorp/terraform-plugin-framework v1.5.0 github.com/hashicorp/terraform-plugin-framework-validators v0.9.0 - github.com/hashicorp/terraform-plugin-go v0.14.3 - github.com/hashicorp/terraform-plugin-log v0.7.0 - github.com/hashicorp/terraform-plugin-mux v0.8.0 - github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.0 + github.com/hashicorp/terraform-plugin-go v0.20.0 + github.com/hashicorp/terraform-plugin-log v0.9.0 + github.com/hashicorp/terraform-plugin-mux v0.13.0 + github.com/hashicorp/terraform-plugin-sdk/v2 v2.31.0 github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/hashstructure v1.1.0 github.com/sirupsen/logrus v1.8.1 @@ -39,11 +40,13 @@ require ( cloud.google.com/go/compute/metadata v0.2.3 // indirect cloud.google.com/go/iam v1.1.5 // indirect cloud.google.com/go/longrunning v0.5.4 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect github.com/agext/levenshtein v1.2.2 // indirect - github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect + github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cloudflare/circl v1.3.3 // indirect github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe // indirect github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 // indirect github.com/envoyproxy/go-control-plane v0.11.1 // indirect @@ -63,17 +66,17 @@ require ( github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect github.com/googleapis/gax-go/v2 v2.12.0 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect - github.com/hashicorp/go-hclog v1.2.1 // indirect - github.com/hashicorp/go-plugin v1.4.8 // indirect + github.com/hashicorp/go-hclog v1.5.0 // indirect + github.com/hashicorp/go-plugin v1.6.0 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect - github.com/hashicorp/hc-install v0.4.0 // indirect - github.com/hashicorp/hcl/v2 v2.14.1 // indirect + github.com/hashicorp/hc-install v0.6.2 // indirect + github.com/hashicorp/hcl/v2 v2.19.1 // indirect github.com/hashicorp/logutils v1.0.0 // indirect - github.com/hashicorp/terraform-exec v0.17.3 // indirect - github.com/hashicorp/terraform-json v0.14.0 // indirect - github.com/hashicorp/terraform-registry-address v0.1.0 // indirect - github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 // indirect - github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d // indirect + github.com/hashicorp/terraform-exec v0.19.0 // indirect + github.com/hashicorp/terraform-json v0.18.0 // indirect + github.com/hashicorp/terraform-registry-address v0.2.3 // indirect + github.com/hashicorp/terraform-svchost v0.1.1 // indirect + github.com/hashicorp/yamux v0.1.1 // indirect github.com/kylelemons/godebug v1.1.0 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-isatty v0.0.14 // indirect @@ -84,9 +87,9 @@ require ( github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/oklog/run v1.0.0 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect - github.com/vmihailenco/msgpack/v4 v4.3.12 // indirect - github.com/vmihailenco/tagparser v0.1.2 // indirect - github.com/zclconf/go-cty v1.11.0 // indirect + github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/zclconf/go-cty v1.14.1 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect @@ -94,6 +97,7 @@ require ( go.opentelemetry.io/otel/metric v1.21.0 // indirect go.opentelemetry.io/otel/trace v1.21.0 // indirect golang.org/x/crypto v0.18.0 // indirect + golang.org/x/mod v0.14.0 // indirect golang.org/x/sync v0.6.0 // indirect golang.org/x/sys v0.16.0 // indirect golang.org/x/text v0.14.0 // indirect diff --git a/mmv1/third_party/terraform/go.sum b/mmv1/third_party/terraform/go.sum index ab792bb42cf6..b265f1fc3590 100644 --- a/mmv1/third_party/terraform/go.sum +++ b/mmv1/third_party/terraform/go.sum @@ -1,7 +1,6 @@ bitbucket.org/creachadair/stringset v0.0.8 h1:gQqe4vs8XWgMyijfyKE6K8o4TcyGGrRXe0JvHgx5H+M= bitbucket.org/creachadair/stringset v0.0.8/go.mod h1:AgthVMyMxC/6FK1KBJ2ALdqkZObGN8hOetgpwXyMn34= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.111.0 h1:YHLKNupSD1KqjDbQ3+LVdQ81h/UJbJyZG203cEfnQgM= cloud.google.com/go v0.111.0/go.mod h1:0mibmpKP1TyOOFYQY5izo0LnT+ecvOQ0Sg3OdmMiNRU= cloud.google.com/go/bigtable v1.19.0 h1:wiq9LT0kukfInzvy1joMDijCw/OD1UChpSbORXYn0LI= @@ -14,27 +13,22 @@ cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= cloud.google.com/go/longrunning v0.5.4 h1:w8xEcbZodnA2BbW6sVirkkoC+1gP8wS57EUUgGS0GVg= cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/GoogleCloudPlatform/declarative-resource-client-library v1.62.0 h1:s4Y6r6RrYLBnqosGXLwR0h1Gqr0VT3wgd6rqvHsD9OE= github.com/GoogleCloudPlatform/declarative-resource-client-library v1.62.0/go.mod h1:pL2Qt5HT+x6xrTd806oMiM3awW6kNIXB/iiuClz6m6k= -github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= -github.com/Microsoft/go-winio v0.4.16 h1:FtSW/jqD+l4ba5iPBj9CODVtgfYAD8w2wS923g/cFDk= -github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= -github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ= -github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= -github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= -github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= +github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/agext/levenshtein v1.2.2 h1:0S/Yg6LYmFJ5stwQeRp6EeOcCbj7xiqQSdNelsXvaqE= github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= -github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I= -github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= -github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= -github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= -github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= +github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= +github.com/bufbuild/protocompile v0.4.0 h1:LbFKd2XowZvQ/kajzguUp2DC9UEIQhIq77fZZlaQsNA= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4= github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -43,6 +37,8 @@ github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91 github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= @@ -50,14 +46,13 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/creachadair/staticfile v0.1.2/go.mod h1:a3qySzCIXEprDGxk6tSxSI+dBBdLzqeBOMhZ+o2d3pM= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dnaeon/go-vcr v1.0.1 h1:r8L/HqC0Hje5AXMu1ooW8oyQyOFv4GxqpL0nRP7SLLY= github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E= -github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -70,20 +65,13 @@ github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/gammazero/deque v0.0.0-20180920172122-f6adf94963e4 h1:R+19WKQClnfMXS60cP5BmMe1wjZ4u0evY2p2Ar0ZTXo= github.com/gammazero/deque v0.0.0-20180920172122-f6adf94963e4/go.mod h1:GeIq9qoE43YdGnDXURnmKTnGg15pQz4mYkXSTChbneI= github.com/gammazero/workerpool v0.0.0-20181230203049-86a96b5d5d92 h1:EipXK6U05IQ2wtuFRn4k3h0+2lXypzItoXGVyf4r9Io= github.com/gammazero/workerpool v0.0.0-20181230203049-86a96b5d5d92/go.mod h1:w9RqFVO2BM3xwWEcAB8Fwp0OviTBBEiRmSBDfbXnd3w= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4= -github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E= -github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34= -github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0= -github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= -github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4= -github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-git/v5 v5.10.1 h1:tu8/D8i+TWxgKpzQ3Vc43e+kkhXqtsZCKI/egajKnxk= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -104,10 +92,8 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4er github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -127,8 +113,6 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cpy v0.0.0-20211218193943-a9c933c06932 h1:5/4TSDzpDnHQ8rKEEQBjRlYx77mHOvXu08oGchxej7o= @@ -149,75 +133,63 @@ github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI= github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= -github.com/hashicorp/go-hclog v1.2.1 h1:YQsLlGDJgwhXFpucSPyVbCBviQtjlHv3jLTlp8YmtEw= -github.com/hashicorp/go-hclog v1.2.1/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= +github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-plugin v1.4.8 h1:CHGwpxYDOttQOY7HOWgETU9dyVjOXzniXDqJcYJE1zM= -github.com/hashicorp/go-plugin v1.4.8/go.mod h1:viDMjcLJuDui6pXb8U4HVfb8AamCWhHGUjr2IrTF67s= +github.com/hashicorp/go-plugin v1.6.0 h1:wgd4KxHJTVGGqWBq4QPB1i5BZNEx9BR8+OFmHDmTk8A= +github.com/hashicorp/go-plugin v1.6.0/go.mod h1:lBS5MtSSBZk0SHc66KACcjjlU6WzEVP/8pwz68aMkCI= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek= github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/hc-install v0.4.0 h1:cZkRFr1WVa0Ty6x5fTvL1TuO1flul231rWkGH92oYYk= -github.com/hashicorp/hc-install v0.4.0/go.mod h1:5d155H8EC5ewegao9A4PUTMNPZaq+TbOzkJJZ4vrXeI= -github.com/hashicorp/hcl/v2 v2.14.1 h1:x0BpjfZ+CYdbiz+8yZTQ+gdLO7IXvOut7Da+XJayx34= -github.com/hashicorp/hcl/v2 v2.14.1/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0= +github.com/hashicorp/hc-install v0.6.2 h1:V1k+Vraqz4olgZ9UzKiAcbman9i9scg9GgSt/U3mw/M= +github.com/hashicorp/hc-install v0.6.2/go.mod h1:2JBpd+NCFKiHiu/yYCGaPyPHhZLxXTpz8oreHa/a3Ps= +github.com/hashicorp/hcl/v2 v2.19.1 h1://i05Jqznmb2EXqa39Nsvyan2o5XyMowW5fnCKW5RPI= +github.com/hashicorp/hcl/v2 v2.19.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE= github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/terraform-exec v0.17.3 h1:MX14Kvnka/oWGmIkyuyvL6POx25ZmKrjlaclkx3eErU= -github.com/hashicorp/terraform-exec v0.17.3/go.mod h1:+NELG0EqQekJzhvikkeQsOAZpsw0cv/03rbeQJqscAI= -github.com/hashicorp/terraform-json v0.14.0 h1:sh9iZ1Y8IFJLx+xQiKHGud6/TSUCM0N8e17dKDpqV7s= -github.com/hashicorp/terraform-json v0.14.0/go.mod h1:5A9HIWPkk4e5aeeXIBbkcOvaZbIYnAIkEyqP2pNSckM= -github.com/hashicorp/terraform-plugin-framework v1.1.1 h1:PbnEKHsIU8KTTzoztHQGgjZUWx7Kk8uGtpGMMc1p+oI= -github.com/hashicorp/terraform-plugin-framework v1.1.1/go.mod h1:DyZPxQA+4OKK5ELxFIIcqggcszqdWWUpTLPHAhS/tkY= +github.com/hashicorp/terraform-exec v0.19.0 h1:FpqZ6n50Tk95mItTSS9BjeOVUb4eg81SpgVtZNNtFSM= +github.com/hashicorp/terraform-exec v0.19.0/go.mod h1:tbxUpe3JKruE9Cuf65mycSIT8KiNPZ0FkuTE3H4urQg= +github.com/hashicorp/terraform-json v0.18.0 h1:pCjgJEqqDESv4y0Tzdqfxr/edOIGkjs8keY42xfNBwU= +github.com/hashicorp/terraform-json v0.18.0/go.mod h1:qdeBs11ovMzo5puhrRibdD6d2Dq6TyE/28JiU4tIQxk= +github.com/hashicorp/terraform-plugin-framework v1.5.0 h1:8kcvqJs/x6QyOFSdeAyEgsenVOUeC/IyKpi2ul4fjTg= +github.com/hashicorp/terraform-plugin-framework v1.5.0/go.mod h1:6waavirukIlFpVpthbGd2PUNYaFedB0RwW3MDzJ/rtc= github.com/hashicorp/terraform-plugin-framework-validators v0.9.0 h1:LYz4bXh3t7bTEydXOmPDPupRRnA480B/9+jV8yZvxBA= github.com/hashicorp/terraform-plugin-framework-validators v0.9.0/go.mod h1:+BVERsnfdlhYR2YkXMBtPnmn9UsL19U3qUtSZ+Y/5MY= -github.com/hashicorp/terraform-plugin-go v0.14.3 h1:nlnJ1GXKdMwsC8g1Nh05tK2wsC3+3BL/DBBxFEki+j0= -github.com/hashicorp/terraform-plugin-go v0.14.3/go.mod h1:7ees7DMZ263q8wQ6E4RdIdR6nHHJtrdt4ogX5lPkX1A= -github.com/hashicorp/terraform-plugin-log v0.7.0 h1:SDxJUyT8TwN4l5b5/VkiTIaQgY6R+Y2BQ0sRZftGKQs= -github.com/hashicorp/terraform-plugin-log v0.7.0/go.mod h1:p4R1jWBXRTvL4odmEkFfDdhUjHf9zcs/BCoNHAc7IK4= -github.com/hashicorp/terraform-plugin-mux v0.8.0 h1:WCTP66mZ+iIaIrCNJnjPEYnVjawTshnDJu12BcXK1EI= -github.com/hashicorp/terraform-plugin-mux v0.8.0/go.mod h1:vdW0daEi8Kd4RFJmet5Ot+SIVB/B8SwQVJiYKQwdCy8= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.0 h1:FtCLTiTcykdsURXPt/ku7fYXm3y19nbzbZcUxHx9RbI= -github.com/hashicorp/terraform-plugin-sdk/v2 v2.24.0/go.mod h1:80wf5oad1tW+oLnbXS4UTYmDCrl7BuN1Q+IA91X1a4Y= -github.com/hashicorp/terraform-registry-address v0.1.0 h1:W6JkV9wbum+m516rCl5/NjKxCyTVaaUBbzYcMzBDO3U= -github.com/hashicorp/terraform-registry-address v0.1.0/go.mod h1:EnyO2jYO6j29DTHbJcm00E5nQTFeTtyZH3H5ycydQ5A= -github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0= -github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg= -github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= -github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= +github.com/hashicorp/terraform-plugin-go v0.20.0 h1:oqvoUlL+2EUbKNsJbIt3zqqZ7wi6lzn4ufkn/UA51xQ= +github.com/hashicorp/terraform-plugin-go v0.20.0/go.mod h1:Rr8LBdMlY53a3Z/HpP+ZU3/xCDqtKNCkeI9qOyT10QE= +github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0= +github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow= +github.com/hashicorp/terraform-plugin-mux v0.13.0 h1:79U401/3nd8CWwDGtTHc8F3miSCAS9XGtVarxSTDgwA= +github.com/hashicorp/terraform-plugin-mux v0.13.0/go.mod h1:Ndv0FtwDG2ogzH59y64f2NYimFJ6I0smRgFUKfm6dyQ= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.31.0 h1:Bl3e2ei2j/Z3Hc2HIS15Gal2KMKyLAZ2om1HCEvK6es= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.31.0/go.mod h1:i2C41tszDjiWfziPQDL5R/f3Zp0gahXe5No/MIO9rCE= +github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI= +github.com/hashicorp/terraform-registry-address v0.2.3/go.mod h1:lFHA76T8jfQteVfT7caREqguFrW3c4MFSPhZB7HHgUM= +github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S52uzrw4x0jKQ= +github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc= +github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= +github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= -github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= -github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck= -github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40= github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= @@ -238,30 +210,25 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/sebdah/goldie v1.0.0/go.mod h1:jXP4hmWywNEwZzhMuv2ccnqTSFpuq8iyQhtQdkkZBH4= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -270,22 +237,16 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= -github.com/vmihailenco/msgpack/v4 v4.3.12 h1:07s4sz9IReOgdikxLTKNbBdqDMLsjPKXwvCazn8G65U= -github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= -github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= -github.com/vmihailenco/tagparser v0.1.2 h1:gnjoVuB/kljJ5wICEEOpx98oXMWPLj22G67Vbd1qPqc= -github.com/vmihailenco/tagparser v0.1.2/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= -github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI= -github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= +github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8= +github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s= -github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8= -github.com/zclconf/go-cty v1.10.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= -github.com/zclconf/go-cty v1.11.0 h1:726SxLdi2SDnjY+BStqB9J1hNp4+2WlzyXLuimibIe0= -github.com/zclconf/go-cty v1.11.0/go.mod h1:s9IfD1LK5ccNMSWCVFCE2rJfHiZgi7JijgeWIMfhLvA= -github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b/go.mod h1:ZRKQfBXbGkpdV6QMzT3rU1kSTAnfu1dO8dPKjYprgj8= +github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA= +github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= @@ -302,14 +263,12 @@ go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+ go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -319,72 +278,72 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -398,6 +357,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -406,7 +367,6 @@ google.golang.org/api v0.156.0 h1:yloYcGbBtVYjLKQe4enCunxvwn3s2w/XPrrhVf6MsvQ= google.golang.org/api v0.156.0/go.mod h1:bUSmn4KFO0Q+69zo9CNIDp4Psi6BqM0np0CbzKRSiSY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -441,16 +401,10 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= -gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From b7e1e25a635c74eb6c5f6b13828ddcefa67eecd7 Mon Sep 17 00:00:00 2001 From: Jesse Liddle Date: Wed, 21 Feb 2024 14:03:16 -0500 Subject: [PATCH 43/77] Adding Data Source Forwarding Rules (#10004) --- .../provider/provider_mmv1_resources.go.erb | 1 + ..._source_google_compute_forwarding_rules.go | 102 ++++++++++++++++++ ...ce_google_compute_forwarding_rules_test.go | 53 +++++++++ .../d/compute_forwarding_rules.html.markdown | 42 ++++++++ 4 files changed, 198 insertions(+) create mode 100644 mmv1/third_party/terraform/services/compute/data_source_google_compute_forwarding_rules.go create mode 100644 mmv1/third_party/terraform/services/compute/data_source_google_compute_forwarding_rules_test.go create mode 100644 mmv1/third_party/terraform/website/docs/d/compute_forwarding_rules.html.markdown diff --git a/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.erb b/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.erb index e37501f6d8bd..33109889347c 100644 --- a/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.erb +++ b/mmv1/third_party/terraform/provider/provider_mmv1_resources.go.erb @@ -60,6 +60,7 @@ var handwrittenDatasources = map[string]*schema.Resource{ "google_compute_default_service_account": compute.DataSourceGoogleComputeDefaultServiceAccount(), "google_compute_disk": compute.DataSourceGoogleComputeDisk(), "google_compute_forwarding_rule": compute.DataSourceGoogleComputeForwardingRule(), + "google_compute_forwarding_rules": compute.DataSourceGoogleComputeForwardingRules(), "google_compute_global_address": compute.DataSourceGoogleComputeGlobalAddress(), "google_compute_global_forwarding_rule": compute.DataSourceGoogleComputeGlobalForwardingRule(), "google_compute_ha_vpn_gateway": compute.DataSourceGoogleComputeHaVpnGateway(), diff --git a/mmv1/third_party/terraform/services/compute/data_source_google_compute_forwarding_rules.go b/mmv1/third_party/terraform/services/compute/data_source_google_compute_forwarding_rules.go new file mode 100644 index 000000000000..80f467829735 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/data_source_google_compute_forwarding_rules.go @@ -0,0 +1,102 @@ +package compute + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func DataSourceGoogleComputeForwardingRules() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGoogleComputeForwardingRulesRead, + + Schema: map[string]*schema.Schema{ + + "project": { + Type: schema.TypeString, + Optional: true, + }, + + "region": { + Type: schema.TypeString, + Optional: true, + }, + + "rules": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: tpgresource.DatasourceSchemaFromResourceSchema(ResourceComputeForwardingRule().Schema), + }, + }, + }, + } +} + +func dataSourceGoogleComputeForwardingRulesRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return err + } + + region, err := tpgresource.GetRegion(d, config) + if err != nil { + return err + } + + id := fmt.Sprintf("projects/%s/regions/%s/forwardingRules", project, region) + d.SetId(id) + + forwardingRulesAggregatedList, err := config.NewComputeClient(userAgent).ForwardingRules.List(project, region).Do() + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("Forwarding Rules Not Found : %s", project)) + } + + forwardingRules := make([]map[string]interface{}, 0, len(forwardingRulesAggregatedList.Items)) + + for i := 0; i < len(forwardingRulesAggregatedList.Items); i++ { + rule := forwardingRulesAggregatedList.Items[i] + mappedData := map[string]interface{}{ + "name": rule.Name, + "network": rule.Network, + "subnetwork": rule.Subnetwork, + "backend_service": rule.BackendService, + "ip_address": rule.IPAddress, + "service_name": rule.ServiceName, + "service_label": rule.ServiceLabel, + "description": rule.Description, + "self_link": rule.SelfLink, + "labels": rule.Labels, + "ports": rule.Ports, + "region": rule.Region, + "target": rule.Target, + "ip_version": rule.IpVersion, + "network_tier": rule.NetworkTier, + "base_forwarding_rule": rule.BaseForwardingRule, + "port_range": rule.PortRange, + } + forwardingRules = append(forwardingRules, mappedData) + } + + if err := d.Set("rules", forwardingRules); err != nil { + return fmt.Errorf("Error setting the forwarding rules names: %s", err) + } + + if err := d.Set("project", project); err != nil { + return fmt.Errorf("Error setting the network names: %s", err) + } + + if err := d.Set("region", region); err != nil { + return fmt.Errorf("Error setting the region: %s", err) + } + + return nil +} diff --git a/mmv1/third_party/terraform/services/compute/data_source_google_compute_forwarding_rules_test.go b/mmv1/third_party/terraform/services/compute/data_source_google_compute_forwarding_rules_test.go new file mode 100644 index 000000000000..c0bc3e9004f9 --- /dev/null +++ b/mmv1/third_party/terraform/services/compute/data_source_google_compute_forwarding_rules_test.go @@ -0,0 +1,53 @@ +package compute_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccDataSourceGoogleForwardingRules(t *testing.T) { + t.Parallel() + + poolName := fmt.Sprintf("tf-%s", acctest.RandString(t, 10)) + ruleName := fmt.Sprintf("tf-%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccDataSourceGoogleForwardingRuleConfig(poolName, ruleName), + Check: acctest.CheckDataSourceStateMatchesResourceState("data.google_compute_forwarding_rule.my_forwarding_rule", "google_compute_forwarding_rule.foobar-fr"), + }, + }, + }) +} + +func testAccDataSourceGoogleForwardingRulesConfig(poolName, ruleName string) string { + return fmt.Sprintf(` +resource "google_compute_target_pool" "foobar-tp" { + description = "Resource created for Terraform acceptance testing" + instances = ["us-central1-a/foo", "us-central1-b/bar"] + name = "%s" +} + +resource "google_compute_forwarding_rule" "foobar-fr" { + description = "Resource created for Terraform acceptance testing" + ip_protocol = "UDP" + name = "%s" + port_range = "80-81" + target = google_compute_target_pool.foobar-tp.self_link + labels = { + my-label = "my-label-value" + } +} + +data "google_compute_forwarding_rules" "my_forwarding_rule" { + project = google_compute_forwarding_rule.foobar-fr.project + region = google_compute_forwarding_rule.foobar-fr.region +} +`, poolName, ruleName) +} diff --git a/mmv1/third_party/terraform/website/docs/d/compute_forwarding_rules.html.markdown b/mmv1/third_party/terraform/website/docs/d/compute_forwarding_rules.html.markdown new file mode 100644 index 000000000000..7c930a68a15d --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/d/compute_forwarding_rules.html.markdown @@ -0,0 +1,42 @@ +--- +subcategory: "Compute Engine" +description: |- + List forwarding rules in a region of a Google Cloud project. +--- + +# google\_compute\_forwarding\_rules + +List all networks in a specified Google Cloud project. + +## Example Usage + +```tf +data "google_compute_forwarding_rules" "my-forwarding-rules" { + project = "my-cloud-project" + region = "us-central1" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `project` - (Optional) The name of the project. + +* `region` - (Optional) The region you want to get the forwarding rules from. + +These arguments must be set in either the provider or the resouce in order for the information to be queried. + +## Attributes Reference + +In addition to the arguments listed above, the following attributes are exported: + +* `id` - an identifier for the resource with format projects/{{project}}/region/{{region}}/forwardingRules + +* `project` - The project name being queried. + +* `region` - The region being queried. + +* `rules` - This is a list of the forwarding rules in the project. Each forwarding rule will list the backend, description, ip address. name, network, self link, service label, service name, and subnet. + +* `self_link` - The URI of the resource. From 41c5863df55c2efc1d821e869aa8ef8c56df8852 Mon Sep 17 00:00:00 2001 From: Wessel Blokzijl Date: Wed, 21 Feb 2024 20:03:52 +0100 Subject: [PATCH 44/77] Fix broken terraform datasource google_compute_machine_types example (#10020) --- .../website/docs/d/compute_machine_types.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmv1/third_party/terraform/website/docs/d/compute_machine_types.html.markdown b/mmv1/third_party/terraform/website/docs/d/compute_machine_types.html.markdown index b0cc4784099c..eb42c5054471 100644 --- a/mmv1/third_party/terraform/website/docs/d/compute_machine_types.html.markdown +++ b/mmv1/third_party/terraform/website/docs/d/compute_machine_types.html.markdown @@ -20,7 +20,7 @@ Configure a Google Kubernetes Engine (GKE) cluster with node auto-provisioning, ```hcl data "google_compute_machine_types" "example" { - filter = "name = 'n1-standard-1'" + filter = "name = \"n1-standard-1\"" zone = "us-central1-a" } From 6aba2a9bda474112d1d59bf0b8e7b627afb2ee7a Mon Sep 17 00:00:00 2001 From: Jack McCluskey <34928439+jrmccluskey@users.noreply.github.com> Date: Wed, 21 Feb 2024 14:05:08 -0500 Subject: [PATCH 45/77] Add check for Environment proto field before accessing in Dataflow provider (#10016) --- .../terraform/services/dataflow/resource_dataflow_job.go.erb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mmv1/third_party/terraform/services/dataflow/resource_dataflow_job.go.erb b/mmv1/third_party/terraform/services/dataflow/resource_dataflow_job.go.erb index 9ecdbd2443ff..e2a0bb2f1b95 100644 --- a/mmv1/third_party/terraform/services/dataflow/resource_dataflow_job.go.erb +++ b/mmv1/third_party/terraform/services/dataflow/resource_dataflow_job.go.erb @@ -371,6 +371,9 @@ func resourceDataflowJobRead(d *schema.ResourceData, meta interface{}) error { if err := d.Set("effective_labels", job.Labels); err != nil { return fmt.Errorf("Error setting effective_labels: %s", err) } + if job.Environment == nil { + return fmt.Errorf("Error accessing Environment proto: proto is nil") + } if err := d.Set("kms_key_name", job.Environment.ServiceKmsKeyName); err != nil { return fmt.Errorf("Error setting kms_key_name: %s", err) } From f56992625c9b27c1d828e81f87b42f5f2de426f9 Mon Sep 17 00:00:00 2001 From: hao-nan-li <100219545+hao-nan-li@users.noreply.github.com> Date: Wed, 21 Feb 2024 11:09:39 -0800 Subject: [PATCH 46/77] Add comments to skipped sweeper (#10023) --- mmv1/products/alloydb/User.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/mmv1/products/alloydb/User.yaml b/mmv1/products/alloydb/User.yaml index 1f3ad0f76698..895f7557d924 100644 --- a/mmv1/products/alloydb/User.yaml +++ b/mmv1/products/alloydb/User.yaml @@ -24,6 +24,7 @@ references: !ruby/object:Api::Resource::ReferenceLinks 'AlloyDB': 'https://cloud.google.com/alloydb/docs/' api: 'https://cloud.google.com/alloydb/docs/reference/rest/v1/projects.locations.clusters.users/create' import_format: ['projects/{{project}}/locations/{{location}}/clusters/{{cluster}}/users/{{user_id}}'] +# Skipping the sweeper because instances will be deleted during cluster sweeps skip_sweeper: true autogen_async: true custom_code: !ruby/object:Provider::Terraform::CustomCode From fcf7d34078cbbecc309e7d5d6c7b5198df189f4a Mon Sep 17 00:00:00 2001 From: hao-nan-li <100219545+hao-nan-li@users.noreply.github.com> Date: Wed, 21 Feb 2024 11:09:52 -0800 Subject: [PATCH 47/77] Add comments for skipped sweepers (#10024) --- mmv1/products/firebase/AndroidApp.yaml | 1 + mmv1/products/firebase/AppleApp.yaml | 1 + mmv1/products/firebase/WebApp.yaml | 1 + 3 files changed, 3 insertions(+) diff --git a/mmv1/products/firebase/AndroidApp.yaml b/mmv1/products/firebase/AndroidApp.yaml index 8cd21b2db2ba..3e58993f5e98 100644 --- a/mmv1/products/firebase/AndroidApp.yaml +++ b/mmv1/products/firebase/AndroidApp.yaml @@ -52,6 +52,7 @@ import_format: '{{app_id}}', ] autogen_async: true +# Sweeper skipped as this resource has customized deletion. skip_sweeper: true identity: - appId diff --git a/mmv1/products/firebase/AppleApp.yaml b/mmv1/products/firebase/AppleApp.yaml index 7c9ab93c8258..f40d18733008 100644 --- a/mmv1/products/firebase/AppleApp.yaml +++ b/mmv1/products/firebase/AppleApp.yaml @@ -52,6 +52,7 @@ import_format: '{{app_id}}' ] autogen_async: true +# Sweeper skipped as this resource has customized deletion. skip_sweeper: true identity: - appId diff --git a/mmv1/products/firebase/WebApp.yaml b/mmv1/products/firebase/WebApp.yaml index e6682fdb76df..1ccebb6f418d 100644 --- a/mmv1/products/firebase/WebApp.yaml +++ b/mmv1/products/firebase/WebApp.yaml @@ -52,6 +52,7 @@ import_format: '{{app_id}}', ] autogen_async: true +# Sweeper skipped as this resource has customized deletion. skip_sweeper: true identity: - appId From 580624e69b30b3a2fa911f092ff118787521a918 Mon Sep 17 00:00:00 2001 From: Salome Papiashvili Date: Wed, 21 Feb 2024 20:13:29 +0100 Subject: [PATCH 48/77] C3 version schema (#9986) * add support for build number in composerEnvironmentVersionRegexp and composerImageVersionDiffSuppress * make build number optional * regroup regex, cleaner comparison of versions * correction --- .../resource_composer_environment.go.erb | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb b/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb index 8dae1cc3ab12..536af7709b4b 100644 --- a/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb +++ b/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb @@ -27,7 +27,7 @@ import ( const ( composerEnvironmentEnvVariablesRegexp = "[a-zA-Z_][a-zA-Z0-9_]*." composerEnvironmentReservedAirflowEnvVarRegexp = "AIRFLOW__[A-Z0-9_]+__[A-Z0-9_]+" - composerEnvironmentVersionRegexp = `composer-(([0-9]+)(\.[0-9]+\.[0-9]+(-preview\.[0-9]+)?)?|latest)-airflow-(([0-9]+)((\.[0-9]+)(\.[0-9]+)?)?)` + composerEnvironmentVersionRegexp = `composer-(([0-9]+)(\.[0-9]+\.[0-9]+(-preview\.[0-9]+)?)?|latest)-airflow-(([0-9]+)((\.[0-9]+)(\.[0-9]+)?)?(-build\.[0-9]+)?)` ) var composerEnvironmentReservedEnvVar = map[string]struct{}{ @@ -2827,7 +2827,7 @@ func composerImageVersionDiffSuppress(_, old, new string, _ *schema.ResourceData versionRe := regexp.MustCompile(composerEnvironmentVersionRegexp) oldVersions := versionRe.FindStringSubmatch(old) newVersions := versionRe.FindStringSubmatch(new) - if oldVersions == nil || len(oldVersions) < 10 { + if oldVersions == nil || len(oldVersions) < 11 { // Somehow one of the versions didn't match the regexp or didn't // have values in the capturing groups. In that case, fall back to // an equality check. @@ -2836,7 +2836,7 @@ func composerImageVersionDiffSuppress(_, old, new string, _ *schema.ResourceData } return old == new } - if newVersions == nil || len(newVersions) < 10 { + if newVersions == nil || len(newVersions) < 11 { // Somehow one of the versions didn't match the regexp or didn't // have values in the capturing groups. In that case, fall back to // an equality check. @@ -2849,9 +2849,11 @@ func composerImageVersionDiffSuppress(_, old, new string, _ *schema.ResourceData oldAirflow := oldVersions[5] oldAirflowMajor := oldVersions[6] oldAirflowMajorMinor := oldVersions[6] + oldVersions[8] + oldAirflowMajorMinorPatch := oldVersions[6] + oldVersions[8] + oldVersions[9] newAirflow := newVersions[5] newAirflowMajor := newVersions[6] newAirflowMajorMinor := newVersions[6] + newVersions[8] + newAirflowMajorMinorPatch := newVersions[6] + newVersions[8] + newVersions[9] // Check Airflow versions. if oldAirflow == oldAirflowMajor || newAirflow == newAirflowMajor { // If one of the Airflow versions specifies only major version @@ -2873,8 +2875,18 @@ func composerImageVersionDiffSuppress(_, old, new string, _ *schema.ResourceData if !eq { return false } + } else if oldAirflow == oldAirflowMajorMinorPatch || newAirflow == newAirflowMajorMinorPatch { + // If one of the Airflow versions specifies only major, minor and patch version + // (like 1.10.15), we can only compare major, minor and patch versions. + eq, err := versionsEqual(oldAirflowMajorMinorPatch, newAirflowMajorMinorPatch) + if err != nil { + log.Printf("[WARN] Could not parse airflow version, %s", err) + } + if !eq { + return false + } } else { - // Otherwise, we compare the full Airflow versions (like 1.10.15). + // Otherwise, we compare the full Airflow versions (like 1.10.15-build.5). eq, err := versionsEqual(oldAirflow, newAirflow) if err != nil { log.Printf("[WARN] Could not parse airflow version, %s", err) From 343ff46df5008cc457392c3baafd0acc6dc97633 Mon Sep 17 00:00:00 2001 From: Max Portocarrero CI&T <105444618+maxi-cit@users.noreply.github.com> Date: Wed, 21 Feb 2024 14:18:48 -0500 Subject: [PATCH 49/77] Add Resource Manager Tags support to 'google_container_cluster' (#9531) * resourceManagerTags added to Cluster Node Config schema * update beta tag * add cluster and node proto tests * add expand and flatten proto * removed beta tag * added to documentation * added resource manager tags to auto pilot * migrating resourceManagerTags tests * migrating node_pools test * migrating additional tests * minor fixes * fixing tests * add in-place update support * fixed tests * fixed annotations * validated clusters and node pools tests. Isolated node pool auto config * isolated resource manager tags from docs * fixed permission issue * fixed spaces * fixed non determinism on tag keys * removed auto_pilot rmts * fixed time_sleep * add depends_on to IAM policies --- .../compute/resource_compute_instance.go.erb | 8 +- .../services/container/node_config.go.erb | 40 +- .../resource_container_cluster.go.erb | 16 +- .../resource_container_cluster_test.go.erb | 150 ++++++- .../resource_container_node_pool.go.erb | 42 ++ .../resource_container_node_pool_test.go.erb | 406 +++++++++++++++++- .../docs/r/container_cluster.html.markdown | 6 +- 7 files changed, 635 insertions(+), 33 deletions(-) diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.erb index 3fb7c963acf1..1a6ad62d42cf 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.erb @@ -651,7 +651,7 @@ func ResourceComputeInstance() *schema.Resource { }, }, - "params": { + "params": { Type: schema.TypeList, MaxItems: 1, Optional: true, @@ -673,7 +673,7 @@ func ResourceComputeInstance() *schema.Resource { Optional: true, Elem: &schema.Schema{Type: schema.TypeString}, Description: `A set of key/value label pairs assigned to the instance. - + **Note**: This field is non-authoritative, and will only manage the labels present in your configuration. Please refer to the field 'effective_labels' for all of the labels present on the resource.`, }, @@ -1422,7 +1422,7 @@ func resourceComputeInstanceCreate(d *schema.ResourceData, meta interface{}) err return fmt.Errorf("Error creating instance while setting the security policies: %s", err) } <% end -%> - + err = waitUntilInstanceHasDesiredStatus(config, d) if err != nil { return fmt.Errorf("Error waiting for status: %s", err) @@ -1936,7 +1936,7 @@ func resourceComputeInstanceUpdate(d *schema.ResourceData, meta interface{}) err return fmt.Errorf("Instance had unexpected number of network interfaces: %d", len(instance.NetworkInterfaces)) } - <% unless version == 'ga' -%> + <% unless version == 'ga' -%> updateSecurityPolicy := false for i := 0; i < len(instance.NetworkInterfaces); i++ { prefix := fmt.Sprintf("network_interface.%d", i) diff --git a/mmv1/third_party/terraform/services/container/node_config.go.erb b/mmv1/third_party/terraform/services/container/node_config.go.erb index af3492f29413..8d53ce85b51d 100644 --- a/mmv1/third_party/terraform/services/container/node_config.go.erb +++ b/mmv1/third_party/terraform/services/container/node_config.go.erb @@ -675,6 +675,11 @@ func schemaNodeConfig() *schema.Schema { }, }, }, + "resource_manager_tags": { + Type: schema.TypeMap, + Optional: true, + Description: `A map of resource manager tags. Resource manager tag keys and values have the same definition as resource manager tags. Keys must be in the format tagKeys/{tag_key_id}, and values are in the format tagValues/456. The field is ignored (both PUT & PATCH) when empty.`, + }, <% unless version == 'ga' -%> "enable_confidential_storage": { Type: schema.TypeBool, @@ -884,6 +889,10 @@ func expandNodeConfig(v interface{}) *container.NodeConfig { nc.ResourceLabels = m } + if v, ok := nodeConfig["resource_manager_tags"]; ok && len(v.(map[string]interface{})) > 0 { + nc.ResourceManagerTags = expandResourceManagerTags(v) + } + if v, ok := nodeConfig["tags"]; ok { tagsList := v.([]interface{}) tags := []string{} @@ -974,7 +983,7 @@ func expandNodeConfig(v interface{}) *container.NodeConfig { nc.EnableConfidentialStorage = v.(bool) } <% end -%> - + <% unless version == "ga" -%> if v, ok := nodeConfig["host_maintenance_policy"]; ok { nc.HostMaintenancePolicy = expandHostMaintenancePolicy(v) @@ -988,6 +997,19 @@ func expandNodeConfig(v interface{}) *container.NodeConfig { return nc } +func expandResourceManagerTags(v interface{}) *container.ResourceManagerTags { + rmts := make(map[string]string) + + if v != nil { + rmts = tpgresource.ConvertStringMap(v.(map[string]interface{})) + } + + return &container.ResourceManagerTags{ + Tags: rmts, + ForceSendFields: []string{"Tags"}, + } +} + func expandWorkloadMetadataConfig(v interface{}) *container.WorkloadMetadataConfig { if v == nil { return nil @@ -1213,7 +1235,8 @@ func flattenNodeConfig(c *container.NodeConfig, v interface{}) []map[string]inte "advanced_machine_features": flattenAdvancedMachineFeaturesConfig(c.AdvancedMachineFeatures), "sole_tenant_config": flattenSoleTenantConfig(c.SoleTenantConfig), "fast_socket": flattenFastSocket(c.FastSocket), - <% unless version == 'ga' -%> + "resource_manager_tags": flattenResourceManagerTags(c.ResourceManagerTags), + <% unless version == 'ga' -%> "enable_confidential_storage": c.EnableConfidentialStorage, <% end -%> }) @@ -1225,6 +1248,19 @@ func flattenNodeConfig(c *container.NodeConfig, v interface{}) []map[string]inte return config } +func flattenResourceManagerTags(c *container.ResourceManagerTags) map[string]interface{} { + rmt := make(map[string]interface{}) + + if c != nil { + for k, v := range c.Tags { + rmt[k] = v + } + + } + + return rmt +} + func flattenAdvancedMachineFeaturesConfig(c *container.AdvancedMachineFeatures) []map[string]interface{} { result := []map[string]interface{}{} if c != nil { diff --git a/mmv1/third_party/terraform/services/container/resource_container_cluster.go.erb b/mmv1/third_party/terraform/services/container/resource_container_cluster.go.erb index 0ab9a425f653..00a3f3aaab84 100644 --- a/mmv1/third_party/terraform/services/container/resource_container_cluster.go.erb +++ b/mmv1/third_party/terraform/services/container/resource_container_cluster.go.erb @@ -97,6 +97,7 @@ var ( forceNewClusterNodeConfigFields = []string{ "labels", "workload_metadata_config", + "resource_manager_tags", } suppressDiffForAutopilot = schema.SchemaDiffSuppressFunc(func(k, oldValue, newValue string, d *schema.ResourceData) bool { @@ -1424,11 +1425,11 @@ func ResourceContainerCluster() *schema.Resource { "node_pool_defaults": clusterSchemaNodePoolDefaults(), "node_pool_auto_config": { - Type: schema.TypeList, - Optional: true, - Computed: true, - MaxItems: 1, - Description: `Node pool configs that apply to all auto-provisioned node pools in autopilot clusters and node auto-provisioning enabled clusters.`, + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Description: `Node pool configs that apply to all auto-provisioned node pools in autopilot clusters and node auto-provisioning enabled clusters.`, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "network_tags": { @@ -5266,7 +5267,7 @@ func expandFleet(configured interface{}) *container.Fleet { return &container.Fleet{ Project: config["project"].(string), } -} +} func expandEnableK8sBetaApis(configured interface{}, enabledAPIs []string) *container.K8sBetaAPIConfig { l := configured.([]interface{}) @@ -5424,6 +5425,7 @@ func expandNodePoolAutoConfig(configured interface{}) *container.NodePoolAutoCon if v, ok := config["network_tags"]; ok && len(v.([]interface{})) > 0 { npac.NetworkTags = expandNodePoolAutoConfigNetworkTags(v) } + return npac } @@ -6129,7 +6131,7 @@ func flattenFleet(c *container.Fleet) []map[string]interface{} { membership_id = match[4] membership_location = match[3] } - + return []map[string]interface{}{ { "project": c.Project, diff --git a/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb b/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb index c57254c7e06d..a542384379f6 100644 --- a/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb +++ b/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb @@ -56,6 +56,43 @@ func TestAccContainerCluster_basic(t *testing.T) { }) } +func TestAccContainerCluster_resourceManagerTags(t *testing.T) { + t.Parallel() + + pid := envvar.GetTestProjectFromEnv() + + randomSuffix := acctest.RandString(t, 10) + clusterName := fmt.Sprintf("tf-test-cluster-%s", randomSuffix) + + networkName := acctest.BootstrapSharedTestNetwork(t, "gke-cluster") + subnetworkName := acctest.BootstrapSubnet(t, "gke-cluster", networkName) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + CheckDestroy: testAccCheckContainerClusterDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccContainerCluster_resourceManagerTags(pid, clusterName, networkName, subnetworkName, randomSuffix), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("google_container_cluster.primary", "self_link"), + resource.TestCheckResourceAttrSet("google_container_cluster.primary", "node_config.0.resource_manager_tags.%"), + ), + }, + { + ResourceName: "google_container_cluster.primary", + ImportStateId: fmt.Sprintf("us-central1-a/%s", clusterName), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"min_master_version", "deletion_protection"}, + }, + }, + }) +} + func TestAccContainerCluster_networkingModeRoutes(t *testing.T) { t.Parallel() @@ -2843,9 +2880,9 @@ func TestAccContainerCluster_withAutopilot(t *testing.T) { clusterName := fmt.Sprintf("tf-test-cluster-%s", acctest.RandString(t, 10)) acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, + PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - CheckDestroy: testAccCheckContainerClusterDestroyProducer(t), + CheckDestroy: testAccCheckContainerClusterDestroyProducer(t), Steps: []resource.TestStep{ { Config: testAccContainerCluster_withAutopilot(pid, containerNetName, clusterName, "us-central1", true, false, ""), @@ -2856,7 +2893,7 @@ func TestAccContainerCluster_withAutopilot(t *testing.T) { { ResourceName: "google_container_cluster.with_autopilot", ImportState: true, - ImportStateVerify: true, + ImportStateVerify: true, ImportStateVerifyIgnore: []string{"min_master_version", "deletion_protection"}, }, }, @@ -2872,9 +2909,9 @@ func TestAccContainerClusterCustomServiceAccount_withAutopilot(t *testing.T) { serviceAccountName := fmt.Sprintf("tf-test-sa-%s", acctest.RandString(t, 10)) acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, + PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - CheckDestroy: testAccCheckContainerClusterDestroyProducer(t), + CheckDestroy: testAccCheckContainerClusterDestroyProducer(t), Steps: []resource.TestStep{ { Config: testAccContainerCluster_withAutopilot(pid, containerNetName, clusterName, "us-central1", true, false, serviceAccountName), @@ -2891,7 +2928,7 @@ func TestAccContainerClusterCustomServiceAccount_withAutopilot(t *testing.T) { { ResourceName: "google_container_cluster.with_autopilot", ImportState: true, - ImportStateVerify: true, + ImportStateVerify: true, ImportStateVerifyIgnore: []string{"min_master_version", "deletion_protection"}, }, }, @@ -2906,9 +2943,9 @@ func TestAccContainerCluster_errorAutopilotLocation(t *testing.T) { clusterName := fmt.Sprintf("tf-test-cluster-%s", acctest.RandString(t, 10)) acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, + PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - CheckDestroy: testAccCheckContainerClusterDestroyProducer(t), + CheckDestroy: testAccCheckContainerClusterDestroyProducer(t), Steps: []resource.TestStep{ { Config: testAccContainerCluster_withAutopilot(pid, containerNetName, clusterName, "us-central1-a", true, false, ""), @@ -2926,9 +2963,9 @@ func TestAccContainerCluster_withAutopilotNetworkTags(t *testing.T) { clusterName := fmt.Sprintf("tf-test-cluster-%s", acctest.RandString(t, 10)) acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, + PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - CheckDestroy: testAccCheckContainerClusterDestroyProducer(t), + CheckDestroy: testAccCheckContainerClusterDestroyProducer(t), Steps: []resource.TestStep{ { Config: testAccContainerCluster_withAutopilot(pid, containerNetName, clusterName, "us-central1", true, true, ""), @@ -4444,11 +4481,11 @@ func testAccContainerCluster_withIncompatibleMasterVersionNodeVersion(name strin resource "google_container_cluster" "gke_cluster" { name = "%s" location = "us-central1" - + min_master_version = "1.10.9-gke.5" node_version = "1.10.6-gke.11" initial_node_count = 1 - + } `, name) } @@ -6674,7 +6711,7 @@ resource "google_container_cluster" "with_autoprovisioning" { min_master_version = data.google_container_engine_versions.central1a.latest_master_version initial_node_count = 1 deletion_protection = false - + network = "%s" subnetwork = "%s" @@ -9250,7 +9287,7 @@ resource "google_compute_resource_policy" "policy" { resource "google_container_cluster" "cluster" { name = "%s" location = "us-central1-a" - + node_pool { name = "%s" initial_node_count = 2 @@ -9285,7 +9322,7 @@ func testAccContainerCluster_additional_pod_ranges_config(name string, nameCount } `, podRangeNamesStr) } - + return fmt.Sprintf(` resource "google_compute_network" "main" { name = "%s" @@ -9561,3 +9598,86 @@ func testAccContainerCluster_withWorkloadALTSConfig(projectID, name, networkName `, projectID, networkName, subnetworkName, name, enable) } <% end -%> + +func testAccContainerCluster_resourceManagerTags(projectID, clusterName, networkName, subnetworkName, randomSuffix string) string { + return fmt.Sprintf(` +data "google_project" "project" { + project_id = "%[1]s" +} + +resource "google_project_iam_binding" "tagHoldAdmin" { + project = "%[1]s" + role = "roles/resourcemanager.tagHoldAdmin" + members = [ + "serviceAccount:service-${data.google_project.project.number}@container-engine-robot.iam.gserviceaccount.com", + ] +} + +resource "google_project_iam_binding" "tagUser" { + project = "%[1]s" + role = "roles/resourcemanager.tagUser" + members = [ + "serviceAccount:service-${data.google_project.project.number}@container-engine-robot.iam.gserviceaccount.com", + "serviceAccount:${data.google_project.project.number}@cloudservices.gserviceaccount.com", + ] + + depends_on = [google_project_iam_binding.tagHoldAdmin] +} + +resource "time_sleep" "wait_120_seconds" { + create_duration = "120s" + + depends_on = [ + google_project_iam_binding.tagHoldAdmin, + google_project_iam_binding.tagUser + ] +} + +resource "google_tags_tag_key" "key" { + parent = "projects/%[1]s" + short_name = "foobarbaz-%[2]s" + description = "For foo/bar resources" + purpose = "GCE_FIREWALL" + purpose_data = { + network = "%[1]s/%[4]s" + } +} + +resource "google_tags_tag_value" "value" { + parent = "tagKeys/${google_tags_tag_key.key.name}" + short_name = "foo-%[2]s" + description = "For foo resources" +} + +data "google_container_engine_versions" "uscentral1a" { + location = "us-central1-a" +} + +resource "google_container_cluster" "primary" { + name = "%[3]s" + location = "us-central1-a" + min_master_version = data.google_container_engine_versions.uscentral1a.release_channel_latest_version["STABLE"] + initial_node_count = 1 + + node_config { + machine_type = "n1-standard-1" // can't be e2 because of local-ssd + disk_size_gb = 15 + + resource_manager_tags = { + "tagKeys/${google_tags_tag_key.key.name}" = "tagValues/${google_tags_tag_value.value.name}" + } + } + + deletion_protection = false + network = "%[4]s" + subnetwork = "%[5]s" + + timeouts { + create = "30m" + update = "40m" + } + + depends_on = [time_sleep.wait_120_seconds] +} +`, projectID, randomSuffix, clusterName, networkName, subnetworkName) +} diff --git a/mmv1/third_party/terraform/services/container/resource_container_node_pool.go.erb b/mmv1/third_party/terraform/services/container/resource_container_node_pool.go.erb index a4208ccfd799..025ed420fdde 100644 --- a/mmv1/third_party/terraform/services/container/resource_container_node_pool.go.erb +++ b/mmv1/third_party/terraform/services/container/resource_container_node_pool.go.erb @@ -1605,6 +1605,48 @@ func nodePoolUpdate(d *schema.ResourceData, meta interface{}, nodePoolInfo *Node log.Printf("[INFO] Updated tags for node pool %s", name) } + if d.HasChange(prefix + "node_config.0.resource_manager_tags") { + req := &container.UpdateNodePoolRequest{ + Name: name, + } + if v, ok := d.GetOk(prefix + "node_config.0.resource_manager_tags"); ok { + req.ResourceManagerTags = expandResourceManagerTags(v) + } + + // sets resource manager tags to the empty list when user removes a previously defined list of tags entriely + // aka the node pool goes from having tags to no longer having any + if req.ResourceManagerTags == nil { + tags := make(map[string]string) + rmTags := &container.ResourceManagerTags{ + Tags: tags, + } + req.ResourceManagerTags = rmTags + } + + updateF := func() error { + clusterNodePoolsUpdateCall := config.NewContainerClient(userAgent).Projects.Locations.Clusters.NodePools.Update(nodePoolInfo.fullyQualifiedName(name), req) + if config.UserProjectOverride { + clusterNodePoolsUpdateCall.Header().Add("X-Goog-User-Project", nodePoolInfo.project) + } + op, err := clusterNodePoolsUpdateCall.Do() + if err != nil { + return err + } + + // Wait until it's updated + return ContainerOperationWait(config, op, + nodePoolInfo.project, + nodePoolInfo.location, + "updating GKE node pool resource manager tags", userAgent, + timeout) + } + + if err := retryWhileIncompatibleOperation(timeout, npLockKey, updateF); err != nil { + return err + } + log.Printf("[INFO] Updated resource manager tags for node pool %s", name) + } + if d.HasChange(prefix + "node_config.0.resource_labels") { req := &container.UpdateNodePoolRequest{ Name: name, diff --git a/mmv1/third_party/terraform/services/container/resource_container_node_pool_test.go.erb b/mmv1/third_party/terraform/services/container/resource_container_node_pool_test.go.erb index e06180e6c0e9..42939e9b7e9b 100644 --- a/mmv1/third_party/terraform/services/container/resource_container_node_pool_test.go.erb +++ b/mmv1/third_party/terraform/services/container/resource_container_node_pool_test.go.erb @@ -37,6 +37,61 @@ func TestAccContainerNodePool_basic(t *testing.T) { }) } +func TestAccContainerNodePool_resourceManagerTags(t *testing.T) { + t.Parallel() + pid := envvar.GetTestProjectFromEnv() + + randomSuffix := acctest.RandString(t, 10) + clusterName := fmt.Sprintf("tf-test-cluster-%s", randomSuffix) + + networkName := acctest.BootstrapSharedTestNetwork(t, "gke-cluster") + subnetworkName := acctest.BootstrapSubnet(t, "gke-cluster", networkName) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "time": {}, + }, + CheckDestroy: testAccCheckContainerClusterDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccContainerNodePool_resourceManagerTags(pid, clusterName, networkName, subnetworkName, randomSuffix), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("google_container_node_pool.primary_nodes", "node_config.0.resource_manager_tags.%"), + ), + }, + { + ResourceName: "google_container_node_pool.primary_nodes", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"min_master_version", "cluster"}, + }, + { + Config: testAccContainerNodePool_resourceManagerTagsUpdate1(pid, clusterName, networkName, subnetworkName, randomSuffix), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("google_container_node_pool.primary_nodes", "node_config.0.resource_manager_tags.%"), + ), + }, + { + ResourceName: "google_container_node_pool.primary_nodes", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"min_master_version", "cluster"}, + }, + { + Config: testAccContainerNodePool_resourceManagerTagsUpdate2(pid, clusterName, networkName, subnetworkName, randomSuffix), + }, + { + ResourceName: "google_container_node_pool.primary_nodes", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"min_master_version", "cluster"}, + }, + }, + }) +} + func TestAccContainerNodePool_basicWithClusterId(t *testing.T) { t.Parallel() @@ -4132,7 +4187,7 @@ resource "google_container_node_pool" "with_confidential_boot_disk" { name = "%s" location = "us-central1-a" cluster = google_container_cluster.cluster.name - + node_config { image_type = "COS_CONTAINERD" boot_disk_kms_key = "%s" @@ -4149,7 +4204,7 @@ resource "google_container_node_pool" "with_confidential_boot_disk" { } func TestAccContainerNodePool_withoutConfidentialBootDisk(t *testing.T) { - t.Parallel() + t.Parallel() cluster := fmt.Sprintf("tf-test-cluster-%s", acctest.RandString(t, 10)) np := fmt.Sprintf("tf-test-np-%s", acctest.RandString(t, 10)) @@ -4193,7 +4248,7 @@ resource "google_container_node_pool" "without_confidential_boot_disk" { name = "%s" location = "us-central1-a" cluster = google_container_cluster.cluster.name - + node_config { image_type = "COS_CONTAINERD" oauth_scopes = [ @@ -4208,3 +4263,348 @@ resource "google_container_node_pool" "without_confidential_boot_disk" { `, cluster, networkName, subnetworkName, np) } <% end -%> + +func testAccContainerNodePool_resourceManagerTags(projectID, clusterName, networkName, subnetworkName, randomSuffix string) string { + return fmt.Sprintf(` +data "google_project" "project" { + project_id = "%[1]s" +} + +resource "google_project_iam_binding" "tagHoldAdmin" { + project = "%[1]s" + role = "roles/resourcemanager.tagHoldAdmin" + members = [ + "serviceAccount:service-${data.google_project.project.number}@container-engine-robot.iam.gserviceaccount.com", + ] +} + +resource "google_project_iam_binding" "tagUser" { + project = "%[1]s" + role = "roles/resourcemanager.tagUser" + members = [ + "serviceAccount:service-${data.google_project.project.number}@container-engine-robot.iam.gserviceaccount.com", + "serviceAccount:${data.google_project.project.number}@cloudservices.gserviceaccount.com", + ] + + depends_on = [google_project_iam_binding.tagHoldAdmin] +} + +resource "time_sleep" "wait_120_seconds" { + create_duration = "120s" + + depends_on = [ + google_project_iam_binding.tagHoldAdmin, + google_project_iam_binding.tagUser + ] +} + +resource "google_tags_tag_key" "key1" { + parent = "projects/%[1]s" + short_name = "foobarbaz1-%[2]s" + description = "For foo/bar1 resources" + purpose = "GCE_FIREWALL" + purpose_data = { + network = "%[1]s/%[4]s" + } +} + +resource "google_tags_tag_value" "value1" { + parent = "tagKeys/${google_tags_tag_key.key1.name}" + short_name = "foo1-%[2]s" + description = "For foo1 resources" +} + +resource "google_tags_tag_key" "key2" { + parent = "projects/%[1]s" + short_name = "foobarbaz2-%[2]s" + description = "For foo/bar2 resources" + purpose = "GCE_FIREWALL" + purpose_data = { + network = "%[1]s/%[4]s" + } + + depends_on = [google_tags_tag_key.key1] +} + +resource "google_tags_tag_value" "value2" { + parent = "tagKeys/${google_tags_tag_key.key2.name}" + short_name = "foo2-%[2]s" + description = "For foo2 resources" +} + +data "google_container_engine_versions" "uscentral1a" { + location = "us-central1-a" +} + +resource "google_container_cluster" "primary" { + name = "%[3]s" + location = "us-central1-a" + min_master_version = data.google_container_engine_versions.uscentral1a.release_channel_latest_version["STABLE"] + + # We can't create a cluster with no node pool defined, but we want to only use + # separately managed node pools. So we create the smallest possible default + # node pool and immediately delete it. + remove_default_node_pool = true + initial_node_count = 1 + + deletion_protection = false + network = "%[4]s" + subnetwork = "%[5]s" + + timeouts { + create = "30m" + update = "40m" + } + + depends_on = [time_sleep.wait_120_seconds] +} + +# Separately Managed Node Pool +resource "google_container_node_pool" "primary_nodes" { + name = google_container_cluster.primary.name + location = "us-central1-a" + cluster = google_container_cluster.primary.name + + version = data.google_container_engine_versions.uscentral1a.release_channel_latest_version["STABLE"] + node_count = 1 + + node_config { + machine_type = "n1-standard-1" // can't be e2 because of local-ssd + disk_size_gb = 15 + + resource_manager_tags = { + "tagKeys/${google_tags_tag_key.key1.name}" = "tagValues/${google_tags_tag_value.value1.name}" + } + } +} +`, projectID, randomSuffix, clusterName, networkName, subnetworkName) +} + +func testAccContainerNodePool_resourceManagerTagsUpdate1(projectID, clusterName, networkName, subnetworkName, randomSuffix string) string { + return fmt.Sprintf(` +data "google_project" "project" { + project_id = "%[1]s" +} + +resource "google_project_iam_binding" "tagHoldAdmin" { + project = "%[1]s" + role = "roles/resourcemanager.tagHoldAdmin" + members = [ + "serviceAccount:service-${data.google_project.project.number}@container-engine-robot.iam.gserviceaccount.com", + ] +} + +resource "google_project_iam_binding" "tagUser" { + project = "%[1]s" + role = "roles/resourcemanager.tagUser" + members = [ + "serviceAccount:service-${data.google_project.project.number}@container-engine-robot.iam.gserviceaccount.com", + "serviceAccount:${data.google_project.project.number}@cloudservices.gserviceaccount.com", + ] + + depends_on = [google_project_iam_binding.tagHoldAdmin] +} + +resource "time_sleep" "wait_120_seconds" { + create_duration = "120s" + + depends_on = [ + google_project_iam_binding.tagHoldAdmin, + google_project_iam_binding.tagUser + ] +} + +resource "google_tags_tag_key" "key1" { + parent = "projects/%[1]s" + short_name = "foobarbaz1-%[2]s" + description = "For foo/bar1 resources" + purpose = "GCE_FIREWALL" + purpose_data = { + network = "%[1]s/%[4]s" + } +} + +resource "google_tags_tag_value" "value1" { + parent = "tagKeys/${google_tags_tag_key.key1.name}" + short_name = "foo1-%[2]s" + description = "For foo1 resources" +} + +resource "google_tags_tag_key" "key2" { + parent = "projects/%[1]s" + short_name = "foobarbaz2-%[2]s" + description = "For foo/bar2 resources" + purpose = "GCE_FIREWALL" + purpose_data = { + network = "%[1]s/%[4]s" + } + + depends_on = [google_tags_tag_key.key1] +} + +resource "google_tags_tag_value" "value2" { + parent = "tagKeys/${google_tags_tag_key.key2.name}" + short_name = "foo2-%[2]s" + description = "For foo2 resources" +} + +data "google_container_engine_versions" "uscentral1a" { + location = "us-central1-a" +} + +resource "google_container_cluster" "primary" { + name = "%[3]s" + location = "us-central1-a" + min_master_version = data.google_container_engine_versions.uscentral1a.release_channel_latest_version["STABLE"] + + # We can't create a cluster with no node pool defined, but we want to only use + # separately managed node pools. So we create the smallest possible default + # node pool and immediately delete it. + remove_default_node_pool = true + initial_node_count = 1 + + deletion_protection = false + network = "%[4]s" + subnetwork = "%[5]s" + + timeouts { + create = "30m" + update = "40m" + } + + depends_on = [time_sleep.wait_120_seconds] +} + +# Separately Managed Node Pool +resource "google_container_node_pool" "primary_nodes" { + name = google_container_cluster.primary.name + location = "us-central1-a" + cluster = google_container_cluster.primary.name + + version = data.google_container_engine_versions.uscentral1a.release_channel_latest_version["STABLE"] + node_count = 1 + + node_config { + machine_type = "n1-standard-1" // can't be e2 because of local-ssd + disk_size_gb = 15 + + resource_manager_tags = { + "tagKeys/${google_tags_tag_key.key1.name}" = "tagValues/${google_tags_tag_value.value1.name}" + "tagKeys/${google_tags_tag_key.key2.name}" = "tagValues/${google_tags_tag_value.value2.name}" + } + } +} +`, projectID, randomSuffix, clusterName, networkName, subnetworkName) +} + +func testAccContainerNodePool_resourceManagerTagsUpdate2(projectID, clusterName, networkName, subnetworkName, randomSuffix string) string { + return fmt.Sprintf(` +data "google_project" "project" { + project_id = "%[1]s" +} + +resource "google_project_iam_binding" "tagHoldAdmin" { + project = "%[1]s" + role = "roles/resourcemanager.tagHoldAdmin" + members = [ + "serviceAccount:service-${data.google_project.project.number}@container-engine-robot.iam.gserviceaccount.com", + ] +} + +resource "google_project_iam_binding" "tagUser" { + project = "%[1]s" + role = "roles/resourcemanager.tagUser" + members = [ + "serviceAccount:service-${data.google_project.project.number}@container-engine-robot.iam.gserviceaccount.com", + "serviceAccount:${data.google_project.project.number}@cloudservices.gserviceaccount.com", + ] + + depends_on = [google_project_iam_binding.tagHoldAdmin] +} + +resource "time_sleep" "wait_120_seconds" { + create_duration = "120s" + + depends_on = [ + google_project_iam_binding.tagHoldAdmin, + google_project_iam_binding.tagUser + ] +} + +resource "google_tags_tag_key" "key1" { + parent = "projects/%[1]s" + short_name = "foobarbaz1-%[2]s" + description = "For foo/bar1 resources" + purpose = "GCE_FIREWALL" + purpose_data = { + network = "%[1]s/%[4]s" + } +} + +resource "google_tags_tag_value" "value1" { + parent = "tagKeys/${google_tags_tag_key.key1.name}" + short_name = "foo1-%[2]s" + description = "For foo1 resources" +} + +resource "google_tags_tag_key" "key2" { + parent = "projects/%[1]s" + short_name = "foobarbaz2-%[2]s" + description = "For foo/bar2 resources" + purpose = "GCE_FIREWALL" + purpose_data = { + network = "%[1]s/%[4]s" + } + + depends_on = [google_tags_tag_key.key1] +} + +resource "google_tags_tag_value" "value2" { + parent = "tagKeys/${google_tags_tag_key.key2.name}" + short_name = "foo2-%[2]s" + description = "For foo2 resources" +} + +data "google_container_engine_versions" "uscentral1a" { + location = "us-central1-a" +} + +resource "google_container_cluster" "primary" { + name = "%[3]s" + location = "us-central1-a" + min_master_version = data.google_container_engine_versions.uscentral1a.release_channel_latest_version["STABLE"] + + # We can't create a cluster with no node pool defined, but we want to only use + # separately managed node pools. So we create the smallest possible default + # node pool and immediately delete it. + remove_default_node_pool = true + initial_node_count = 1 + + deletion_protection = false + network = "%[4]s" + subnetwork = "%[5]s" + + timeouts { + create = "30m" + update = "40m" + } + + depends_on = [time_sleep.wait_120_seconds] +} + +# Separately Managed Node Pool +resource "google_container_node_pool" "primary_nodes" { + name = google_container_cluster.primary.name + location = "us-central1-a" + cluster = google_container_cluster.primary.name + + version = data.google_container_engine_versions.uscentral1a.release_channel_latest_version["STABLE"] + node_count = 1 + + node_config { + machine_type = "n1-standard-1" // can't be e2 because of local-ssd + disk_size_gb = 15 + } +} +`, projectID, randomSuffix, clusterName, networkName, subnetworkName) +} diff --git a/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown b/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown index b7713ba6d51c..3c72beba2d55 100644 --- a/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown @@ -905,6 +905,8 @@ gvnic { * `tags` - (Optional) The list of instance tags applied to all nodes. Tags are used to identify valid sources or targets for network firewalls. +* `resource_manager_tags` - (Optional) A map of resource manager tag keys and values to be attached to the nodes for managing Compute Engine firewalls using Network Firewall Policies. Tags must be according to specifications found [here](https://cloud.google.com/vpc/docs/tags-firewalls-overview#specifications). A maximum of 5 tag key-value pairs can be specified. Existing tags will be replaced with new values. Tags must be in one of the following formats ([KEY]=[VALUE]) 1. `tagKeys/{tag_key_id}=tagValues/{tag_value_id}` 2. `{org_id}/{tag_key_name}={tag_value_name}` 3. `{project_id}/{tag_key_name}={tag_value_name}`. + * `taint` - (Optional) A list of [Kubernetes taints](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/) to apply to nodes. This field will only report drift on taint keys that are @@ -998,7 +1000,7 @@ sole_tenant_config { * `count` (Required) - The number of the guest accelerator cards exposed to this instance. * `gpu_driver_installation_config` (Optional) - Configuration for auto installation of GPU driver. Structure is [documented below](#nested_gpu_driver_installation_config). - + * `gpu_partition_size` (Optional) - Size of partitions to create on the GPU. Valid values are described in the NVIDIA mig [user guide](https://docs.nvidia.com/datacenter/tesla/mig-user-guide/#partitioning). * `gpu_sharing_config` (Optional) - Configuration for GPU sharing. Structure is [documented below](#nested_gpu_sharing_config). @@ -1345,7 +1347,7 @@ exported: * `node_config.0.effective_taints` - List of kubernetes taints applied to each node. Structure is [documented above](#nested_taint). -* `fleet.0.membership` - The resource name of the fleet Membership resource associated to this cluster with format `//gkehub.googleapis.com/projects/{{project}}/locations/{{location}}/memberships/{{name}}`. See the official doc for [fleet management](https://cloud.google.com/kubernetes-engine/docs/fleets-overview). +* `fleet.0.membership` - The resource name of the fleet Membership resource associated to this cluster with format `//gkehub.googleapis.com/projects/{{project}}/locations/{{location}}/memberships/{{name}}`. See the official doc for [fleet management](https://cloud.google.com/kubernetes-engine/docs/fleets-overview). * `fleet.0.membership_id` - The short name of the fleet membership, extracted from `fleet.0.membership`. You can use this field to configure `membership_id` under [google_gkehub_feature_membership](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/gke_hub_feature_membership). From 37fb2ebf10afb245649e86f17bc344bf7b10ef8b Mon Sep 17 00:00:00 2001 From: Oliver Krause <3621164+okrause@users.noreply.github.com> Date: Wed, 21 Feb 2024 22:18:20 +0100 Subject: [PATCH 50/77] Add volume replication support for Google Cloud NetApp Volumes (#9816) * Initial replication commit * Cleanup work - Renamed a lot of files to make clear which resource the belong to - Updated documentation for resource fields - Renamed a few resource fields and changed some types - Disabled the custom code for now. Needs to be discussed first * Update example file * Updated example file * Major updates - Reorganisation of block - Reorganisation of fields to match API documentation - Updated example parameters - Added missing API fields - Improved descriptions - * For replication deletion, stop replication first * Add support for deleting destination volume on replication delete * Make volumes deletable in presence of snapshots. This change will be PRed for volume resource independently. Adding it here while it is not in main. * Improving debug error message * yaml check and format fix * Add wait for mirror to initialize. Required to run destroy shortly after create. * Wait on destroy, not on create * Make deleting a replication more robust - doc improvements - started to implement stop/resume. More work required. - renamed a few files to better reflect what they are good for * adding support for stop/resume * yamlformat and lint * Add force delete to delete volumes with nested snapshots * resource test first version * More changes to make tests solid - Introduced new parameter to wait for mirror_status==MIRRORED - more mirror state reconciliation * Test updates * few cleanups * Make virtual field verifies happy * Minor test improvements * More fine tuning - Remove merge conflict in volume.yaml - make generated test work - make output field work - ignore_read for virtual fields * Resource name change as suggested by @slevenick * Remove snapshot code block and fix typo * Detect manual stop/resume actions * Remove ignore_read for deletion_policy * - Made destinationVolumeParameters immutable. It still requires ignore_read. - removed ignore_read from virtual_fields * destinationVolumeParameters are only evaluated at create. Make the immutable. * Name cleanups and comment improvements * removed comment Co-authored-by: Shuya Ma <87669292+shuyama1@users.noreply.github.com> * tabs to spaces in resource block Co-authored-by: Shuya Ma <87669292+shuyama1@users.noreply.github.com> * Updates to address review comments - make wait_for_mirror also work for stop/resume, additionally to create - convert tabs in test resource blocks to spaces - fix typos * Rewording of comments Co-authored-by: Shuya Ma <87669292+shuyama1@users.noreply.github.com> --------- Co-authored-by: G-NamanGupta Co-authored-by: Shuya Ma <87669292+shuyama1@users.noreply.github.com> --- mmv1/products/netapp/VolumeReplication.yaml | 289 +++++++++++++++++ .../netapp_volume_replication.go.erb | 51 +++ ...tapp_volume_replicaton_mirror_state.go.erb | 20 ++ .../netapp_volume_replication_create.tf.erb | 54 ++++ ...tapp_volume_replication_post_create.go.erb | 7 + ...plication_delete_destination_volume.go.erb | 34 ++ ...app_volume_replication_mirror_state.go.erb | 89 +++++ ...lume_replication_stop_before_delete.go.erb | 33 ++ ...resource_netapp_volume_replication_test.go | 306 ++++++++++++++++++ 9 files changed, 883 insertions(+) create mode 100644 mmv1/products/netapp/VolumeReplication.yaml create mode 100644 mmv1/templates/terraform/constants/netapp_volume_replication.go.erb create mode 100644 mmv1/templates/terraform/custom_flatten/netapp_volume_replicaton_mirror_state.go.erb create mode 100644 mmv1/templates/terraform/examples/netapp_volume_replication_create.tf.erb create mode 100644 mmv1/templates/terraform/post_create/netapp_volume_replication_post_create.go.erb create mode 100644 mmv1/templates/terraform/post_delete/netapp_volume_replication_delete_destination_volume.go.erb create mode 100644 mmv1/templates/terraform/post_update/netapp_volume_replication_mirror_state.go.erb create mode 100644 mmv1/templates/terraform/pre_delete/netapp_volume_replication_stop_before_delete.go.erb create mode 100644 mmv1/third_party/terraform/services/netapp/resource_netapp_volume_replication_test.go diff --git a/mmv1/products/netapp/VolumeReplication.yaml b/mmv1/products/netapp/VolumeReplication.yaml new file mode 100644 index 000000000000..dd7dde9c7f32 --- /dev/null +++ b/mmv1/products/netapp/VolumeReplication.yaml @@ -0,0 +1,289 @@ +# Copyright 2023 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +!ruby/object:Api::Resource +name: "VolumeReplication" +description: | + Volume replication creates an asynchronous mirror of a volume in a different location. This capability + lets you use the replicated volume for critical application activity in case of a location-wide outage + or disaster. + + A new destination volume is created as part of the replication resource. It's content is updated on a + schedule with content of the source volume. It can be used as a read-only copy while the mirror is + enabled, or as an independent read-write volume while the mirror is stopped. A destination volume will + also contain the snapshots of the source volume. Resuming a mirror will overwrite all changes on the + destination volume with the content of the source volume. While is mirror is enabled, all configuration + changes done to source or destination volumes are automatically done to both. Please note that the + destination volume is not a resource managed by Terraform. + + Reversing the replication direction is not supported through the provider. +references: !ruby/object:Api::Resource::ReferenceLinks + guides: + "Documentation": "https://cloud.google.com/netapp/volumes/docs/protect-data/about-volume-replication" + api: "https://cloud.google.com/netapp/volumes/docs/reference/rest/v1/projects.locations.volumes.replications" +base_url: projects/{{project}}/locations/{{location}}/volumes/{{volume_name}}/replications +self_link: projects/{{project}}/locations/{{location}}/volumes/{{volume_name}}/replications/{{name}} +create_url: projects/{{project}}/locations/{{location}}/volumes/{{volume_name}}/replications?replicationId={{name}} +update_url: projects/{{project}}/locations/{{location}}/volumes/{{volume_name}}/replications/{{name}} +update_verb: :PATCH +update_mask: true +autogen_async: true +async: !ruby/object:Api::OpAsync + operation: !ruby/object:Api::OpAsync::Operation + base_url: "{{op_id}}" +id_format: "projects/{{project}}/locations/{{location}}/volumes/{{volume_name}}/replications/{{name}}" +import_format: + [ + "projects/{{project}}/locations/{{location}}/volumes/{{volume_name}}/replications/{{name}}", + ] +examples: + - !ruby/object:Provider::Terraform::Examples + name: "netapp_volume_replication_create" + primary_resource_id: "test_replication" + vars: + source_pool_name: "source-pool" + destination_pool_name: "destination-pool" + volume_name: "source-volume" + replication_name: "test-replication" + destination_volume: "destination-volume" + network_name: "test-network" + ignore_read_extra: + - "delete_destination_volume" + - "replication_enabled" + - "force_stopping" + - "wait_for_mirror" + test_vars_overrides: + network_name: 'acctest.BootstrapSharedServiceNetworkingConnection(t, "gcnv-network-config-1", acctest.ServiceNetworkWithParentService("netapp.servicenetworking.goog"))' +parameters: + - !ruby/object:Api::Type::String + name: "location" + required: true + immutable: true + url_param_only: true + description: | + Name of region for this resource. The resource needs to be created in the region of the destination volume. + - !ruby/object:Api::Type::String + name: "volumeName" + description: The name of the existing source volume. + required: true + immutable: true + url_param_only: true + - !ruby/object:Api::Type::String + name: "name" + description: The name of the replication. Needs to be unique per location. + required: true + immutable: true + url_param_only: true +properties: + - !ruby/object:Api::Type::Enum + name: "state" + description: | + Indicates the state of replication resource. State of the mirror itself is indicated in mirrorState. + values: + - :STATE_UNSPECIFIED + - :CREATING + - :READY + - :UPDATING + - :DELETING + - :ERROR + output: true + - !ruby/object:Api::Type::String + name: "stateDetails" + description: | + State details of the replication resource. + output: true + - !ruby/object:Api::Type::Enum + name: "role" + description: | + Reverting a replication can swap source and destination volume roles. This field indicates if the `location` hosts + the source or destination volume. For resume and revert and resume operations it is critical to understand + which volume is the source volume, since it will overwrite changes done to the destination volume. + values: + - :REPLICATION_ROLE_UNSPECIFIED + - :SOURCE + - :DESTINATION + output: true + - !ruby/object:Api::Type::Enum + name: "replicationSchedule" + description: | + Specifies the replication interval. + values: + - :EVERY_10_MINUTES + - :HOURLY + - :DAILY + required: true + - !ruby/object:Api::Type::Enum + name: "mirrorState" + description: | + Indicates the state of the mirror between source and destination volumes. Depending on the amount of data + in your source volume, PREPARING phase can take hours or days. mirrorState = MIRRORED indicates your baseline + transfer ended and destination volume became accessible read-only. TRANSFERRING means a MIRRORED volume + currently receives an update. Updated every 5 minutes. + values: + - :MIRROR_STATE_UNSPECIFIED + - :PREPARING + - :MIRRORED + - :STOPPED + - :TRANSFERRING + custom_flatten: templates/terraform/custom_flatten/netapp_volume_replicaton_mirror_state.go.erb + output: true + - !ruby/object:Api::Type::String + name: "createTime" + description: | + Create time of the active directory. A timestamp in RFC3339 UTC "Zulu" format. Examples: "2023-06-22T09:13:01.617Z". + output: true + - !ruby/object:Api::Type::String + name: "destinationVolume" + description: | + Full resource name of destination volume with format: `projects/{{project}}/locations/{{location}}/volumes/{{volumeId}}` + output: true + - !ruby/object:Api::Type::NestedObject + name: "transferStats" + description: |- + Replication transfer statistics. All statistics are updated every 5 minutes. + output: true + properties: + - !ruby/object:Api::Type::String + name: "transferBytes" + description: | + Number of bytes transferred so far in current transfer. + output: true + - !ruby/object:Api::Type::String + name: "totalTransferDuration" + description: | + Total time taken so far during current transfer. + output: true + - !ruby/object:Api::Type::String + name: "lastTransferBytes" + description: | + Size of last completed transfer in bytes. + output: true + - !ruby/object:Api::Type::String + name: "lastTransferDuration" + description: | + Time taken during last completed transfer. + output: true + - !ruby/object:Api::Type::String + name: "lagDuration" + description: | + The elapsed time since the creation of the snapshot on the source volume that was last replicated + to the destination volume. Lag time represents the difference in age of the destination volume + data in relation to the source volume data. + output: true + - !ruby/object:Api::Type::String + name: "updateTime" + description: | + Time when progress was updated last. A timestamp in RFC3339 UTC "Zulu" format. Examples: "2023-06-22T09:13:01.617Z". + output: true + - !ruby/object:Api::Type::String + name: "lastTransferEndTime" + description: | + Time when last transfer completed. A timestamp in RFC3339 UTC "Zulu" format. Examples: "2023-06-22T09:13:01.617Z". + output: true + - !ruby/object:Api::Type::String + name: "lastTransferError" + description: | + A message describing the cause of the last transfer failure. + output: true + - !ruby/object:Api::Type::KeyValueLabels + name: "labels" + description: | + Labels as key value pairs. Example: `{ "owner": "Bob", "department": "finance", "purpose": "testing" }` + - !ruby/object:Api::Type::NestedObject + name: "destinationVolumeParameters" + description: |- + Destination volume parameters. + # destinationVolumeParameters is only used on CREATE. Will not be returned on READ. + ignore_read: true + properties: + - !ruby/object:Api::Type::String + name: "storagePool" + description: | + Name of an existing storage pool for the destination volume with format: `projects/{{project}}/locations/{{location}}/storagePools/{{poolId}}` + immutable: true + required: true + - !ruby/object:Api::Type::String + name: "volumeId" + description: | + Name for the destination volume to be created. If not specified, the name of the source volume will be used. + immutable: true + default_from_api: true + - !ruby/object:Api::Type::String + name: "shareName" + description: | + Share name for destination volume. If not specified, name of source volume's share name will be used. + immutable: true + default_from_api: true + - !ruby/object:Api::Type::String + name: "description" + description: | + Description for the destination volume. + immutable: true + - !ruby/object:Api::Type::String + name: "sourceVolume" + description: | + Full resource name of source volume with format: `projects/{{project}}/locations/{{location}}/volumes/{{volumeId}}` + output: true + - !ruby/object:Api::Type::Boolean + name: "healthy" + description: | + Condition of the relationship. Can be one of the following: + - true: The replication relationship is healthy. It has not missed the most recent scheduled transfer. + - false: The replication relationship is not healthy. It has missed the most recent scheduled transfer. + output: true + - !ruby/object:Api::Type::String + name: "description" + description: | + An description of this resource. +virtual_fields: + - !ruby/object:Api::Type::Boolean + name: "delete_destination_volume" + description: | + A destination volume is created as part of replication creation. The destination volume will not became + under Terraform management unless you import it manually. If you delete the replication, this volume + will remain. + Setting this parameter to true will delete the *current* destination volume when destroying the + replication. If you reversed the replication direction, this will be your former source volume! + For production use, it is recommended to keep this parameter false to avoid accidental volume + deletion. Handle with care. Default is false. + default_value: false + - !ruby/object:Api::Type::Boolean + name: "replication_enabled" + description: | + Set to false to stop/break the mirror. Stopping the mirror makes the destination volume read-write + and act independently from the source volume. + Set to true to enable/resume the mirror. WARNING: Resuming a mirror overwrites any changes + done to the destination volume with the content of the source volume. + default_value: true + - !ruby/object:Api::Type::Boolean + name: "force_stopping" + description: | + Only replications with mirror_state=MIRRORED can be stopped. A replication in mirror_state=TRANSFERRING + currently receives an update and stopping the update might be undesirable. Set this parameter to true + to stop anyway. All data transferred to the destination will be discarded and content of destination + volume will remain at the state of the last successful update. Default is false. + default_value: false + - !ruby/object:Api::Type::Boolean + name: "wait_for_mirror" + description: | + Replication resource state is independent of mirror_state. With enough data, it can take many hours + for mirror_state to reach MIRRORED. If you want Terraform to wait for the mirror to finish on + create/stop/resume operations, set this parameter to true. Default is false. + default_value: false +custom_code: !ruby/object:Provider::Terraform::CustomCode + constants: templates/terraform/constants/netapp_volume_replication.go.erb + post_create: templates/terraform/post_create/netapp_volume_replication_post_create.go.erb + pre_delete: templates/terraform/pre_delete/netapp_volume_replication_stop_before_delete.go.erb + post_delete: templates/terraform/post_delete/netapp_volume_replication_delete_destination_volume.go.erb + post_update: templates/terraform/post_update/netapp_volume_replication_mirror_state.go.erb diff --git a/mmv1/templates/terraform/constants/netapp_volume_replication.go.erb b/mmv1/templates/terraform/constants/netapp_volume_replication.go.erb new file mode 100644 index 000000000000..10ec7b806253 --- /dev/null +++ b/mmv1/templates/terraform/constants/netapp_volume_replication.go.erb @@ -0,0 +1,51 @@ +// Custom function to wait for mirrorState target states +func NetAppVolumeReplicationWaitForMirror(d *schema.ResourceData, meta interface{}, targetState string) error { + config := meta.(*transport_tpg.Config) + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + url, err := tpgresource.ReplaceVars(d, config, "{{NetappBasePath}}projects/{{project}}/locations/{{location}}/volumes/{{volume_name}}/replications/{{name}}") + if err != nil { + return err + } + + billingProject := "" + + project, err := tpgresource.GetProject(d, config) + if err != nil { + return fmt.Errorf("Error fetching project for volume replication: %s", err) + } + billingProject = project + + // err == nil indicates that the billing_project value was found + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + for { + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: userAgent, + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("NetappVolumeReplication %q", d.Id())) + } + + log.Printf("[DEBUG] waiting for mirrorState. actual: %v, target: %v", res["mirrorState"], targetState) + + if res["mirrorState"] == targetState { + break + } + + time.Sleep(30 * time.Second) + // This method can potentially run for days, e.g. when setting up a replication for a source volume + // with dozens of TiB of data. Timeout handling yes/no? + } + + return nil +} \ No newline at end of file diff --git a/mmv1/templates/terraform/custom_flatten/netapp_volume_replicaton_mirror_state.go.erb b/mmv1/templates/terraform/custom_flatten/netapp_volume_replicaton_mirror_state.go.erb new file mode 100644 index 000000000000..90881e839b6e --- /dev/null +++ b/mmv1/templates/terraform/custom_flatten/netapp_volume_replicaton_mirror_state.go.erb @@ -0,0 +1,20 @@ +func flatten<%= prefix -%><%= titlelize_property(property) -%>(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Actual state of replication_enabled depends on mirrorState. let's update it. + // This is to pickup manual user STOP/RESUME operations on the replication. + if v == nil { + return v + } + + if v.(string) == "STOPPED" { + if err := d.Set("replication_enabled", false); err != nil { + return fmt.Errorf("Error setting replication_enabled: %s", err) + } + } else { + if err := d.Set("replication_enabled", true); err != nil { + return fmt.Errorf("Error setting replication_enabled: %s", err) + } + } + log.Printf("[DEBUG] value of replication_state : %v", d.Get("replication_enabled")) + + return v +} \ No newline at end of file diff --git a/mmv1/templates/terraform/examples/netapp_volume_replication_create.tf.erb b/mmv1/templates/terraform/examples/netapp_volume_replication_create.tf.erb new file mode 100644 index 000000000000..07b69c542b2b --- /dev/null +++ b/mmv1/templates/terraform/examples/netapp_volume_replication_create.tf.erb @@ -0,0 +1,54 @@ + +data "google_compute_network" "default" { + name = "<%= ctx[:vars]['network_name'] %>" +} + +resource "google_netapp_storage_pool" "source_pool" { + name = "<%= ctx[:vars]['source_pool_name'] %>" + location = "us-central1" + service_level = "PREMIUM" + capacity_gib = 2048 + network = data.google_compute_network.default.id +} + +resource "google_netapp_storage_pool" "destination_pool" { + name = "<%= ctx[:vars]['destination_pool_name'] %>" + location = "us-west2" + service_level = "PREMIUM" + capacity_gib = 2048 + network = data.google_compute_network.default.id +} + +resource "google_netapp_volume" "source_volume" { + location = google_netapp_storage_pool.source_pool.location + name = "<%= ctx[:vars]['volume_name'] %>" + capacity_gib = 100 + share_name = "<%= ctx[:vars]['volume_name'] %>" + storage_pool = google_netapp_storage_pool.source_pool.name + protocols = [ + "NFSV3" + ] + deletion_policy = "FORCE" +} + +resource "google_netapp_volume_replication" "<%= ctx[:primary_resource_id] %>" { + depends_on = [google_netapp_volume.source_volume] + location = google_netapp_volume.source_volume.location + volume_name = google_netapp_volume.source_volume.name + name = "<%= ctx[:vars]['replication_name'] %>" + replication_schedule = "EVERY_10_MINUTES" + description = "This is a replication resource" + destination_volume_parameters { + storage_pool = google_netapp_storage_pool.destination_pool.id + volume_id = "<%= ctx[:vars]['destination_volume'] %>" + # Keeping the share_name of source and destination the same + # simplifies implementing client failover concepts + share_name = "<%= ctx[:vars]['volume_name'] %>" + description = "This is a replicated volume" + } + # WARNING: Setting delete_destination_volume to true, will delete the + # CURRENT destination volume if the replication is deleted. Omit the field + # or set delete_destination_volume=false to avoid accidental volume deletion. + delete_destination_volume = true + wait_for_mirror = true +} diff --git a/mmv1/templates/terraform/post_create/netapp_volume_replication_post_create.go.erb b/mmv1/templates/terraform/post_create/netapp_volume_replication_post_create.go.erb new file mode 100644 index 000000000000..b2d44a9c063e --- /dev/null +++ b/mmv1/templates/terraform/post_create/netapp_volume_replication_post_create.go.erb @@ -0,0 +1,7 @@ +if d.Get("wait_for_mirror").(bool) == true { + // Wait for mirrorState=MIRRORED before treating the resource as created + err = NetAppVolumeReplicationWaitForMirror(d, meta, "MIRRORED") + if err != nil { + return fmt.Errorf("Error waiting for volume replication to reach mirror_state==MIRRORED: %s", err) + } +} \ No newline at end of file diff --git a/mmv1/templates/terraform/post_delete/netapp_volume_replication_delete_destination_volume.go.erb b/mmv1/templates/terraform/post_delete/netapp_volume_replication_delete_destination_volume.go.erb new file mode 100644 index 000000000000..5a14f1fb407c --- /dev/null +++ b/mmv1/templates/terraform/post_delete/netapp_volume_replication_delete_destination_volume.go.erb @@ -0,0 +1,34 @@ +// A replication CREATE also created a destination volume +// A user can chooses to delete the destination volume after deleting the replication +if d.Get("delete_destination_volume").(bool) == true { + log.Printf("[DEBUG] delete_destination_volume is true. Deleting destination volume %v", d.Get("destination_volume")) + destination_volume := d.Get("destination_volume").(string) + del_url, err := tpgresource.ReplaceVars(d, config, "{{NetappBasePath}}"+destination_volume+"?force=true") + if err != nil { + return err + } + + var obj map[string]interface{} + res_del, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "DELETE", + Project: billingProject, + RawURL: del_url, + UserAgent: userAgent, + Body: obj, + Timeout: d.Timeout(schema.TimeoutDelete), + }) + if err != nil { + return transport_tpg.HandleNotFoundError(err, d, "Volume") + } + + err = NetappOperationWaitTime( + config, res_del, project, "Deleting destination volume", userAgent, + d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return err + } + + log.Printf("[DEBUG] Finished deleting destination Volume %q: %#v", destination_volume, res_del) +} \ No newline at end of file diff --git a/mmv1/templates/terraform/post_update/netapp_volume_replication_mirror_state.go.erb b/mmv1/templates/terraform/post_update/netapp_volume_replication_mirror_state.go.erb new file mode 100644 index 000000000000..57a7146702e5 --- /dev/null +++ b/mmv1/templates/terraform/post_update/netapp_volume_replication_mirror_state.go.erb @@ -0,0 +1,89 @@ +// Manage stopping and resuming a mirror + +var obj2 map[string]interface{} +do_change := false +var action string +var targetState string +// state transitions +// there can be a glitch is a transfer starts/ends between reading mirrorState +// and sending the action. This will be very rare. No workaround. +if d.Get("replication_enabled").(bool) == true { + switch d.Get("mirror_state").(string) { + case "STOPPED": + // replication_enabled==true, mirrorState==STOPPED -> resume + action = "resume" + targetState = "MIRRORED" + do_change = true + default: + // replication_enabled==true, mirrorState!=STOPPED -> NOOP + do_change = false + } +} else { + switch d.Get("mirror_state").(string) { + case "MIRRORED": + // replication_enabled==false, mirrorState==MIRRORED -> stop + action = "stop" + targetState = "STOPPED" + do_change = true + case "TRANSFERRING": + // replication_enabled==false, mirrorState==TRANSFERRING -> force stop + // User needs to add force_stopping = true, otherwise will receive error + action = "stop" + targetState = "STOPPED" + do_change = true + case "PREPARING": + // replication_enabled==false, mirrorState==PREPARING -> stop + // Currently cannot be stopped. User will receive following error: + // Error code 3, message: invalid request error: "Replication in preparing state. Please wait until replication is in 'READY' STATE and try again later.". + // User needs to wait until mirrorState=MIRRORED + action = "stop" + targetState = "STOPPED" + do_change = true + default: + // replication_enabled==false, mirrorState==STOPPED -> NOOP + do_change = false + } + + if do_change == true && d.Get("force_stopping").(bool) == true { + obj2 = map[string]interface{}{ + "force": true, + } + } +} + +if do_change { + // We need to send STOP/RESUME API calls + rawurl, err := tpgresource.ReplaceVars(d, config, "{{NetappBasePath}}projects/{{project}}/locations/{{location}}/volumes/{{volume_name}}/replications/{{name}}:"+action) + if err != nil { + return err + } + + res2, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: billingProject, + RawURL: rawurl, + UserAgent: userAgent, + Body: obj2, + Timeout: d.Timeout(schema.TimeoutUpdate), + }) + if err != nil { + return fmt.Errorf("Error stopping/resuming replication %q: %s", d.Id(), err) + } + + err = NetappOperationWaitTime( + config, res2, project, "volume replication "+action, userAgent, + d.Timeout(schema.TimeoutDelete)) + + if err != nil { + return err + } + + // If user specified to wait for mirror operations, wait to reach target state + if d.Get("wait_for_mirror").(bool) == true { + err = NetAppVolumeReplicationWaitForMirror(d, meta, targetState) + if err != nil { + return fmt.Errorf("Error waiting for volume replication to reach mirror_state==%s: %s", targetState, err) + } + } +} diff --git a/mmv1/templates/terraform/pre_delete/netapp_volume_replication_stop_before_delete.go.erb b/mmv1/templates/terraform/pre_delete/netapp_volume_replication_stop_before_delete.go.erb new file mode 100644 index 000000000000..4e5c188acf2a --- /dev/null +++ b/mmv1/templates/terraform/pre_delete/netapp_volume_replication_stop_before_delete.go.erb @@ -0,0 +1,33 @@ +// A replication can only be deleted if mirrorState==STOPPED +// We are about to delete the replication and need to stop the mirror before. +// FYI: Stopping a PREPARING mirror currently doesn't work. User have to wait until +// mirror reaches MIRRORED. +if d.Get("mirror_state") != "STOPPED" { + rawurl, err := tpgresource.ReplaceVars(d, config, "{{NetappBasePath}}projects/{{project}}/locations/{{location}}/volumes/{{volume_name}}/replications/{{name}}:stop") + if err != nil { + return err + } + + reso, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "POST", + Project: billingProject, + RawURL: rawurl, + UserAgent: userAgent, + // We delete anyway, so lets always use force stop + Body: map[string]interface{}{ + "force": true, + }, + Timeout: d.Timeout(schema.TimeoutUpdate), + }) + if err != nil { + return fmt.Errorf("Error stopping volume replication %q before deleting it: %s", d.Id(), err) + } + + err = NetappOperationWaitTime( + config, reso, project, "Deleting volume replication", userAgent, + d.Timeout(schema.TimeoutDelete)) + if err != nil { + return err + } +} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/netapp/resource_netapp_volume_replication_test.go b/mmv1/third_party/terraform/services/netapp/resource_netapp_volume_replication_test.go new file mode 100644 index 000000000000..e663c41e7274 --- /dev/null +++ b/mmv1/third_party/terraform/services/netapp/resource_netapp_volume_replication_test.go @@ -0,0 +1,306 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package netapp_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccNetappVolumeReplication_netappVolumeReplicationCreateExample_update(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "network_name": acctest.BootstrapSharedServiceNetworkingConnection(t, "gcnv-network-config-1", acctest.ServiceNetworkWithParentService("netapp.servicenetworking.goog")), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckNetappVolumeReplicationDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccNetappVolumeReplication_netappVolumeReplicationCreateExample_basic(context), + }, + { + ResourceName: "google_netapp_volume_replication.test_replication", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"destination_volume_parameters", "location", "volume_name", "name", "delete_destination_volume", "replication_enabled", "force_stopping", "wait_for_mirror", "labels", "terraform_labels"}, + }, + { + Config: testAccNetappVolumeReplication_netappVolumeReplicationCreateExample_stop(context), + }, + { + ResourceName: "google_netapp_volume_replication.test_replication", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"destination_volume_parameters", "location", "volume_name", "name", "delete_destination_volume", "replication_enabled", "force_stopping", "wait_for_mirror", "labels", "terraform_labels"}, + }, + { + Config: testAccNetappVolumeReplication_netappVolumeReplicationCreateExample_resume(context), + }, + { + ResourceName: "google_netapp_volume_replication.test_replication", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"destination_volume_parameters", "location", "volume_name", "name", "delete_destination_volume", "replication_enabled", "force_stopping", "wait_for_mirror", "labels", "terraform_labels"}, + }, + { + Config: testAccNetappVolumeReplication_netappVolumeReplicationCreateExample_update(context), + }, + { + ResourceName: "google_netapp_volume_replication.test_replication", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"destination_volume_parameters", "location", "volume_name", "name", "delete_destination_volume", "replication_enabled", "force_stopping", "wait_for_mirror", "labels", "terraform_labels"}, + }, + }, + }) +} + +// Basic replication +func testAccNetappVolumeReplication_netappVolumeReplicationCreateExample_basic(context map[string]interface{}) string { + return acctest.Nprintf(` +data "google_compute_network" "default" { + name = "%{network_name}" +} + +resource "google_netapp_storage_pool" "source_pool" { + name = "tf-test-source-pool%{random_suffix}" + location = "us-central1" + service_level = "PREMIUM" + capacity_gib = 2048 + network = data.google_compute_network.default.id +} + +resource "google_netapp_storage_pool" "destination_pool" { + name = "tf-test-destination-pool%{random_suffix}" + location = "us-west2" + service_level = "PREMIUM" + capacity_gib = 2048 + network = data.google_compute_network.default.id +} + +resource "google_netapp_volume" "source_volume" { + location = google_netapp_storage_pool.source_pool.location + name = "tf-test-source-volume%{random_suffix}" + capacity_gib = 100 + share_name = "tf-test-source-volume%{random_suffix}" + storage_pool = google_netapp_storage_pool.source_pool.name + protocols = [ + "NFSV3" + ] + deletion_policy = "FORCE" +} + +resource "google_netapp_volume_replication" "test_replication" { + depends_on = [google_netapp_volume.source_volume] + location = google_netapp_volume.source_volume.location + volume_name = google_netapp_volume.source_volume.name + name = "tf-test-test-replication%{random_suffix}" + replication_schedule = "EVERY_10_MINUTES" + destination_volume_parameters { + storage_pool = google_netapp_storage_pool.destination_pool.id + volume_id = "tf-test-destination-volume%{random_suffix}" + # Keeping the share_name of source and destination the same + # simplifies implementing client failover concepts + share_name = "tf-test-source-volume%{random_suffix}" + description = "This is a replicated volume" + } + delete_destination_volume = true + wait_for_mirror = true +} +`, context) +} + +// Update parameters +func testAccNetappVolumeReplication_netappVolumeReplicationCreateExample_update(context map[string]interface{}) string { + return acctest.Nprintf(` +data "google_compute_network" "default" { + name = "%{network_name}" +} + +resource "google_netapp_storage_pool" "source_pool" { + name = "tf-test-source-pool%{random_suffix}" + location = "us-central1" + service_level = "PREMIUM" + capacity_gib = 2048 + network = data.google_compute_network.default.id +} + +resource "google_netapp_storage_pool" "destination_pool" { + name = "tf-test-destination-pool%{random_suffix}" + location = "us-west2" + service_level = "PREMIUM" + capacity_gib = 2048 + network = data.google_compute_network.default.id +} + +resource "google_netapp_volume" "source_volume" { + location = google_netapp_storage_pool.source_pool.location + name = "tf-test-source-volume%{random_suffix}" + capacity_gib = 100 + share_name = "tf-test-source-volume%{random_suffix}" + storage_pool = google_netapp_storage_pool.source_pool.name + protocols = [ + "NFSV3" + ] + deletion_policy = "FORCE" +} + +resource "google_netapp_volume_replication" "test_replication" { + depends_on = [google_netapp_volume.source_volume] + location = google_netapp_volume.source_volume.location + volume_name = google_netapp_volume.source_volume.name + name = "tf-test-test-replication%{random_suffix}" + replication_schedule = "EVERY_10_MINUTES" + description = "This is a replication resource" + labels = { + key = "test" + value = "replication" + } + destination_volume_parameters { + storage_pool = google_netapp_storage_pool.destination_pool.id + volume_id = "tf-test-destination-volume%{random_suffix}" + # Keeping the share_name of source and destination the same + # simplifies implementing client failover concepts + share_name = "tf-test-source-volume%{random_suffix}" + description = "This is a replicated volume" + } + replication_enabled = true + delete_destination_volume = true + force_stopping = true + wait_for_mirror = true +} +`, context) +} + +// Stop replication +func testAccNetappVolumeReplication_netappVolumeReplicationCreateExample_stop(context map[string]interface{}) string { + return acctest.Nprintf(` +data "google_compute_network" "default" { + name = "%{network_name}" +} + +resource "google_netapp_storage_pool" "source_pool" { + name = "tf-test-source-pool%{random_suffix}" + location = "us-central1" + service_level = "PREMIUM" + capacity_gib = 2048 + network = data.google_compute_network.default.id +} + +resource "google_netapp_storage_pool" "destination_pool" { + name = "tf-test-destination-pool%{random_suffix}" + location = "us-west2" + service_level = "PREMIUM" + capacity_gib = 2048 + network = data.google_compute_network.default.id +} + +resource "google_netapp_volume" "source_volume" { + location = google_netapp_storage_pool.source_pool.location + name = "tf-test-source-volume%{random_suffix}" + capacity_gib = 100 + share_name = "tf-test-source-volume%{random_suffix}" + storage_pool = google_netapp_storage_pool.source_pool.name + protocols = [ + "NFSV3" + ] + deletion_policy = "FORCE" +} + +resource "google_netapp_volume_replication" "test_replication" { + depends_on = [google_netapp_volume.source_volume] + location = google_netapp_volume.source_volume.location + volume_name = google_netapp_volume.source_volume.name + name = "tf-test-test-replication%{random_suffix}" + replication_schedule = "EVERY_10_MINUTES" + description = "This is a replication resource" + labels = { + key = "test" + value = "replication2" + } + destination_volume_parameters { + storage_pool = google_netapp_storage_pool.destination_pool.id + volume_id = "tf-test-destination-volume%{random_suffix}" + # Keeping the share_name of source and destination the same + # simplifies implementing client failover concepts + share_name = "tf-test-source-volume%{random_suffix}" + description = "This is a replicated volume" + } + replication_enabled = false + delete_destination_volume = true + force_stopping = true + wait_for_mirror = true +} +`, context) +} + +// resume replication +func testAccNetappVolumeReplication_netappVolumeReplicationCreateExample_resume(context map[string]interface{}) string { + return acctest.Nprintf(` +data "google_compute_network" "default" { + name = "%{network_name}" +} + +resource "google_netapp_storage_pool" "source_pool" { + name = "tf-test-source-pool%{random_suffix}" + location = "us-central1" + service_level = "PREMIUM" + capacity_gib = 2048 + network = data.google_compute_network.default.id +} + +resource "google_netapp_storage_pool" "destination_pool" { + name = "tf-test-destination-pool%{random_suffix}" + location = "us-west2" + service_level = "PREMIUM" + capacity_gib = 2048 + network = data.google_compute_network.default.id +} + +resource "google_netapp_volume" "source_volume" { + location = google_netapp_storage_pool.source_pool.location + name = "tf-test-source-volume%{random_suffix}" + capacity_gib = 100 + share_name = "tf-test-source-volume%{random_suffix}" + storage_pool = google_netapp_storage_pool.source_pool.name + protocols = [ + "NFSV3" + ] + deletion_policy = "FORCE" +} + +resource "google_netapp_volume_replication" "test_replication" { + depends_on = [google_netapp_volume.source_volume] + location = google_netapp_volume.source_volume.location + volume_name = google_netapp_volume.source_volume.name + name = "tf-test-test-replication%{random_suffix}" + replication_schedule = "HOURLY" + description = "This is a replication resource" + labels = { + key = "test" + value = "replication2" + } + destination_volume_parameters { + storage_pool = google_netapp_storage_pool.destination_pool.id + volume_id = "tf-test-destination-volume%{random_suffix}" + # Keeping the share_name of source and destination the same + # simplifies implementing client failover concepts + share_name = "tf-test-source-volume%{random_suffix}" + description = "This is a replicated volume" + } + replication_enabled = true + delete_destination_volume = true + force_stopping = true + wait_for_mirror = true +} +`, context) +} From d9c78713a1229b452f880d271f76f8923fa9f76b Mon Sep 17 00:00:00 2001 From: "Stephen Lewis (Burrows)" Date: Wed, 21 Feb 2024 15:42:34 -0800 Subject: [PATCH 51/77] Ensured that beta runs in TeamCity use only beta paths (#10025) * Ensured that beta runs in TeamCity use only beta paths * Added tests for sweeper package path --- .../terraform/.teamcity/CONTRIBUTION_GUIDE.md | 10 ++- .../.teamcity/components/inputs/packages.kt | 62 ++++++++++++++++--- .../projects/project_sweeper_project.kt | 4 +- .../components/projects/reused/mm_upstream.kt | 20 ++++-- .../projects/reused/nightly_tests.kt | 12 +++- .../components/projects/root_project.kt | 13 ++-- .../terraform/.teamcity/tests/sweepers.kt | 51 +++++++++++++++ 7 files changed, 144 insertions(+), 28 deletions(-) diff --git a/mmv1/third_party/terraform/.teamcity/CONTRIBUTION_GUIDE.md b/mmv1/third_party/terraform/.teamcity/CONTRIBUTION_GUIDE.md index 911460cd190c..5d803e699493 100644 --- a/mmv1/third_party/terraform/.teamcity/CONTRIBUTION_GUIDE.md +++ b/mmv1/third_party/terraform/.teamcity/CONTRIBUTION_GUIDE.md @@ -17,6 +17,14 @@ Note: these instructions need to be tested and improved. Please contact @SarahFr You will need to install: * Java 17 * `brew install openjdk@17` +* Maven + * `brew install --ignore-dependencies maven` + +Add the following to `~/.zshrc` and reload your terminal: + +``` +export JAVA_HOME=/usr/local/Cellar/openjdk@17/17.0.9/libexec/openjdk.jdk/Contents/Home +``` ## Getting started @@ -27,7 +35,7 @@ You will need to install: * Run `make validate` to check the code for both: * Errors that prevent the code building * Logical errors in TeamCity-specific logic, e.g. the need for unique identifiers for builds. -* Run `make tests` to run the automated tests defined in `.teamcity/tests` +* Run `make test` to run the automated tests defined in `.teamcity/tests` ## Rough description of the code base diff --git a/mmv1/third_party/terraform/.teamcity/components/inputs/packages.kt b/mmv1/third_party/terraform/.teamcity/components/inputs/packages.kt index 19b107e2e72d..5ea3d2a5d48a 100644 --- a/mmv1/third_party/terraform/.teamcity/components/inputs/packages.kt +++ b/mmv1/third_party/terraform/.teamcity/components/inputs/packages.kt @@ -7,7 +7,7 @@ package generated -var PackagesList = mapOf( +var PackagesListGa = mapOf( "envvar" to mapOf( "name" to "envvar", "displayName" to "Environment Variables", @@ -50,7 +50,7 @@ var PackagesList = mapOf( ) ) -var SweepersList = mapOf( +var SweepersListGa = mapOf( "sweeper" to mapOf( "name" to "sweeper", "displayName" to "Sweeper", @@ -58,11 +58,53 @@ var SweepersList = mapOf( ) ) -fun GetPackageNameList(): List { - var packageNameList: ArrayList = arrayListOf() - PackagesList.forEach{ p -> - var packageName = p.value.getValue("name").toString() - packageNameList.add(packageName) - } - return packageNameList -} +var PackagesListBeta = mapOf( + "envvar" to mapOf( + "name" to "envvar", + "displayName" to "Environment Variables", + "path" to "./google-beta/envvar" + ), + "fwmodels" to mapOf( + "name" to "fwmodels", + "displayName" to "Framework Models", + "path" to "./google-beta/fwmodels" + ), + "fwprovider" to mapOf( + "name" to "fwprovider", + "displayName" to "Framework Provider", + "path" to "./google-beta/fwprovider" + ), + "fwresource" to mapOf( + "name" to "fwresource", + "displayName" to "Framework Resource", + "path" to "./google-beta/fwresource" + ), + "fwtransport" to mapOf( + "name" to "fwtransport", + "displayName" to "Framework Transport", + "path" to "./google-beta/fwtransport" + ), + "provider" to mapOf( + "name" to "provider", + "displayName" to "SDK Provider", + "path" to "./google-beta/provider" + ), + "transport" to mapOf( + "name" to "transport", + "displayName" to "Transport", + "path" to "./google-beta/transport" + ), + "google" to mapOf( + "name" to "google", + "displayName" to "Google", + "path" to "./google-beta" + ) +) + +var SweepersListBeta = mapOf( + "sweeper" to mapOf( + "name" to "sweeper", + "displayName" to "Sweeper", + "path" to "./google-beta/sweeper" + ) +) diff --git a/mmv1/third_party/terraform/.teamcity/components/projects/project_sweeper_project.kt b/mmv1/third_party/terraform/.teamcity/components/projects/project_sweeper_project.kt index f8da47ef5290..732822a52ff6 100644 --- a/mmv1/third_party/terraform/.teamcity/components/projects/project_sweeper_project.kt +++ b/mmv1/third_party/terraform/.teamcity/components/projects/project_sweeper_project.kt @@ -12,7 +12,7 @@ import SharedResourceNameBeta import SharedResourceNameGa import SharedResourceNameVcr import builds.* -import generated.SweepersList +import generated.SweepersListGa import jetbrains.buildServer.configs.kotlin.Project import replaceCharsId import vcs_roots.HashiCorpVCSRootGa @@ -31,7 +31,7 @@ fun projectSweeperSubProject(allConfig: AllContextParameters): Project { // Create build config for sweeping project resources // Uses the HashiCorpVCSRootGa VCS Root so that the latest sweepers in hashicorp/terraform-provider-google are used - val serviceSweeperConfig = BuildConfigurationForProjectSweeper("N/A", ProjectSweeperName, SweepersList, projectId, HashiCorpVCSRootGa, sharedResources, gaConfig) + val serviceSweeperConfig = BuildConfigurationForProjectSweeper("N/A", ProjectSweeperName, SweepersListGa, projectId, HashiCorpVCSRootGa, sharedResources, gaConfig) val trigger = NightlyTriggerConfiguration(startHour=12) serviceSweeperConfig.addTrigger(trigger) diff --git a/mmv1/third_party/terraform/.teamcity/components/projects/reused/mm_upstream.kt b/mmv1/third_party/terraform/.teamcity/components/projects/reused/mm_upstream.kt index 3b57d2fc12c4..c26ed498edd4 100644 --- a/mmv1/third_party/terraform/.teamcity/components/projects/reused/mm_upstream.kt +++ b/mmv1/third_party/terraform/.teamcity/components/projects/reused/mm_upstream.kt @@ -13,10 +13,12 @@ import ProviderNameGa import ServiceSweeperName import SharedResourceNameVcr import builds.* -import generated.PackagesList -import generated.ServicesListGa +import generated.PackagesListBeta +import generated.PackagesListGa import generated.ServicesListBeta -import generated.SweepersList +import generated.ServicesListGa +import generated.SweepersListBeta +import generated.SweepersListGa import jetbrains.buildServer.configs.kotlin.BuildType import jetbrains.buildServer.configs.kotlin.Project import jetbrains.buildServer.configs.kotlin.vcs.GitVcsRoot @@ -36,7 +38,13 @@ fun mmUpstream(parentProject: String, providerName: String, vcsRoot: GitVcsRoot, val packageBuildConfigs = BuildConfigurationsForPackages(allPackages, providerName, projectId, vcsRoot, sharedResources, config) // Create build config for sweeping the VCR test project - everything except projects - val serviceSweeperConfig = BuildConfigurationForServiceSweeper(providerName, ServiceSweeperName, SweepersList, projectId, vcsRoot, sharedResources, config) + var sweepersList: Map> + when(providerName) { + ProviderNameGa -> sweepersList = SweepersListGa + ProviderNameBeta -> sweepersList = SweepersListBeta + else -> throw Exception("Provider name not supplied when generating a nightly test subproject") + } + val serviceSweeperConfig = BuildConfigurationForServiceSweeper(providerName, ServiceSweeperName, sweepersList, projectId, vcsRoot, sharedResources, config) val trigger = NightlyTriggerConfiguration(startHour=12) serviceSweeperConfig.addTrigger(trigger) // Only the sweeper is on a schedule in this project @@ -60,10 +68,10 @@ fun mmUpstream(parentProject: String, providerName: String, vcsRoot: GitVcsRoot, fun getAllPackageInProviderVersion(providerName: String): Map> { var allPackages: Map> = mapOf() if (providerName == ProviderNameGa){ - allPackages = PackagesList + ServicesListGa + allPackages = PackagesListGa + ServicesListGa } if (providerName == ProviderNameBeta){ - allPackages = PackagesList + ServicesListBeta + allPackages = PackagesListBeta + ServicesListBeta } return allPackages } \ No newline at end of file diff --git a/mmv1/third_party/terraform/.teamcity/components/projects/reused/nightly_tests.kt b/mmv1/third_party/terraform/.teamcity/components/projects/reused/nightly_tests.kt index 0c531f952e40..6fda2b7b7ab1 100644 --- a/mmv1/third_party/terraform/.teamcity/components/projects/reused/nightly_tests.kt +++ b/mmv1/third_party/terraform/.teamcity/components/projects/reused/nightly_tests.kt @@ -14,8 +14,8 @@ import ServiceSweeperName import SharedResourceNameBeta import SharedResourceNameGa import builds.* -import generated.PackagesList -import generated.SweepersList +import generated.SweepersListBeta +import generated.SweepersListGa import jetbrains.buildServer.configs.kotlin.Project import jetbrains.buildServer.configs.kotlin.vcs.GitVcsRoot import replaceCharsId @@ -44,7 +44,13 @@ fun nightlyTests(parentProject:String, providerName: String, vcsRoot: GitVcsRoot } // Create build config for sweeping the nightly test project - val serviceSweeperConfig = BuildConfigurationForServiceSweeper(providerName, ServiceSweeperName, SweepersList, projectId, vcsRoot, sharedResources, config) + var sweepersList: Map> + when(providerName) { + ProviderNameGa -> sweepersList = SweepersListGa + ProviderNameBeta -> sweepersList = SweepersListBeta + else -> throw Exception("Provider name not supplied when generating a nightly test subproject") + } + val serviceSweeperConfig = BuildConfigurationForServiceSweeper(providerName, ServiceSweeperName, sweepersList, projectId, vcsRoot, sharedResources, config) val sweeperTrigger = NightlyTriggerConfiguration(startHour=12) // Override hour serviceSweeperConfig.addTrigger(sweeperTrigger) diff --git a/mmv1/third_party/terraform/.teamcity/components/projects/root_project.kt b/mmv1/third_party/terraform/.teamcity/components/projects/root_project.kt index c3ffd869756f..0c130da8eca5 100644 --- a/mmv1/third_party/terraform/.teamcity/components/projects/root_project.kt +++ b/mmv1/third_party/terraform/.teamcity/components/projects/root_project.kt @@ -12,7 +12,8 @@ import SharedResourceNameGa import SharedResourceNameVcr import builds.AllContextParameters import builds.readOnlySettings -import generated.GetPackageNameList +import generated.PackagesListBeta +import generated.PackagesListGa import generated.ServicesListBeta import generated.ServicesListGa import jetbrains.buildServer.configs.kotlin.Project @@ -38,21 +39,21 @@ fun googleCloudRootProject(allConfig: AllContextParameters): Project { id = "GA_NIGHTLY_SERVICE_LOCK_SHARED_RESOURCE" name = SharedResourceNameGa enabled = true - resourceType = customValues(getServiceNameList(ServicesListGa) + GetPackageNameList()) + resourceType = customValues(getPackageNameList(ServicesListGa) + getPackageNameList(PackagesListGa)) } // For controlling sweeping of the Beta nightly test project sharedResource { id = "BETA_NIGHTLY_SERVICE_LOCK_SHARED_RESOURCE" name = SharedResourceNameBeta enabled = true - resourceType = customValues(getServiceNameList(ServicesListBeta) + GetPackageNameList()) + resourceType = customValues(getPackageNameList(ServicesListBeta) + getPackageNameList(PackagesListBeta)) } // For controlling sweeping of the PR testing project sharedResource { id = "PR_SERVICE_LOCK_SHARED_RESOURCE" name = SharedResourceNameVcr enabled = true - resourceType = customValues(getServiceNameList(ServicesListBeta) + GetPackageNameList()) // Use Beta list of services here, assuming Beta is a superset of GA + resourceType = customValues(getPackageNameList(ServicesListBeta) + getPackageNameList(PackagesListBeta)) // Use Beta list of services here, assuming Beta is a superset of GA } } @@ -66,11 +67,11 @@ fun googleCloudRootProject(allConfig: AllContextParameters): Project { } } -fun getServiceNameList(servicesList: Map>): List { +fun getPackageNameList(servicesList: Map>): List { var serviceNameList: ArrayList = arrayListOf() servicesList.forEach{ s -> var serviceName = s.value.getValue("name").toString() serviceNameList.add(serviceName) } return serviceNameList -} \ No newline at end of file +} diff --git a/mmv1/third_party/terraform/.teamcity/tests/sweepers.kt b/mmv1/third_party/terraform/.teamcity/tests/sweepers.kt index 27e55f737a1f..1603aaeda776 100644 --- a/mmv1/third_party/terraform/.teamcity/tests/sweepers.kt +++ b/mmv1/third_party/terraform/.teamcity/tests/sweepers.kt @@ -9,6 +9,7 @@ package tests import ServiceSweeperName import jetbrains.buildServer.configs.kotlin.BuildType +import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test import jetbrains.buildServer.configs.kotlin.Project @@ -62,6 +63,31 @@ class SweeperTests { assertTrue("env.SKIP_PROJECT_SWEEPER is set to a non-empty string, so project sweepers are skipped. Value = `${value}` ", value != "") } + @Test + fun gaNightlyProjectServiceSweeperRunsInGoogle() { + val project = googleCloudRootProject(testContextParameters()) + + // Find GA nightly test project + val gaProject: Project? = project.subProjects.find { p-> p.name == gaProjectName} + if (gaProject == null) { + Assert.fail("Could not find the Google (GA) project") + } + val gaNightlyTestProject: Project? = gaProject!!.subProjects.find { p-> p.name == nightlyTestsProjectName} + if (gaNightlyTestProject == null) { + Assert.fail("Could not find the Google (GA) Nightly Test project") + } + + // Find sweeper inside + val sweeper: BuildType? = gaNightlyTestProject!!.buildTypes.find { p-> p.name == ServiceSweeperName} + if (sweeper == null) { + Assert.fail("Could not find the sweeper build in the Google (GA) Nightly Test project") + } + + // Check PACKAGE_PATH is in google (not google-beta) + val value = sweeper!!.params.findRawParam("PACKAGE_PATH")!!.value + assertEquals("./google/sweeper", value) + } + @Test fun betaNightlyProjectServiceSweeperSkipsProjectSweep() { val project = googleCloudRootProject(testContextParameters()) @@ -88,4 +114,29 @@ class SweeperTests { val value = sweeper!!.params.findRawParam("env.SKIP_PROJECT_SWEEPER")!!.value assertTrue("env.SKIP_PROJECT_SWEEPER is set to a non-empty string, so project sweepers are skipped. Value = `${value}` ", value != "") } + + @Test + fun betaNightlyProjectServiceSweeperRunsInGoogleBeta() { + val project = googleCloudRootProject(testContextParameters()) + + // Find Beta nightly test project + val betaProject: Project? = project.subProjects.find { p-> p.name == betaProjectName} + if (betaProject == null) { + Assert.fail("Could not find the Google (GA) project") + } + val betaNightlyTestProject: Project? = betaProject!!.subProjects.find { p-> p.name == nightlyTestsProjectName} + if (betaNightlyTestProject == null) { + Assert.fail("Could not find the Google (GA) Nightly Test project") + } + + // Find sweeper inside + val sweeper: BuildType? = betaNightlyTestProject!!.buildTypes.find { p-> p.name == ServiceSweeperName} + if (sweeper == null) { + Assert.fail("Could not find the sweeper build in the Google (GA) Nightly Test project") + } + + // Check PACKAGE_PATH is in google-beta + val value = sweeper!!.params.findRawParam("PACKAGE_PATH")!!.value + assertEquals("./google-beta/sweeper", value) + } } From f45d7c311f1b4b90d56222c7e1ed8929c919b136 Mon Sep 17 00:00:00 2001 From: Yanwei Guo Date: Thu, 22 Feb 2024 09:31:17 -0800 Subject: [PATCH 52/77] Adds description for default value of `cpuidle` field (#10005) * add description * remove tail space --- mmv1/products/cloudrunv2/Service.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mmv1/products/cloudrunv2/Service.yaml b/mmv1/products/cloudrunv2/Service.yaml index 1d4c3b7a0895..4c7198049bfe 100644 --- a/mmv1/products/cloudrunv2/Service.yaml +++ b/mmv1/products/cloudrunv2/Service.yaml @@ -430,7 +430,8 @@ properties: - !ruby/object:Api::Type::Boolean name: 'cpuIdle' description: |- - Determines whether CPU should be throttled or not outside of requests. + Determines whether CPU is only allocated during requests. True by default if the parent `resources` field is not set. However, if + `resources` is set, this field must be explicitly set to true to preserve the default behavior. - !ruby/object:Api::Type::Boolean name: 'startupCpuBoost' description: |- From f60f2e6424a7eb3746a8b8cfff9fccceaa272ab7 Mon Sep 17 00:00:00 2001 From: Hamzawy63 <43001514+Hamzawy63@users.noreply.github.com> Date: Thu, 22 Feb 2024 19:29:01 +0100 Subject: [PATCH 53/77] Add location field in DNS authorization resource. (#9968) * Add location field in DNS authorization resource * Fixed the provider version of the updated config --------- Co-authored-by: Hamza Hassan --- .../certificatemanager/DnsAuthorization.yaml | 17 +++- ...ate_manager_dns_authorization_basic.tf.erb | 3 +- ...rtificate_manager_dns_authorization.go.erb | 91 +++++++++++++++++++ ..._manager_dns_authorization_upgrade_test.go | 78 ++++++++++++++++ 4 files changed, 184 insertions(+), 5 deletions(-) create mode 100644 mmv1/templates/terraform/state_migrations/certificate_manager_dns_authorization.go.erb create mode 100644 mmv1/third_party/terraform/services/certificatemanager/resource_certificate_manager_dns_authorization_upgrade_test.go diff --git a/mmv1/products/certificatemanager/DnsAuthorization.yaml b/mmv1/products/certificatemanager/DnsAuthorization.yaml index bcb50c60c329..33cd7604ed80 100644 --- a/mmv1/products/certificatemanager/DnsAuthorization.yaml +++ b/mmv1/products/certificatemanager/DnsAuthorization.yaml @@ -13,9 +13,9 @@ --- !ruby/object:Api::Resource name: 'DnsAuthorization' -base_url: 'projects/{{project}}/locations/global/dnsAuthorizations' -create_url: 'projects/{{project}}/locations/global/dnsAuthorizations?dnsAuthorizationId={{name}}' -self_link: 'projects/{{project}}/locations/global/dnsAuthorizations/{{name}}' +base_url: 'projects/{{project}}/locations/{{location}}/dnsAuthorizations' +create_url: 'projects/{{project}}/locations/{{location}}/dnsAuthorizations?dnsAuthorizationId={{name}}' +self_link: 'projects/{{project}}/locations/{{location}}/dnsAuthorizations/{{name}}' update_verb: :PATCH update_mask: true description: | @@ -39,7 +39,9 @@ async: !ruby/object:Api::OpAsync docs: !ruby/object:Provider::Terraform::Docs autogen_async: true import_format: - ['projects/{{project}}/locations/global/dnsAuthorizations/{{name}}'] + ['projects/{{project}}/locations/{{location}}/dnsAuthorizations/{{name}}'] +schema_version: 1 +state_upgraders: true examples: - !ruby/object:Provider::Terraform::Examples name: 'certificate_manager_dns_authorization_basic' @@ -58,6 +60,13 @@ parameters: Name of the resource; provided by the client when the resource is created. The name must be 1-64 characters long, and match the regular expression [a-zA-Z][a-zA-Z0-9_-]* which means the first character must be a letter, and all following characters must be a dash, underscore, letter or digit. + - !ruby/object:Api::Type::String + name: 'location' + description: | + The Certificate Manager location. If not specified, "global" is used. + default_value: global + immutable: true + url_param_only: true properties: - !ruby/object:Api::Type::String name: 'description' diff --git a/mmv1/templates/terraform/examples/certificate_manager_dns_authorization_basic.tf.erb b/mmv1/templates/terraform/examples/certificate_manager_dns_authorization_basic.tf.erb index c5abd47bc47b..a63cbe5392b2 100644 --- a/mmv1/templates/terraform/examples/certificate_manager_dns_authorization_basic.tf.erb +++ b/mmv1/templates/terraform/examples/certificate_manager_dns_authorization_basic.tf.erb @@ -1,6 +1,7 @@ resource "google_certificate_manager_dns_authorization" "<%= ctx[:primary_resource_id] %>" { name = "<%= ctx[:vars]['dns_auth_name'] %>" - description = "The default dnss" + location = "global" + description = "The default dns" domain = "<%= ctx[:vars]['subdomain'] %>.hashicorptest.com" } diff --git a/mmv1/templates/terraform/state_migrations/certificate_manager_dns_authorization.go.erb b/mmv1/templates/terraform/state_migrations/certificate_manager_dns_authorization.go.erb new file mode 100644 index 000000000000..b3d29dc64136 --- /dev/null +++ b/mmv1/templates/terraform/state_migrations/certificate_manager_dns_authorization.go.erb @@ -0,0 +1,91 @@ +func ResourceCertificateManagerDnsAuthorizationUpgradeV0(_ context.Context, rawState map[string]interface{}, meta interface{}) (map[string]interface{}, error) { + log.Printf("[DEBUG] Attributes before migration: %#v", rawState) + // Version 0 didn't support location. Default it to global. + rawState["location"] = "global" + log.Printf("[DEBUG] Attributes after migration: %#v", rawState) + return rawState, nil +} + +func resourceCertificateManagerDnsAuthorizationResourceV0() *schema.Resource { + return &schema.Resource{ + Schema: map[string]*schema.Schema{ + "domain": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `A domain which is being authorized. A DnsAuthorization resource covers a +single domain and its wildcard, e.g. authorization for "example.com" can +be used to issue certificates for "example.com" and "*.example.com".`, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `Name of the resource; provided by the client when the resource is created. +The name must be 1-64 characters long, and match the regular expression [a-zA-Z][a-zA-Z0-9_-]* which means the first character must be a letter, +and all following characters must be a dash, underscore, letter or digit.`, + }, + "description": { + Type: schema.TypeString, + Optional: true, + Description: `A human-readable description of the resource.`, + }, + "labels": { + Type: schema.TypeMap, + Optional: true, + Description: `Set of label tags associated with the DNS Authorization resource. + +**Note**: This field is non-authoritative, and will only manage the labels present in your configuration. +Please refer to the field 'effective_labels' for all of the labels present on the resource.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "dns_resource_record": { + Type: schema.TypeList, + Computed: true, + Description: `The structure describing the DNS Resource Record that needs to be added +to DNS configuration for the authorization to be usable by +certificate.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "data": { + Type: schema.TypeString, + Computed: true, + Description: `Data of the DNS Resource Record.`, + }, + "name": { + Type: schema.TypeString, + Computed: true, + Description: `Fully qualified name of the DNS Resource Record. +E.g. '_acme-challenge.example.com'.`, + }, + "type": { + Type: schema.TypeString, + Computed: true, + Description: `Type of the DNS Resource Record.`, + }, + }, + }, + }, + "effective_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `All of labels (key/value pairs) present on the resource in GCP, including the labels configured through Terraform, other clients and services.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "terraform_labels": { + Type: schema.TypeMap, + Computed: true, + Description: `The combination of labels configured directly on the resource + and default labels configured on the provider.`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "project": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + }, + } + +} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/certificatemanager/resource_certificate_manager_dns_authorization_upgrade_test.go b/mmv1/third_party/terraform/services/certificatemanager/resource_certificate_manager_dns_authorization_upgrade_test.go new file mode 100644 index 000000000000..293628ee322b --- /dev/null +++ b/mmv1/third_party/terraform/services/certificatemanager/resource_certificate_manager_dns_authorization_upgrade_test.go @@ -0,0 +1,78 @@ +package certificatemanager_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +// Tests schema version migration by creating a dns authorization with an old version of the provider (5.15.0) +// and then updating it with the current version the provider. +func TestAccCertificateManagerDnsAuthorization_migration(t *testing.T) { + acctest.SkipIfVcr(t) + t.Parallel() + name := fmt.Sprintf("tf-test-%d", acctest.RandInt(t)) + + oldVersion := map[string]resource.ExternalProvider{ + "google": { + VersionConstraint: "5.15.0", // a version that doesn't support location yet. + Source: "registry.terraform.io/hashicorp/google", + }, + } + newVersion := map[string]func() (*schema.Provider, error){ + "mynewprovider": func() (*schema.Provider, error) { return acctest.TestAccProviders["google"], nil }, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + CheckDestroy: testAccCheckCertificateManagerDnsAuthorizationDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: dnsAuthorizationResourceConfig(name), + ExternalProviders: oldVersion, + }, + { + ResourceName: "google_certificate_manager_dns_authorization.default", + ImportState: true, + ImportStateVerifyIgnore: []string{"location"}, + ExternalProviders: oldVersion, + }, + { + Config: dnsAuthorizationResourceConfigUpdated(name), + ProviderFactories: newVersion, + }, + { + ResourceName: "google_certificate_manager_dns_authorization.default", + ImportState: true, + ImportStateVerifyIgnore: []string{"location"}, + ProviderFactories: newVersion, + }, + }, + }) +} + +func dnsAuthorizationResourceConfig(name string) string { + return fmt.Sprintf(` + resource "google_certificate_manager_dns_authorization" "default" { + name = "%s" + description = "The default dns" + domain = "domain.hashicorptest.com" + } + `, name) +} + +func dnsAuthorizationResourceConfigUpdated(name string) string { + return fmt.Sprintf(` + provider "mynewprovider" {} + + resource "google_certificate_manager_dns_authorization" "default" { + provider = mynewprovider + name = "%s" + description = "The migrated default dns" + domain = "domain.hashicorptest.com" + } + `, name) +} From 1e6f8743250a05b91e6bbae7eec08624e7a37323 Mon Sep 17 00:00:00 2001 From: Ryan Oaks Date: Thu, 22 Feb 2024 14:40:07 -0500 Subject: [PATCH 54/77] Add discoveryengine service (#10017) --- .ci/infra/terraform/main.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci/infra/terraform/main.tf b/.ci/infra/terraform/main.tf index 7c1fc897bfa3..33422f4e6948 100644 --- a/.ci/infra/terraform/main.tf +++ b/.ci/infra/terraform/main.tf @@ -222,6 +222,7 @@ module "project-services" { "datastream.googleapis.com", "deploymentmanager.googleapis.com", "dialogflow.googleapis.com", + "discoveryengine.googleapis.com", "dlp.googleapis.com", "dns.googleapis.com", "documentai.googleapis.com", From a58f0e2a4505a5debeac9813042c60f46567c42e Mon Sep 17 00:00:00 2001 From: Salome Papiashvili Date: Thu, 22 Feb 2024 22:58:09 +0100 Subject: [PATCH 55/77] Add validations for Composer 2/3 only fields (#9917) * block upgrade to composer 3 * make isComposer3 more generic, correct imageVersionChangeValidationFunc * added validation for Composer 2/3 specific fields * add tests for validation * add checks in flattenComposerEnvironmentConfig * Update attributes of fields not used in Composer 3 * make customizeDiff functions beta only * remove Computed from gke_cluster * remove Optional instead of Computed * add envCfg.PrivateEnvironmentConfig is nil check * modify isComposer3 to take string * minor correction to avoid merge conflicts --- .../resource_composer_environment.go.erb | 70 ++++++++-- .../resource_composer_environment_test.go.erb | 131 ++++++++++++++++++ 2 files changed, 193 insertions(+), 8 deletions(-) diff --git a/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb b/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb index 536af7709b4b..0369ce49f4d0 100644 --- a/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb +++ b/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb @@ -7,6 +7,7 @@ import ( "regexp" "strings" "time" + "context" "github.com/hashicorp/go-version" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" @@ -168,6 +169,10 @@ func ResourceComposerEnvironment() *schema.Resource { tpgresource.DefaultProviderProject, tpgresource.DefaultProviderRegion, tpgresource.SetLabelsDiff, +<% unless version == "ga" -%> + customdiff.ValidateChange("config.0.software_config.0.image_version", imageVersionChangeValidationFunc), + versionValidationCustomizeDiffFunc, +<% end -%> ), Schema: map[string]*schema.Schema{ @@ -1592,10 +1597,15 @@ func flattenComposerEnvironmentConfig(envCfg *composer.EnvironmentConfig) interf transformed["airflow_uri"] = envCfg.AirflowUri transformed["node_config"] = flattenComposerEnvironmentConfigNodeConfig(envCfg.NodeConfig) transformed["software_config"] = flattenComposerEnvironmentConfigSoftwareConfig(envCfg.SoftwareConfig) - transformed["private_environment_config"] = flattenComposerEnvironmentConfigPrivateEnvironmentConfig(envCfg.PrivateEnvironmentConfig) + imageVersion := envCfg.SoftwareConfig.ImageVersion + if !isComposer3(imageVersion){ + transformed["private_environment_config"] = flattenComposerEnvironmentConfigPrivateEnvironmentConfig(envCfg.PrivateEnvironmentConfig) + } <% unless version == "ga" -%> - transformed["enable_private_environment"] = envCfg.PrivateEnvironmentConfig.EnablePrivateEnvironment - transformed["enable_private_builds_only"] = envCfg.PrivateEnvironmentConfig.EnablePrivateBuildsOnly + if isComposer3(imageVersion) && envCfg.PrivateEnvironmentConfig != nil { + transformed["enable_private_environment"] = envCfg.PrivateEnvironmentConfig.EnablePrivateEnvironment + transformed["enable_private_builds_only"] = envCfg.PrivateEnvironmentConfig.EnablePrivateBuildsOnly + } <% end -%> transformed["web_server_network_access_control"] = flattenComposerEnvironmentConfigWebServerNetworkAccessControl(envCfg.WebServerNetworkAccessControl) transformed["database_config"] = flattenComposerEnvironmentConfigDatabaseConfig(envCfg.DatabaseConfig) @@ -1803,7 +1813,9 @@ func flattenComposerEnvironmentConfigWorkloadsConfig(workloadsConfig *composer.W transformed["web_server"] = []interface{}{transformedWebServer} transformed["worker"] = []interface{}{transformedWorker} <% unless version == "ga" -%> - transformed["dag_processor"] = []interface{}{transformedDagProcessor} + if transformedDagProcessor != nil { + transformed["dag_processor"] = []interface{}{transformedDagProcessor} + } <% end -%> @@ -1982,7 +1994,8 @@ func expandComposerEnvironmentConfig(v interface{}, d *schema.ResourceData, conf composer.PrivateEnvironmentConfig.EnablePrivateEnvironment in API. Check image version to avoid overriding EnablePrivateEnvironment in case of other versions. */ - if isComposer3(d, config) { + imageVersion := d.Get("config.0.software_config.0.image_version").(string) + if isComposer3(imageVersion) { transformed.PrivateEnvironmentConfig = &composer.PrivateEnvironmentConfig{} if enablePrivateEnvironmentRaw, ok := original["enable_private_environment"]; ok { transformed.PrivateEnvironmentConfig.EnablePrivateEnvironment = enablePrivateEnvironmentRaw.(bool) @@ -2934,7 +2947,48 @@ func versionsEqual(old, new string) (bool, error) { return o.Equal(n), nil } -func isComposer3(d *schema.ResourceData, config *transport_tpg.Config) bool { - image_version := d.Get("config.0.software_config.0.image_version").(string) - return strings.Contains(image_version, "composer-3") +func isComposer3(imageVersion string) bool { + return strings.Contains(imageVersion, "composer-3") } + +func imageVersionChangeValidationFunc(ctx context.Context, old, new, meta any) error { + if old.(string) != "" && !isComposer3(old.(string)) && isComposer3(new.(string)) { + return fmt.Errorf("upgrade to composer 3 is not yet supported") + } + return nil +} + +func validateComposer3FieldUsage(d *schema.ResourceDiff, key string, requireComposer3 bool) error { + _, ok := d.GetOk(key) + imageVersion := d.Get("config.0.software_config.0.image_version").(string) + if ok && ( isComposer3(imageVersion) != requireComposer3 ) { + if requireComposer3 { + return fmt.Errorf("error in configuration, %s should only be used in Composer 3", key) + } else { + return fmt.Errorf("error in configuration, %s should not be used in Composer 3", key) + } + } + return nil +} + +func versionValidationCustomizeDiffFunc(ctx context.Context, d *schema.ResourceDiff, meta interface{}) error { + composer3FieldUsagePolicy := map[string]bool{ + "config.0.node_config.0.max_pods_per_node": false, // not allowed in composer 3 + "config.0.node_config.0.enable_ip_masq_agent": false, + "config.0.node_config.0.config.0.node_config.0.ip_allocation_policy": false, + "config.0.private_environment_config": false, + "config.0.master_authorized_networks_config": false, + "config.0.node_config.0.composer_network_attachment": true, // allowed only in composer 3 + "config.0.node_config.0.composer_internal_ipv4_cidr_block": true, + "config.0.software_config.0.web_server_plugins_mode": true, + "config.0.enable_private_environment": true, + "config.0.enable_private_builds_only": true, + "config.0.workloads_config.0.dag_processor": true, + } + for key, allowed := range composer3FieldUsagePolicy { + if err := validateComposer3FieldUsage(d, key, allowed); err != nil { + return err + } + } + return nil +} \ No newline at end of file diff --git a/mmv1/third_party/terraform/services/composer/resource_composer_environment_test.go.erb b/mmv1/third_party/terraform/services/composer/resource_composer_environment_test.go.erb index 80e870eac07a..1ddb9257f35e 100644 --- a/mmv1/third_party/terraform/services/composer/resource_composer_environment_test.go.erb +++ b/mmv1/third_party/terraform/services/composer/resource_composer_environment_test.go.erb @@ -1186,6 +1186,77 @@ func TestAccComposerEnvironmentComposer3_update(t *testing.T) { }) } +func TestAccComposerEnvironmentComposer3_upgrade_expectError(t *testing.T) { + t.Parallel() + + envName := fmt.Sprintf("%s-%d", testComposerEnvironmentPrefix, acctest.RandInt(t)) + network := fmt.Sprintf("%s-%d", testComposerNetworkPrefix, acctest.RandInt(t)) + subnetwork := network + "-1" + errorRegExp, _ := regexp.Compile(".*upgrade to composer 3 is not yet supported.*") + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccComposerEnvironmentDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComposerEnvironmentComposer2_empty(envName, network, subnetwork), + }, + { + Config: testAccComposerEnvironmentComposer3_empty(envName, network, subnetwork), + ExpectError: errorRegExp, + }, + // This is a terrible clean-up step in order to get destroy to succeed, + // due to dangling firewall rules left by the Composer Environment blocking network deletion. + // TODO: Remove this check if firewall rules bug gets fixed by Composer. + { + PlanOnly: true, + ExpectNonEmptyPlan: false, + Config: testAccComposerEnvironmentComposer2_empty(envName, network, subnetwork), + Check: testAccCheckClearComposerEnvironmentFirewalls(t, network), + }, + }, + }) +} + +func TestAccComposerEnvironmentComposer2_usesUnsupportedField_expectError(t *testing.T) { + t.Parallel() + + envName := fmt.Sprintf("%s-%d", testComposerEnvironmentPrefix, acctest.RandInt(t)) + errorRegExp, _ := regexp.Compile(".*error in configuration, .* should only be used in Composer 3.*") + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccComposerEnvironmentDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComposerEnvironmentComposer2_usesUnsupportedField(envName), + ExpectError: errorRegExp, + }, + }, + }) +} + +func TestAccComposerEnvironmentComposer3_usesUnsupportedField_expectError(t *testing.T) { + t.Parallel() + + envName := fmt.Sprintf("%s-%d", testComposerEnvironmentPrefix, acctest.RandInt(t)) + errorRegExp, _ := regexp.Compile(".*error in configuration, .* should not be used in Composer 3.*") + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccComposerEnvironmentDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComposerEnvironmentComposer3_usesUnsupportedField(envName), + ExpectError: errorRegExp, + }, + }, + }) +} + // Checks Composer 3 specific updatable fields. func TestAccComposerEnvironmentComposer3_updateToEmpty(t *testing.T) { t.Parallel() @@ -2835,6 +2906,34 @@ resource "google_project_iam_member" "composer-worker" { } <% unless version == "ga" -%> +func testAccComposerEnvironmentComposer2_empty(name, network, subnetwork string) string { + return fmt.Sprintf(` +resource "google_composer_environment" "test" { + name = "%s" + region = "us-central1" + config { + software_config { + image_version = "composer-2-airflow-2" + } + } +} + +// use a separate network to avoid conflicts with other tests running in parallel +// that use the default network/subnet +resource "google_compute_network" "test" { + name = "%s" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "test" { + name = "%s" + ip_cidr_range = "10.2.0.0/16" + region = "us-central1" + network = google_compute_network.test.self_link +} +`, name, network, subnetwork) +} + func testAccComposerEnvironmentComposer3_empty(name, network, subnetwork string) string { return fmt.Sprintf(` resource "google_composer_environment" "test" { @@ -2863,6 +2962,38 @@ resource "google_compute_subnetwork" "test" { `, name, network, subnetwork) } +func testAccComposerEnvironmentComposer2_usesUnsupportedField(name string) string { +return fmt.Sprintf(` +resource "google_composer_environment" "test" { + name = "%s" + region = "us-central1" + config { + software_config { + image_version = "composer-2-airflow-2" + web_server_plugins_mode = "ENABLED" + } + } +} +`, name) +} + +func testAccComposerEnvironmentComposer3_usesUnsupportedField(name string) string { +return fmt.Sprintf(` +resource "google_composer_environment" "test" { + name = "%s" + region = "us-central1" + config { + node_config { + enable_ip_masq_agent = true + } + software_config { + image_version = "composer-3-airflow-2" + } + } +} +`, name) +} + func testAccComposerEnvironmentComposer3_basic(name, network, subnetwork string) string { return fmt.Sprintf(` resource "google_composer_environment" "test" { From c4260af062bfbc3dd321ad3990ba3a735d537291 Mon Sep 17 00:00:00 2001 From: "Stephen Lewis (Burrows)" Date: Thu, 22 Feb 2024 15:36:59 -0800 Subject: [PATCH 56/77] Made TestAccContainerCluster_withGatewayApiConfig error regex more forgiving (#10034) Fixed https://github.com/hashicorp/terraform-provider-google/issues/17319 --- .../services/container/resource_container_cluster_test.go.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb b/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb index a542384379f6..3699a6ba9662 100644 --- a/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb +++ b/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb @@ -4230,7 +4230,7 @@ func TestAccContainerCluster_withGatewayApiConfig(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccContainerCluster_withGatewayApiConfig(clusterName, "CANARY", networkName, subnetworkName), - ExpectError: regexp.MustCompile(`expected gateway_api_config\.0\.channel to be one of \[CHANNEL_DISABLED CHANNEL_EXPERIMENTAL CHANNEL_STANDARD\], got CANARY`), + ExpectError: regexp.MustCompile(`expected gateway_api_config\.0\.channel to be one of [^,]+, got CANARY`), }, { Config: testAccContainerCluster_withGatewayApiConfig(clusterName, "CHANNEL_DISABLED", networkName, subnetworkName), From 1470d00e90e813f69d09aa9f55589884cbc27900 Mon Sep 17 00:00:00 2001 From: Hamzawy63 <43001514+Hamzawy63@users.noreply.github.com> Date: Fri, 23 Feb 2024 17:33:59 +0100 Subject: [PATCH 57/77] Add ceritificateManagerCertificates field to ComputeRegionTargetHttpsProxy resource (#10011) Co-authored-by: Hamza Hassan --- .../compute/RegionTargetHttpsProxy.yaml | 34 ++++++++++++++++--- .../compute_region_target_https_proxy.go.erb | 15 ++++++++ .../compute_region_target_https_proxy.go.erb | 10 ++++++ ...oxy_certificate_manager_certificate.tf.erb | 28 +++++++++++++++ 4 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 mmv1/templates/terraform/decoders/compute_region_target_https_proxy.go.erb create mode 100644 mmv1/templates/terraform/encoders/compute_region_target_https_proxy.go.erb create mode 100644 mmv1/templates/terraform/examples/region_target_https_proxy_certificate_manager_certificate.tf.erb diff --git a/mmv1/products/compute/RegionTargetHttpsProxy.yaml b/mmv1/products/compute/RegionTargetHttpsProxy.yaml index 723d03ad87af..553bd1a5655a 100644 --- a/mmv1/products/compute/RegionTargetHttpsProxy.yaml +++ b/mmv1/products/compute/RegionTargetHttpsProxy.yaml @@ -41,6 +41,9 @@ async: !ruby/object:Api::OpAsync error: !ruby/object:Api::OpAsync::Error path: 'error/errors' message: 'message' +custom_code: !ruby/object:Provider::Terraform::CustomCode + encoder: templates/terraform/encoders/compute_region_target_https_proxy.go.erb + decoder: templates/terraform/decoders/compute_region_target_https_proxy.go.erb examples: - !ruby/object:Provider::Terraform::Examples name: 'region_target_https_proxy_basic' @@ -51,6 +54,14 @@ examples: region_url_map_name: 'url-map' region_backend_service_name: 'backend-service' region_health_check_name: 'http-health-check' + - !ruby/object:Provider::Terraform::Examples + name: 'region_target_https_proxy_certificate_manager_certificate' + primary_resource_id: 'default' + vars: + region_target_https_proxy_name: 'target-http-proxy' + certificate_manager_certificate_name: 'my-certificate' + region_url_map_name: 'url-map' + region_backend_service_name: 'backend-service' parameters: - !ruby/object:Api::Type::ResourceRef name: 'region' @@ -109,13 +120,26 @@ properties: # update_verb: :POST # update_url: # 'projects/{{project}}/regions/{{region}}/targetHttpsProxies/{{name}}/setQuicOverride' + - !ruby/object:Api::Type::Array + name: 'certificateManagerCertificates' + description: | + URLs to certificate manager certificate resources that are used to authenticate connections between users and the load balancer. + Currently, you may specify up to 15 certificates. Certificate manager certificates do not apply when the load balancing scheme is set to INTERNAL_SELF_MANAGED. + sslCertificates and certificateManagerCertificates fields can not be defined together. + Accepted format is `//certificatemanager.googleapis.com/projects/{project}/locations/{location}/certificates/{resourceName}` or just the self_link `projects/{project}/locations/{location}/certificates/{resourceName}` + update_verb: :POST + update_url: 'projects/{{project}}/regions/{{region}}/targetHttpsProxies/{{name}}/setSslCertificates' + item_type: Api::Type::String + custom_expand: 'templates/terraform/custom_expand/certificate_manager_certificate_construct_full_url.go.erb' + diff_suppress_func: 'tpgresource.CompareResourceNames' + conflicts: + - ssl_certificates - !ruby/object:Api::Type::Array name: 'sslCertificates' description: | - A list of RegionSslCertificate resources that are used to authenticate - connections between users and the load balancer. Currently, exactly - one SSL certificate must be specified. - required: true + URLs to SslCertificate resources that are used to authenticate connections between users and the load balancer. + At least one SSL certificate must be specified. Currently, you may specify up to 15 SSL certificates. + sslCertificates do not apply when the load balancing scheme is set to INTERNAL_SELF_MANAGED. update_verb: :POST update_url: 'projects/{{project}}/regions/{{region}}/targetHttpsProxies/{{name}}/setSslCertificates' item_type: !ruby/object:Api::Type::ResourceRef @@ -124,6 +148,8 @@ properties: imports: 'selfLink' description: 'The SSL certificates used by this TargetHttpsProxy' custom_expand: 'templates/terraform/custom_expand/array_resourceref_with_validation.go.erb' + conflicts: + - certificate_manager_certificates - !ruby/object:Api::Type::ResourceRef name: 'sslPolicy' resource: 'RegionSslPolicy' diff --git a/mmv1/templates/terraform/decoders/compute_region_target_https_proxy.go.erb b/mmv1/templates/terraform/decoders/compute_region_target_https_proxy.go.erb new file mode 100644 index 000000000000..0a72fe1c476a --- /dev/null +++ b/mmv1/templates/terraform/decoders/compute_region_target_https_proxy.go.erb @@ -0,0 +1,15 @@ +// Since both sslCertificates and certificateManagerCertificates maps to the same API field (sslCertificates), we need to check the types +// of certificates that exist in the array and decide whether to change the field to certificateManagerCertificate or not. +// The decoder logic depends on the fact that the API does not allow mixed type of certificates and it returns +// certificate manager certificates in the format of //certificatemanager.googleapis.com/projects/*/locations/*/certificates/* +if sslCertificates, ok := res["sslCertificates"].([]interface{}); ok && len(sslCertificates) > 0 { + regPat, _ := regexp.Compile("//certificatemanager.googleapis.com/projects/(.*)/locations/(.*)/certificates/(.*)") + + if regPat.MatchString(sslCertificates[0].(string)) { + // It is enough to check only the type of one of the provided certificates beacuse all the certificates should be the same type. + log.Printf("[DEBUG] The field sslCertificates contains certificateManagerCertificates, the field name will be converted to certificateManagerCertificates") + res["certificateManagerCertificates"] = res["sslCertificates"] + delete(res, "sslCertificates") + } +} +return res, nil \ No newline at end of file diff --git a/mmv1/templates/terraform/encoders/compute_region_target_https_proxy.go.erb b/mmv1/templates/terraform/encoders/compute_region_target_https_proxy.go.erb new file mode 100644 index 000000000000..168d4a65c5ef --- /dev/null +++ b/mmv1/templates/terraform/encoders/compute_region_target_https_proxy.go.erb @@ -0,0 +1,10 @@ + +if _, ok := obj["certificateManagerCertificates"]; ok { + // The field certificateManagerCertificates should not be included in the API request, and it should be renamed to `sslCertificates` + // The API does not allow using both certificate manager certificates and sslCertificates. If that changes + // in the future, the encoder logic should change accordingly because this will mean that both fields are no longer mutual exclusive. + log.Printf("[DEBUG] converting the field CertificateManagerCertificates to sslCertificates before sending the request") + obj["sslCertificates"] = obj["certificateManagerCertificates"] + delete(obj, "certificateManagerCertificates") +} +return obj, nil \ No newline at end of file diff --git a/mmv1/templates/terraform/examples/region_target_https_proxy_certificate_manager_certificate.tf.erb b/mmv1/templates/terraform/examples/region_target_https_proxy_certificate_manager_certificate.tf.erb new file mode 100644 index 000000000000..05c8d90b46f9 --- /dev/null +++ b/mmv1/templates/terraform/examples/region_target_https_proxy_certificate_manager_certificate.tf.erb @@ -0,0 +1,28 @@ +resource "google_compute_region_target_https_proxy" "<%= ctx[:primary_resource_id] %>" { + name = "<%= ctx[:vars]['region_target_https_proxy_name'] %>" + url_map = google_compute_region_url_map.default.id + certificate_manager_certificates = ["//certificatemanager.googleapis.com/${google_certificate_manager_certificate.default.id}"] # [google_certificate_manager_certificate.default.id] is also acceptable +} + +resource "google_certificate_manager_certificate" "default" { + name = "<%= ctx[:vars]['certificate_manager_certificate_name'] %>" + location = "us-central1" + self_managed { + pem_certificate = file("test-fixtures/cert.pem") + pem_private_key = file("test-fixtures/private-key.pem") + } +} + +resource "google_compute_region_url_map" "default" { + name = "<%= ctx[:vars]['region_url_map_name'] %>" + default_service = google_compute_region_backend_service.default.id + region = "us-central1" +} + +resource "google_compute_region_backend_service" "default" { + name = "<%= ctx[:vars]['region_backend_service_name'] %>" + region = "us-central1" + protocol = "HTTPS" + timeout_sec = 30 + load_balancing_scheme = "INTERNAL_MANAGED" +} \ No newline at end of file From 326caf3235a24fbb7e8140baed87619a409712a6 Mon Sep 17 00:00:00 2001 From: "Stephen Lewis (Burrows)" Date: Fri, 23 Feb 2024 08:56:40 -0800 Subject: [PATCH 58/77] Added missing quote marks to TEST_PREFIX (#10035) Without this, | gets interpreted as a pipe and the test count always becomes 0 if there are multiple prefixes supplied --- .../terraform/.teamcity/components/builds/build_steps.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmv1/third_party/terraform/.teamcity/components/builds/build_steps.kt b/mmv1/third_party/terraform/.teamcity/components/builds/build_steps.kt index 4faed1046b65..78f942cf380d 100644 --- a/mmv1/third_party/terraform/.teamcity/components/builds/build_steps.kt +++ b/mmv1/third_party/terraform/.teamcity/components/builds/build_steps.kt @@ -118,7 +118,7 @@ fun BuildSteps.runAcceptanceTests() { exit 0 fi - export TEST_COUNT=${'$'}(./test-binary -test.list=%TEST_PREFIX% | wc -l) + export TEST_COUNT=${'$'}(./test-binary -test.list="%TEST_PREFIX%" | wc -l) echo "Found ${'$'}{TEST_COUNT} tests that match the given test prefix %TEST_PREFIX%" if test ${'$'}TEST_COUNT -le "0"; then echo "Skipping test execution; no tests to run" From 77453ca7f52504372082b2f2b9e1b3aebd388b26 Mon Sep 17 00:00:00 2001 From: Sneha-at Date: Fri, 23 Feb 2024 09:45:18 -0800 Subject: [PATCH 59/77] Promote enable_confidential_storage from beta to GA (#9993) --- mmv1/third_party/terraform/go.mod.erb | 42 ++++----- mmv1/third_party/terraform/go.sum | 88 +++++++++---------- .../services/container/node_config.go.erb | 8 +- .../resource_container_cluster_test.go.erb | 2 - .../resource_container_node_pool_test.go.erb | 3 - .../docs/r/container_cluster.html.markdown | 3 +- 6 files changed, 67 insertions(+), 79 deletions(-) diff --git a/mmv1/third_party/terraform/go.mod.erb b/mmv1/third_party/terraform/go.mod.erb index 0d5943fb44fc..2d2a0081a295 100644 --- a/mmv1/third_party/terraform/go.mod.erb +++ b/mmv1/third_party/terraform/go.mod.erb @@ -25,21 +25,21 @@ require ( github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/hashstructure v1.1.0 github.com/sirupsen/logrus v1.8.1 - golang.org/x/net v0.20.0 - golang.org/x/oauth2 v0.16.0 - google.golang.org/api v0.156.0 - google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 - google.golang.org/grpc v1.60.1 + golang.org/x/net v0.21.0 + golang.org/x/oauth2 v0.17.0 + google.golang.org/api v0.166.0 + google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 + google.golang.org/grpc v1.61.1 google.golang.org/protobuf v1.32.0 ) require ( bitbucket.org/creachadair/stringset v0.0.8 // indirect - cloud.google.com/go v0.111.0 // indirect - cloud.google.com/go/compute v1.23.3 // indirect + cloud.google.com/go v0.112.0 // indirect + cloud.google.com/go/compute v1.23.4 // indirect cloud.google.com/go/compute/metadata v0.2.3 // indirect - cloud.google.com/go/iam v1.1.5 // indirect - cloud.google.com/go/longrunning v0.5.4 // indirect + cloud.google.com/go/iam v1.1.6 // indirect + cloud.google.com/go/longrunning v0.5.5 // indirect github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect github.com/agext/levenshtein v1.2.2 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect @@ -48,7 +48,7 @@ require ( github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cloudflare/circl v1.3.3 // indirect github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe // indirect - github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 // indirect + github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 // indirect github.com/envoyproxy/go-control-plane v0.11.1 // indirect github.com/envoyproxy/protoc-gen-validate v1.0.2 // indirect github.com/fatih/color v1.13.0 // indirect @@ -62,9 +62,9 @@ require ( github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cpy v0.0.0-20211218193943-a9c933c06932 // indirect github.com/google/s2a-go v0.1.7 // indirect - github.com/google/uuid v1.5.0 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect - github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/googleapis/gax-go/v2 v2.12.1 // indirect github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-hclog v1.5.0 // indirect github.com/hashicorp/go-plugin v1.6.0 // indirect @@ -91,19 +91,19 @@ require ( github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/zclconf/go-cty v1.14.1 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect - go.opentelemetry.io/otel v1.21.0 // indirect - go.opentelemetry.io/otel/metric v1.21.0 // indirect - go.opentelemetry.io/otel/trace v1.21.0 // indirect - golang.org/x/crypto v0.18.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 // indirect + go.opentelemetry.io/otel v1.23.0 // indirect + go.opentelemetry.io/otel/metric v1.23.0 // indirect + go.opentelemetry.io/otel/trace v1.23.0 // indirect + golang.org/x/crypto v0.19.0 // indirect golang.org/x/mod v0.14.0 // indirect golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.16.0 // indirect + golang.org/x/sys v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 // indirect + google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/mmv1/third_party/terraform/go.sum b/mmv1/third_party/terraform/go.sum index b265f1fc3590..70ac88701502 100644 --- a/mmv1/third_party/terraform/go.sum +++ b/mmv1/third_party/terraform/go.sum @@ -1,18 +1,18 @@ bitbucket.org/creachadair/stringset v0.0.8 h1:gQqe4vs8XWgMyijfyKE6K8o4TcyGGrRXe0JvHgx5H+M= bitbucket.org/creachadair/stringset v0.0.8/go.mod h1:AgthVMyMxC/6FK1KBJ2ALdqkZObGN8hOetgpwXyMn34= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.111.0 h1:YHLKNupSD1KqjDbQ3+LVdQ81h/UJbJyZG203cEfnQgM= -cloud.google.com/go v0.111.0/go.mod h1:0mibmpKP1TyOOFYQY5izo0LnT+ecvOQ0Sg3OdmMiNRU= +cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= +cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= cloud.google.com/go/bigtable v1.19.0 h1:wiq9LT0kukfInzvy1joMDijCw/OD1UChpSbORXYn0LI= cloud.google.com/go/bigtable v1.19.0/go.mod h1:xl5kPa8PTkJjdBxg6qdGH88464nNqmbISHSRU+D2yFE= -cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= -cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= +cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wvAw= +cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= -cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= -cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= -cloud.google.com/go/longrunning v0.5.4 h1:w8xEcbZodnA2BbW6sVirkkoC+1gP8wS57EUUgGS0GVg= -cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/longrunning v0.5.5 h1:GOE6pZFdSrTb4KAiKnXsJBtlE6mEyaW44oKyMILWnOg= +cloud.google.com/go/longrunning v0.5.5/go.mod h1:WV2LAxD8/rg5Z1cNW6FJ/ZpX4E4VnDnoTk0yawPBB7s= dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/GoogleCloudPlatform/declarative-resource-client-library v1.62.0 h1:s4Y6r6RrYLBnqosGXLwR0h1Gqr0VT3wgd6rqvHsD9OE= @@ -43,8 +43,8 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k= -github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY= +github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/creachadair/staticfile v0.1.2/go.mod h1:a3qySzCIXEprDGxk6tSxSI+dBBdLzqeBOMhZ+o2d3pM= github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -120,12 +120,12 @@ github.com/google/go-cpy v0.0.0-20211218193943-a9c933c06932/go.mod h1:cC6EdPbj/1 github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= -github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= -github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/googleapis/gax-go/v2 v2.12.1 h1:9F8GV9r9ztXyAi00gsMQHNoF51xPZm8uj1dpYt2ZETM= +github.com/googleapis/gax-go/v2 v2.12.1/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 h1:+9834+KizmvFV7pXQGSXQTsaWhq2GjuNUt0aUU0YBYw= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= @@ -249,17 +249,17 @@ github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM= -go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0 h1:P+/g8GpuJGYbOp2tAdKrIPUX9JO02q8Q0YNlHolpibA= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.48.0/go.mod h1:tIKj3DbO8N9Y2xo52og3irLsPI4GW02DSMtrVgNMgxg= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0 h1:doUP+ExOpH3spVTLS0FcWGLnQrPct/hD/bCPbDRUEAU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.48.0/go.mod h1:rdENBZMT2OE6Ne/KLwpiXudnAsbdrdBaqBvTN8M8BgA= +go.opentelemetry.io/otel v1.23.0 h1:Df0pqjqExIywbMCMTxkAwzjLZtRf+bBKLbUcpxO2C9E= +go.opentelemetry.io/otel v1.23.0/go.mod h1:YCycw9ZeKhcJFrb34iVSkyT0iczq/zYDtZYFufObyB0= +go.opentelemetry.io/otel/metric v1.23.0 h1:pazkx7ss4LFVVYSxYew7L5I6qvLXHA0Ap2pwV+9Cnpo= +go.opentelemetry.io/otel/metric v1.23.0/go.mod h1:MqUW2X2a6Q8RN96E2/nqNoT+z9BSms20Jb7Bbp+HiTo= +go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8= +go.opentelemetry.io/otel/trace v1.23.0 h1:37Ik5Ib7xfYVb4V1UtnT97T1jI+AoIYkJyPkuL4iJgI= +go.opentelemetry.io/otel/trace v1.23.0/go.mod h1:GSGTbIClEsuZrGIzoEHqsVfxgn5UkggkflQwDScNUsk= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= @@ -269,8 +269,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -295,11 +295,11 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= -golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= +golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -328,14 +328,14 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -363,8 +363,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.156.0 h1:yloYcGbBtVYjLKQe4enCunxvwn3s2w/XPrrhVf6MsvQ= -google.golang.org/api v0.156.0/go.mod h1:bUSmn4KFO0Q+69zo9CNIDp4Psi6BqM0np0CbzKRSiSY= +google.golang.org/api v0.166.0 h1:6m4NUwrZYhAaVIHZWxaKjw1L1vNAjtMwORmKRyEEo24= +google.golang.org/api v0.166.0/go.mod h1:4FcBc686KFi7QI/U51/2GKKevfZMpM17sCdibqe/bSA= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= @@ -373,20 +373,20 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= -google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= -google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0 h1:s1w3X6gQxwrLEpxnLd/qXTVLgQE2yXwaOaoa6IlY/+o= -google.golang.org/genproto/googleapis/api v0.0.0-20231212172506-995d672761c0/go.mod h1:CAny0tYF+0/9rmDB9fahA9YLzX3+AEVl1qXbv5hhj6c= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 h1:gphdwh0npgs8elJ4T6J+DQJHPVF7RsuJHCfwztUb4J4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= +google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 h1:g/4bk7P6TPMkAUbUhquq98xey1slwvuVJPosdBqYJlU= +google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M= +google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 h1:x9PwdEgd11LgK+orcck69WVRo7DezSO4VUMPI4xpc8A= +google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9 h1:hZB7eLIaYlW9qXRfCq/qDaPdbeY3757uARz5Vvfv+cY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:YUWgXUFRPfoYK1IHMuxH5K6nPEXSCzIMljnQ59lLRCk= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= -google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= +google.golang.org/grpc v1.61.1 h1:kLAiWrZs7YeDM6MumDe7m3y4aM6wacLzM1Y/wiLP9XY= +google.golang.org/grpc v1.61.1/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/mmv1/third_party/terraform/services/container/node_config.go.erb b/mmv1/third_party/terraform/services/container/node_config.go.erb index 8d53ce85b51d..089c5943aaea 100644 --- a/mmv1/third_party/terraform/services/container/node_config.go.erb +++ b/mmv1/third_party/terraform/services/container/node_config.go.erb @@ -680,14 +680,12 @@ func schemaNodeConfig() *schema.Schema { Optional: true, Description: `A map of resource manager tags. Resource manager tag keys and values have the same definition as resource manager tags. Keys must be in the format tagKeys/{tag_key_id}, and values are in the format tagValues/456. The field is ignored (both PUT & PATCH) when empty.`, }, - <% unless version == 'ga' -%> "enable_confidential_storage": { Type: schema.TypeBool, Optional: true, ForceNew: true, Description: `If enabled boot disks are configured with confidential mode.`, }, - <% end -%> }, }, } @@ -978,12 +976,10 @@ func expandNodeConfig(v interface{}) *container.NodeConfig { nc.SoleTenantConfig = expandSoleTenantConfig(v) } - <% unless version == 'ga' -%> if v,ok := nodeConfig["enable_confidential_storage"]; ok { nc.EnableConfidentialStorage = v.(bool) } - <% end -%> - + <% unless version == "ga" -%> if v, ok := nodeConfig["host_maintenance_policy"]; ok { nc.HostMaintenancePolicy = expandHostMaintenancePolicy(v) @@ -1236,9 +1232,7 @@ func flattenNodeConfig(c *container.NodeConfig, v interface{}) []map[string]inte "sole_tenant_config": flattenSoleTenantConfig(c.SoleTenantConfig), "fast_socket": flattenFastSocket(c.FastSocket), "resource_manager_tags": flattenResourceManagerTags(c.ResourceManagerTags), - <% unless version == 'ga' -%> "enable_confidential_storage": c.EnableConfidentialStorage, - <% end -%> }) if len(c.OauthScopes) > 0 { diff --git a/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb b/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb index 3699a6ba9662..910fba9602b0 100644 --- a/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb +++ b/mmv1/third_party/terraform/services/container/resource_container_cluster_test.go.erb @@ -9389,7 +9389,6 @@ func testAccContainerCluster_additional_pod_ranges_config(name string, nameCount `, name, name, name, aprc) } -<% unless version == 'ga' -%> func TestAccContainerCluster_withConfidentialBootDisk(t *testing.T) { t.Parallel() @@ -9558,7 +9557,6 @@ resource "google_container_cluster" "without_confidential_boot_disk" { } `, clusterName, npName, networkName, subnetworkName) } -<% end -%> <% unless version == 'ga' -%> func testAccContainerCluster_withWorkloadALTSConfig(projectID, name, networkName, subnetworkName string, enable bool) string { diff --git a/mmv1/third_party/terraform/services/container/resource_container_node_pool_test.go.erb b/mmv1/third_party/terraform/services/container/resource_container_node_pool_test.go.erb index 42939e9b7e9b..ec3e852d8ce6 100644 --- a/mmv1/third_party/terraform/services/container/resource_container_node_pool_test.go.erb +++ b/mmv1/third_party/terraform/services/container/resource_container_node_pool_test.go.erb @@ -4135,8 +4135,6 @@ resource "google_container_node_pool" "np" { } <% end -%> -<% unless version == 'ga' -%> - func TestAccContainerNodePool_withConfidentialBootDisk(t *testing.T) { t.Parallel() @@ -4262,7 +4260,6 @@ resource "google_container_node_pool" "without_confidential_boot_disk" { } `, cluster, networkName, subnetworkName, np) } -<% end -%> func testAccContainerNodePool_resourceManagerTags(projectID, clusterName, networkName, subnetworkName, randomSuffix string) string { return fmt.Sprintf(` diff --git a/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown b/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown index 3c72beba2d55..983dd05befe4 100644 --- a/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/container_cluster.html.markdown @@ -790,8 +790,7 @@ The `master_authorized_networks_config.cidr_blocks` block supports: * `disk_type` - (Optional) Type of the disk attached to each node (e.g. 'pd-standard', 'pd-balanced' or 'pd-ssd'). If unspecified, the default disk type is 'pd-standard' -* `enable_confidential_storage` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) -Enabling Confidential Storage will create boot disk with confidential mode. It is disabled by default. +* `enable_confidential_storage` - (Optional) Enabling Confidential Storage will create boot disk with confidential mode. It is disabled by default. * `ephemeral_storage_config` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) Parameters for the ephemeral storage filesystem. If unspecified, ephemeral storage is backed by the boot disk. Structure is [documented below](#nested_ephemeral_storage_config). From 39bd019d029e4f9f69179a8b5545bfe3f83ff966 Mon Sep 17 00:00:00 2001 From: Shogo Watanabe <1286807+nownabe@users.noreply.github.com> Date: Sat, 24 Feb 2024 03:33:32 +0900 Subject: [PATCH 60/77] Add IAM resources for Cloud Deploy Target (#9927) * Add IAM resources for Cloud Deploy Target * update * add back import_format --- mmv1/products/clouddeploy/Target.yaml | 40 +++++++++++++++++++ .../examples/clouddeploy_target_basic.tf.erb | 4 ++ 2 files changed, 44 insertions(+) create mode 100644 mmv1/products/clouddeploy/Target.yaml create mode 100644 mmv1/templates/terraform/examples/clouddeploy_target_basic.tf.erb diff --git a/mmv1/products/clouddeploy/Target.yaml b/mmv1/products/clouddeploy/Target.yaml new file mode 100644 index 000000000000..b8ab9d6fd154 --- /dev/null +++ b/mmv1/products/clouddeploy/Target.yaml @@ -0,0 +1,40 @@ +# Copyright 2024 Google Inc. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- !ruby/object:Api::Resource +name: 'Target' +description: | + The Cloud Deploy `Target` resource. +base_url: 'projects/{{project}}/locations/{{location}}/targets' +self_link: 'projects/{{project}}/locations/{{location}}/targets/{{name}}' +exclude_resource: true +id_format: 'projects/{{project}}/locations/{{location}}/targets/{{name}}' +import_format: + - 'projects/{{project}}/locations/{{location}}/targets/{{name}}' +iam_policy: !ruby/object:Api::Resource::IamPolicy + parent_resource_attribute: 'name' + method_name_separator: ':' + base_url: 'projects/{{project}}/locations/{{location}}/targets/{{name}}' + import_format: ['projects/{{project}}/locations/{{location}}/targets/{{name}}', '{{name}}'] +examples: + - !ruby/object:Provider::Terraform::Examples + name: 'clouddeploy_target_basic' + primary_resource_id: 'default' + primary_resource_name: 'fmt.Sprintf("tf-test-cd-target%s", context["random_suffix"])' + vars: + target: 'cd-target' +properties: + - !ruby/object:Api::Type::String + name: "name" + description: "Dummy property." + required: true diff --git a/mmv1/templates/terraform/examples/clouddeploy_target_basic.tf.erb b/mmv1/templates/terraform/examples/clouddeploy_target_basic.tf.erb new file mode 100644 index 000000000000..5fd51566834c --- /dev/null +++ b/mmv1/templates/terraform/examples/clouddeploy_target_basic.tf.erb @@ -0,0 +1,4 @@ +resource "google_clouddeploy_target" "<%= ctx[:primary_resource_id] %>" { + name = "<%= ctx[:vars]['target'] %>" + location = "us-central1" + } From 0ce23ad244ece88e2e71b7a556e5f55841d1e514 Mon Sep 17 00:00:00 2001 From: hao-nan-li <100219545+hao-nan-li@users.noreply.github.com> Date: Fri, 23 Feb 2024 11:32:33 -0800 Subject: [PATCH 61/77] Add comments to skipped sweepers (#10028) --- mmv1/products/secretmanager/SecretVersion.yaml | 1 + mmv1/products/spanner/Database.yaml | 1 + mmv1/products/sql/Database.yaml | 1 + 3 files changed, 3 insertions(+) diff --git a/mmv1/products/secretmanager/SecretVersion.yaml b/mmv1/products/secretmanager/SecretVersion.yaml index 0161b2e6d0d3..9db3d9e31bcb 100644 --- a/mmv1/products/secretmanager/SecretVersion.yaml +++ b/mmv1/products/secretmanager/SecretVersion.yaml @@ -20,6 +20,7 @@ delete_url: '{{name}}:destroy' delete_verb: :POST description: | A secret version resource. +# Sweeper skipped as this resource has customized deletion. skip_sweeper: true examples: - !ruby/object:Provider::Terraform::Examples diff --git a/mmv1/products/spanner/Database.yaml b/mmv1/products/spanner/Database.yaml index 9feb815c7cb9..ea33c9ad211c 100644 --- a/mmv1/products/spanner/Database.yaml +++ b/mmv1/products/spanner/Database.yaml @@ -41,6 +41,7 @@ async: !ruby/object:Api::OpAsync path: 'error' message: 'message' autogen_async: true +# Sweeper skipped as this resource has customized deletion. skip_sweeper: true id_format: '{{instance}}/{{name}}' import_format: diff --git a/mmv1/products/sql/Database.yaml b/mmv1/products/sql/Database.yaml index 1c6c56a9ed14..eca5f0a5c533 100644 --- a/mmv1/products/sql/Database.yaml +++ b/mmv1/products/sql/Database.yaml @@ -30,6 +30,7 @@ import_format: '{{instance}}/{{name}}', '{{name}}', ] +# Sweeper skipped as this resource has customized deletion. skip_sweeper: true examples: - !ruby/object:Provider::Terraform::Examples From 7beb4e694352b2164ca630357ad429c03a69f707 Mon Sep 17 00:00:00 2001 From: hao-nan-li <100219545+hao-nan-li@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:16:01 -0800 Subject: [PATCH 62/77] Add sweepers for gkebackupPlan and restorePlan (#10026) --- mmv1/products/gkebackup/BackupPlan.yaml | 1 - mmv1/products/gkebackup/RestorePlan.yaml | 1 - 2 files changed, 2 deletions(-) diff --git a/mmv1/products/gkebackup/BackupPlan.yaml b/mmv1/products/gkebackup/BackupPlan.yaml index f3937b278d0c..26733710637e 100644 --- a/mmv1/products/gkebackup/BackupPlan.yaml +++ b/mmv1/products/gkebackup/BackupPlan.yaml @@ -105,7 +105,6 @@ examples: deletion_protection: 'false' test_env_vars: project: :PROJECT_NAME -skip_sweeper: true parameters: - !ruby/object:Api::Type::String name: 'location' diff --git a/mmv1/products/gkebackup/RestorePlan.yaml b/mmv1/products/gkebackup/RestorePlan.yaml index 479946268fda..38bcb5216b5c 100644 --- a/mmv1/products/gkebackup/RestorePlan.yaml +++ b/mmv1/products/gkebackup/RestorePlan.yaml @@ -134,7 +134,6 @@ examples: subnetwork_name: 'acctest.BootstrapSubnet(t, "gke-cluster", acctest.BootstrapSharedTestNetwork(t, "gke-cluster"))' oics_vars_overrides: deletion_protection: 'false' -skip_sweeper: true parameters: - !ruby/object:Api::Type::String name: 'location' From 8365dfab7960fb8cc9aa5b169d5f9178271f58fa Mon Sep 17 00:00:00 2001 From: Obada Alabbadi <76101898+obada-ab@users.noreply.github.com> Date: Fri, 23 Feb 2024 23:16:55 +0100 Subject: [PATCH 63/77] add `remote_function_options` to bigquery_routine (#9893) * Add dataGovernanceType and remoteFunctionOptions to bigquery_routine * add function-sources.zip to biguquery fixtures * fix resource names in TestAccBigQueryRoutine * add bigquery routine remote function example --- mmv1/products/bigquery/Routine.yaml | 50 +++++- ...c.tf.erb => bigquery_routine_basic.tf.erb} | 0 ...on.tf.erb => bigquery_routine_json.tf.erb} | 0 ...tf.erb => bigquery_routine_pyspark.tf.erb} | 0 ... bigquery_routine_pyspark_mainfile.tf.erb} | 0 .../bigquery_routine_remote_function.tf.erb | 27 +++ ....erb => bigquery_routine_spark_jar.tf.erb} | 0 ...tvf.tf.erb => bigquery_routine_tvf.tf.erb} | 0 .../resource_bigquery_routine_test.go | 168 ++++++++++++++++++ .../test-fixtures/function-source.zip | Bin 0 -> 458 bytes 10 files changed, 239 insertions(+), 6 deletions(-) rename mmv1/templates/terraform/examples/{big_query_routine_basic.tf.erb => bigquery_routine_basic.tf.erb} (100%) rename mmv1/templates/terraform/examples/{big_query_routine_json.tf.erb => bigquery_routine_json.tf.erb} (100%) rename mmv1/templates/terraform/examples/{big_query_routine_pyspark.tf.erb => bigquery_routine_pyspark.tf.erb} (100%) rename mmv1/templates/terraform/examples/{big_query_routine_pyspark_mainfile.tf.erb => bigquery_routine_pyspark_mainfile.tf.erb} (100%) create mode 100644 mmv1/templates/terraform/examples/bigquery_routine_remote_function.tf.erb rename mmv1/templates/terraform/examples/{big_query_routine_spark_jar.tf.erb => bigquery_routine_spark_jar.tf.erb} (100%) rename mmv1/templates/terraform/examples/{big_query_routine_tvf.tf.erb => bigquery_routine_tvf.tf.erb} (100%) create mode 100644 mmv1/third_party/terraform/services/bigquery/test-fixtures/function-source.zip diff --git a/mmv1/products/bigquery/Routine.yaml b/mmv1/products/bigquery/Routine.yaml index 513a80b503d4..3dbbfd3b0577 100644 --- a/mmv1/products/bigquery/Routine.yaml +++ b/mmv1/products/bigquery/Routine.yaml @@ -26,7 +26,7 @@ import_format: ['projects/{{project}}/datasets/{{dataset_id}}/routines/{{routine_id}}'] examples: - !ruby/object:Provider::Terraform::Examples - name: 'big_query_routine_basic' + name: 'bigquery_routine_basic' primary_resource_id: 'sproc' primary_resource_name: "fmt.Sprintf(\"tf_test_dataset_id%s\", context[\"random_suffix\"\ @@ -35,7 +35,7 @@ examples: dataset_id: 'dataset_id' routine_id: 'routine_id' - !ruby/object:Provider::Terraform::Examples - name: 'big_query_routine_json' + name: 'bigquery_routine_json' primary_resource_id: 'sproc' primary_resource_name: "fmt.Sprintf(\"tf_test_dataset_id%s\", context[\"random_suffix\"\ @@ -44,7 +44,7 @@ examples: dataset_id: 'dataset_id' routine_id: 'routine_id' - !ruby/object:Provider::Terraform::Examples - name: 'big_query_routine_tvf' + name: 'bigquery_routine_tvf' primary_resource_id: 'sproc' primary_resource_name: "fmt.Sprintf(\"tf_test_dataset_id%s\", context[\"random_suffix\"\ @@ -53,26 +53,34 @@ examples: dataset_id: 'dataset_id' routine_id: 'routine_id' - !ruby/object:Provider::Terraform::Examples - name: 'big_query_routine_pyspark' + name: 'bigquery_routine_pyspark' primary_resource_id: 'pyspark' vars: dataset_id: 'dataset_id' connection_id: 'connection_id' routine_id: 'routine_id' - !ruby/object:Provider::Terraform::Examples - name: 'big_query_routine_pyspark_mainfile' + name: 'bigquery_routine_pyspark_mainfile' primary_resource_id: 'pyspark_mainfile' vars: dataset_id: 'dataset_id' connection_id: 'connection_id' routine_id: 'routine_id' - !ruby/object:Provider::Terraform::Examples - name: 'big_query_routine_spark_jar' + name: 'bigquery_routine_spark_jar' primary_resource_id: 'spark_jar' vars: dataset_id: 'dataset_id' connection_id: 'connection_id' routine_id: 'routine_id' + - !ruby/object:Provider::Terraform::Examples + skip_test: true + name: 'bigquery_routine_remote_function' + primary_resource_id: 'remote_function' + vars: + dataset_id: 'dataset_id' + connection_id: 'connection_id' + routine_id: 'routine_id' properties: - !ruby/object:Api::Type::NestedObject name: routineReference @@ -283,3 +291,33 @@ properties: description: | The fully qualified name of a class in jarUris, for example, com.example.wordcount. Exactly one of mainClass and main_jar_uri field should be set for Java/Scala language type. + - !ruby/object:Api::Type::NestedObject + name: 'remoteFunctionOptions' + description: Remote function specific options. + properties: + - !ruby/object:Api::Type::String + name: 'endpoint' + description: | + Endpoint of the user-provided remote service, e.g. + `https://us-east1-my_gcf_project.cloudfunctions.net/remote_add` + - !ruby/object:Api::Type::String + name: 'connection' + description: | + Fully qualified name of the user-provided connection object which holds + the authentication information to send requests to the remote service. + Format: "projects/{projectId}/locations/{locationId}/connections/{connectionId}" + - !ruby/object:Api::Type::KeyValuePairs + name: 'userDefinedContext' + description: | + User-defined context as a set of key/value pairs, which will be sent as function + invocation context together with batched arguments in the requests to the remote + service. The total number of bytes of keys and values must be less than 8KB. + + An object containing a list of "key": value pairs. Example: + `{ "name": "wrench", "mass": "1.3kg", "count": "3" }`. + default_from_api: true + - !ruby/object:Api::Type::String + name: 'maxBatchingRows' + description: | + Max number of rows in each batch sent to the remote service. If absent or if 0, + BigQuery dynamically decides the number of rows in a batch. diff --git a/mmv1/templates/terraform/examples/big_query_routine_basic.tf.erb b/mmv1/templates/terraform/examples/bigquery_routine_basic.tf.erb similarity index 100% rename from mmv1/templates/terraform/examples/big_query_routine_basic.tf.erb rename to mmv1/templates/terraform/examples/bigquery_routine_basic.tf.erb diff --git a/mmv1/templates/terraform/examples/big_query_routine_json.tf.erb b/mmv1/templates/terraform/examples/bigquery_routine_json.tf.erb similarity index 100% rename from mmv1/templates/terraform/examples/big_query_routine_json.tf.erb rename to mmv1/templates/terraform/examples/bigquery_routine_json.tf.erb diff --git a/mmv1/templates/terraform/examples/big_query_routine_pyspark.tf.erb b/mmv1/templates/terraform/examples/bigquery_routine_pyspark.tf.erb similarity index 100% rename from mmv1/templates/terraform/examples/big_query_routine_pyspark.tf.erb rename to mmv1/templates/terraform/examples/bigquery_routine_pyspark.tf.erb diff --git a/mmv1/templates/terraform/examples/big_query_routine_pyspark_mainfile.tf.erb b/mmv1/templates/terraform/examples/bigquery_routine_pyspark_mainfile.tf.erb similarity index 100% rename from mmv1/templates/terraform/examples/big_query_routine_pyspark_mainfile.tf.erb rename to mmv1/templates/terraform/examples/bigquery_routine_pyspark_mainfile.tf.erb diff --git a/mmv1/templates/terraform/examples/bigquery_routine_remote_function.tf.erb b/mmv1/templates/terraform/examples/bigquery_routine_remote_function.tf.erb new file mode 100644 index 000000000000..9ef5b2a0dd2a --- /dev/null +++ b/mmv1/templates/terraform/examples/bigquery_routine_remote_function.tf.erb @@ -0,0 +1,27 @@ +resource "google_bigquery_dataset" "test" { + dataset_id = "<%= ctx[:vars]['dataset_id'] %>" +} + +resource "google_bigquery_connection" "test" { + connection_id = "<%= ctx[:vars]['connection_id'] %>" + location = "US" + cloud_resource { } +} + +resource "google_bigquery_routine" "<%= ctx[:primary_resource_id] %>" { + dataset_id = google_bigquery_dataset.test.dataset_id + routine_id = "<%= ctx[:vars]['routine_id'] %>" + routine_type = "SCALAR_FUNCTION" + definition_body = "" + + return_type = "{\"typeKind\" : \"STRING\"}" + + remote_function_options { + endpoint = "https://us-east1-my_gcf_project.cloudfunctions.net/remote_add" + connection = google_bigquery_connection.test.name + max_batching_rows = "10" + user_defined_context = { + "z": "1.5", + } + } +} \ No newline at end of file diff --git a/mmv1/templates/terraform/examples/big_query_routine_spark_jar.tf.erb b/mmv1/templates/terraform/examples/bigquery_routine_spark_jar.tf.erb similarity index 100% rename from mmv1/templates/terraform/examples/big_query_routine_spark_jar.tf.erb rename to mmv1/templates/terraform/examples/bigquery_routine_spark_jar.tf.erb diff --git a/mmv1/templates/terraform/examples/big_query_routine_tvf.tf.erb b/mmv1/templates/terraform/examples/bigquery_routine_tvf.tf.erb similarity index 100% rename from mmv1/templates/terraform/examples/big_query_routine_tvf.tf.erb rename to mmv1/templates/terraform/examples/bigquery_routine_tvf.tf.erb diff --git a/mmv1/third_party/terraform/services/bigquery/resource_bigquery_routine_test.go b/mmv1/third_party/terraform/services/bigquery/resource_bigquery_routine_test.go index bd106a6f079b..00f5763b505b 100644 --- a/mmv1/third_party/terraform/services/bigquery/resource_bigquery_routine_test.go +++ b/mmv1/third_party/terraform/services/bigquery/resource_bigquery_routine_test.go @@ -173,3 +173,171 @@ resource "google_bigquery_routine" "spark_jar" { } `, context) } + +func TestAccBigQueryRoutine_bigQueryRoutineRemoteFunction(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "zip_path": "./test-fixtures/function-source.zip", + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckBigQueryRoutineDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccBigQueryRoutine_bigQueryRoutineRemoteFunction(context), + }, + { + ResourceName: "google_bigquery_routine.remote_function_routine", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccBigQueryRoutine_bigQueryRoutineRemoteFunction_Update(context), + }, + { + ResourceName: "google_bigquery_routine.remote_function_routine", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccBigQueryRoutine_bigQueryRoutineRemoteFunction(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_storage_bucket" "default" { + name = "%{random_suffix}-gcf-source" + location = "US" + uniform_bucket_level_access = true +} + +resource "google_storage_bucket_object" "object" { + name = "function-source.zip" + bucket = google_storage_bucket.default.name + source = "%{zip_path}" +} + +resource "google_cloudfunctions2_function" "default" { + name = "function-v2-0" + location = "us-central1" + description = "a new function" + + build_config { + runtime = "nodejs18" + entry_point = "helloHttp" + source { + storage_source { + bucket = google_storage_bucket.default.name + object = google_storage_bucket_object.object.name + } + } + } + + service_config { + max_instance_count = 1 + available_memory = "256M" + timeout_seconds = 60 + } +} + +resource "google_bigquery_connection" "test" { + connection_id = "tf_test_connection_id%{random_suffix}" + location = "US" + cloud_resource { } +} + +resource "google_bigquery_dataset" "test" { + dataset_id = "tf_test_dataset_id%{random_suffix}" +} + +resource "google_bigquery_routine" "remote_function_routine" { + dataset_id = "${google_bigquery_dataset.test.dataset_id}" + routine_id = "tf_test_routine_id%{random_suffix}" + routine_type = "SCALAR_FUNCTION" + definition_body = "" + + return_type = "{\"typeKind\" : \"STRING\"}" + + remote_function_options { + endpoint = google_cloudfunctions2_function.default.service_config[0].uri + connection = "${google_bigquery_connection.test.name}" + max_batching_rows = "10" + user_defined_context = { + "z": "1.5", + } + } +} +`, context) +} + +func testAccBigQueryRoutine_bigQueryRoutineRemoteFunction_Update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_storage_bucket" "default" { + name = "%{random_suffix}-gcf-source" + location = "US" + uniform_bucket_level_access = true +} + +resource "google_storage_bucket_object" "object" { + name = "function-source.zip" + bucket = google_storage_bucket.default.name + source = "%{zip_path}" +} + +resource "google_cloudfunctions2_function" "default2" { + name = "function-v2-1" + location = "us-central1" + description = "a new new function" + + build_config { + runtime = "nodejs18" + entry_point = "helloHttp" + source { + storage_source { + bucket = google_storage_bucket.default.name + object = google_storage_bucket_object.object.name + } + } + } + + service_config { + max_instance_count = 1 + available_memory = "256M" + timeout_seconds = 60 + } +} + +resource "google_bigquery_connection" "test2" { + connection_id = "tf_test_connection2_id%{random_suffix}" + location = "US" + cloud_resource { } +} + +resource "google_bigquery_dataset" "test" { + dataset_id = "tf_test_dataset_id%{random_suffix}" +} + +resource "google_bigquery_routine" "remote_function_routine" { + dataset_id = "${google_bigquery_dataset.test.dataset_id}" + routine_id = "tf_test_routine_id%{random_suffix}" + routine_type = "SCALAR_FUNCTION" + definition_body = "" + + return_type = "{\"typeKind\" : \"STRING\"}" + + remote_function_options { + endpoint = google_cloudfunctions2_function.default2.service_config[0].uri + connection = "${google_bigquery_connection.test2.name}" + max_batching_rows = "5" + user_defined_context = { + "z": "1.2", + "w": "test", + } + } +} +`, context) +} diff --git a/mmv1/third_party/terraform/services/bigquery/test-fixtures/function-source.zip b/mmv1/third_party/terraform/services/bigquery/test-fixtures/function-source.zip new file mode 100644 index 0000000000000000000000000000000000000000..1cb571888ef575c261c2c42e8315daddbb653b5a GIT binary patch literal 458 zcmWIWW@Zs#U|`^2Fbc5`5s?gR?g8?)fJGP>GV@YWEA+C8U3-1GnhgZpzFQs@;p$xQ zlJUr;rRFcLUF)$oIeX<#Kvz}y@!q?(c5?5tPquQz7UjxFE@bKtma^5VeBD{q?V7DQ z^YlWIx%GQKdjC`19Mq9~-ML3zm3_;!EVr4>kHXF!oZwj68u?}gv(@5RRo5TbY+ks$ z<==AI@WjY(^?y}9%RiaB$F#`S^w0LRr8gJ?P+Yt`ex_Fd(6xR*%mc&)iOJcC>8U_B z=jVx@-ph4Vfyd$D-Q^rNx7sH!xAR<>A+pmO>_D}O5o3PC@B#&PV36>4;W@Hj!z#UpZ>yZE~?9g?g eyBMKm6Of7Q{s3=QHjpe65EcMw9Yzoj7XSctwvFxp literal 0 HcmV?d00001 From 7c2fc273c82b16d883976068d13a2bf9d52ef16b Mon Sep 17 00:00:00 2001 From: NA2047 <12290725+NA2047@users.noreply.github.com> Date: Fri, 23 Feb 2024 18:14:54 -0500 Subject: [PATCH 64/77] Adding documentaiton build_worker_pool (#10022) --- .../website/docs/r/cloudfunctions_function.html.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mmv1/third_party/terraform/website/docs/r/cloudfunctions_function.html.markdown b/mmv1/third_party/terraform/website/docs/r/cloudfunctions_function.html.markdown index 8a8b26b87091..5cfb46f700fe 100644 --- a/mmv1/third_party/terraform/website/docs/r/cloudfunctions_function.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/cloudfunctions_function.html.markdown @@ -149,6 +149,8 @@ Please refer to the field 'effective_labels' for all of the labels present on th * `build_environment_variables` - (Optional) A set of key/value environment variable pairs available during build time. +* `build_worker_pool` - (Optional) Name of the Cloud Build Custom Worker Pool that should be used to build the function. + * `vpc_connector` - (Optional) The VPC Network Connector that this cloud function can connect to. It should be set up as fully-qualified URI. The format of this field is `projects/*/locations/*/connectors/*`. * `vpc_connector_egress_settings` - (Optional) The egress settings for the connector, controlling what traffic is diverted through it. Allowed values are `ALL_TRAFFIC` and `PRIVATE_RANGES_ONLY`. Defaults to `PRIVATE_RANGES_ONLY`. If unset, this field preserves the previously set value. From 5599650ebf0ace9601ddfea4dd785741c7e359b9 Mon Sep 17 00:00:00 2001 From: Yuki Watanabe <47182350+yuki0920@users.noreply.github.com> Date: Sat, 24 Feb 2024 08:53:34 +0900 Subject: [PATCH 65/77] docs: fix import example in google_project_iam (#10007) Fix the example in the `google_project_iam` documentation. https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/google_project_iam#import --- .../terraform/website/docs/r/google_project_iam.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mmv1/third_party/terraform/website/docs/r/google_project_iam.html.markdown b/mmv1/third_party/terraform/website/docs/r/google_project_iam.html.markdown index 419315c503d7..33ee748e341d 100644 --- a/mmv1/third_party/terraform/website/docs/r/google_project_iam.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/google_project_iam.html.markdown @@ -228,7 +228,7 @@ An [`import` block](https://developer.hashicorp.com/terraform/language/import) ( ```tf import { - id = ""{{project_id}} roles/viewer user:foo@example.com"m" + id = "{{project_id}} roles/viewer user:foo@example.com" to = google_project_iam_member.default } ``` From b361a7b4732fee45a86abe87bfd1e809dda47ec6 Mon Sep 17 00:00:00 2001 From: Scott Suarez Date: Mon, 26 Feb 2024 10:09:25 -0800 Subject: [PATCH 66/77] ScottSuarez not on vacation anymore (#10052) * I'm on vaction :) * ScottSuarez not vaction anymore * ScottSuarez not vaction anymore --- .ci/magician/github/membership.go | 1 - 1 file changed, 1 deletion(-) diff --git a/.ci/magician/github/membership.go b/.ci/magician/github/membership.go index fd151935d98b..c1f5081de1ca 100644 --- a/.ci/magician/github/membership.go +++ b/.ci/magician/github/membership.go @@ -49,7 +49,6 @@ var ( onVacationReviewers = []string{ "zli82016", "NickElliot", - "ScottSuarez", } ) From 14a412945fd6d802dcdb8bd2ead14891268334b4 Mon Sep 17 00:00:00 2001 From: askubis Date: Mon, 26 Feb 2024 19:34:13 +0100 Subject: [PATCH 67/77] Promote (R)IGM.AllInstancesConfig to V1 (#9964) --- ...urce_compute_instance_group_manager.go.erb | 25 ------------------- ...compute_instance_group_manager_test.go.erb | 6 ----- ...mpute_region_instance_group_manager.go.erb | 21 ---------------- ..._region_instance_group_manager_test.go.erb | 4 --- ...mpute_instance_group_manager.html.markdown | 6 ++--- ...egion_instance_group_manager.html.markdown | 6 ++--- 6 files changed, 6 insertions(+), 62 deletions(-) diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager.go.erb index d61f2457be99..878c8c2a2545 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager.go.erb @@ -316,7 +316,6 @@ func ResourceComputeInstanceGroupManager() *schema.Resource { }, }, - <% unless version == "ga" -%> "all_instances_config": { Type: schema.TypeList, Optional: true, @@ -341,7 +340,6 @@ func ResourceComputeInstanceGroupManager() *schema.Resource { }, }, }, - <% end -%> "wait_for_instances": { Type: schema.TypeBool, Optional: true, @@ -353,12 +351,7 @@ func ResourceComputeInstanceGroupManager() *schema.Resource { Optional: true, Default: "STABLE", ValidateFunc: validation.StringInSlice([]string{"STABLE", "UPDATED"}, false), - - <% if version == "ga" -%> - Description: `When used with wait_for_instances specifies the status to wait for. When STABLE is specified this resource will wait until the instances are stable before returning. When UPDATED is set, it will wait for the version target to be reached and any per instance configs to be effective as well as all instances to be stable before returning.`, - <% else -%> Description: `When used with wait_for_instances specifies the status to wait for. When STABLE is specified this resource will wait until the instances are stable before returning. When UPDATED is set, it will wait for the version target to be reached and any per instance configs to be effective and all instances configs to be effective as well as all instances to be stable before returning.`, - <% end -%> }, "stateful_internal_ip": { Type: schema.TypeList, @@ -454,7 +447,6 @@ func ResourceComputeInstanceGroupManager() *schema.Resource { }, }, }, - <% unless version == "ga" -%> "all_instances_config": { Type: schema.TypeList, Computed: true, @@ -469,7 +461,6 @@ func ResourceComputeInstanceGroupManager() *schema.Resource { }, }, }, - <% end -%> "stateful": { Type: schema.TypeList, Computed: true, @@ -589,9 +580,7 @@ func resourceComputeInstanceGroupManagerCreate(d *schema.ResourceData, meta inte Versions: expandVersions(d.Get("version").([]interface{})), UpdatePolicy: expandUpdatePolicy(d.Get("update_policy").([]interface{})), InstanceLifecyclePolicy: expandInstanceLifecyclePolicy(d.Get("instance_lifecycle_policy").([]interface{})), - <% unless version == "ga" -%> AllInstancesConfig: expandAllInstancesConfig(nil, d.Get("all_instances_config").([]interface{})), - <% end -%> StatefulPolicy: expandStatefulPolicy(d), // Force send TargetSize to allow a value of 0. @@ -815,13 +804,11 @@ func resourceComputeInstanceGroupManagerRead(d *schema.ResourceData, meta interf if err = d.Set("instance_lifecycle_policy", flattenInstanceLifecyclePolicy(manager.InstanceLifecyclePolicy)); err != nil { return fmt.Errorf("Error setting instance lifecycle policy in state: %s", err.Error()) } - <% unless version == "ga" -%> if manager.AllInstancesConfig != nil { if err = d.Set("all_instances_config", flattenAllInstancesConfig(manager.AllInstancesConfig)); err != nil { return fmt.Errorf("Error setting all_instances_config in state: %s", err.Error()) } } - <% end -%> if err = d.Set("status", flattenStatus(manager.Status)); err != nil { return fmt.Errorf("Error setting status in state: %s", err.Error()) } @@ -892,7 +879,6 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte change = true } - <% unless version == "ga" -%> if d.HasChange("all_instances_config") { oldAic, newAic := d.GetChange("all_instances_config") if newAic == nil || len(newAic.([]interface{})) == 0 { @@ -902,7 +888,6 @@ func resourceComputeInstanceGroupManagerUpdate(d *schema.ResourceData, meta inte } change = true } - <% end -%> if d.HasChange("stateful_internal_ip") || d.HasChange("stateful_external_ip") || d.HasChange("stateful_disk") { updatedManager.StatefulPolicy = expandStatefulPolicy(d) @@ -1045,11 +1030,7 @@ func resourceComputeInstanceGroupManagerDelete(d *schema.ResourceData, meta inte func computeIGMWaitForInstanceStatus(d *schema.ResourceData, meta interface{}) error { waitForUpdates := d.Get("wait_for_instances_status").(string) == "UPDATED" conf := resource.StateChangeConf{ - <% if version == "ga" -%> - Pending: []string{"creating", "error", "updating per instance configs", "reaching version target"}, - <% else -%> Pending: []string{"creating", "error", "updating per instance configs", "reaching version target", "updating all instances config"}, - <% end -%> Target: []string{"created"}, Refresh: waitForInstancesRefreshFunc(getManager, waitForUpdates, d, meta), Timeout: d.Timeout(schema.TimeoutCreate), @@ -1400,7 +1381,6 @@ func flattenInstanceLifecyclePolicy(instanceLifecyclePolicy *compute.InstanceGro return results } -<% unless version == "ga" -%> func expandAllInstancesConfig(old []interface{}, new []interface{}) *compute.InstanceGroupManagerAllInstancesConfig { var properties *compute.InstancePropertiesPatch for _, raw := range new { @@ -1456,7 +1436,6 @@ func flattenAllInstancesConfig(allInstancesConfig *compute.InstanceGroupManagerA results = append(results, props) return results } -<% end -%> func flattenStatus(status *compute.InstanceGroupManagerStatus) []map[string]interface{} { results := []map[string]interface{}{} @@ -1465,11 +1444,9 @@ func flattenStatus(status *compute.InstanceGroupManagerStatus) []map[string]inte "stateful": flattenStatusStateful(status.Stateful), "version_target": flattenStatusVersionTarget(status.VersionTarget), } - <% unless version == "ga" -%> if status.AllInstancesConfig != nil { data["all_instances_config"] = flattenStatusAllInstancesConfig(status.AllInstancesConfig) } - <% end -%> results = append(results, data) return results } @@ -1502,7 +1479,6 @@ func flattenStatusVersionTarget(versionTarget *compute.InstanceGroupManagerStatu return results } -<% unless version == "ga" -%> func flattenStatusAllInstancesConfig(allInstancesConfig *compute.InstanceGroupManagerStatusAllInstancesConfig) []map[string]interface{} { results := []map[string]interface{}{} data := map[string]interface{}{ @@ -1511,7 +1487,6 @@ func flattenStatusAllInstancesConfig(allInstancesConfig *compute.InstanceGroupMa results = append(results, data) return results } -<% end -%> func resourceInstanceGroupManagerStateImporter(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { if err := d.Set("wait_for_instances", false); err != nil { diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager_test.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager_test.go.erb index 7c3322419219..c02ed9a13c1b 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager_test.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_group_manager_test.go.erb @@ -660,7 +660,6 @@ resource "google_compute_instance_group_manager" "igm-update" { name = "customhttp" port = 8080 } -<% unless version == "ga" -%> all_instances_config { metadata = { foo = "bar" @@ -669,7 +668,6 @@ resource "google_compute_instance_group_manager" "igm-update" { doo = "dad" } } -<% end -%> instance_lifecycle_policy { force_update_on_repair = "YES" @@ -766,7 +764,6 @@ resource "google_compute_instance_group_manager" "igm-update" { port = 8443 } -<% unless version == "ga" -%> all_instances_config { metadata = { doo = "dad" @@ -775,7 +772,6 @@ resource "google_compute_instance_group_manager" "igm-update" { foo = "bar" } } -<% end -%> instance_lifecycle_policy { force_update_on_repair = "NO" @@ -1780,7 +1776,6 @@ resource "google_compute_instance_group_manager" "igm-basic" { max_surge_fixed = 0 max_unavailable_percent = 50 } -<% unless version == "ga" -%> all_instances_config { metadata = { doo = "dad" @@ -1789,7 +1784,6 @@ resource "google_compute_instance_group_manager" "igm-basic" { foo = "bar" } } -<% end -%> instance_lifecycle_policy { force_update_on_repair = "YES" } diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager.go.erb index 8530b1e3e6b5..46cfbffd60e9 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager.go.erb @@ -208,12 +208,7 @@ func ResourceComputeRegionInstanceGroupManager() *schema.Resource { Optional: true, Default: "STABLE", ValidateFunc: validation.StringInSlice([]string{"STABLE", "UPDATED"}, false), - - <% if version == "ga" -%> - Description: `When used with wait_for_instances specifies the status to wait for. When STABLE is specified this resource will wait until the instances are stable before returning. When UPDATED is set, it will wait for the version target to be reached and any per instance configs to be effective as well as all instances to be stable before returning.`, - <% else -%> Description: `When used with wait_for_instances specifies the status to wait for. When STABLE is specified this resource will wait until the instances are stable before returning. When UPDATED is set, it will wait for the version target to be reached and any per instance configs to be effective and all instances configs to be effective as well as all instances to be stable before returning.`, - <% end -%> }, "auto_healing_policies": { @@ -365,7 +360,6 @@ func ResourceComputeRegionInstanceGroupManager() *schema.Resource { }, }, }, - <% unless version == "ga" -%> "all_instances_config": { Type: schema.TypeList, Optional: true, @@ -390,7 +384,6 @@ func ResourceComputeRegionInstanceGroupManager() *schema.Resource { }, }, }, - <% end -%> "stateful_internal_ip": { Type: schema.TypeList, Optional: true, @@ -481,7 +474,6 @@ func ResourceComputeRegionInstanceGroupManager() *schema.Resource { }, }, }, - <% unless version == "ga" -%> "all_instances_config": { Type: schema.TypeList, Computed: true, @@ -496,7 +488,6 @@ func ResourceComputeRegionInstanceGroupManager() *schema.Resource { }, }, }, - <% end -%> "stateful": { Type: schema.TypeList, Computed: true, @@ -562,9 +553,7 @@ func resourceComputeRegionInstanceGroupManagerCreate(d *schema.ResourceData, met Versions: expandVersions(d.Get("version").([]interface{})), UpdatePolicy: expandRegionUpdatePolicy(d.Get("update_policy").([]interface{})), InstanceLifecyclePolicy: expandInstanceLifecyclePolicy(d.Get("instance_lifecycle_policy").([]interface{})), - <% unless version == "ga" -%> AllInstancesConfig: expandAllInstancesConfig(nil, d.Get("all_instances_config").([]interface{})), - <% end -%> DistributionPolicy: expandDistributionPolicy(d), StatefulPolicy: expandStatefulPolicy(d), // Force send TargetSize to allow size of 0. @@ -602,11 +591,7 @@ func resourceComputeRegionInstanceGroupManagerCreate(d *schema.ResourceData, met func computeRIGMWaitForInstanceStatus(d *schema.ResourceData, meta interface{}) error { waitForUpdates := d.Get("wait_for_instances_status").(string) == "UPDATED" conf := resource.StateChangeConf{ - <% if version == "ga" -%> - Pending: []string{"creating", "error", "updating per instance configs", "reaching version target"}, - <% else -%> Pending: []string{"creating", "error", "updating per instance configs", "reaching version target", "updating all instances config"}, - <% end -%> Target: []string{"created"}, Refresh: waitForInstancesRefreshFunc(getRegionalManager, waitForUpdates, d, meta), Timeout: d.Timeout(schema.TimeoutCreate), @@ -674,11 +659,9 @@ func waitForInstancesRefreshFunc(f getInstanceManagerFunc, waitForUpdates bool, if !m.Status.VersionTarget.IsReached { return false, "reaching version target", nil } - <% unless version == "ga" -%> if !m.Status.AllInstancesConfig.Effective { return false, "updating all instances config", nil } - <% end -%> } return true, "created", nil } else { @@ -763,13 +746,11 @@ func resourceComputeRegionInstanceGroupManagerRead(d *schema.ResourceData, meta if err = d.Set("instance_lifecycle_policy", flattenInstanceLifecyclePolicy(manager.InstanceLifecyclePolicy)); err != nil { return fmt.Errorf("Error setting instance lifecycle policy in state: %s", err.Error()) } - <% unless version == "ga" -%> if manager.AllInstancesConfig != nil { if err = d.Set("all_instances_config", flattenAllInstancesConfig(manager.AllInstancesConfig)); err != nil { return fmt.Errorf("Error setting all_instances_config in state: %s", err.Error()) } } - <% end -%> if err = d.Set("stateful_disk", flattenStatefulPolicy(manager.StatefulPolicy)); err != nil { return fmt.Errorf("Error setting stateful_disk in state: %s", err.Error()) } @@ -852,7 +833,6 @@ func resourceComputeRegionInstanceGroupManagerUpdate(d *schema.ResourceData, met change = true } - <% unless version == "ga" -%> if d.HasChange("all_instances_config") { oldAic, newAic := d.GetChange("all_instances_config") if newAic == nil || len(newAic.([]interface{})) == 0 { @@ -862,7 +842,6 @@ func resourceComputeRegionInstanceGroupManagerUpdate(d *schema.ResourceData, met } change = true } - <% end -%> if d.HasChange("list_managed_instances_results") { updatedManager.ListManagedInstancesResults = d.Get("list_managed_instances_results").(string) diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager_test.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager_test.go.erb index a5470d09b032..4e4ef9645074 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager_test.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_group_manager_test.go.erb @@ -562,7 +562,6 @@ resource "google_compute_region_instance_group_manager" "igm-update" { port = 8080 } -<% unless version == "ga" -%> all_instances_config { metadata = { foo = "bar" @@ -571,7 +570,6 @@ resource "google_compute_region_instance_group_manager" "igm-update" { doo = "dad" } } -<% end -%> instance_lifecycle_policy { force_update_on_repair = "YES" @@ -668,7 +666,6 @@ resource "google_compute_region_instance_group_manager" "igm-update" { port = 8443 } -<% unless version == "ga" -%> all_instances_config { metadata = { doo = "dad" @@ -677,7 +674,6 @@ resource "google_compute_region_instance_group_manager" "igm-update" { foo = "bar" } } -<% end -%> instance_lifecycle_policy { force_update_on_repair = "NO" diff --git a/mmv1/third_party/terraform/website/docs/r/compute_instance_group_manager.html.markdown b/mmv1/third_party/terraform/website/docs/r/compute_instance_group_manager.html.markdown index f6dead3b4382..a79b67e8c81c 100644 --- a/mmv1/third_party/terraform/website/docs/r/compute_instance_group_manager.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/compute_instance_group_manager.html.markdown @@ -153,7 +153,7 @@ The following arguments are supported: * `auto_healing_policies` - (Optional) The autohealing policies for this managed instance group. You can specify only one value. Structure is [documented below](#nested_auto_healing_policies). For more information, see the [official documentation](https://cloud.google.com/compute/docs/instance-groups/creating-groups-of-managed-instances#monitoring_groups). -* `all_instances_config` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) +* `all_instances_config` - (Optional) Properties to set on all instances in the group. After setting allInstancesConfig on the group, you must update the group's instances to apply the configuration. @@ -226,9 +226,9 @@ all_instances_config { } ``` -* `metadata` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)), The metadata key-value pairs that you want to patch onto the instance. For more information, see [Project and instance metadata](https://cloud.google.com/compute/docs/metadata#project_and_instance_metadata). +* `metadata` - (Optional), The metadata key-value pairs that you want to patch onto the instance. For more information, see [Project and instance metadata](https://cloud.google.com/compute/docs/metadata#project_and_instance_metadata). -* `labels` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)), The label key-value pairs that you want to patch onto the instance. +* `labels` - (Optional), The label key-value pairs that you want to patch onto the instance. - - - diff --git a/mmv1/third_party/terraform/website/docs/r/compute_region_instance_group_manager.html.markdown b/mmv1/third_party/terraform/website/docs/r/compute_region_instance_group_manager.html.markdown index 0a16ac30b14f..cad9a1343d81 100644 --- a/mmv1/third_party/terraform/website/docs/r/compute_region_instance_group_manager.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/compute_region_instance_group_manager.html.markdown @@ -155,7 +155,7 @@ The following arguments are supported: * `auto_healing_policies` - (Optional) The autohealing policies for this managed instance group. You can specify only one value. Structure is documented below. For more information, see the [official documentation](https://cloud.google.com/compute/docs/instance-groups/creating-groups-of-managed-instances#monitoring_groups). -* `all_instances_config` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) +* `all_instances_config` - (Optional) Properties to set on all instances in the group. After setting allInstancesConfig on the group, you must update the group's instances to apply the configuration. @@ -235,9 +235,9 @@ all_instances_config { } ``` -* `metadata` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)), The metadata key-value pairs that you want to patch onto the instance. For more information, see [Project and instance metadata](https://cloud.google.com/compute/docs/metadata#project_and_instance_metadata). +* `metadata` - (Optional), The metadata key-value pairs that you want to patch onto the instance. For more information, see [Project and instance metadata](https://cloud.google.com/compute/docs/metadata#project_and_instance_metadata). -* `labels` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)), The label key-value pairs that you want to patch onto the instance. +* `labels` - (Optional), The label key-value pairs that you want to patch onto the instance. - - - From c3ce700765fbc4b3dc9896da767194b8eda9a13d Mon Sep 17 00:00:00 2001 From: Pavan Kumar Sunkara Date: Mon, 26 Feb 2024 19:18:08 +0000 Subject: [PATCH 68/77] Promote metric settings in compute region autoscaler to GA (#10045) --- mmv1/products/compute/RegionAutoscaler.yaml | 3 --- .../compute/resource_compute_region_autoscaler_test.go.erb | 4 ---- 2 files changed, 7 deletions(-) diff --git a/mmv1/products/compute/RegionAutoscaler.yaml b/mmv1/products/compute/RegionAutoscaler.yaml index 931e07443408..7ef41e624626 100644 --- a/mmv1/products/compute/RegionAutoscaler.yaml +++ b/mmv1/products/compute/RegionAutoscaler.yaml @@ -140,7 +140,6 @@ properties: Defines operating mode for this policy. - !ruby/object:Api::Type::NestedObject name: 'scaleDownControl' - min_version: beta description: | Defines scale down controls to reduce the risk of response latency and outages due to abrupt scale-in events @@ -265,7 +264,6 @@ properties: required: true - !ruby/object:Api::Type::Double name: 'singleInstanceAssignment' - min_version: beta description: | If scaling is based on a per-group metric value that represents the total amount of work to be done or resource usage, set this value to @@ -341,7 +339,6 @@ properties: (if you are using gce_instance resource type). If multiple TimeSeries are returned upon the query execution, the autoscaler will sum their respective values to obtain its scaling value. - min_version: beta - !ruby/object:Api::Type::NestedObject name: 'loadBalancingUtilization' description: | diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_region_autoscaler_test.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_region_autoscaler_test.go.erb index 1d6f65491513..64f15c2fb80e 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_region_autoscaler_test.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_region_autoscaler_test.go.erb @@ -217,14 +217,12 @@ resource "google_compute_region_autoscaler" "foobar" { target = 0.5 predictive_method = "OPTIMIZE_AVAILABILITY" } -<% unless version == 'ga' -%> scale_down_control { max_scaled_down_replicas { percent = 80 } time_window_sec = 300 } -<% end -%> } } `, autoscalerName) @@ -269,14 +267,12 @@ resource "google_compute_region_autoscaler" "foobar" { cpu_utilization { target = 0.5 } -<% unless version == 'ga' -%> scale_down_control { max_scaled_down_replicas { percent = 80 } time_window_sec = 300 } -<% end -%> scaling_schedules { name = "every-weekday-morning" description = "Increase to 2 every weekday at 7AM for 6 hours." From b449d45a3ff892722c699d8a38e84a3309a31b9c Mon Sep 17 00:00:00 2001 From: "Stephen Lewis (Burrows)" Date: Mon, 26 Feb 2024 11:36:01 -0800 Subject: [PATCH 69/77] Fixed flakiness in TestAccDataPipelinePipeline_dataPipelinePipelineExample (#10040) --- mmv1/products/datapipeline/Pipeline.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mmv1/products/datapipeline/Pipeline.yaml b/mmv1/products/datapipeline/Pipeline.yaml index c3e24c9fcd9e..1bf821d94bff 100644 --- a/mmv1/products/datapipeline/Pipeline.yaml +++ b/mmv1/products/datapipeline/Pipeline.yaml @@ -31,6 +31,8 @@ examples: primary_resource_name: 'fmt.Sprintf("tf-test-my-pipeline%s", context["random_suffix"])' primary_resource_id: 'primary' + ignore_read_extra: + - 'schedule_info.0.next_job_time' vars: pipeline_name: 'my-pipeline' account_id: 'my-account' From 7faaacc8f1d429d6d0d6317ba98e962bf9bd1ae4 Mon Sep 17 00:00:00 2001 From: ajaybgunjal1 <161062655+ajaybgunjal1@users.noreply.github.com> Date: Mon, 26 Feb 2024 20:46:06 +0000 Subject: [PATCH 70/77] Retry delete network step while creating a google project. (#10046) --- .../services/resourcemanager/resource_google_project.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mmv1/third_party/terraform/services/resourcemanager/resource_google_project.go b/mmv1/third_party/terraform/services/resourcemanager/resource_google_project.go index acf1db96fa56..1d2c97855fe0 100644 --- a/mmv1/third_party/terraform/services/resourcemanager/resource_google_project.go +++ b/mmv1/third_party/terraform/services/resourcemanager/resource_google_project.go @@ -227,7 +227,13 @@ func resourceGoogleProjectCreate(d *schema.ResourceData, meta interface{}) error return errwrap.Wrapf("Error enabling the Compute Engine API required to delete the default network: {{err}} ", err) } - if err = forceDeleteComputeNetwork(d, config, project.ProjectId, "default"); err != nil { + err = forceDeleteComputeNetwork(d, config, project.ProjectId, "default") + // Retry if API is not yet enabled. + if err != nil && transport_tpg.IsGoogleApiErrorWithCode(err, 403) { + time.Sleep(10 * time.Second) + err = forceDeleteComputeNetwork(d, config, project.ProjectId, "default") + } + if err != nil { if transport_tpg.IsGoogleApiErrorWithCode(err, 404) { log.Printf("[DEBUG] Default network not found for project %q, no need to delete it", project.ProjectId) } else { From 3e13564ac5d3ac814949b399e0fd56058445a717 Mon Sep 17 00:00:00 2001 From: Hossein Golestani Date: Mon, 26 Feb 2024 13:46:12 -0800 Subject: [PATCH 71/77] Adding the namespace_labels field to the GKE Hub Scope resource (#9972) * initial commit for scope-level namespace labels * Add validation exceptions for the field of the GKEHub Scope and Namespace resources to be of type * Undoing unnecessary changes * Fixing the type of Scope namespace_labels field --- mmv1/products/gkehub2/Scope.yaml | 8 ++++++++ .../terraform/examples/gkehub_scope_basic.tf.erb | 5 +++++ .../services/gkehub2/resource_gke_hub_scope_test.go | 10 ++++++++++ 3 files changed, 23 insertions(+) diff --git a/mmv1/products/gkehub2/Scope.yaml b/mmv1/products/gkehub2/Scope.yaml index 7c12b64c03b4..ff73465a443e 100644 --- a/mmv1/products/gkehub2/Scope.yaml +++ b/mmv1/products/gkehub2/Scope.yaml @@ -117,6 +117,14 @@ properties: - :READY - :DELETING - :UPDATING + - !ruby/object:Api::Type::KeyValuePairs + name: 'namespaceLabels' + description: | + Scope-level cluster namespace labels. For the member clusters bound + to the Scope, these labels are applied to each namespace under the + Scope. Scope-level labels take precedence over Namespace-level + labels (`namespace_labels` in the Fleet Namespace resource) if they + share a key. Keys and values must be Kubernetes-conformant. - !ruby/object:Api::Type::KeyValueLabels name: 'labels' description: | diff --git a/mmv1/templates/terraform/examples/gkehub_scope_basic.tf.erb b/mmv1/templates/terraform/examples/gkehub_scope_basic.tf.erb index 107fa956c82d..63efb8be3c78 100644 --- a/mmv1/templates/terraform/examples/gkehub_scope_basic.tf.erb +++ b/mmv1/templates/terraform/examples/gkehub_scope_basic.tf.erb @@ -1,5 +1,10 @@ resource "google_gke_hub_scope" "<%= ctx[:primary_resource_id] %>" { scope_id = "<%= ctx[:vars]['resource_name'] %>" + namespace_labels = { + keyb = "valueb" + keya = "valuea" + keyc = "valuec" + } labels = { keyb = "valueb" keya = "valuea" diff --git a/mmv1/third_party/terraform/services/gkehub2/resource_gke_hub_scope_test.go b/mmv1/third_party/terraform/services/gkehub2/resource_gke_hub_scope_test.go index 967fe08c4bc2..be00b628a7c6 100644 --- a/mmv1/third_party/terraform/services/gkehub2/resource_gke_hub_scope_test.go +++ b/mmv1/third_party/terraform/services/gkehub2/resource_gke_hub_scope_test.go @@ -47,6 +47,11 @@ func testAccGKEHub2Scope_gkehubScopeBasicExample_basic(context map[string]interf return acctest.Nprintf(` resource "google_gke_hub_scope" "scope" { scope_id = "tf-test-scope%{random_suffix}" + namespace_labels = { + keyb = "valueb" + keya = "valuea" + keyc = "valuec" + } labels = { keyb = "valueb" keya = "valuea" @@ -60,6 +65,11 @@ func testAccGKEHub2Scope_gkehubScopeBasicExample_update(context map[string]inter return acctest.Nprintf(` resource "google_gke_hub_scope" "scope" { scope_id = "tf-test-scope%{random_suffix}" + namespace_labels = { + updated_keyb = "updated_valueb" + updated_keya = "updated_valuea" + updated_keyc = "updated_valuec" + } labels = { updated_keyb = "updated_valueb" updated_keya = "updated_valuea" From 76474ecb686e095b4436de3ce17d739a2a1a4b21 Mon Sep 17 00:00:00 2001 From: Salome Papiashvili Date: Mon, 26 Feb 2024 22:54:28 +0100 Subject: [PATCH 72/77] Support connectivity fields for Composer 3 (#9889) * add composer_network_attachment * indicate conflicting configs * commas * no need for bidirectional conflict definition (generates double errors) * protect nit PrivateClusterConfig * for optimizing error messages about conflicts * add 2 step update for composer_network_attachment * make composer_network_attachment available in beta only * add two step update for network and subnetwork * corrections in 2 phase update for network/subnetwork * remove composer3 check(CustomizeDiff will solve this), filter api error, add tests (unsetting netwok/subnetwork not working) * added ForceNewIf fot network/subnetwork, problem with unsetting these fields remains * add docs for composer_network_attachment * add test for network attachment * ignore non empty plan in network attachment test * add networkAttachment update and conflicting fields tests * add ComputedIf for network, change isComposer3 * minor corrections * remove computedIf * filter equivalent values of network/subnetwork in ForceNewIf * simplify ResourceConditionFunc, add beta/ga version conditions * typo * more general comparison of network references * use tpgresource.CompareSelfLinkRelativePaths instead of custom function * modify isComposer3 to avoid merge conflicts later. * removing this since documentation is handled in other PR and to avoid conflicts while merging. * replace ExpectNonEmptyPlan with lifecycle.ignore_changes * add testcase for changing network attachment to network and subnetwork * add third step to TestAccComposerEnvironmentComposer3_updateWithNetworkAndSubnetwork * modify tests to use different network for attachment * remove unused constant * remove ExpectNonEmptyPlan (already replaced with lifecycle.ignore_changes) --- .../resource_composer_environment.go.erb | 109 +++++- .../resource_composer_environment_test.go.erb | 357 ++++++++++++++++-- 2 files changed, 441 insertions(+), 25 deletions(-) diff --git a/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb b/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb index 0369ce49f4d0..e192b510fa65 100644 --- a/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb +++ b/mmv1/third_party/terraform/services/composer/resource_composer_environment.go.erb @@ -170,7 +170,9 @@ func ResourceComposerEnvironment() *schema.Resource { tpgresource.DefaultProviderRegion, tpgresource.SetLabelsDiff, <% unless version == "ga" -%> - customdiff.ValidateChange("config.0.software_config.0.image_version", imageVersionChangeValidationFunc), + customdiff.ForceNewIf("config.0.node_config.0.network", forceNewCustomDiff("config.0.node_config.0.network")), + customdiff.ForceNewIf("config.0.node_config.0.subnetwork", forceNewCustomDiff("config.0.node_config.0.subnetwork")), + customdiff.ValidateChange("config.0.software_config.0.image_version", imageVersionChangeValidationFunc), versionValidationCustomizeDiffFunc, <% end -%> ), @@ -242,17 +244,37 @@ func ResourceComposerEnvironment() *schema.Resource { Type: schema.TypeString, Computed: true, Optional: true, +<% if version == "ga" -%> ForceNew: true, +<% else -%> + ForceNew: false, + ConflictsWith: []string{"config.0.node_config.0.composer_network_attachment"}, +<% end -%> DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, Description: `The Compute Engine machine type used for cluster instances, specified as a name or relative resource name. For example: "projects/{project}/zones/{zone}/machineTypes/{machineType}". Must belong to the enclosing environment's project and region/zone. The network must belong to the environment's project. If unspecified, the "default" network ID in the environment's project is used. If a Custom Subnet Network is provided, subnetwork must also be provided.`, }, "subnetwork": { Type: schema.TypeString, Optional: true, +<% if version == "ga" -%> ForceNew: true, +<% else -%> + ForceNew: false, + Computed: true, + ConflictsWith: []string{"config.0.node_config.0.composer_network_attachment"}, +<% end -%> DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, - Description: `The Compute Engine subnetwork to be used for machine communications, , specified as a self-link, relative resource name (e.g. "projects/{project}/regions/{region}/subnetworks/{subnetwork}"), or by name. If subnetwork is provided, network must also be provided and the subnetwork must belong to the enclosing environment's project and region.`, + Description: `The Compute Engine subnetwork to be used for machine communications, specified as a self-link, relative resource name (e.g. "projects/{project}/regions/{region}/subnetworks/{subnetwork}"), or by name. If subnetwork is provided, network must also be provided and the subnetwork must belong to the enclosing environment's project and region.`, + }, +<% unless version == "ga" -%> + "composer_network_attachment": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: false, + Description: `PSC (Private Service Connect) Network entry point. Customers can pre-create the Network Attachment and point Cloud Composer environment to use. It is possible to share network attachment among many environments, provided enough IP addresses are available.`, }, +<% end -%> "disk_size_gb": { Type: schema.TypeInt, Computed: true, @@ -1195,6 +1217,68 @@ func resourceComposerEnvironmentUpdate(d *schema.ResourceData, meta interface{}) return err } +<% unless version == "ga" -%> + noChangeErrorMessage := "Update request does not result in any change to the environment's configuration" + if d.HasChange("config.0.node_config.0.network") || d.HasChange("config.0.node_config.0.subnetwork"){ + // step 1: update with empty network and subnetwork + patchObjEmpty := &composer.Environment{ + Config: &composer.EnvironmentConfig{ + NodeConfig: &composer.NodeConfig{}, + }, + } + err = resourceComposerEnvironmentPatchField("config.nodeConfig.network,config.nodeConfig.subnetwork", userAgent, patchObjEmpty, d, tfConfig) + if err != nil && !strings.Contains(err.Error(), noChangeErrorMessage){ + return err + } + + // step 2: update with new network and subnetwork, if new values are not empty + if (config.NodeConfig.Network != "" && config.NodeConfig.Subnetwork != ""){ + patchObj := &composer.Environment{ + Config: &composer.EnvironmentConfig{ + NodeConfig: &composer.NodeConfig{}, + }, + } + if config != nil && config.NodeConfig != nil { + patchObj.Config.NodeConfig.Network = config.NodeConfig.Network + patchObj.Config.NodeConfig.Subnetwork = config.NodeConfig.Subnetwork + } + err = resourceComposerEnvironmentPatchField("config.nodeConfig.network,config.nodeConfig.subnetwork", userAgent, patchObj, d, tfConfig) + if err != nil { + return err + } + } + } + + if d.HasChange("config.0.node_config.0.composer_network_attachment") { + // step 1: update with empty composer_network_attachment + patchObjEmpty := &composer.Environment{ + Config: &composer.EnvironmentConfig{ + NodeConfig: &composer.NodeConfig{}, + }, + } + err = resourceComposerEnvironmentPatchField("config.nodeConfig.composerNetworkAttachment", userAgent, patchObjEmpty, d, tfConfig) + if err != nil && !strings.Contains(err.Error(), noChangeErrorMessage){ + return err + } + + // step 2: update with new composer_network_attachment + if (config.NodeConfig.ComposerNetworkAttachment != ""){ + patchObj := &composer.Environment{ + Config: &composer.EnvironmentConfig{ + NodeConfig: &composer.NodeConfig{}, + }, + } + if config != nil && config.NodeConfig != nil { + patchObj.Config.NodeConfig.ComposerNetworkAttachment = config.NodeConfig.ComposerNetworkAttachment + } + err = resourceComposerEnvironmentPatchField("config.nodeConfig.composerNetworkAttachment", userAgent, patchObj, d, tfConfig) + if err != nil { + return err + } + } + } +<% end -%> + <% unless version == "ga" -%> if d.HasChange("config.0.software_config.0.image_version") { patchObj := &composer.Environment{ @@ -1853,6 +1937,9 @@ func flattenComposerEnvironmentConfigNodeConfig(nodeCfg *composer.NodeConfig) in transformed["machine_type"] = nodeCfg.MachineType transformed["network"] = nodeCfg.Network transformed["subnetwork"] = nodeCfg.Subnetwork +<% unless version == "ga" -%> + transformed["composer_network_attachment"] = nodeCfg.ComposerNetworkAttachment +<% end -%> transformed["disk_size_gb"] = nodeCfg.DiskSizeGb transformed["service_account"] = nodeCfg.ServiceAccount transformed["oauth_scopes"] = flattenComposerEnvironmentConfigNodeConfigOauthScopes(nodeCfg.OauthScopes) @@ -2470,6 +2557,13 @@ func expandComposerEnvironmentConfigNodeConfig(v interface{}, d *schema.Resource } transformed.Subnetwork = transformedSubnetwork } + +<% unless version == "ga" -%> + if v, ok := original["composer_network_attachment"]; ok { + transformed.ComposerNetworkAttachment = v.(string) + } +<% end -%> + transformedIPAllocationPolicy, err := expandComposerEnvironmentIPAllocationPolicy(original["ip_allocation_policy"], d, config) if err != nil { return nil, err @@ -2951,6 +3045,17 @@ func isComposer3(imageVersion string) bool { return strings.Contains(imageVersion, "composer-3") } +func forceNewCustomDiff(key string) customdiff.ResourceConditionFunc { + return func(ctx context.Context, d *schema.ResourceDiff, meta interface{}) bool { + old, new := d.GetChange(key) + imageVersion := d.Get("config.0.software_config.0.image_version").(string) + if isComposer3(imageVersion) || tpgresource.CompareSelfLinkRelativePaths("", old.(string), new.(string), nil) { + return false + } + return true + } +} + func imageVersionChangeValidationFunc(ctx context.Context, old, new, meta any) error { if old.(string) != "" && !isComposer3(old.(string)) && isComposer3(new.(string)) { return fmt.Errorf("upgrade to composer 3 is not yet supported") diff --git a/mmv1/third_party/terraform/services/composer/resource_composer_environment_test.go.erb b/mmv1/third_party/terraform/services/composer/resource_composer_environment_test.go.erb index 1ddb9257f35e..bde25f487b1f 100644 --- a/mmv1/third_party/terraform/services/composer/resource_composer_environment_test.go.erb +++ b/mmv1/third_party/terraform/services/composer/resource_composer_environment_test.go.erb @@ -21,6 +21,7 @@ import ( const testComposerEnvironmentPrefix = "tf-test-composer-env" const testComposerNetworkPrefix = "tf-test-composer-net" const testComposerBucketPrefix = "tf-test-composer-bucket" +const testComposerNetworkAttachmentPrefix = "tf-test-composer-nta" func allComposerServiceAgents() []string { return []string{ @@ -1186,13 +1187,13 @@ func TestAccComposerEnvironmentComposer3_update(t *testing.T) { }) } -func TestAccComposerEnvironmentComposer3_upgrade_expectError(t *testing.T) { +func TestAccComposerEnvironmentComposer3_withNetworkSubnetworkAndAttachment_expectError(t *testing.T) { t.Parallel() envName := fmt.Sprintf("%s-%d", testComposerEnvironmentPrefix, acctest.RandInt(t)) network := fmt.Sprintf("%s-%d", testComposerNetworkPrefix, acctest.RandInt(t)) subnetwork := network + "-1" - errorRegExp, _ := regexp.Compile(".*upgrade to composer 3 is not yet supported.*") + networkAttachment := fmt.Sprintf("%s-%d", testComposerNetworkAttachmentPrefix, acctest.RandInt(t)) acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, @@ -1200,58 +1201,128 @@ func TestAccComposerEnvironmentComposer3_upgrade_expectError(t *testing.T) { CheckDestroy: testAccComposerEnvironmentDestroyProducer(t), Steps: []resource.TestStep{ { - Config: testAccComposerEnvironmentComposer2_empty(envName, network, subnetwork), + Config: testAccComposerEnvironmentComposer3_withNetworkSubnetworkAndAttachment_expectError(envName, networkAttachment, network, subnetwork), + ExpectError: regexp.MustCompile("Conflicting configuration arguments"), }, + // This is a terrible clean-up step in order to get destroy to succeed, + // due to dangling firewall rules left by the Composer Environment blocking network deletion. + // TODO: Remove this check if firewall rules bug gets fixed by Composer. { - Config: testAccComposerEnvironmentComposer3_empty(envName, network, subnetwork), - ExpectError: errorRegExp, + PlanOnly: true, + ExpectNonEmptyPlan: true, + Config: testAccComposerEnvironmentComposer3_basic(envName, network, subnetwork), + Check: testAccCheckClearComposerEnvironmentFirewalls(t, network), + }, + }, + }) +} + +func TestAccComposerEnvironmentComposer3_withNetworkAttachment(t *testing.T) { + t.Parallel() + + envName := fmt.Sprintf("%s-%d", testComposerEnvironmentPrefix, acctest.RandInt(t)) + network := fmt.Sprintf("%s-%d", testComposerNetworkPrefix, acctest.RandInt(t)) + subnetwork := network + "-1" + networkAttachment := fmt.Sprintf("%s-%d", testComposerNetworkAttachmentPrefix, acctest.RandInt(t)) + fullFormNetworkAttachmentName := fmt.Sprintf("projects/%s/regions/%s/networkAttachments/%s", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), networkAttachment) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccComposerEnvironmentDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComposerEnvironmentComposer3_withNetworkAttachment(envName, networkAttachment, network, subnetwork), + }, + { + ResourceName: "google_composer_environment.test", + ImportState: true, + ImportStateVerify: true, }, // This is a terrible clean-up step in order to get destroy to succeed, // due to dangling firewall rules left by the Composer Environment blocking network deletion. // TODO: Remove this check if firewall rules bug gets fixed by Composer. { PlanOnly: true, - ExpectNonEmptyPlan: false, - Config: testAccComposerEnvironmentComposer2_empty(envName, network, subnetwork), + Config: testAccComposerEnvironmentComposer3_withNetworkAttachment(envName, fullFormNetworkAttachmentName, network, subnetwork), Check: testAccCheckClearComposerEnvironmentFirewalls(t, network), + ExpectNonEmptyPlan: true, }, }, }) } -func TestAccComposerEnvironmentComposer2_usesUnsupportedField_expectError(t *testing.T) { +func TestAccComposerEnvironmentComposer3_updateWithNetworkAttachment(t *testing.T) { t.Parallel() envName := fmt.Sprintf("%s-%d", testComposerEnvironmentPrefix, acctest.RandInt(t)) - errorRegExp, _ := regexp.Compile(".*error in configuration, .* should only be used in Composer 3.*") + network := fmt.Sprintf("%s-%d", testComposerNetworkPrefix, acctest.RandInt(t)) + subnetwork := network + "-1" + networkAttachment := fmt.Sprintf("%s-%d", testComposerNetworkAttachmentPrefix, acctest.RandInt(t)) + fullFormNetworkAttachmentName := fmt.Sprintf("projects/%s/regions/%s/networkAttachments/%s", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), networkAttachment) acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, + PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), CheckDestroy: testAccComposerEnvironmentDestroyProducer(t), Steps: []resource.TestStep{ { - Config: testAccComposerEnvironmentComposer2_usesUnsupportedField(envName), - ExpectError: errorRegExp, + Config: testAccComposerEnvironmentComposer3_withNetworkAndSubnetwork(envName, networkAttachment, network, subnetwork), + }, + { + Config: testAccComposerEnvironmentComposer3_withNetworkAttachment(envName, networkAttachment, network, subnetwork), + }, + { + ResourceName: "google_composer_environment.test", + ImportState: true, + ImportStateVerify: true, + }, + // This is a terrible clean-up step in order to get destroy to succeed, + // due to dangling firewall rules left by the Composer Environment blocking network deletion. + // TODO: Remove this check if firewall rules bug gets fixed by Composer. + { + PlanOnly: true, + Config: testAccComposerEnvironmentComposer3_withNetworkAttachment(envName, fullFormNetworkAttachmentName, network, subnetwork), + Check: testAccCheckClearComposerEnvironmentFirewalls(t, network), + ExpectNonEmptyPlan: true, }, }, }) } -func TestAccComposerEnvironmentComposer3_usesUnsupportedField_expectError(t *testing.T) { +func TestAccComposerEnvironmentComposer3_updateWithNetworkAndSubnetwork(t *testing.T) { t.Parallel() envName := fmt.Sprintf("%s-%d", testComposerEnvironmentPrefix, acctest.RandInt(t)) - errorRegExp, _ := regexp.Compile(".*error in configuration, .* should not be used in Composer 3.*") + network := fmt.Sprintf("%s-%d", testComposerNetworkPrefix, acctest.RandInt(t)) + subnetwork := network + "-1" + networkAttachment := fmt.Sprintf("%s-%d", testComposerNetworkAttachmentPrefix, acctest.RandInt(t)) + fullFormNetworkAttachmentName := fmt.Sprintf("projects/%s/regions/%s/networkAttachments/%s", envvar.GetTestProjectFromEnv(), envvar.GetTestRegionFromEnv(), networkAttachment) acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, + PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), CheckDestroy: testAccComposerEnvironmentDestroyProducer(t), Steps: []resource.TestStep{ { - Config: testAccComposerEnvironmentComposer3_usesUnsupportedField(envName), - ExpectError: errorRegExp, + Config: testAccComposerEnvironmentComposer3_withNetworkAttachment(envName, networkAttachment, network, subnetwork), + }, + { + Config: testAccComposerEnvironmentComposer3_withNetworkAndSubnetwork(envName, networkAttachment, network, subnetwork), + }, + { + ResourceName: "google_composer_environment.test", + ImportState: true, + ImportStateVerify: true, + }, + // This is a terrible clean-up step in order to get destroy to succeed, + // due to dangling firewall rules left by the Composer Environment blocking network deletion. + // TODO: Remove this check if firewall rules bug gets fixed by Composer. + { + PlanOnly: true, + Config: testAccComposerEnvironmentComposer3_withNetworkAttachment(envName, fullFormNetworkAttachmentName, network, subnetwork), + Check: testAccCheckClearComposerEnvironmentFirewalls(t, network), + ExpectNonEmptyPlan: true, }, }, }) @@ -1266,7 +1337,7 @@ func TestAccComposerEnvironmentComposer3_updateToEmpty(t *testing.T) { subnetwork := network + "-1" acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, + PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), CheckDestroy: testAccComposerEnvironmentDestroyProducer(t), Steps: []resource.TestStep{ @@ -1303,7 +1374,7 @@ func TestAccComposerEnvironmentComposer3_updateFromEmpty(t *testing.T) { subnetwork := network + "-1" acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, + PreCheck: func() { acctest.AccTestPreCheck(t) }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), CheckDestroy: testAccComposerEnvironmentDestroyProducer(t), Steps: []resource.TestStep{ @@ -1330,6 +1401,77 @@ func TestAccComposerEnvironmentComposer3_updateFromEmpty(t *testing.T) { }, }) } + +func TestAccComposerEnvironmentComposer3_upgrade_expectError(t *testing.T) { + t.Parallel() + + envName := fmt.Sprintf("%s-%d", testComposerEnvironmentPrefix, acctest.RandInt(t)) + network := fmt.Sprintf("%s-%d", testComposerNetworkPrefix, acctest.RandInt(t)) + subnetwork := network + "-1" + errorRegExp, _ := regexp.Compile(".*upgrade to composer 3 is not yet supported.*") + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccComposerEnvironmentDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComposerEnvironmentComposer2_empty(envName, network, subnetwork), + }, + { + Config: testAccComposerEnvironmentComposer3_empty(envName, network, subnetwork), + ExpectError: errorRegExp, + }, + // This is a terrible clean-up step in order to get destroy to succeed, + // due to dangling firewall rules left by the Composer Environment blocking network deletion. + // TODO: Remove this check if firewall rules bug gets fixed by Composer. + { + PlanOnly: true, + ExpectNonEmptyPlan: false, + Config: testAccComposerEnvironmentComposer2_empty(envName, network, subnetwork), + Check: testAccCheckClearComposerEnvironmentFirewalls(t, network), + }, + }, + }) +} + +func TestAccComposerEnvironmentComposer2_usesUnsupportedField_expectError(t *testing.T) { + t.Parallel() + + envName := fmt.Sprintf("%s-%d", testComposerEnvironmentPrefix, acctest.RandInt(t)) + errorRegExp, _ := regexp.Compile(".*error in configuration, .* should only be used in Composer 3.*") + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccComposerEnvironmentDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComposerEnvironmentComposer2_usesUnsupportedField(envName), + ExpectError: errorRegExp, + }, + }, + }) +} + +func TestAccComposerEnvironmentComposer3_usesUnsupportedField_expectError(t *testing.T) { + t.Parallel() + + envName := fmt.Sprintf("%s-%d", testComposerEnvironmentPrefix, acctest.RandInt(t)) + errorRegExp, _ := regexp.Compile(".*error in configuration, .* should not be used in Composer 3.*") + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccComposerEnvironmentDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComposerEnvironmentComposer3_usesUnsupportedField(envName), + ExpectError: errorRegExp, + }, + }, + }) +} <% end -%> func testAccComposerEnvironment_customBucket(bucketName, envName, network, subnetwork string) string { @@ -2943,6 +3085,10 @@ resource "google_composer_environment" "test" { software_config { image_version = "composer-3-airflow-2" } + node_config { + network = google_compute_network.test.id + subnetwork = google_compute_subnetwork.test.id + } } } @@ -3000,11 +3146,13 @@ resource "google_composer_environment" "test" { name = "%s" region = "us-central1" config { - software_config { - image_version = "composer-3-airflow-2" - } node_config { composer_internal_ipv4_cidr_block = "100.64.128.0/20" + network = google_compute_network.test.id + subnetwork = google_compute_subnetwork.test.id + } + software_config { + image_version = "composer-3-airflow-2" } workloads_config { dag_processor { @@ -3041,6 +3189,8 @@ resource "google_composer_environment" "test" { region = "us-central1" config { node_config { + network = google_compute_network.test_1.id + subnetwork = google_compute_subnetwork.test_1.id composer_internal_ipv4_cidr_block = "100.64.128.0/20" } software_config { @@ -3072,7 +3222,168 @@ resource "google_compute_subnetwork" "test" { region = "us-central1" network = google_compute_network.test.self_link } -`, name, network, subnetwork) + +resource "google_compute_network" "test_1" { + name = "%s" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "test_1" { + name = "%s" + ip_cidr_range = "10.3.0.0/16" + region = "us-central1" + network = google_compute_network.test_1.self_link +} +`, name, network, subnetwork, network + "-update", subnetwork + "update") +} + +func testAccComposerEnvironmentComposer3_withNetworkAttachment(name, networkAttachment, network, subnetwork string) string { + return fmt.Sprintf(` +resource "google_composer_environment" "test" { + name = "%s" + region = "us-central1" + config { + node_config { + composer_network_attachment = google_compute_network_attachment.test.id + } + software_config { + image_version = "composer-3-airflow-2" + } + } +} + +resource "google_compute_network_attachment" "test" { + name = "%s" + region = "us-central1" + subnetworks = [ google_compute_subnetwork.test-att.id ] + connection_preference = "ACCEPT_MANUAL" + // Composer 3 is modifying producer_accept_lists outside terraform, ignoring this change for now + lifecycle { + ignore_changes = [producer_accept_lists] + } +} + +resource "google_compute_network" "test-att" { + name = "%s-att" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "test-att" { + name = "%s-att" + ip_cidr_range = "10.3.0.0/16" + region = "us-central1" + network = google_compute_network.test-att.self_link +} + +// use a separate network to avoid conflicts with other tests running in parallel +// that use the default network/subnet +resource "google_compute_network" "test" { + name = "%s" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "test" { + name = "%s" + ip_cidr_range = "10.2.0.0/16" + region = "us-central1" + network = google_compute_network.test.self_link +} +`, name, networkAttachment, network, subnetwork, network, subnetwork) +} + +func testAccComposerEnvironmentComposer3_withNetworkAndSubnetwork(name, networkAttachment, network, subnetwork string) string { + return fmt.Sprintf(` +resource "google_composer_environment" "test" { + name = "%s" + region = "us-central1" + config { + node_config { + network = google_compute_network.test.id + subnetwork = google_compute_subnetwork.test.id + } + software_config { + image_version = "composer-3-airflow-2" + } + } +} + +resource "google_compute_network_attachment" "test" { + name = "%s" + region = "us-central1" + subnetworks = [ google_compute_subnetwork.test-att.id ] + connection_preference = "ACCEPT_MANUAL" + // Composer 3 is modifying producer_accept_lists outside terraform, ignoring this change for now + lifecycle { + ignore_changes = [producer_accept_lists] + } +} + +resource "google_compute_network" "test-att" { + name = "%s-att" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "test-att" { + name = "%s-att" + ip_cidr_range = "10.3.0.0/16" + region = "us-central1" + network = google_compute_network.test-att.self_link +} + +// use a separate network to avoid conflicts with other tests running in parallel +// that use the default network/subnet +resource "google_compute_network" "test" { + name = "%s" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "test" { + name = "%s" + ip_cidr_range = "10.2.0.0/16" + region = "us-central1" + network = google_compute_network.test.self_link +} +`, name, networkAttachment, network, subnetwork, network, subnetwork) +} + +func testAccComposerEnvironmentComposer3_withNetworkSubnetworkAndAttachment_expectError(name, networkAttachment, network, subnetwork string) string { + return fmt.Sprintf(` +resource "google_composer_environment" "test" { + name = "%s" + region = "us-central1" + config { + node_config { + network = google_compute_network.test.id + subnetwork = google_compute_subnetwork.test.id + composer_network_attachment = google_compute_network_attachment.test.id + } + software_config { + image_version = "composer-3-airflow-2" + } + } +} + +resource "google_compute_network_attachment" "test" { + name = "%s" + region = "us-central1" + subnetworks = [ google_compute_subnetwork.test.id ] + connection_preference = "ACCEPT_MANUAL" +} + +// use a separate network to avoid conflicts with other tests running in parallel +// that use the default network/subnet +resource "google_compute_network" "test" { + name = "%s" + auto_create_subnetworks = false +} + +resource "google_compute_subnetwork" "test" { + name = "%s" + ip_cidr_range = "10.2.0.0/16" + region = "us-central1" + network = google_compute_network.test.self_link +} +`, name, networkAttachment, network, subnetwork) } <% end -%> From 9f8d2aa14d34b8b09e65cb2e91179895fb2f30a5 Mon Sep 17 00:00:00 2001 From: Sarah French <15078782+SarahFrench@users.noreply.github.com> Date: Tue, 27 Feb 2024 10:03:51 +0000 Subject: [PATCH 73/77] Fix resource name to have sweepable prefix (#9984) --- .../resource_compute_region_target_tcp_proxy_test.go.erb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_region_target_tcp_proxy_test.go.erb b/mmv1/third_party/terraform/services/compute/resource_compute_region_target_tcp_proxy_test.go.erb index 6b7cfd194215..535218117c07 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_region_target_tcp_proxy_test.go.erb +++ b/mmv1/third_party/terraform/services/compute/resource_compute_region_target_tcp_proxy_test.go.erb @@ -13,9 +13,9 @@ import ( func TestAccComputeRegionTargetTcpProxy_update(t *testing.T) { t.Parallel() - target := fmt.Sprintf("trtcp-test-%s", acctest.RandString(t, 10)) - backend := fmt.Sprintf("trtcp-test-%s", acctest.RandString(t, 10)) - hc := fmt.Sprintf("trtcp-test-%s", acctest.RandString(t, 10)) + target := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + backend := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + hc := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, From b1f7bf9b0987f3040fd4820f34587b7101fa77c7 Mon Sep 17 00:00:00 2001 From: rahul2393 Date: Tue, 27 Feb 2024 20:16:04 +0530 Subject: [PATCH 74/77] doc(spanner): update documents to have example for IAM conditions use with google spanner database (#10049) --- .../docs/r/spanner_database_iam.html.markdown | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/mmv1/third_party/terraform/website/docs/r/spanner_database_iam.html.markdown b/mmv1/third_party/terraform/website/docs/r/spanner_database_iam.html.markdown index 1de101713eb3..ef09772c1fd0 100644 --- a/mmv1/third_party/terraform/website/docs/r/spanner_database_iam.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/spanner_database_iam.html.markdown @@ -39,6 +39,32 @@ resource "google_spanner_database_iam_policy" "database" { } ``` +With IAM Conditions: + +```hcl +data "google_iam_policy" "admin" { + binding { + role = "roles/editor" + + members = [ + "user:jane@example.com", + ] + + condition { + title = "My Role" + description = "Grant permissions on my_role" + expression = "(resource.type == \"spanner.googleapis.com/DatabaseRole\" && (resource.name.endsWith(\"/myrole\")))" + } + } +} + +resource "google_spanner_database_iam_policy" "database" { + instance = "your-instance-name" + database = "your-database-name" + policy_data = data.google_iam_policy.admin.policy_data +} +``` + ## google\_spanner\_database\_iam\_binding ```hcl @@ -53,6 +79,26 @@ resource "google_spanner_database_iam_binding" "database" { } ``` +With IAM Conditions: + +```hcl +resource "google_spanner_database_iam_binding" "database" { + instance = "your-instance-name" + database = "your-database-name" + role = "roles/compute.networkUser" + + members = [ + "user:jane@example.com", + ] + + condition { + title = "My Role" + description = "Grant permissions on my_role" + expression = "(resource.type == \"spanner.googleapis.com/DatabaseRole\" && (resource.name.endsWith(\"/myrole\")))" + } +} +``` + ## google\_spanner\_database\_iam\_member ```hcl @@ -64,6 +110,23 @@ resource "google_spanner_database_iam_member" "database" { } ``` +With IAM Conditions: + +```hcl +resource "google_spanner_database_iam_member" "database" { + instance = "your-instance-name" + database = "your-database-name" + role = "roles/compute.networkUser" + member = "user:jane@example.com" + + condition { + title = "My Role" + description = "Grant permissions on my_role" + expression = "(resource.type == \"spanner.googleapis.com/DatabaseRole\" && (resource.name.endsWith(\"/myrole\")))" + } +} +``` + ## Argument Reference The following arguments are supported: @@ -91,6 +154,23 @@ The following arguments are supported: * `project` - (Optional) The ID of the project in which the resource belongs. If it is not provided, the provider project is used. +* `condition` - (Optional) An [IAM Condition](https://cloud.google.com/iam/docs/conditions-overview) for a given binding. + Structure is [documented below](#nested_condition). + +--- + +The `condition` block supports: + +* `expression` - (Required) Textual representation of an expression in Common Expression Language syntax. + +* `title` - (Required) A title for the expression, i.e. a short string describing its purpose. + +* `description` - (Optional) An optional description of the expression. This is a longer text which describes the expression, e.g. when hovered over it in a UI. + +~> **Warning:** Terraform considers the `role` and condition contents (`title`+`description`+`expression`) as the +identifier for the binding. This means that if any part of the condition is changed out-of-band, Terraform will +consider it to be an entirely different resource and will treat it as such. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are From aee8d1d332c09af8dda321a9a466cd8ae7232602 Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 27 Feb 2024 14:51:19 +0000 Subject: [PATCH 75/77] Promote Cloud Deploy Automation to GA (#10043) * Add Cloud Deploy Automation * Attempt to solve the test errors based on https://yaqs.corp.google.com/eng/q/7753655943518224384 * Add update test for the new automation resource * fix lint errors * fix lint errors * fix errors in GA provider test * add the missing test * add a full test * Attempt to fix the acceptance test errors * fix a lint error * mark labels as default_from_api:true * fix advance rollout rule definition * Mark service_account as 'ignore_read: true' * Fix test errors * Resolve review comments * Format test file * promote google_clouddeploy_automation to GA * promote google_clouddeploy_automation to GA * fix lint errors --- mmv1/products/clouddeploy/Automation.yaml | 5 +- .../clouddeploy_automation_basic.tf.erb | 2 - .../clouddeploy_automation_full.tf.erb | 2 - ...> resource_clouddeploy_automation_test.go} | 81 +++++++++---------- 4 files changed, 38 insertions(+), 52 deletions(-) rename mmv1/third_party/terraform/services/clouddeploy/{resource_clouddeploy_automation_test.go.erb => resource_clouddeploy_automation_test.go} (57%) diff --git a/mmv1/products/clouddeploy/Automation.yaml b/mmv1/products/clouddeploy/Automation.yaml index 6af88d3d88f4..bb46c92440bb 100644 --- a/mmv1/products/clouddeploy/Automation.yaml +++ b/mmv1/products/clouddeploy/Automation.yaml @@ -21,7 +21,7 @@ references: !ruby/object:Api::Resource::ReferenceLinks api: 'https://cloud.google.com/deploy/docs/api/reference/rest/v1/projects.locations.deliveryPipelines.automations' base_url: 'projects/{{project}}/locations/{{location}}/deliveryPipelines/{{delivery_pipeline}}/automations' self_link: 'projects/{{project}}/locations/{{location}}/deliveryPipelines/{{delivery_pipeline}}/automations/{{name}}' -min_version: beta + create_url: 'projects/{{project}}/locations/{{location}}/deliveryPipelines/{{delivery_pipeline}}/automations?automationId={{name}}' update_verb: :PATCH update_mask: true @@ -51,7 +51,6 @@ autogen_async: true examples: - !ruby/object:Provider::Terraform::Examples name: "clouddeploy_automation_basic" - min_version: beta primary_resource_id: "b-automation" vars: automation: "cd-automation" @@ -60,7 +59,7 @@ examples: service_account: :SERVICE_ACCT - !ruby/object:Provider::Terraform::Examples name: "clouddeploy_automation_full" - min_version: beta + primary_resource_id: "f-automation" vars: automation: "cd-automation" diff --git a/mmv1/templates/terraform/examples/clouddeploy_automation_basic.tf.erb b/mmv1/templates/terraform/examples/clouddeploy_automation_basic.tf.erb index fa7ad4fb230e..41b460f1aefb 100644 --- a/mmv1/templates/terraform/examples/clouddeploy_automation_basic.tf.erb +++ b/mmv1/templates/terraform/examples/clouddeploy_automation_basic.tf.erb @@ -1,5 +1,4 @@ resource "google_clouddeploy_automation" "<%= ctx[:primary_resource_id] %>" { - provider = google-beta name = "<%= ctx[:vars]['automation'] %>" project = google_clouddeploy_delivery_pipeline.pipeline.project location = google_clouddeploy_delivery_pipeline.pipeline.location @@ -19,7 +18,6 @@ resource "google_clouddeploy_automation" "<%= ctx[:primary_resource_id] %>" { } resource "google_clouddeploy_delivery_pipeline" "pipeline" { - provider = google-beta name = "<%= ctx[:vars]['delivery_pipeline'] %>" location = "us-central1" serial_pipeline { diff --git a/mmv1/templates/terraform/examples/clouddeploy_automation_full.tf.erb b/mmv1/templates/terraform/examples/clouddeploy_automation_full.tf.erb index 8cd21d0e10d3..51bf98d1bca1 100644 --- a/mmv1/templates/terraform/examples/clouddeploy_automation_full.tf.erb +++ b/mmv1/templates/terraform/examples/clouddeploy_automation_full.tf.erb @@ -1,5 +1,4 @@ resource "google_clouddeploy_automation" "<%= ctx[:primary_resource_id] %>" { - provider = google-beta name = "<%= ctx[:vars]['automation'] %>" location = "us-central1" delivery_pipeline = google_clouddeploy_delivery_pipeline.pipeline.name @@ -40,7 +39,6 @@ resource "google_clouddeploy_automation" "<%= ctx[:primary_resource_id] %>" { } resource "google_clouddeploy_delivery_pipeline" "pipeline" { - provider = google-beta name = "<%= ctx[:vars]['delivery_pipeline'] %>" location = "us-central1" serial_pipeline { diff --git a/mmv1/third_party/terraform/services/clouddeploy/resource_clouddeploy_automation_test.go.erb b/mmv1/third_party/terraform/services/clouddeploy/resource_clouddeploy_automation_test.go similarity index 57% rename from mmv1/third_party/terraform/services/clouddeploy/resource_clouddeploy_automation_test.go.erb rename to mmv1/third_party/terraform/services/clouddeploy/resource_clouddeploy_automation_test.go index 601f55640516..82f1fe3a0e5c 100644 --- a/mmv1/third_party/terraform/services/clouddeploy/resource_clouddeploy_automation_test.go.erb +++ b/mmv1/third_party/terraform/services/clouddeploy/resource_clouddeploy_automation_test.go @@ -1,56 +1,52 @@ -<% autogen_exception -%> package clouddeploy_test - -<% unless version == 'ga' -%> import ( - "testing" + "testing" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" - "github.com/hashicorp/terraform-provider-google/google/acctest" - "github.com/hashicorp/terraform-provider-google/google/envvar" + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" ) func TestAccClouddeployAutomation_update(t *testing.T) { - t.Parallel() + t.Parallel() - context := map[string]interface{}{ - "service_account": envvar.GetTestServiceAccountFromEnv(t), - "random_suffix": acctest.RandString(t, 10), - } + context := map[string]interface{}{ + "service_account": envvar.GetTestServiceAccountFromEnv(t), + "random_suffix": acctest.RandString(t, 10), + } - acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), - CheckDestroy: testAccCheckClouddeployAutomationDestroyProducer(t), - Steps: []resource.TestStep{ - { - Config: testAccClouddeployAutomation_basic(context), - }, - { - ResourceName: "google_clouddeploy_automation.automation", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "delivery_pipeline", "annotations", "labels", "terraform_labels"}, - }, - { - Config: testAccClouddeployAutomation_update(context), - }, - { - ResourceName: "google_clouddeploy_automation.automation", - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "delivery_pipeline", "annotations", "labels", "terraform_labels"}, - }, - }, - }) + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckClouddeployAutomationDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccClouddeployAutomation_basic(context), + }, + { + ResourceName: "google_clouddeploy_automation.automation", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "delivery_pipeline", "annotations", "labels", "terraform_labels"}, + }, + { + Config: testAccClouddeployAutomation_update(context), + }, + { + ResourceName: "google_clouddeploy_automation.automation", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "delivery_pipeline", "annotations", "labels", "terraform_labels"}, + }, + }, + }) } func testAccClouddeployAutomation_basic(context map[string]interface{}) string { - return acctest.Nprintf(` + return acctest.Nprintf(` resource "google_clouddeploy_automation" "automation" { - provider = google-beta name = "tf-test-cd-automation%{random_suffix}" location = "us-central1" delivery_pipeline = google_clouddeploy_delivery_pipeline.pipeline.name @@ -71,7 +67,6 @@ resource "google_clouddeploy_automation" "automation" { } resource "google_clouddeploy_delivery_pipeline" "pipeline" { - provider = google-beta name = "tf-test-cd-pipeline%{random_suffix}" location = "us-central1" serial_pipeline { @@ -85,10 +80,9 @@ resource "google_clouddeploy_delivery_pipeline" "pipeline" { } func testAccClouddeployAutomation_update(context map[string]interface{}) string { - return acctest.Nprintf(` + return acctest.Nprintf(` resource "google_clouddeploy_automation" "automation" { - provider = google-beta name = "tf-test-cd-automation%{random_suffix}" location = "us-central1" delivery_pipeline = google_clouddeploy_delivery_pipeline.pipeline.name @@ -129,7 +123,6 @@ resource "google_clouddeploy_automation" "automation" { } resource "google_clouddeploy_delivery_pipeline" "pipeline" { - provider = google-beta name = "tf-test-cd-pipeline%{random_suffix}" location = "us-central1" serial_pipeline { @@ -141,5 +134,3 @@ resource "google_clouddeploy_delivery_pipeline" "pipeline" { } `, context) } -<% end -%> - From 0a3c61d90cd8ed2f6c66e5ab52afc0805330ef2e Mon Sep 17 00:00:00 2001 From: Ryan Oaks Date: Tue, 27 Feb 2024 11:59:17 -0500 Subject: [PATCH 76/77] Add cloudquota service (#10063) --- .ci/infra/terraform/main.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/.ci/infra/terraform/main.tf b/.ci/infra/terraform/main.tf index 33422f4e6948..a6f8c58a5f69 100644 --- a/.ci/infra/terraform/main.tf +++ b/.ci/infra/terraform/main.tf @@ -196,6 +196,7 @@ module "project-services" { "cloudidentity.googleapis.com", "cloudiot.googleapis.com", "cloudkms.googleapis.com", + "cloudquotas.googleapis.com", "cloudresourcemanager.googleapis.com", "cloudscheduler.googleapis.com", "cloudtasks.googleapis.com", From d4a4dc20c5b871e685e6043cb66011102b8ff27c Mon Sep 17 00:00:00 2001 From: Mauricio Alvarez Leon <65101411+BBBmau@users.noreply.github.com> Date: Tue, 27 Feb 2024 09:26:34 -0800 Subject: [PATCH 77/77] TeamCity: Add validating GHAs that check Kotlin files listing services (#9999) * services diff gha * add needs * use setup-go@v3 * add artifacts * remove checkout * update directory * update common-copy.yaml * update common-copy.yaml * remove data print * add pull-request check on teamcitydiff * update paths in GHA * add exit code in diff_check * update exit output * add exit code diff_check.go * services_beta diff check support * beta services support args * add arg for services kt file * services_ga.kt in gha * move diff_check to tools folder * remove go command * provide path for artifacts download * add cd in Build Provider * update diff_check_beta.yml * fix paths * yml typo beta * directory testing * directory testing * fix directory issues with commands * refactor tools/teamcity-diff-check/main.go * directory check * typo * remove common copy * generate both providers into one gha * type artifacts name * add -o flag into artifacts download * use merge multiple artifacts * use artifact@v4 * use mmv1 directory for services file * remove .zip * output missing services from diff * find artifacts folder * use beta provider as only artifact * include google ga and beta in gha * artifact name * -o flag in artifacts * output stdout from go list command * diff test * output beta main.go * remove err check * remove services print / refactor for final review * output cleanup * uncomment go list err * regex assert * add check for new services in PR / set googleServices as groundtruth in serviceDifference function * add actions/checkout * logic fix * add needs: check-pr * add mmv1/products for pull-request event * set force depth 0 * Update .github/workflows/teamcity-services-diff-check.yml Co-authored-by: Sarah French <15078782+SarahFrench@users.noreply.github.com> * Update .github/workflows/teamcity-services-diff-check.yml Co-authored-by: Sarah French <15078782+SarahFrench@users.noreply.github.com> * use text file for services, add if statement in gha * directory typo * typo * typo in grep * quotations on if statement * unquote GITHUB_OUTPUT * add quotes on output.services * if test * echo output * github_output error fix * services.outputs * proper if statement syntax gpush * invalid 0 format * add missing assignment * fix openfile error * remove types in pull_request trigger * send txt files to correct directory * check services directory for ls command * add weekly workflow for teamcity diff check * change name for weekly check --------- Co-authored-by: Sarah French <15078782+SarahFrench@users.noreply.github.com> --- .../teamcity-services-diff-check-weekly.yml | 71 ++++++++++++++ .../teamcity-services-diff-check.yml | 94 +++++++++++++++++++ tools/teamcity-diff-check/main.go | 92 ++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 .github/workflows/teamcity-services-diff-check-weekly.yml create mode 100644 .github/workflows/teamcity-services-diff-check.yml create mode 100644 tools/teamcity-diff-check/main.go diff --git a/.github/workflows/teamcity-services-diff-check-weekly.yml b/.github/workflows/teamcity-services-diff-check-weekly.yml new file mode 100644 index 000000000000..49289dc24ea0 --- /dev/null +++ b/.github/workflows/teamcity-services-diff-check-weekly.yml @@ -0,0 +1,71 @@ +name: TeamCity Services Weekly Diff Check +permissions: read-all + +on: + schedule: + # Runs every tuesday morning + - cron: '0 4 * * 2' + +jobs: + terraform-provider-google: + uses: ./.github/workflows/build-downstream.yml + with: + repo: 'terraform-provider-google' + + terraform-provider-google-beta: + uses: ./.github/workflows/build-downstream.yml + with: + repo: 'terraform-provider-google-beta' + + teamcity-services-diff-check: + needs: [terraform-provider-google, terraform-provider-google-beta] + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + + - name: Download built artifacts - GA provider + uses: actions/download-artifact@v2 + with: + name: artifact-terraform-provider-google + path: artifacts + + - name: Unzip the artifacts and delete the zip + run: | + unzip -o artifacts/output.zip -d ./provider + rm artifacts/output.zip + + - name: Download built artifacts - Beta provider + uses: actions/download-artifact@v2 + with: + name: artifact-terraform-provider-google-beta + path: artifacts + + - name: Unzip the artifacts and delete the zip + run: | + unzip -o artifacts/output.zip -d ./provider + rm artifacts/output.zip + + - name: Setup Go + uses: actions/setup-go@v3 + with: + go-version: '^1.20' + + - name: Cache Go modules and build cache + uses: actions/cache@v3 + with: + path: | + ~/go/pkg/mod + ~/.cache/go-build + key: ${{ runner.os }}-test-terraform-provider-google-${{hashFiles('go.sum','google-*/transport/**','google-*/tpgresource/**','google-*/acctest/**','google-*/envvar/**','google-*/sweeper/**','google-*/verify/**') }} + restore-keys: | + ${{ runner.os }}-test-terraform-provider-google-${{ hashFiles('go.sum') }} + ${{ runner.os }}-test-terraform-provider-google- + + - name: Diff Check + run: | + ls provider/google/services > tools/teamcity-diff-check/services_ga.txt + ls provider/google-beta/services > tools/teamcity-diff-check/services_beta.txt + cd tools/teamcity-diff-check + go run main.go -service_file=services_ga + go run main.go -service_file=services_beta + \ No newline at end of file diff --git a/.github/workflows/teamcity-services-diff-check.yml b/.github/workflows/teamcity-services-diff-check.yml new file mode 100644 index 000000000000..535ff9fb6293 --- /dev/null +++ b/.github/workflows/teamcity-services-diff-check.yml @@ -0,0 +1,94 @@ +name: TeamCity Services Diff Check +permissions: read-all + +on: + workflow_dispatch: + pull_request: + paths: + - '.github/workflows/teamcity-services-diff-check.yml' + - 'mmv1/third_party/terraform/.teamcity/components/inputs/services_ga.kt' + - 'mmv1/third_party/terraform/.teamcity/components/inputs/services_beta.kt' + - 'mmv1/products/**' +jobs: + check-pr: + runs-on: ubuntu-22.04 + outputs: + services: ${{steps.services.outputs.services}} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - id: services + name: "Check for New Services" + run: | + newServices=$(($(git diff --name-only --diff-filter=A origin/main HEAD | grep -P "mmv1/products/.*/product.yaml" | wc -l))) + echo "services=$newServices" >> "${GITHUB_OUTPUT}" + if [ "$newServices" = "0" ];then + echo "No new service found." + fi + terraform-provider-google: + if: ${{needs.check-pr.outputs.services != '0'}} + needs: check-pr + uses: ./.github/workflows/build-downstream.yml + with: + repo: 'terraform-provider-google' + + terraform-provider-google-beta: + if: ${{needs.check-pr.outputs.services != '0'}} + needs: check-pr + uses: ./.github/workflows/build-downstream.yml + with: + repo: 'terraform-provider-google-beta' + + teamcity-services-diff-check: + needs: [terraform-provider-google, terraform-provider-google-beta] + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + + - name: Download built artifacts - GA provider + uses: actions/download-artifact@v2 + with: + name: artifact-terraform-provider-google + path: artifacts + + - name: Unzip the artifacts and delete the zip + run: | + unzip -o artifacts/output.zip -d ./provider + rm artifacts/output.zip + + - name: Download built artifacts - Beta provider + uses: actions/download-artifact@v2 + with: + name: artifact-terraform-provider-google-beta + path: artifacts + + - name: Unzip the artifacts and delete the zip + run: | + unzip -o artifacts/output.zip -d ./provider + rm artifacts/output.zip + + - name: Setup Go + uses: actions/setup-go@v3 + with: + go-version: '^1.20' + + - name: Cache Go modules and build cache + uses: actions/cache@v3 + with: + path: | + ~/go/pkg/mod + ~/.cache/go-build + key: ${{ runner.os }}-test-terraform-provider-google-${{hashFiles('go.sum','google-*/transport/**','google-*/tpgresource/**','google-*/acctest/**','google-*/envvar/**','google-*/sweeper/**','google-*/verify/**') }} + restore-keys: | + ${{ runner.os }}-test-terraform-provider-google-${{ hashFiles('go.sum') }} + ${{ runner.os }}-test-terraform-provider-google- + + - name: Diff Check + run: | + ls provider/google/services > tools/teamcity-diff-check/services_ga.txt + ls provider/google-beta/services > tools/teamcity-diff-check/services_beta.txt + cd tools/teamcity-diff-check + go run main.go -service_file=services_ga + go run main.go -service_file=services_beta + \ No newline at end of file diff --git a/tools/teamcity-diff-check/main.go b/tools/teamcity-diff-check/main.go new file mode 100644 index 000000000000..b3a71436e8fa --- /dev/null +++ b/tools/teamcity-diff-check/main.go @@ -0,0 +1,92 @@ +package main + +import ( + "bufio" + "flag" + "fmt" + "io" + "os" + "regexp" +) + +var serviceFile = flag.String("service_file", "services_ga", "kotlin service file to be parsed") + +func serviceDifference(gS, tS []string) []string { + t := make(map[string]struct{}, len(tS)) + for _, s := range tS { + t[s] = struct{}{} + } + + var diff []string + for _, s := range gS { + if _, found := t[s]; !found { + diff = append(diff, s) + } + } + + return diff +} + +func main() { + flag.Parse() + + file, err := os.Open(*serviceFile + ".txt") + if err != nil { + fmt.Println(err) + return + } + defer file.Close() + + googleServices := []string{} + scanner := bufio.NewScanner(file) + for scanner.Scan() { + googleServices = append(googleServices, scanner.Text()) + } + + //////////////////////////////////////////////////////////////////////////////// + + f, err := os.Open(fmt.Sprintf("../../mmv1/third_party/terraform/.teamcity/components/inputs/%s", *serviceFile+".kt")) + if err != nil { + panic(err) + } + + // Get the file size + stat, err := f.Stat() + if err != nil { + fmt.Println(err) + return + } + + // Read the file into a byte slice + bs := make([]byte, stat.Size()) + _, err = bufio.NewReader(f).Read(bs) + if err != nil && err != io.EOF { + fmt.Println(err) + return + } + + // Regex pattern captures "services" from *serviceFile. + pattern := regexp.MustCompile(`(?m)"(?P\w+)"\sto\s+mapOf`) + + template := []byte("$service") + + dst := []byte{} + teamcityServices := []string{} + + // For each match of the regex in the content. + for _, submatches := range pattern.FindAllSubmatchIndex(bs, -1) { + service := pattern.Expand(dst, template, bs, submatches) + teamcityServices = append(teamcityServices, string(service)) + } + if len(teamcityServices) == 0 { + fmt.Fprintf(os.Stderr, "teamcityServices error: regex produced no matches.\n") + os.Exit(1) + } + + if diff := serviceDifference(googleServices, teamcityServices); len(diff) != 0 { + fmt.Fprintf(os.Stderr, "error: diff in %s\n", *serviceFile) + fmt.Fprintf(os.Stderr, "Missing Services: %s\n", diff) + os.Exit(1) + } + +}