diff --git a/docs/resources/gaussdb_opengauss_instance.md b/docs/resources/gaussdb_opengauss_instance.md index 80e4e2cbf5..3630a84b40 100644 --- a/docs/resources/gaussdb_opengauss_instance.md +++ b/docs/resources/gaussdb_opengauss_instance.md @@ -135,7 +135,7 @@ The following arguments are supported: Changing this parameter will create a new resource. -* `configuration_id` - (Optional, String, ForceNew) Specifies the parameter template ID. +* `configuration_id` - (Optional, String) Specifies the parameter template ID. Changing this parameter will create a new resource. * `sharding_num` - (Optional, Int) Specifies the sharding number. diff --git a/huaweicloud/services/acceptance/gaussdb/resource_huaweicloud_gaussdb_opengauss_instance_test.go b/huaweicloud/services/acceptance/gaussdb/resource_huaweicloud_gaussdb_opengauss_instance_test.go index aa6e855324..4ef2c30a3b 100644 --- a/huaweicloud/services/acceptance/gaussdb/resource_huaweicloud_gaussdb_opengauss_instance_test.go +++ b/huaweicloud/services/acceptance/gaussdb/resource_huaweicloud_gaussdb_opengauss_instance_test.go @@ -326,6 +326,22 @@ data "huaweicloud_gaussdb_opengauss_flavors" "test" { ha_mode = "enterprise" } +resource "huaweicloud_gaussdb_opengauss_parameter_template" "test" { + name = "%[2]s" + engine_version = "8.201" + instance_mode = "independent" + + parameters { + name = "cn:auto_explain_log_min_duration" + value = "1000" + } + + parameters { + name = "dn:a_format_date_timestamp" + value = "on" + } +} + resource "huaweicloud_gaussdb_opengauss_instance" "test" { depends_on = [ huaweicloud_networking_secgroup_rule.in_v4_tcp_opengauss, @@ -342,6 +358,7 @@ resource "huaweicloud_gaussdb_opengauss_instance" "test" { sharding_num = 2 coordinator_num = 3 replica_num = %[4]d + configuration_id = huaweicloud_gaussdb_opengauss_parameter_template.test.id availability_zone = join(",", [data.huaweicloud_availability_zones.test.names[0], data.huaweicloud_availability_zones.test.names[1], data.huaweicloud_availability_zones.test.names[2]]) diff --git a/huaweicloud/services/gaussdb/resource_huaweicloud_gaussdb_opengauss_instance.go b/huaweicloud/services/gaussdb/resource_huaweicloud_gaussdb_opengauss_instance.go index de4348d8b0..fe090fc3fb 100644 --- a/huaweicloud/services/gaussdb/resource_huaweicloud_gaussdb_opengauss_instance.go +++ b/huaweicloud/services/gaussdb/resource_huaweicloud_gaussdb_opengauss_instance.go @@ -39,6 +39,7 @@ const ( // @API GaussDB POST /v3/{project_id}/instances/{instance_id}/action // @API GaussDB PUT /v3/{project_id}/instances/{instance_id}/backups/policy // @API GaussDB PUT /v3/{project_id}/instance/{instance_id}/flavor +// @API GaussDB PUT /v3/{project_id}/configurations/{config_id}/apply // @API GaussDB DELETE /v3/{project_id}/instances/{instance_id}/tag // @API GaussDB DELETE /v3/{project_id}/instances/{instance_id} // @API BSS GET /v2/orders/customer-orders/details/{order_id} @@ -181,7 +182,6 @@ func ResourceOpenGaussInstance() *schema.Resource { "configuration_id": { Type: schema.TypeString, Optional: true, - ForceNew: true, }, "port": { Type: schema.TypeString, @@ -839,11 +839,6 @@ func setOpenGaussPrivateIpsAndEndpoints(d *schema.ResourceData, instance interfa } func setGaussDBMySQLParameters(ctx context.Context, d *schema.ResourceData, client *golangsdk.ServiceClient) diag.Diagnostics { - rawParameters := d.Get("parameters").(*schema.Set) - if rawParameters.Len() == 0 { - return nil - } - var ( httpUrl = "v3.1/{project_id}/instances/{instance_id}/configurations" ) @@ -865,16 +860,21 @@ func setGaussDBMySQLParameters(ctx context.Context, d *schema.ResourceData, clie return diag.FromErr(err) } + rawParameters := d.Get("parameters").(*schema.Set) rawParameterMap := make(map[string]bool) for _, rawParameter := range rawParameters.List() { rawParameterMap[rawParameter.(map[string]interface{})["name"].(string)] = true } + var configurationRestart bool var params []map[string]interface{} parametersList := utils.PathSearch("configuration_parameters", getRespBody, make([]interface{}, 0)).([]interface{}) for _, v := range parametersList { name := utils.PathSearch("name", v, "").(string) value := utils.PathSearch("value", v, nil) + if utils.PathSearch("restart_required", v, false).(bool) { + configurationRestart = true + } if rawParameterMap[name] { p := map[string]interface{}{ "name": name, @@ -897,6 +897,13 @@ func setGaussDBMySQLParameters(ctx context.Context, d *schema.ResourceData, clie }) } } + if configurationRestart && ctx.Value(ctxType("configurationChanged")) == "true" { + diagnostics = append(diagnostics, diag.Diagnostic{ + Severity: diag.Warning, + Summary: "Configuration Changed", + Detail: "Configuration changed, the instance may needs reboot.", + }) + } if len(diagnostics) > 0 { return diagnostics } @@ -959,7 +966,23 @@ func resourceOpenGaussInstanceUpdate(ctx context.Context, d *schema.ResourceData } } - if d.HasChange("parameters") { + if d.HasChanges("configuration_id") { + ctx, err = updateConfiguration(ctx, d, client) + if err != nil { + return diag.FromErr(err) + } + + // if parameters is set, it should be modified + if params, ok := d.GetOk("parameters"); ok { + updateOpts := buildGaussDBOpenGaussParameters(params.(*schema.Set).List()) + _, err = modifyParameters(ctx, client, d, schema.TimeoutUpdate, &updateOpts) + if err != nil { + return diag.FromErr(err) + } + } + } + + if d.HasChange("parameters") && !d.HasChanges("configuration_id") { ctx, err = updateParameters(ctx, d, client) if err != nil { return diag.FromErr(err) @@ -1340,6 +1363,63 @@ func buildUpdateInstanceFlavorBodyParams(d *schema.ResourceData) map[string]inte return bodyParams } +func updateConfiguration(ctx context.Context, d *schema.ResourceData, client *golangsdk.ServiceClient) (context.Context, error) { + var ( + httpUrl = "v3/{project_id}/configurations/{config_id}/apply" + ) + + updatePath := client.Endpoint + httpUrl + updatePath = strings.ReplaceAll(updatePath, "{project_id}", client.ProjectID) + updatePath = strings.ReplaceAll(updatePath, "{config_id}", d.Get("configuration_id").(string)) + + updateOpt := golangsdk.RequestOpts{ + KeepResponseBody: true, + } + updateOpt.JSONBody = utils.RemoveNil(buildUpdateInstanceConfigurationBodyParams(d)) + retryFunc := func() (interface{}, bool, error) { + res, err := client.Request("PUT", updatePath, &updateOpt) + retry, err := handleMultiOperationsError(err) + return res, retry, err + } + r, err := common.RetryContextWithWaitForState(&common.RetryContextWithWaitForStateParam{ + Ctx: ctx, + RetryFunc: retryFunc, + WaitFunc: instanceStateRefreshFunc(client, d.Id()), + WaitTarget: []string{"ACTIVE"}, + Timeout: d.Timeout(schema.TimeoutUpdate), + DelayTimeout: 10 * time.Second, + PollInterval: 10 * time.Second, + }) + if err != nil { + return ctx, fmt.Errorf("error updating GaussDB OpenGauss instance (%s) configuration: %s", d.Id(), err) + } + + updateRespBody, err := utils.FlattenResponse(r.(*http.Response)) + if err != nil { + return ctx, err + } + jobId := utils.PathSearch("job_id", updateRespBody, nil) + if jobId == nil { + return ctx, fmt.Errorf("error updating GaussDB OpenGauss instance configuration: job_id is not found in API response") + } + err = checkGaussDBOpenGaussJobFinish(ctx, client, jobId.(string), 2, d.Timeout(schema.TimeoutUpdate)) + if err != nil { + return ctx, err + } + + // Sending configurationChanged to Read to warn users the instance needs a reboot. + ctx = context.WithValue(ctx, ctxType("configurationChanged"), "true") + + return ctx, nil +} + +func buildUpdateInstanceConfigurationBodyParams(d *schema.ResourceData) map[string]interface{} { + bodyParams := map[string]interface{}{ + "instance_ids": []string{d.Id()}, + } + return bodyParams +} + func updateParameters(ctx context.Context, d *schema.ResourceData, client *golangsdk.ServiceClient) (context.Context, error) { o, n := d.GetChange("parameters") os, ns := o.(*schema.Set), n.(*schema.Set)