Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

r/redshift_usage_limit - new resource #24916

Merged
merged 5 commits into from
May 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/24916.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_redshift_usage_limit
```
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -1771,6 +1771,7 @@ func Provider() *schema.Provider {
"aws_redshift_snapshot_schedule": redshift.ResourceSnapshotSchedule(),
"aws_redshift_snapshot_schedule_association": redshift.ResourceSnapshotScheduleAssociation(),
"aws_redshift_subnet_group": redshift.ResourceSubnetGroup(),
"aws_redshift_usage_limit": redshift.ResourceUsageLimit(),

"aws_resourcegroups_group": resourcegroups.ResourceGroup(),

Expand Down
29 changes: 29 additions & 0 deletions internal/service/redshift/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,32 @@ func FindHsmClientCertificateByID(conn *redshift.Redshift, id string) (*redshift

return out.HsmClientCertificates[0], nil
}

func FindUsageLimitByID(conn *redshift.Redshift, id string) (*redshift.UsageLimit, error) {
input := &redshift.DescribeUsageLimitsInput{
UsageLimitId: aws.String(id),
}

output, err := conn.DescribeUsageLimits(input)

if tfawserr.ErrCodeEquals(err, redshift.ErrCodeUsageLimitNotFoundFault) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil || len(output.UsageLimits) == 0 || output.UsageLimits[0] == nil {
return nil, tfresource.NewEmptyResultError(input)
}

if count := len(output.UsageLimits); count > 1 {
return nil, tfresource.NewTooManyResultsError(count, input)
}

return output.UsageLimits[0], nil
}
209 changes: 209 additions & 0 deletions internal/service/redshift/usage_limit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
package redshift

import (
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/service/redshift"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
)

func ResourceUsageLimit() *schema.Resource {
return &schema.Resource{
Create: resourceUsageLimitCreate,
Read: resourceUsageLimitRead,
Update: resourceUsageLimitUpdate,
Delete: resourceUsageLimitDelete,

Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"amount": {
Type: schema.TypeInt,
Required: true,
},
"arn": {
Type: schema.TypeString,
Computed: true,
},
"breach_action": {
Type: schema.TypeString,
Optional: true,
Default: redshift.UsageLimitBreachActionLog,
ValidateFunc: validation.StringInSlice(redshift.UsageLimitBreachAction_Values(), false),
},
"cluster_identifier": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"feature_type": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice(redshift.UsageLimitFeatureType_Values(), false),
},
"limit_type": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice(redshift.UsageLimitLimitType_Values(), false),
},
"period": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Default: redshift.UsageLimitPeriodMonthly,
ValidateFunc: validation.StringInSlice(redshift.UsageLimitPeriod_Values(), false),
},
"tags": tftags.TagsSchema(),
"tags_all": tftags.TagsSchemaComputed(),
},

CustomizeDiff: verify.SetTagsDiff,
}
}

func resourceUsageLimitCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).RedshiftConn
defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig
tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{})))

clusterId := d.Get("cluster_identifier").(string)

input := redshift.CreateUsageLimitInput{
Amount: aws.Int64(int64(d.Get("amount").(int))),
ClusterIdentifier: aws.String(clusterId),
FeatureType: aws.String(d.Get("feature_type").(string)),
LimitType: aws.String(d.Get("limit_type").(string)),
}

if v, ok := d.GetOk("breach_action"); ok {
input.BreachAction = aws.String(v.(string))
}

if v, ok := d.GetOk("period"); ok {
input.Period = aws.String(v.(string))
}

input.Tags = Tags(tags.IgnoreAWS())

out, err := conn.CreateUsageLimit(&input)

if err != nil {
return fmt.Errorf("error creating Redshift Usage Limit (%s): %s", clusterId, err)
}

d.SetId(aws.StringValue(out.UsageLimitId))

return resourceUsageLimitRead(d, meta)
}

func resourceUsageLimitRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).RedshiftConn
defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig
ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig

out, err := FindUsageLimitByID(conn, d.Id())
if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] Redshift Usage Limit (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("error reading Redshift Usage Limit (%s): %w", d.Id(), err)
}

arn := arn.ARN{
Partition: meta.(*conns.AWSClient).Partition,
Service: "redshift",
Region: meta.(*conns.AWSClient).Region,
AccountID: meta.(*conns.AWSClient).AccountID,
Resource: fmt.Sprintf("usagelimit:%s", d.Id()),
}.String()

d.Set("arn", arn)
d.Set("amount", out.Amount)
d.Set("period", out.Period)
d.Set("limit_type", out.LimitType)
d.Set("feature_type", out.FeatureType)
d.Set("breach_action", out.BreachAction)
d.Set("cluster_identifier", out.ClusterIdentifier)

tags := KeyValueTags(out.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig)

//lintignore:AWSR002
if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil {
return fmt.Errorf("error setting tags: %w", err)
}

if err := d.Set("tags_all", tags.Map()); err != nil {
return fmt.Errorf("error setting tags_all: %w", err)
}

return nil
}

func resourceUsageLimitUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).RedshiftConn

if d.HasChangesExcept("tags", "tags_all") {
input := &redshift.ModifyUsageLimitInput{
UsageLimitId: aws.String(d.Id()),
}

if d.HasChange("amount") {
input.Amount = aws.Int64(int64(d.Get("amount").(int)))
}

if d.HasChange("breach_action") {
input.BreachAction = aws.String(d.Get("breach_action").(string))
}

_, err := conn.ModifyUsageLimit(input)
if err != nil {
return fmt.Errorf("error updating Redshift Usage Limit (%s): %w", d.Id(), err)
}
}

if d.HasChange("tags_all") {
o, n := d.GetChange("tags_all")

if err := UpdateTags(conn, d.Get("arn").(string), o, n); err != nil {
return fmt.Errorf("error updating Redshift Usage Limit (%s) tags: %s", d.Get("arn").(string), err)
}
}

return resourceUsageLimitRead(d, meta)
}

func resourceUsageLimitDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).RedshiftConn

deleteInput := redshift.DeleteUsageLimitInput{
UsageLimitId: aws.String(d.Id()),
}

log.Printf("[DEBUG] Deleting snapshot copy grant: %s", d.Id())
_, err := conn.DeleteUsageLimit(&deleteInput)

if err != nil {
if tfawserr.ErrCodeEquals(err, redshift.ErrCodeUsageLimitNotFoundFault) {
return nil
}
return err
}

return err
}
Loading