Skip to content

Commit

Permalink
Merge pull request #26636 from DrFaust92/redshift-serverless-usage-limit
Browse files Browse the repository at this point in the history
r/aws_redshiftserverless_usage_limit - new resource
  • Loading branch information
ewbankkit committed Sep 6, 2022
2 parents 993770a + 9e6dc7e commit 79d028e
Show file tree
Hide file tree
Showing 7 changed files with 382 additions and 6 deletions.
3 changes: 3 additions & 0 deletions .changelog/26636.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_redshiftserverless_usage_limit
```
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -1867,6 +1867,7 @@ func New(_ context.Context) (*schema.Provider, error) {

"aws_redshiftserverless_endpoint_access": redshiftserverless.ResourceEndpointAccess(),
"aws_redshiftserverless_namespace": redshiftserverless.ResourceNamespace(),
"aws_redshiftserverless_usage_limit": redshiftserverless.ResourceUsageLimit(),
"aws_redshiftserverless_workgroup": redshiftserverless.ResourceWorkgroup(),

"aws_resourcegroups_group": resourcegroups.ResourceGroup(),
Expand Down
25 changes: 25 additions & 0 deletions internal/service/redshiftserverless/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,3 +82,28 @@ func FindEndpointAccessByName(conn *redshiftserverless.RedshiftServerless, name

return output.Endpoint, nil
}

func FindUsageLimitByName(conn *redshiftserverless.RedshiftServerless, id string) (*redshiftserverless.UsageLimit, error) {
input := &redshiftserverless.GetUsageLimitInput{
UsageLimitId: aws.String(id),
}

output, err := conn.GetUsageLimit(input)

if tfawserr.ErrMessageContains(err, redshiftserverless.ErrCodeValidationException, "does not exist") {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil {
return nil, tfresource.NewEmptyResultError(input)
}

return output.UsageLimit, nil
}
157 changes: 157 additions & 0 deletions internal/service/redshiftserverless/usage_limit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package redshiftserverless

import (
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/redshiftserverless"
"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"
"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{
"arn": {
Type: schema.TypeString,
Computed: true,
},
"amount": {
Type: schema.TypeInt,
Required: true,
},
"breach_action": {
Type: schema.TypeString,
Optional: true,
Default: redshiftserverless.UsageLimitBreachActionLog,
ValidateFunc: validation.StringInSlice(redshiftserverless.UsageLimitBreachAction_Values(), false),
},
"period": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
Default: redshiftserverless.UsageLimitPeriodMonthly,
ValidateFunc: validation.StringInSlice(redshiftserverless.UsageLimitPeriod_Values(), false),
},
"resource_arn": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: verify.ValidARN,
},
"usage_type": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice(redshiftserverless.UsageLimitUsageType_Values(), false),
},
},
}
}

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

input := redshiftserverless.CreateUsageLimitInput{
Amount: aws.Int64(int64(d.Get("amount").(int))),
ResourceArn: aws.String(d.Get("resource_arn").(string)),
UsageType: aws.String(d.Get("usage_type").(string)),
}

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

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

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

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

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

return resourceUsageLimitRead(d, meta)
}

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

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

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

d.Set("arn", out.UsageLimitArn)
d.Set("breach_action", out.BreachAction)
d.Set("period", out.Period)
d.Set("usage_type", out.UsageType)
d.Set("resource_arn", out.ResourceArn)
d.Set("amount", out.Amount)

return nil
}

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

input := &redshiftserverless.UpdateUsageLimitInput{
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.UpdateUsageLimit(input)
if err != nil {
return fmt.Errorf("error updating Redshift Serverless Usage Limit (%s): %w", d.Id(), err)
}

return resourceUsageLimitRead(d, meta)
}

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

log.Printf("[DEBUG] Deleting Redshift Serverless Usage Limit: %s", d.Id())
_, err := conn.DeleteUsageLimit(&redshiftserverless.DeleteUsageLimitInput{
UsageLimitId: aws.String(d.Id()),
})

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

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

return nil
}
136 changes: 136 additions & 0 deletions internal/service/redshiftserverless/usage_limit_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package redshiftserverless_test

import (
"fmt"
"testing"

"github.com/aws/aws-sdk-go/service/redshiftserverless"
sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
tfredshiftserverless "github.com/hashicorp/terraform-provider-aws/internal/service/redshiftserverless"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
)

func TestAccRedshiftServerlessUsageLimit_basic(t *testing.T) {
resourceName := "aws_redshiftserverless_usage_limit.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, redshiftserverless.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckUsageLimitDestroy,
Steps: []resource.TestStep{
{
Config: testAccUsageLimitConfig_basic(rName, 60),
Check: resource.ComposeTestCheckFunc(
testAccCheckUsageLimitExists(resourceName),
resource.TestCheckResourceAttrPair(resourceName, "resource_arn", "aws_redshiftserverless_workgroup.test", "arn"),
resource.TestCheckResourceAttr(resourceName, "amount", "60"),
resource.TestCheckResourceAttr(resourceName, "usage_type", "serverless-compute"),
resource.TestCheckResourceAttr(resourceName, "breach_action", "log"),
resource.TestCheckResourceAttr(resourceName, "period", "monthly"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccUsageLimitConfig_basic(rName, 120),
Check: resource.ComposeTestCheckFunc(
testAccCheckUsageLimitExists(resourceName),
resource.TestCheckResourceAttrPair(resourceName, "resource_arn", "aws_redshiftserverless_workgroup.test", "arn"),
resource.TestCheckResourceAttr(resourceName, "amount", "120"),
),
},
},
})
}

func TestAccRedshiftServerlessUsageLimit_disappears(t *testing.T) {
resourceName := "aws_redshiftserverless_usage_limit.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, redshiftserverless.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckUsageLimitDestroy,
Steps: []resource.TestStep{
{
Config: testAccUsageLimitConfig_basic(rName, 60),
Check: resource.ComposeTestCheckFunc(
testAccCheckUsageLimitExists(resourceName),
acctest.CheckResourceDisappears(acctest.Provider, tfredshiftserverless.ResourceUsageLimit(), resourceName),
),
ExpectNonEmptyPlan: true,
},
},
})
}

func testAccCheckUsageLimitDestroy(s *terraform.State) error {
conn := acctest.Provider.Meta().(*conns.AWSClient).RedshiftServerlessConn

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_redshiftserverless_usage_limit" {
continue
}
_, err := tfredshiftserverless.FindUsageLimitByName(conn, rs.Primary.ID)

if tfresource.NotFound(err) {
continue
}

if err != nil {
return err
}

return fmt.Errorf("Redshift Serverless Usage Limit %s still exists", rs.Primary.ID)
}

return nil
}

func testAccCheckUsageLimitExists(name string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[name]
if !ok {
return fmt.Errorf("not found: %s", name)
}

if rs.Primary.ID == "" {
return fmt.Errorf("Redshift Serverless Usage Limit is not set")
}

conn := acctest.Provider.Meta().(*conns.AWSClient).RedshiftServerlessConn

_, err := tfredshiftserverless.FindUsageLimitByName(conn, rs.Primary.ID)

return err
}
}

func testAccUsageLimitConfig_basic(rName string, amount int) string {
return fmt.Sprintf(`
resource "aws_redshiftserverless_namespace" "test" {
namespace_name = %[1]q
}
resource "aws_redshiftserverless_workgroup" "test" {
namespace_name = aws_redshiftserverless_namespace.test.namespace_name
workgroup_name = %[1]q
}
resource "aws_redshiftserverless_usage_limit" "test" {
resource_arn = aws_redshiftserverless_workgroup.test.arn
usage_type = "serverless-compute"
amount = %[2]d
}
`, rName, amount)
}
15 changes: 9 additions & 6 deletions internal/service/redshiftserverless/workgroup.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package redshiftserverless
import (
"fmt"
"log"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/redshiftserverless"
Expand Down Expand Up @@ -322,12 +323,14 @@ func resourceWorkgroupUpdate(d *schema.ResourceData, meta interface{}) error {
func resourceWorkgroupDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).RedshiftServerlessConn

deleteInput := redshiftserverless.DeleteWorkgroupInput{
WorkgroupName: aws.String(d.Id()),
}

log.Printf("[DEBUG] Deleting Redshift Serverless Workgroup: %s", d.Id())
_, err := conn.DeleteWorkgroup(&deleteInput)
_, err := tfresource.RetryWhenAWSErrMessageContains(10*time.Minute,
func() (interface{}, error) {
return conn.DeleteWorkgroup(&redshiftserverless.DeleteWorkgroupInput{
WorkgroupName: aws.String(d.Id()),
})
},
// "ConflictException: There is an operation running on the workgroup. Try deleting the workgroup again later."
redshiftserverless.ErrCodeConflictException, "operation running")

if err != nil {
if tfawserr.ErrCodeEquals(err, redshiftserverless.ErrCodeResourceNotFoundException) {
Expand Down

0 comments on commit 79d028e

Please sign in to comment.