Skip to content

Commit

Permalink
Merge pull request #31747 from hashicorp/b-aws_redshiftserverless_wor…
Browse files Browse the repository at this point in the history
…kgroup.config_parameter

r/aws_redshiftserverless_workgroup: `config_parameter` fixes
  • Loading branch information
ewbankkit authored Jun 2, 2023
2 parents ff69dbc + faf58aa commit a79e83a
Show file tree
Hide file tree
Showing 4 changed files with 309 additions and 49 deletions.
11 changes: 11 additions & 0 deletions .changelog/31747.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
```release-note:enhancement
resource/aws_redshiftserverless_workgroup: Additional supported values for `config_parameter.parameter_key`
```

```release-note:bug
resource/aws_redshiftserverless_workgroup: Change `config_parameter` from `TypeList` to `TypeSet` as order is not significant
```

```release-note:bug
resource/aws_redshiftserverless_workgroup: Fix `ValidationException: Can't update multiple configurations at the same time` errors
```
162 changes: 114 additions & 48 deletions internal/service/redshiftserverless/workgroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package redshiftserverless

import (
"context"
"fmt"
"log"
"time"

Expand Down Expand Up @@ -50,15 +51,33 @@ func ResourceWorkgroup() *schema.Resource {
Computed: true,
},
"config_parameter": {
Type: schema.TypeList,
Type: schema.TypeSet,
Optional: true,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"parameter_key": {
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice([]string{"datestyle", "enable_user_activity_logging", "query_group", "search_path", "max_query_execution_time"}, false),
Required: true,
Type: schema.TypeString,
ValidateFunc: validation.StringInSlice([]string{
// https://docs.aws.amazon.com/redshift-serverless/latest/APIReference/API_CreateWorkgroup.html#redshiftserverless-CreateWorkgroup-request-configParameters
"auto_mv",
"datestyle",
"enable_case_sensitive_identifier", // "ValidationException: The parameter key enable_case_sensitivity_identifier isn't supported. Supported values: [[max_query_cpu_usage_percent, max_join_row_count, auto_mv, max_query_execution_time, max_query_queue_time, max_query_blocks_read, max_return_row_count, search_path, datestyle, max_query_cpu_time, max_io_skew, max_scan_row_count, query_group, enable_user_activity_logging, enable_case_sensitive_identifier, max_nested_loop_join_row_count, max_query_temp_blocks_to_disk, max_cpu_skew]]"
"enable_user_activity_logging",
"query_group",
"search_path",
// https://docs.aws.amazon.com/redshift/latest/dg/cm-c-wlm-query-monitoring-rules.html#cm-c-wlm-query-monitoring-metrics-serverless
"max_query_cpu_time",
"max_query_blocks_read",
"max_scan_row_count",
"max_query_execution_time",
"max_query_queue_time",
"max_query_cpu_usage_percent",
"max_query_temp_blocks_to_disk",
"max_join_row_count",
"max_nested_loop_join_row_count",
}, false),
Required: true,
},
"parameter_value": {
Type: schema.TypeString,
Expand All @@ -85,14 +104,6 @@ func ResourceWorkgroup() *schema.Resource {
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"vpc_endpoint_id": {
Type: schema.TypeString,
Computed: true,
},
"vpc_id": {
Type: schema.TypeString,
Computed: true,
},
"network_interface": {
Type: schema.TypeList,
Computed: true,
Expand All @@ -117,6 +128,14 @@ func ResourceWorkgroup() *schema.Resource {
},
},
},
"vpc_endpoint_id": {
Type: schema.TypeString,
Computed: true,
},
"vpc_id": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
Expand Down Expand Up @@ -173,18 +192,19 @@ func resourceWorkgroupCreate(ctx context.Context, d *schema.ResourceData, meta i
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).RedshiftServerlessConn()

name := d.Get("workgroup_name").(string)
input := redshiftserverless.CreateWorkgroupInput{
NamespaceName: aws.String(d.Get("namespace_name").(string)),
Tags: GetTagsIn(ctx),
WorkgroupName: aws.String(d.Get("workgroup_name").(string)),
WorkgroupName: aws.String(name),
}

if v, ok := d.GetOk("base_capacity"); ok {
input.BaseCapacity = aws.Int64(int64(v.(int)))
}

if v, ok := d.GetOk("config_parameter"); ok && len(v.([]interface{})) > 0 {
input.ConfigParameters = expandConfigParameters(v.([]interface{}))
if v, ok := d.GetOk("config_parameter"); ok && v.(*schema.Set).Len() > 0 {
input.ConfigParameters = expandConfigParameters(v.(*schema.Set).List())
}

if v, ok := d.GetOk("enhanced_vpc_routing"); ok {
Expand All @@ -203,16 +223,16 @@ func resourceWorkgroupCreate(ctx context.Context, d *schema.ResourceData, meta i
input.SubnetIds = flex.ExpandStringSet(v.(*schema.Set))
}

out, err := conn.CreateWorkgroupWithContext(ctx, &input)
output, err := conn.CreateWorkgroupWithContext(ctx, &input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "creating Redshift Serverless Workgroup : %s", err)
return sdkdiag.AppendErrorf(diags, "creating Redshift Serverless Workgroup (%s): %s", name, err)
}

d.SetId(aws.StringValue(out.Workgroup.WorkgroupName))
d.SetId(aws.StringValue(output.Workgroup.WorkgroupName))

if _, err := waitWorkgroupAvailable(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil {
return sdkdiag.AppendErrorf(diags, "waiting for Redshift Serverless Workgroup (%s) to be created: %s", d.Id(), err)
return sdkdiag.AppendErrorf(diags, "waiting for Redshift Serverless Workgroup (%s) create: %s", d.Id(), err)
}

return append(diags, resourceWorkgroupRead(ctx, d, meta)...)
Expand All @@ -223,6 +243,7 @@ func resourceWorkgroupRead(ctx context.Context, d *schema.ResourceData, meta int
conn := meta.(*conns.AWSClient).RedshiftServerlessConn()

out, err := FindWorkgroupByName(ctx, conn, d.Id())

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] Redshift Serverless Workgroup (%s) not found, removing from state", d.Id())
d.SetId("")
Expand All @@ -236,20 +257,19 @@ func resourceWorkgroupRead(ctx context.Context, d *schema.ResourceData, meta int
arn := aws.StringValue(out.WorkgroupArn)
d.Set("arn", arn)
d.Set("base_capacity", out.BaseCapacity)
if err := d.Set("config_parameter", flattenConfigParameters(out.ConfigParameters)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting config_parameter: %s", err)
}
if err := d.Set("endpoint", []interface{}{flattenEndpoint(out.Endpoint)}); err != nil {
return sdkdiag.AppendErrorf(diags, "setting endpoint: %s", err)
}
d.Set("enhanced_vpc_routing", out.EnhancedVpcRouting)
d.Set("namespace_name", out.NamespaceName)
d.Set("publicly_accessible", out.PubliclyAccessible)
d.Set("security_group_ids", flex.FlattenStringSet(out.SecurityGroupIds))
d.Set("subnet_ids", flex.FlattenStringSet(out.SubnetIds))
d.Set("workgroup_id", out.WorkgroupId)
d.Set("workgroup_name", out.WorkgroupName)
if err := d.Set("config_parameter", flattenConfigParameters(out.ConfigParameters)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting config_parameter: %s", err)
}

if err := d.Set("endpoint", []interface{}{flattenEndpoint(out.Endpoint)}); err != nil {
return sdkdiag.AppendErrorf(diags, "setting endpoint: %s", err)
}

return diags
}
Expand All @@ -258,42 +278,71 @@ func resourceWorkgroupUpdate(ctx context.Context, d *schema.ResourceData, meta i
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).RedshiftServerlessConn()

if d.HasChangesExcept("tags", "tags_all") {
// You can't update multiple parameters in one request.

if d.HasChange("base_capacity") {
input := &redshiftserverless.UpdateWorkgroupInput{
BaseCapacity: aws.Int64(int64(d.Get("base_capacity").(int))),
WorkgroupName: aws.String(d.Id()),
}

if v, ok := d.GetOk("base_capacity"); ok {
input.BaseCapacity = aws.Int64(int64(v.(int)))
if err := updateWorkgroup(ctx, conn, input, d.Timeout(schema.TimeoutUpdate)); err != nil {
return sdkdiag.AppendFromErr(diags, err)
}
}

if d.HasChange("config_parameter") {
input := &redshiftserverless.UpdateWorkgroupInput{
ConfigParameters: expandConfigParameters(d.Get("config_parameter").(*schema.Set).List()),
WorkgroupName: aws.String(d.Id()),
}

if v, ok := d.GetOk("config_parameter"); ok && len(v.([]interface{})) > 0 {
input.ConfigParameters = expandConfigParameters(v.([]interface{}))
if err := updateWorkgroup(ctx, conn, input, d.Timeout(schema.TimeoutUpdate)); err != nil {
return sdkdiag.AppendFromErr(diags, err)
}
}

if v, ok := d.GetOk("enhanced_vpc_routing"); ok {
input.EnhancedVpcRouting = aws.Bool(v.(bool))
if d.HasChange("enhanced_vpc_routing") {
input := &redshiftserverless.UpdateWorkgroupInput{
EnhancedVpcRouting: aws.Bool(d.Get("enhanced_vpc_routing").(bool)),
WorkgroupName: aws.String(d.Id()),
}

if v, ok := d.GetOk("publicly_accessible"); ok {
input.PubliclyAccessible = aws.Bool(v.(bool))
if err := updateWorkgroup(ctx, conn, input, d.Timeout(schema.TimeoutUpdate)); err != nil {
return sdkdiag.AppendFromErr(diags, err)
}
}

if v, ok := d.GetOk("security_group_ids"); ok && v.(*schema.Set).Len() > 0 {
input.SecurityGroupIds = flex.ExpandStringSet(v.(*schema.Set))
if d.HasChange("publicly_accessible") {
input := &redshiftserverless.UpdateWorkgroupInput{
PubliclyAccessible: aws.Bool(d.Get("publicly_accessible").(bool)),
WorkgroupName: aws.String(d.Id()),
}

if v, ok := d.GetOk("subnet_ids"); ok && v.(*schema.Set).Len() > 0 {
input.SubnetIds = flex.ExpandStringSet(v.(*schema.Set))
if err := updateWorkgroup(ctx, conn, input, d.Timeout(schema.TimeoutUpdate)); err != nil {
return sdkdiag.AppendFromErr(diags, err)
}
}

_, err := conn.UpdateWorkgroupWithContext(ctx, input)
if err != nil {
return sdkdiag.AppendErrorf(diags, "updating Redshift Serverless Workgroup (%s): %s", d.Id(), err)
if d.HasChange("security_group_ids") {
input := &redshiftserverless.UpdateWorkgroupInput{
SecurityGroupIds: flex.ExpandStringSet(d.Get("security_group_ids").(*schema.Set)),
WorkgroupName: aws.String(d.Id()),
}

if _, err := waitWorkgroupAvailable(ctx, conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil {
return sdkdiag.AppendErrorf(diags, "waiting for Redshift Serverless Workgroup (%s) to be updated: %s", d.Id(), err)
if err := updateWorkgroup(ctx, conn, input, d.Timeout(schema.TimeoutUpdate)); err != nil {
return sdkdiag.AppendFromErr(diags, err)
}
}

if d.HasChange("subnet_ids") {
input := &redshiftserverless.UpdateWorkgroupInput{
SubnetIds: flex.ExpandStringSet(d.Get("subnet_ids").(*schema.Set)),
WorkgroupName: aws.String(d.Id()),
}

if err := updateWorkgroup(ctx, conn, input, d.Timeout(schema.TimeoutUpdate)); err != nil {
return sdkdiag.AppendFromErr(diags, err)
}
}

Expand All @@ -304,6 +353,7 @@ func resourceWorkgroupDelete(ctx context.Context, d *schema.ResourceData, meta i
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).RedshiftServerlessConn()

log.Printf("[DEBUG] Deleting Redshift Serverless Workgroup: %s", d.Id())
_, err := tfresource.RetryWhenAWSErrMessageContains(ctx, 10*time.Minute,
func() (interface{}, error) {
return conn.DeleteWorkgroupWithContext(ctx, &redshiftserverless.DeleteWorkgroupInput{
Expand All @@ -313,20 +363,36 @@ func resourceWorkgroupDelete(ctx context.Context, d *schema.ResourceData, meta i
// "ConflictException: There is an operation running on the workgroup. Try deleting the workgroup again later."
redshiftserverless.ErrCodeConflictException, "operation running")

if tfawserr.ErrCodeEquals(err, redshiftserverless.ErrCodeResourceNotFoundException) {
return diags
}

if err != nil {
if tfawserr.ErrCodeEquals(err, redshiftserverless.ErrCodeResourceNotFoundException) {
return diags
}
return sdkdiag.AppendErrorf(diags, "deleting Redshift Serverless Workgroup (%s): %s", d.Id(), err)
}

if _, err := waitWorkgroupDeleted(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil {
return sdkdiag.AppendErrorf(diags, "deleting Redshift Serverless Workgroup (%s): waiting for completion: %s", d.Id(), err)
return sdkdiag.AppendErrorf(diags, "waiting for Redshift Serverless Workgroup (%s) delete: %s", d.Id(), err)
}

return diags
}

func updateWorkgroup(ctx context.Context, conn *redshiftserverless.RedshiftServerless, input *redshiftserverless.UpdateWorkgroupInput, timeout time.Duration) error {
name := aws.StringValue(input.WorkgroupName)
_, err := conn.UpdateWorkgroupWithContext(ctx, input)

if err != nil {
return fmt.Errorf("updating Redshift Serverless Workgroup (%s): %w", name, err)
}

if _, err := waitWorkgroupAvailable(ctx, conn, name, timeout); err != nil {
return fmt.Errorf("waiting for Redshift Serverless Workgroup (%s) update: %w", name, err)
}

return nil
}

func expandConfigParameter(tfMap map[string]interface{}) *redshiftserverless.ConfigParameter {
if tfMap == nil {
return nil
Expand Down
Loading

0 comments on commit a79e83a

Please sign in to comment.