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/aws_dynamo_contributor_insights: Add new resource #23947

Merged
merged 13 commits into from
Apr 4, 2022
Merged
3 changes: 3 additions & 0 deletions .changelog/23947.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_dynamodb_contributor_insights
```
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,7 @@ func Provider() *schema.Provider {
"aws_directory_service_directory": ds.ResourceDirectory(),
"aws_directory_service_log_subscription": ds.ResourceLogSubscription(),

"aws_dynamodb_contributor_insights": dynamodb.ResourceContributorInsights(),
"aws_dynamodb_global_table": dynamodb.ResourceGlobalTable(),
"aws_dynamodb_kinesis_streaming_destination": dynamodb.ResourceKinesisStreamingDestination(),
"aws_dynamodb_table": dynamodb.ResourceTable(),
Expand Down
156 changes: 156 additions & 0 deletions internal/service/dynamodb/contributor_insights.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
package dynamodb

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

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
)

func ResourceContributorInsights() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceContributorInsightsCreate,
ReadWithoutTimeout: resourceContributorInsightsRead,
DeleteWithoutTimeout: resourceContributorInsightsDelete,
Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(5 * time.Minute),
Delete: schema.DefaultTimeout(5 * time.Minute),
},

Schema: map[string]*schema.Schema{
"index_name": {
Type: schema.TypeString,
ForceNew: true,
Optional: true,
},
"table_name": {
Type: schema.TypeString,
ForceNew: true,
Required: true,
},
},
}
}

func resourceContributorInsightsCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).DynamoDBConn

input := &dynamodb.UpdateContributorInsightsInput{
ContributorInsightsAction: aws.String(dynamodb.ContributorInsightsActionEnable),
}

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

var indexName string
if v, ok := d.GetOk("index_name"); ok {
input.IndexName = aws.String(v.(string))
indexName = v.(string)
}

output, err := conn.UpdateContributorInsightsWithContext(ctx, input)
if err != nil {
return diag.Errorf("creating DynamoDB ContributorInsights for table (%s): %s", d.Get("table_name").(string), err)
}

id := EncodeContributorInsightsID(aws.StringValue(output.TableName), indexName, meta.(*conns.AWSClient).AccountID)
d.SetId(id)

if err := waitContributorInsightsCreated(ctx, conn, aws.StringValue(output.TableName), indexName, d.Timeout(schema.TimeoutCreate)); err != nil {
return diag.Errorf("waiting for DynamoDB ContributorInsights (%s) create: %s", d.Id(), err)
}

return resourceContributorInsightsRead(ctx, d, meta)
}

func resourceContributorInsightsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).DynamoDBConn

tableName, indexName, err := DecodeContributorInsightsID(d.Id())
if err != nil {
return diag.Errorf("unable to decode DynamoDB ContributorInsights ID (%s): %s", d.Id(), err)
}

out, err := FindContributorInsights(ctx, conn, tableName, indexName)

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] DynamoDB ContributorInsights (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return diag.Errorf("reading DynamoDB ContributorInsights (%s): %s", d.Id(), err)
}

d.Set("index_name", out.IndexName)
d.Set("table_name", out.TableName)

return nil
}

func resourceContributorInsightsDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).DynamoDBConn

log.Printf("[INFO] Deleting DynamoDB ContributorInsights %s", d.Id())

tableName, indexName, err := DecodeContributorInsightsID(d.Id())
if err != nil {
return diag.Errorf("unable to decode DynamoDB ContributorInsights ID (%s): %s", d.Id(), err)
}

input := &dynamodb.UpdateContributorInsightsInput{
ContributorInsightsAction: aws.String(dynamodb.ContributorInsightsActionDisable),
TableName: aws.String(tableName),
}

if indexName != "" {
input.IndexName = aws.String(indexName)
}

_, err = conn.UpdateContributorInsightsWithContext(ctx, input)

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

if err != nil {
return diag.Errorf("deleting DynamoDB ContributorInsights (%s): %s", d.Id(), err)
}

if err := waitContributorInsightsDeleted(ctx, conn, tableName, indexName, d.Timeout(schema.TimeoutDelete)); err != nil {
return diag.Errorf("waiting for DynamoDB ContributorInsights (%s) to be deleted: %s", d.Id(), err)
}

return nil
}

func EncodeContributorInsightsID(tableName, indexName, accountID string) string {
return fmt.Sprintf("name:%s/index:%s/%s", tableName, indexName, accountID)
}

func DecodeContributorInsightsID(id string) (string, string, error) {
idParts := strings.Split(id, "/")
if len(idParts) != 3 || idParts[0] == "" || idParts[2] == "" {
return "", "", fmt.Errorf("expected ID in the form of table_name/account_id, given: %q", id)
}

tableName := strings.TrimPrefix(idParts[0], "name:")
indexName := strings.TrimPrefix(idParts[1], "index:")

return tableName, indexName, nil
}
176 changes: 176 additions & 0 deletions internal/service/dynamodb/contributor_insights_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package dynamodb_test

import (
"context"
"fmt"
"log"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/dynamodb"
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"
tfdynamodb "github.com/hashicorp/terraform-provider-aws/internal/service/dynamodb"
)

func TestAccContributorInsights_basic(t *testing.T) {
johnsonaj marked this conversation as resolved.
Show resolved Hide resolved
var conf dynamodb.DescribeContributorInsightsOutput
rName := fmt.Sprintf("tf-acc-test-%s", sdkacctest.RandString(8))
indexName := fmt.Sprintf("%s-index", rName)
resourceName := "aws_dynamodb_contributor_insights.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, dynamodb.EndpointsID),
Providers: acctest.Providers,
CheckDestroy: testAccCheckContributorInsightsDestroy,
Steps: []resource.TestStep{
{
Config: testAccContributorInsightsBasicConfig(rName, ""),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckContributorInsightsExists(resourceName, &conf),
resource.TestCheckResourceAttr(resourceName, "table_name", rName),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccContributorInsightsBasicConfig(rName, indexName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckContributorInsightsExists(resourceName, &conf),
resource.TestCheckResourceAttr(resourceName, "index_name", indexName),
),
},
},
})
}

func TestAccContributorInsights_disappears(t *testing.T) {
var conf dynamodb.DescribeContributorInsightsOutput
rName := fmt.Sprintf("tf-acc-test-%s", sdkacctest.RandString(8))
resourceName := "aws_dynamodb_contributor_insights.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, dynamodb.EndpointsID),
Providers: acctest.Providers,
CheckDestroy: testAccCheckContributorInsightsDestroy,
Steps: []resource.TestStep{
{
Config: testAccContributorInsightsBasicConfig(rName, ""),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckContributorInsightsExists(resourceName, &conf),
acctest.CheckResourceDisappears(acctest.Provider, tfdynamodb.ResourceContributorInsights(), resourceName),
),
},
},
})
}

func testAccContributorInsightsBaseConfig(rName string) string {
return fmt.Sprintf(`
resource "aws_dynamodb_table" "test" {
name = %[1]q
read_capacity = 2
write_capacity = 2
hash_key = %[1]q

attribute {
name = %[1]q
type = "S"
}

global_secondary_index {
name = "%[1]s-index"
hash_key = %[1]q
projection_type = "ALL"
read_capacity = 1
write_capacity = 1
}
}
`, rName)
}

func testAccContributorInsightsBasicConfig(rName, indexName string) string {
return acctest.ConfigCompose(testAccContributorInsightsBaseConfig(rName), fmt.Sprintf(`
resource "aws_dynamodb_contributor_insights" "test" {
table_name = aws_dynamodb_table.test.name
index_name = %[2]q
}
`, rName, indexName))
}

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

if rs.Primary.ID == "" {
return fmt.Errorf("no DynamodDB Contributor Insights ID is set")
}

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

tableName, indexName, err := tfdynamodb.DecodeContributorInsightsID(rs.Primary.ID)
if err != nil {
return err
}

output, err := tfdynamodb.FindContributorInsights(context.Background(), conn, tableName, indexName)
if err != nil {
return err
}

ci = output

return nil
}
}

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

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_dynamodb_contributor_insights" {
continue
}

log.Printf("[DEBUG] Checking if DynamoDB Contributor Insights %s exists", rs.Primary.ID)

tableName, indexName, err := tfdynamodb.DecodeContributorInsightsID(rs.Primary.ID)
if err != nil {
return err
}

in := &dynamodb.DescribeContributorInsightsInput{
johnsonaj marked this conversation as resolved.
Show resolved Hide resolved
TableName: aws.String(tableName),
}

if indexName != "" {
in.IndexName = aws.String(indexName)
}

_, err = conn.DescribeContributorInsightsWithContext(context.Background(), in)
if err == nil {
return fmt.Errorf("the DynamoDB Contributor Insights %s still exists. Failing", rs.Primary.ID)
}

// Verify the error is what we want
if dbErr, ok := err.(awserr.Error); ok && dbErr.Code() == "ResourceNotFoundException" {
return nil
}

return err
}

return nil
}
17 changes: 17 additions & 0 deletions internal/service/dynamodb/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,20 @@ func FindDynamoDBTTLRDescriptionByTableName(conn *dynamodb.DynamoDB, tableName s

return output.TimeToLiveDescription, nil
}

func FindContributorInsights(ctx context.Context, conn *dynamodb.DynamoDB, tableName, indexName string) (*dynamodb.DescribeContributorInsightsOutput, error) {
input := &dynamodb.DescribeContributorInsightsInput{
TableName: aws.String(tableName),
}

if indexName != "" {
input.IndexName = aws.String(indexName)
}

output, err := conn.DescribeContributorInsightsWithContext(ctx, input)
if err != nil {
return nil, err
}
johnsonaj marked this conversation as resolved.
Show resolved Hide resolved

return output, nil
}
20 changes: 20 additions & 0 deletions internal/service/dynamodb/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,23 @@ func statusDynamoDBTableSES(conn *dynamodb.DynamoDB, tableName string) resource.
return table, aws.StringValue(table.SSEDescription.Status), nil
}
}

func statusContributorInsights(ctx context.Context, conn *dynamodb.DynamoDB, tableName, indexName string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
insight, err := FindContributorInsights(ctx, conn, tableName, indexName)

if tfawserr.ErrCodeEquals(err, dynamodb.ErrCodeResourceNotFoundException) {
return nil, "", nil
}
johnsonaj marked this conversation as resolved.
Show resolved Hide resolved

if err != nil {
return nil, "", err
}

if insight == nil {
return nil, "", nil
}

return insight, aws.StringValue(insight.ContributorInsightsStatus), nil
}
}
Loading