From 30f34689e92a8ea8980187ce29e796942731f0d4 Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Wed, 18 Jan 2023 22:40:58 +0000 Subject: [PATCH] Share settings for sole-tenant node groups. (#7059) * Share settings for sole-tenant node groups. * Fixes after review. Co-authored-by: Igor Dyczko Signed-off-by: Modular Magician --- .changelog/7059.txt | 3 + google/resource_compute_node_group.go | 146 ++++++++++++++++++ ...ource_compute_node_group_generated_test.go | 59 +++++++ .../docs/r/compute_node_group.html.markdown | 59 +++++++ 4 files changed, 267 insertions(+) create mode 100644 .changelog/7059.txt diff --git a/.changelog/7059.txt b/.changelog/7059.txt new file mode 100644 index 00000000000..347ede44cb9 --- /dev/null +++ b/.changelog/7059.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +compute: added `share_settings` field to the `google_compute_node_group` resource. +``` diff --git a/google/resource_compute_node_group.go b/google/resource_compute_node_group.go index 7237dd2c460..5dcd79fcdcb 100644 --- a/google/resource_compute_node_group.go +++ b/google/resource_compute_node_group.go @@ -133,6 +133,46 @@ than or equal to max-nodes. The default value is 0.`, ForceNew: true, Description: `Name of the resource.`, }, + "share_settings": { + Type: schema.TypeList, + Computed: true, + Optional: true, + ForceNew: true, + Description: `Share settings for the node group.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "share_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateEnum([]string{"ORGANIZATION", "SPECIFIC_PROJECTS", "LOCAL"}), + Description: `Node group sharing type. Possible values: ["ORGANIZATION", "SPECIFIC_PROJECTS", "LOCAL"]`, + }, + "project_map": { + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Description: `A map of project id and project config. This is only valid when shareType's value is SPECIFIC_PROJECTS.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "project_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + Description: `The project id/number should be the same as the key of this project config in the project map.`, + }, + }, + }, + }, + }, + }, + }, "size": { Type: schema.TypeInt, Computed: true, @@ -219,6 +259,12 @@ func resourceComputeNodeGroupCreate(d *schema.ResourceData, meta interface{}) er } else if v, ok := d.GetOkExists("autoscaling_policy"); !isEmptyValue(reflect.ValueOf(autoscalingPolicyProp)) && (ok || !reflect.DeepEqual(v, autoscalingPolicyProp)) { obj["autoscalingPolicy"] = autoscalingPolicyProp } + shareSettingsProp, err := expandComputeNodeGroupShareSettings(d.Get("share_settings"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("share_settings"); !isEmptyValue(reflect.ValueOf(shareSettingsProp)) && (ok || !reflect.DeepEqual(v, shareSettingsProp)) { + obj["shareSettings"] = shareSettingsProp + } zoneProp, err := expandComputeNodeGroupZone(d.Get("zone"), d, config) if err != nil { return err @@ -338,6 +384,9 @@ func resourceComputeNodeGroupRead(d *schema.ResourceData, meta interface{}) erro if err := d.Set("autoscaling_policy", flattenComputeNodeGroupAutoscalingPolicy(res["autoscalingPolicy"], d, config)); err != nil { return fmt.Errorf("Error reading NodeGroup: %s", err) } + if err := d.Set("share_settings", flattenComputeNodeGroupShareSettings(res["shareSettings"], d, config)); err != nil { + return fmt.Errorf("Error reading NodeGroup: %s", err) + } if err := d.Set("zone", flattenComputeNodeGroupZone(res["zone"], d, config)); err != nil { return fmt.Errorf("Error reading NodeGroup: %s", err) } @@ -583,6 +632,44 @@ func flattenComputeNodeGroupAutoscalingPolicyMaxNodes(v interface{}, d *schema.R return v // let terraform core handle it otherwise } +func flattenComputeNodeGroupShareSettings(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["share_type"] = + flattenComputeNodeGroupShareSettingsShareType(original["shareType"], d, config) + transformed["project_map"] = + flattenComputeNodeGroupShareSettingsProjectMap(original["projectMap"], d, config) + return []interface{}{transformed} +} +func flattenComputeNodeGroupShareSettingsShareType(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + +func flattenComputeNodeGroupShareSettingsProjectMap(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return v + } + l := v.(map[string]interface{}) + transformed := make([]interface{}, 0, len(l)) + for k, raw := range l { + original := raw.(map[string]interface{}) + transformed = append(transformed, map[string]interface{}{ + "id": k, + "project_id": flattenComputeNodeGroupShareSettingsProjectMapProjectId(original["projectId"], d, config), + }) + } + return transformed +} +func flattenComputeNodeGroupShareSettingsProjectMapProjectId(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + func flattenComputeNodeGroupZone(v interface{}, d *schema.ResourceData, config *Config) interface{} { if v == nil { return v @@ -682,6 +769,65 @@ func expandComputeNodeGroupAutoscalingPolicyMaxNodes(v interface{}, d TerraformR return v, nil } +func expandComputeNodeGroupShareSettings(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedShareType, err := expandComputeNodeGroupShareSettingsShareType(original["share_type"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedShareType); val.IsValid() && !isEmptyValue(val) { + transformed["shareType"] = transformedShareType + } + + transformedProjectMap, err := expandComputeNodeGroupShareSettingsProjectMap(original["project_map"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedProjectMap); val.IsValid() && !isEmptyValue(val) { + transformed["projectMap"] = transformedProjectMap + } + + return transformed, nil +} + +func expandComputeNodeGroupShareSettingsShareType(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandComputeNodeGroupShareSettingsProjectMap(v interface{}, d TerraformResourceData, config *Config) (map[string]interface{}, error) { + if v == nil { + return map[string]interface{}{}, nil + } + m := make(map[string]interface{}) + for _, raw := range v.(*schema.Set).List() { + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedProjectId, err := expandComputeNodeGroupShareSettingsProjectMapProjectId(original["project_id"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedProjectId); val.IsValid() && !isEmptyValue(val) { + transformed["projectId"] = transformedProjectId + } + + transformedId, err := expandString(original["id"], d, config) + if err != nil { + return nil, err + } + m[transformedId] = transformed + } + return m, nil +} + +func expandComputeNodeGroupShareSettingsProjectMapProjectId(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandComputeNodeGroupZone(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { f, err := parseGlobalFieldValue("zones", v.(string), "project", d, config, true) if err != nil { diff --git a/google/resource_compute_node_group_generated_test.go b/google/resource_compute_node_group_generated_test.go index fce30529de2..e112e99c514 100644 --- a/google/resource_compute_node_group_generated_test.go +++ b/google/resource_compute_node_group_generated_test.go @@ -119,6 +119,65 @@ resource "google_compute_node_group" "nodes" { `, context) } +func TestAccComputeNodeGroup_nodeGroupShareSettingsExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "org_id": getTestOrgFromEnv(t), + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeNodeGroupDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeNodeGroup_nodeGroupShareSettingsExample(context), + }, + { + ResourceName: "google_compute_node_group.nodes", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"node_template", "initial_size", "zone"}, + }, + }, + }) +} + +func testAccComputeNodeGroup_nodeGroupShareSettingsExample(context map[string]interface{}) string { + return Nprintf(` +resource "google_project" "guest_project" { + project_id = "tf-test-project-id%{random_suffix}" + name = "tf-test-project-name%{random_suffix}" + org_id = "%{org_id}" +} + +resource "google_compute_node_template" "soletenant-tmpl" { + name = "tf-test-soletenant-tmpl%{random_suffix}" + region = "us-central1" + node_type = "n1-node-96-624" +} + +resource "google_compute_node_group" "nodes" { + name = "tf-test-soletenant-group%{random_suffix}" + zone = "us-central1-f" + description = "example google_compute_node_group for Terraform Google Provider" + + size = 1 + node_template = google_compute_node_template.soletenant-tmpl.id + + share_settings { + share_type = "SPECIFIC_PROJECTS" + project_map { + id = google_project.guest_project.project_id + project_id = google_project.guest_project.project_id + } + } +} +`, context) +} + func testAccCheckComputeNodeGroupDestroyProducer(t *testing.T) func(s *terraform.State) error { return func(s *terraform.State) error { for name, rs := range s.RootModule().Resources { diff --git a/website/docs/r/compute_node_group.html.markdown b/website/docs/r/compute_node_group.html.markdown index 5bc81bb0927..bb7432d45e7 100644 --- a/website/docs/r/compute_node_group.html.markdown +++ b/website/docs/r/compute_node_group.html.markdown @@ -90,6 +90,39 @@ resource "google_compute_node_group" "nodes" { } } ``` +## Example Usage - Node Group Share Settings + + +```hcl +resource "google_project" "guest_project" { + project_id = "project-id" + name = "project-name" + org_id = "123456789" +} + +resource "google_compute_node_template" "soletenant-tmpl" { + name = "soletenant-tmpl" + region = "us-central1" + node_type = "n1-node-96-624" +} + +resource "google_compute_node_group" "nodes" { + name = "soletenant-group" + zone = "us-central1-f" + description = "example google_compute_node_group for Terraform Google Provider" + + size = 1 + node_template = google_compute_node_template.soletenant-tmpl.id + + share_settings { + share_type = "SPECIFIC_PROJECTS" + project_map { + id = google_project.guest_project.project_id + project_id = google_project.guest_project.project_id + } + } +} +``` ## Argument Reference @@ -135,6 +168,11 @@ The following arguments are supported: group autoscaler to automatically manage the sizes of your node groups. Structure is [documented below](#nested_autoscaling_policy). +* `share_settings` - + (Optional) + Share settings for the node group. + Structure is [documented below](#nested_share_settings). + * `zone` - (Optional) Zone where this node group is located @@ -171,6 +209,27 @@ The following arguments are supported: Maximum size of the node group. Set to a value less than or equal to 100 and greater than or equal to min-nodes. +The `share_settings` block supports: + +* `share_type` - + (Required) + Node group sharing type. + Possible values are `ORGANIZATION`, `SPECIFIC_PROJECTS`, and `LOCAL`. + +* `project_map` - + (Optional) + A map of project id and project config. This is only valid when shareType's value is SPECIFIC_PROJECTS. + Structure is [documented below](#nested_project_map). + + +The `project_map` block supports: + +* `id` - (Required) The identifier for this object. Format specified above. + +* `project_id` - + (Required) + The project id/number should be the same as the key of this project config in the project map. + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are exported: