| // 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 compute |
| |
| import ( |
| "errors" |
| "fmt" |
| "log" |
| "reflect" |
| "regexp" |
| "strings" |
| "time" |
| |
| "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" |
| "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" |
| |
| "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" |
| transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" |
| "github.com/hashicorp/terraform-provider-google-beta/google-beta/verify" |
| ) |
| |
| func ResourceComputeNodeGroup() *schema.Resource { |
| return &schema.Resource{ |
| Create: resourceComputeNodeGroupCreate, |
| Read: resourceComputeNodeGroupRead, |
| Update: resourceComputeNodeGroupUpdate, |
| Delete: resourceComputeNodeGroupDelete, |
| |
| Importer: &schema.ResourceImporter{ |
| State: resourceComputeNodeGroupImport, |
| }, |
| |
| Timeouts: &schema.ResourceTimeout{ |
| Create: schema.DefaultTimeout(20 * time.Minute), |
| Update: schema.DefaultTimeout(20 * time.Minute), |
| Delete: schema.DefaultTimeout(20 * time.Minute), |
| }, |
| |
| CustomizeDiff: customdiff.All( |
| tpgresource.DefaultProviderProject, |
| ), |
| |
| Schema: map[string]*schema.Schema{ |
| "node_template": { |
| Type: schema.TypeString, |
| Required: true, |
| DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, |
| Description: `The URL of the node template to which this node group belongs.`, |
| }, |
| "autoscaling_policy": { |
| Type: schema.TypeList, |
| Computed: true, |
| Optional: true, |
| Description: `If you use sole-tenant nodes for your workloads, you can use the node |
| group autoscaler to automatically manage the sizes of your node groups. |
| |
| One of 'initial_size' or 'autoscaling_policy' must be configured on resource creation.`, |
| MaxItems: 1, |
| Elem: &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "max_nodes": { |
| Type: schema.TypeInt, |
| Computed: true, |
| Optional: true, |
| Description: `Maximum size of the node group. Set to a value less than or equal |
| to 100 and greater than or equal to min-nodes.`, |
| }, |
| "mode": { |
| Type: schema.TypeString, |
| Computed: true, |
| Optional: true, |
| ValidateFunc: verify.ValidateEnum([]string{"OFF", "ON", "ONLY_SCALE_OUT"}), |
| Description: `The autoscaling mode. Set to one of the following: |
| - OFF: Disables the autoscaler. |
| - ON: Enables scaling in and scaling out. |
| - ONLY_SCALE_OUT: Enables only scaling out. |
| You must use this mode if your node groups are configured to |
| restart their hosted VMs on minimal servers. Possible values: ["OFF", "ON", "ONLY_SCALE_OUT"]`, |
| }, |
| "min_nodes": { |
| Type: schema.TypeInt, |
| Computed: true, |
| Optional: true, |
| Description: `Minimum size of the node group. Must be less |
| than or equal to max-nodes. The default value is 0.`, |
| }, |
| }, |
| }, |
| }, |
| "description": { |
| Type: schema.TypeString, |
| Optional: true, |
| Description: `An optional textual description of the resource.`, |
| }, |
| "initial_size": { |
| Type: schema.TypeInt, |
| Optional: true, |
| Description: `The initial number of nodes in the node group. One of 'initial_size' or 'autoscaling_policy' must be configured on resource creation.`, |
| }, |
| "maintenance_interval": { |
| Type: schema.TypeString, |
| Computed: true, |
| Optional: true, |
| ValidateFunc: verify.ValidateEnum([]string{"AS_NEEDED", "RECURRENT", ""}), |
| Description: `Specifies the frequency of planned maintenance events. Set to one of the following: |
| - AS_NEEDED: Hosts are eligible to receive infrastructure and hypervisor updates as they become available. |
| - RECURRENT: Hosts receive planned infrastructure and hypervisor updates on a periodic basis, but not more frequently than every 28 days. This minimizes the number of planned maintenance operations on individual hosts and reduces the frequency of disruptions, both live migrations and terminations, on individual VMs. Possible values: ["AS_NEEDED", "RECURRENT"]`, |
| }, |
| "maintenance_policy": { |
| Type: schema.TypeString, |
| Optional: true, |
| Description: `Specifies how to handle instances when a node in the group undergoes maintenance. Set to one of: DEFAULT, RESTART_IN_PLACE, or MIGRATE_WITHIN_NODE_GROUP. The default value is DEFAULT.`, |
| Default: "DEFAULT", |
| }, |
| "maintenance_window": { |
| Type: schema.TypeList, |
| Optional: true, |
| Description: `contains properties for the timeframe of maintenance`, |
| MaxItems: 1, |
| Elem: &schema.Resource{ |
| Schema: map[string]*schema.Schema{ |
| "start_time": { |
| Type: schema.TypeString, |
| Required: true, |
| Description: `instances.start time of the window. This must be in UTC format that resolves to one of 00:00, 04:00, 08:00, 12:00, 16:00, or 20:00. For example, both 13:00-5 and 08:00 are valid.`, |
| }, |
| }, |
| }, |
| }, |
| "name": { |
| Type: schema.TypeString, |
| Optional: true, |
| Description: `Name of the resource.`, |
| }, |
| "share_settings": { |
| Type: schema.TypeList, |
| Computed: true, |
| Optional: 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, |
| ValidateFunc: verify.ValidateEnum([]string{"ORGANIZATION", "SPECIFIC_PROJECTS", "LOCAL"}), |
| Description: `Node group sharing type. Possible values: ["ORGANIZATION", "SPECIFIC_PROJECTS", "LOCAL"]`, |
| }, |
| "project_map": { |
| Type: schema.TypeSet, |
| Optional: 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, |
| }, |
| "project_id": { |
| Type: schema.TypeString, |
| Required: true, |
| Description: `The project id/number should be the same as the key of this project config in the project map.`, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| }, |
| "zone": { |
| Type: schema.TypeString, |
| Computed: true, |
| Optional: true, |
| DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, |
| Description: `Zone where this node group is located`, |
| }, |
| "creation_timestamp": { |
| Type: schema.TypeString, |
| Computed: true, |
| Description: `Creation timestamp in RFC3339 text format.`, |
| }, |
| "size": { |
| Type: schema.TypeInt, |
| Computed: true, |
| Description: `The total number of nodes in the node group.`, |
| }, |
| "project": { |
| Type: schema.TypeString, |
| Optional: true, |
| Computed: true, |
| ForceNew: true, |
| }, |
| "self_link": { |
| Type: schema.TypeString, |
| Computed: true, |
| }, |
| }, |
| UseJSONNumber: true, |
| } |
| } |
| |
| func resourceComputeNodeGroupCreate(d *schema.ResourceData, meta interface{}) error { |
| config := meta.(*transport_tpg.Config) |
| userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) |
| if err != nil { |
| return err |
| } |
| |
| obj := make(map[string]interface{}) |
| descriptionProp, err := expandComputeNodeGroupDescription(d.Get("description"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("description"); !tpgresource.IsEmptyValue(reflect.ValueOf(descriptionProp)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { |
| obj["description"] = descriptionProp |
| } |
| nameProp, err := expandComputeNodeGroupName(d.Get("name"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("name"); !tpgresource.IsEmptyValue(reflect.ValueOf(nameProp)) && (ok || !reflect.DeepEqual(v, nameProp)) { |
| obj["name"] = nameProp |
| } |
| nodeTemplateProp, err := expandComputeNodeGroupNodeTemplate(d.Get("node_template"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("node_template"); !tpgresource.IsEmptyValue(reflect.ValueOf(nodeTemplateProp)) && (ok || !reflect.DeepEqual(v, nodeTemplateProp)) { |
| obj["nodeTemplate"] = nodeTemplateProp |
| } |
| maintenancePolicyProp, err := expandComputeNodeGroupMaintenancePolicy(d.Get("maintenance_policy"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("maintenance_policy"); !tpgresource.IsEmptyValue(reflect.ValueOf(maintenancePolicyProp)) && (ok || !reflect.DeepEqual(v, maintenancePolicyProp)) { |
| obj["maintenancePolicy"] = maintenancePolicyProp |
| } |
| maintenanceWindowProp, err := expandComputeNodeGroupMaintenanceWindow(d.Get("maintenance_window"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("maintenance_window"); !tpgresource.IsEmptyValue(reflect.ValueOf(maintenanceWindowProp)) && (ok || !reflect.DeepEqual(v, maintenanceWindowProp)) { |
| obj["maintenanceWindow"] = maintenanceWindowProp |
| } |
| autoscalingPolicyProp, err := expandComputeNodeGroupAutoscalingPolicy(d.Get("autoscaling_policy"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("autoscaling_policy"); !tpgresource.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"); !tpgresource.IsEmptyValue(reflect.ValueOf(shareSettingsProp)) && (ok || !reflect.DeepEqual(v, shareSettingsProp)) { |
| obj["shareSettings"] = shareSettingsProp |
| } |
| maintenanceIntervalProp, err := expandComputeNodeGroupMaintenanceInterval(d.Get("maintenance_interval"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("maintenance_interval"); !tpgresource.IsEmptyValue(reflect.ValueOf(maintenanceIntervalProp)) && (ok || !reflect.DeepEqual(v, maintenanceIntervalProp)) { |
| obj["maintenanceInterval"] = maintenanceIntervalProp |
| } |
| zoneProp, err := expandComputeNodeGroupZone(d.Get("zone"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("zone"); !tpgresource.IsEmptyValue(reflect.ValueOf(zoneProp)) && (ok || !reflect.DeepEqual(v, zoneProp)) { |
| obj["zone"] = zoneProp |
| } |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/nodeGroups?initialNodeCount=PRE_CREATE_REPLACE_ME") |
| if err != nil { |
| return err |
| } |
| |
| log.Printf("[DEBUG] Creating new NodeGroup: %#v", obj) |
| billingProject := "" |
| |
| project, err := tpgresource.GetProject(d, config) |
| if err != nil { |
| return fmt.Errorf("Error fetching project for NodeGroup: %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 |
| } |
| |
| var sizeParam string |
| if v, ok := d.GetOkExists("initial_size"); ok { |
| sizeParam = fmt.Sprintf("%v", v) |
| } else { |
| if _, ok := d.GetOkExists("autoscaling_policy"); ok { |
| sizeParam = fmt.Sprintf("%v", d.Get("autoscaling_policy.min_nodes")) |
| } else { |
| return errors.New("An initial_size or autoscaling_policy must be configured on node group creation.") |
| } |
| } |
| |
| url = regexp.MustCompile("PRE_CREATE_REPLACE_ME").ReplaceAllLiteralString(url, sizeParam) |
| res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ |
| Config: config, |
| Method: "POST", |
| Project: billingProject, |
| RawURL: url, |
| UserAgent: userAgent, |
| Body: obj, |
| Timeout: d.Timeout(schema.TimeoutCreate), |
| }) |
| if err != nil { |
| return fmt.Errorf("Error creating NodeGroup: %s", err) |
| } |
| |
| // Store the ID now |
| id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/zones/{{zone}}/nodeGroups/{{name}}") |
| if err != nil { |
| return fmt.Errorf("Error constructing id: %s", err) |
| } |
| d.SetId(id) |
| |
| err = ComputeOperationWaitTime( |
| config, res, project, "Creating NodeGroup", userAgent, |
| d.Timeout(schema.TimeoutCreate)) |
| |
| if err != nil { |
| // The resource didn't actually create |
| d.SetId("") |
| return fmt.Errorf("Error waiting to create NodeGroup: %s", err) |
| } |
| |
| log.Printf("[DEBUG] Finished creating NodeGroup %q: %#v", d.Id(), res) |
| |
| return resourceComputeNodeGroupRead(d, meta) |
| } |
| |
| func resourceComputeNodeGroupRead(d *schema.ResourceData, meta interface{}) error { |
| config := meta.(*transport_tpg.Config) |
| userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) |
| if err != nil { |
| return err |
| } |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/nodeGroups/{{name}}") |
| if err != nil { |
| return err |
| } |
| |
| billingProject := "" |
| |
| project, err := tpgresource.GetProject(d, config) |
| if err != nil { |
| return fmt.Errorf("Error fetching project for NodeGroup: %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 |
| } |
| |
| 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("ComputeNodeGroup %q", d.Id())) |
| } |
| |
| if err := d.Set("project", project); err != nil { |
| return fmt.Errorf("Error reading NodeGroup: %s", err) |
| } |
| |
| if err := d.Set("creation_timestamp", flattenComputeNodeGroupCreationTimestamp(res["creationTimestamp"], d, config)); err != nil { |
| return fmt.Errorf("Error reading NodeGroup: %s", err) |
| } |
| if err := d.Set("description", flattenComputeNodeGroupDescription(res["description"], d, config)); err != nil { |
| return fmt.Errorf("Error reading NodeGroup: %s", err) |
| } |
| if err := d.Set("name", flattenComputeNodeGroupName(res["name"], d, config)); err != nil { |
| return fmt.Errorf("Error reading NodeGroup: %s", err) |
| } |
| if err := d.Set("node_template", flattenComputeNodeGroupNodeTemplate(res["nodeTemplate"], d, config)); err != nil { |
| return fmt.Errorf("Error reading NodeGroup: %s", err) |
| } |
| if err := d.Set("size", flattenComputeNodeGroupSize(res["size"], d, config)); err != nil { |
| return fmt.Errorf("Error reading NodeGroup: %s", err) |
| } |
| if err := d.Set("maintenance_policy", flattenComputeNodeGroupMaintenancePolicy(res["maintenancePolicy"], d, config)); err != nil { |
| return fmt.Errorf("Error reading NodeGroup: %s", err) |
| } |
| if err := d.Set("maintenance_window", flattenComputeNodeGroupMaintenanceWindow(res["maintenanceWindow"], d, config)); err != nil { |
| return fmt.Errorf("Error reading NodeGroup: %s", err) |
| } |
| 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("maintenance_interval", flattenComputeNodeGroupMaintenanceInterval(res["maintenanceInterval"], 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) |
| } |
| if err := d.Set("self_link", tpgresource.ConvertSelfLinkToV1(res["selfLink"].(string))); err != nil { |
| return fmt.Errorf("Error reading NodeGroup: %s", err) |
| } |
| |
| return nil |
| } |
| |
| func resourceComputeNodeGroupUpdate(d *schema.ResourceData, meta interface{}) error { |
| config := meta.(*transport_tpg.Config) |
| userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) |
| if err != nil { |
| return err |
| } |
| |
| billingProject := "" |
| |
| project, err := tpgresource.GetProject(d, config) |
| if err != nil { |
| return fmt.Errorf("Error fetching project for NodeGroup: %s", err) |
| } |
| billingProject = project |
| |
| obj := make(map[string]interface{}) |
| descriptionProp, err := expandComputeNodeGroupDescription(d.Get("description"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("description"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, descriptionProp)) { |
| obj["description"] = descriptionProp |
| } |
| nameProp, err := expandComputeNodeGroupName(d.Get("name"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("name"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, nameProp)) { |
| obj["name"] = nameProp |
| } |
| maintenancePolicyProp, err := expandComputeNodeGroupMaintenancePolicy(d.Get("maintenance_policy"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("maintenance_policy"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, maintenancePolicyProp)) { |
| obj["maintenancePolicy"] = maintenancePolicyProp |
| } |
| maintenanceWindowProp, err := expandComputeNodeGroupMaintenanceWindow(d.Get("maintenance_window"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("maintenance_window"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, maintenanceWindowProp)) { |
| obj["maintenanceWindow"] = maintenanceWindowProp |
| } |
| autoscalingPolicyProp, err := expandComputeNodeGroupAutoscalingPolicy(d.Get("autoscaling_policy"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("autoscaling_policy"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (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"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, shareSettingsProp)) { |
| obj["shareSettings"] = shareSettingsProp |
| } |
| maintenanceIntervalProp, err := expandComputeNodeGroupMaintenanceInterval(d.Get("maintenance_interval"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("maintenance_interval"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, maintenanceIntervalProp)) { |
| obj["maintenanceInterval"] = maintenanceIntervalProp |
| } |
| zoneProp, err := expandComputeNodeGroupZone(d.Get("zone"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("zone"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, zoneProp)) { |
| obj["zone"] = zoneProp |
| } |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/nodeGroups/{{name}}") |
| if err != nil { |
| return err |
| } |
| |
| log.Printf("[DEBUG] Updating NodeGroup %q: %#v", d.Id(), obj) |
| updateMask := []string{} |
| |
| if d.HasChange("description") { |
| updateMask = append(updateMask, "description") |
| } |
| |
| if d.HasChange("name") { |
| updateMask = append(updateMask, "name") |
| } |
| |
| if d.HasChange("maintenance_policy") { |
| updateMask = append(updateMask, "maintenancePolicy") |
| } |
| |
| if d.HasChange("maintenance_window") { |
| updateMask = append(updateMask, "maintenanceWindow") |
| } |
| |
| if d.HasChange("autoscaling_policy") { |
| updateMask = append(updateMask, "autoscalingPolicy") |
| } |
| |
| if d.HasChange("share_settings") { |
| updateMask = append(updateMask, "shareSettings") |
| } |
| |
| if d.HasChange("maintenance_interval") { |
| updateMask = append(updateMask, "maintenanceInterval") |
| } |
| |
| if d.HasChange("zone") { |
| updateMask = append(updateMask, "zone") |
| } |
| // updateMask is a URL parameter but not present in the schema, so ReplaceVars |
| // won't set it |
| url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) |
| if err != nil { |
| return err |
| } |
| |
| // err == nil indicates that the billing_project value was found |
| if bp, err := tpgresource.GetBillingProject(d, config); err == nil { |
| billingProject = bp |
| } |
| |
| // if updateMask is empty we are not updating anything so skip the post |
| if len(updateMask) > 0 { |
| res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ |
| Config: config, |
| Method: "PATCH", |
| Project: billingProject, |
| RawURL: url, |
| UserAgent: userAgent, |
| Body: obj, |
| Timeout: d.Timeout(schema.TimeoutUpdate), |
| }) |
| |
| if err != nil { |
| return fmt.Errorf("Error updating NodeGroup %q: %s", d.Id(), err) |
| } else { |
| log.Printf("[DEBUG] Finished updating NodeGroup %q: %#v", d.Id(), res) |
| } |
| |
| err = ComputeOperationWaitTime( |
| config, res, project, "Updating NodeGroup", userAgent, |
| d.Timeout(schema.TimeoutUpdate)) |
| |
| if err != nil { |
| return err |
| } |
| } |
| d.Partial(true) |
| |
| if d.HasChange("node_template") { |
| obj := make(map[string]interface{}) |
| |
| nodeTemplateProp, err := expandComputeNodeGroupNodeTemplate(d.Get("node_template"), d, config) |
| if err != nil { |
| return err |
| } else if v, ok := d.GetOkExists("node_template"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, nodeTemplateProp)) { |
| obj["nodeTemplate"] = nodeTemplateProp |
| } |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/nodeGroups/{{name}}/setNodeTemplate") |
| if err != nil { |
| return err |
| } |
| |
| // err == nil indicates that the billing_project value was found |
| if bp, err := tpgresource.GetBillingProject(d, config); err == nil { |
| billingProject = bp |
| } |
| |
| res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ |
| Config: config, |
| Method: "POST", |
| Project: billingProject, |
| RawURL: url, |
| UserAgent: userAgent, |
| Body: obj, |
| Timeout: d.Timeout(schema.TimeoutUpdate), |
| }) |
| if err != nil { |
| return fmt.Errorf("Error updating NodeGroup %q: %s", d.Id(), err) |
| } else { |
| log.Printf("[DEBUG] Finished updating NodeGroup %q: %#v", d.Id(), res) |
| } |
| |
| err = ComputeOperationWaitTime( |
| config, res, project, "Updating NodeGroup", userAgent, |
| d.Timeout(schema.TimeoutUpdate)) |
| if err != nil { |
| return err |
| } |
| } |
| |
| d.Partial(false) |
| |
| return resourceComputeNodeGroupRead(d, meta) |
| } |
| |
| func resourceComputeNodeGroupDelete(d *schema.ResourceData, meta interface{}) error { |
| config := meta.(*transport_tpg.Config) |
| userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) |
| if err != nil { |
| return err |
| } |
| |
| billingProject := "" |
| |
| project, err := tpgresource.GetProject(d, config) |
| if err != nil { |
| return fmt.Errorf("Error fetching project for NodeGroup: %s", err) |
| } |
| billingProject = project |
| |
| url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/zones/{{zone}}/nodeGroups/{{name}}") |
| if err != nil { |
| return err |
| } |
| |
| var obj map[string]interface{} |
| log.Printf("[DEBUG] Deleting NodeGroup %q", d.Id()) |
| |
| // err == nil indicates that the billing_project value was found |
| if bp, err := tpgresource.GetBillingProject(d, config); err == nil { |
| billingProject = bp |
| } |
| |
| res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ |
| Config: config, |
| Method: "DELETE", |
| Project: billingProject, |
| RawURL: url, |
| UserAgent: userAgent, |
| Body: obj, |
| Timeout: d.Timeout(schema.TimeoutDelete), |
| }) |
| if err != nil { |
| return transport_tpg.HandleNotFoundError(err, d, "NodeGroup") |
| } |
| |
| err = ComputeOperationWaitTime( |
| config, res, project, "Deleting NodeGroup", userAgent, |
| d.Timeout(schema.TimeoutDelete)) |
| |
| if err != nil { |
| return err |
| } |
| |
| log.Printf("[DEBUG] Finished deleting NodeGroup %q: %#v", d.Id(), res) |
| return nil |
| } |
| |
| func resourceComputeNodeGroupImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { |
| config := meta.(*transport_tpg.Config) |
| if err := tpgresource.ParseImportId([]string{ |
| "^projects/(?P<project>[^/]+)/zones/(?P<zone>[^/]+)/nodeGroups/(?P<name>[^/]+)$", |
| "^(?P<project>[^/]+)/(?P<zone>[^/]+)/(?P<name>[^/]+)$", |
| "^(?P<zone>[^/]+)/(?P<name>[^/]+)$", |
| "^(?P<name>[^/]+)$", |
| }, d, config); err != nil { |
| return nil, err |
| } |
| |
| // Replace import id for the resource id |
| id, err := tpgresource.ReplaceVars(d, config, "projects/{{project}}/zones/{{zone}}/nodeGroups/{{name}}") |
| if err != nil { |
| return nil, fmt.Errorf("Error constructing id: %s", err) |
| } |
| d.SetId(id) |
| |
| return []*schema.ResourceData{d}, nil |
| } |
| |
| func flattenComputeNodeGroupCreationTimestamp(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeNodeGroupDescription(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeNodeGroupName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeNodeGroupNodeTemplate(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return v |
| } |
| return tpgresource.ConvertSelfLinkToV1(v.(string)) |
| } |
| |
| func flattenComputeNodeGroupSize(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| // Handles the string fixed64 format |
| if strVal, ok := v.(string); ok { |
| if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { |
| return intVal |
| } |
| } |
| |
| // number values are represented as float64 |
| if floatVal, ok := v.(float64); ok { |
| intVal := int(floatVal) |
| return intVal |
| } |
| |
| return v // let terraform core handle it otherwise |
| } |
| |
| func flattenComputeNodeGroupMaintenancePolicy(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeNodeGroupMaintenanceWindow(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return nil |
| } |
| original := v.(map[string]interface{}) |
| if len(original) == 0 { |
| return nil |
| } |
| transformed := make(map[string]interface{}) |
| transformed["start_time"] = |
| flattenComputeNodeGroupMaintenanceWindowStartTime(original["startTime"], d, config) |
| return []interface{}{transformed} |
| } |
| func flattenComputeNodeGroupMaintenanceWindowStartTime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeNodeGroupAutoscalingPolicy(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return nil |
| } |
| original := v.(map[string]interface{}) |
| if len(original) == 0 { |
| return nil |
| } |
| transformed := make(map[string]interface{}) |
| transformed["mode"] = |
| flattenComputeNodeGroupAutoscalingPolicyMode(original["mode"], d, config) |
| transformed["min_nodes"] = |
| flattenComputeNodeGroupAutoscalingPolicyMinNodes(original["minNodes"], d, config) |
| transformed["max_nodes"] = |
| flattenComputeNodeGroupAutoscalingPolicyMaxNodes(original["maxNodes"], d, config) |
| return []interface{}{transformed} |
| } |
| func flattenComputeNodeGroupAutoscalingPolicyMode(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeNodeGroupAutoscalingPolicyMinNodes(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| // Handles the string fixed64 format |
| if strVal, ok := v.(string); ok { |
| if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { |
| return intVal |
| } |
| } |
| |
| // number values are represented as float64 |
| if floatVal, ok := v.(float64); ok { |
| intVal := int(floatVal) |
| return intVal |
| } |
| |
| return v // let terraform core handle it otherwise |
| } |
| |
| func flattenComputeNodeGroupAutoscalingPolicyMaxNodes(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| // Handles the string fixed64 format |
| if strVal, ok := v.(string); ok { |
| if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { |
| return intVal |
| } |
| } |
| |
| // number values are represented as float64 |
| if floatVal, ok := v.(float64); ok { |
| intVal := int(floatVal) |
| return intVal |
| } |
| |
| return v // let terraform core handle it otherwise |
| } |
| |
| func flattenComputeNodeGroupShareSettings(v interface{}, d *schema.ResourceData, config *transport_tpg.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 *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeNodeGroupShareSettingsProjectMap(v interface{}, d *schema.ResourceData, config *transport_tpg.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 *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeNodeGroupMaintenanceInterval(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| return v |
| } |
| |
| func flattenComputeNodeGroupZone(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { |
| if v == nil { |
| return v |
| } |
| return tpgresource.NameFromSelfLinkStateFunc(v) |
| } |
| |
| func expandComputeNodeGroupDescription(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeNodeGroupName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeNodeGroupNodeTemplate(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| f, err := tpgresource.ParseRegionalFieldValue("nodeTemplates", v.(string), "project", "region", "zone", d, config, true) |
| if err != nil { |
| return nil, fmt.Errorf("Invalid value for node_template: %s", err) |
| } |
| return f.RelativeLink(), nil |
| } |
| |
| func expandComputeNodeGroupMaintenancePolicy(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeNodeGroupMaintenanceWindow(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.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{}) |
| |
| transformedStartTime, err := expandComputeNodeGroupMaintenanceWindowStartTime(original["start_time"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedStartTime); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["startTime"] = transformedStartTime |
| } |
| |
| return transformed, nil |
| } |
| |
| func expandComputeNodeGroupMaintenanceWindowStartTime(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeNodeGroupAutoscalingPolicy(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.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{}) |
| |
| transformedMode, err := expandComputeNodeGroupAutoscalingPolicyMode(original["mode"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedMode); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["mode"] = transformedMode |
| } |
| |
| transformedMinNodes, err := expandComputeNodeGroupAutoscalingPolicyMinNodes(original["min_nodes"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedMinNodes); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["minNodes"] = transformedMinNodes |
| } |
| |
| transformedMaxNodes, err := expandComputeNodeGroupAutoscalingPolicyMaxNodes(original["max_nodes"], d, config) |
| if err != nil { |
| return nil, err |
| } else if val := reflect.ValueOf(transformedMaxNodes); val.IsValid() && !tpgresource.IsEmptyValue(val) { |
| transformed["maxNodes"] = transformedMaxNodes |
| } |
| |
| return transformed, nil |
| } |
| |
| func expandComputeNodeGroupAutoscalingPolicyMode(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeNodeGroupAutoscalingPolicyMinNodes(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeNodeGroupAutoscalingPolicyMaxNodes(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeNodeGroupShareSettings(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.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() && !tpgresource.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() && !tpgresource.IsEmptyValue(val) { |
| transformed["projectMap"] = transformedProjectMap |
| } |
| |
| return transformed, nil |
| } |
| |
| func expandComputeNodeGroupShareSettingsShareType(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeNodeGroupShareSettingsProjectMap(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.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() && !tpgresource.IsEmptyValue(val) { |
| transformed["projectId"] = transformedProjectId |
| } |
| |
| transformedId, err := tpgresource.ExpandString(original["id"], d, config) |
| if err != nil { |
| return nil, err |
| } |
| m[transformedId] = transformed |
| } |
| return m, nil |
| } |
| |
| func expandComputeNodeGroupShareSettingsProjectMapProjectId(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeNodeGroupMaintenanceInterval(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| return v, nil |
| } |
| |
| func expandComputeNodeGroupZone(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { |
| f, err := tpgresource.ParseGlobalFieldValue("zones", v.(string), "project", d, config, true) |
| if err != nil { |
| return nil, fmt.Errorf("Invalid value for zone: %s", err) |
| } |
| return f.RelativeLink(), nil |
| } |