Skip to content

Commit

Permalink
Merge pull request #36595 from danquack/dynamodb-policy
Browse files Browse the repository at this point in the history
r/dynamodb_resource_policy
  • Loading branch information
ewbankkit authored Mar 27, 2024
2 parents 80e647a + 22b7ca3 commit 78729c3
Show file tree
Hide file tree
Showing 14 changed files with 566 additions and 27 deletions.
3 changes: 3 additions & 0 deletions .archive/changelog/36595.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_dynamodb_resource_policy
```
2 changes: 1 addition & 1 deletion internal/errs/fwdiag/diags.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@ func NewResourceNotFoundWarningDiagnostic(err error) diag.Diagnostic {
)
}

func AsErr[T any](x T, diags diag.Diagnostics) (T, error) {
func AsError[T any](x T, diags diag.Diagnostics) (T, error) {
return x, DiagnosticsError(diags)
}
2 changes: 1 addition & 1 deletion internal/errs/fwdiag/must.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ import (
// [1]: https://pkg.go.dev/text/template#Must
// [2]: https://pkg.go.dev/regexp#MustCompile
func Must[T any](x T, diags diag.Diagnostics) T {
return errs.Must(AsErr(x, diags))
return errs.Must(AsError(x, diags))
}
2 changes: 1 addition & 1 deletion internal/service/cloudfrontkeyvaluestore/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ func (data *keyResourceModel) InitFromID() error {
return err
}

v, err := fwdiag.AsErr(fwtypes.ARNValue(parts[0]))
v, err := fwdiag.AsError(fwtypes.ARNValue(parts[0]))
if err != nil {
return err
}
Expand Down
10 changes: 10 additions & 0 deletions internal/service/dynamodb/consts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package dynamodb

import "time"

const (
propagationTimeout = 2 * time.Minute
)
2 changes: 2 additions & 0 deletions internal/service/dynamodb/exports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ package dynamodb
var (
ResourceKinesisStreamingDestination = resourceKinesisStreamingDestination
ResourceTag = resourceTag
ResourceResourcePolicy = newResourcePolicyResource

FindKinesisDataStreamDestinationByTwoPartKey = findKinesisDataStreamDestinationByTwoPartKey
FindResourcePolicyByARN = findResourcePolicyByARN
ListTags = listTags
)
254 changes: 254 additions & 0 deletions internal/service/dynamodb/resource_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package dynamodb

import (
"context"
"fmt"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
awstypes "github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-provider-aws/internal/errs"
"github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag"
"github.com/hashicorp/terraform-provider-aws/internal/framework"
fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @FrameworkResource(name="Resource Policy")
func newResourcePolicyResource(_ context.Context) (resource.ResourceWithConfigure, error) {
r := &resourcePolicyResource{}

return r, nil
}

type resourcePolicyResource struct {
framework.ResourceWithConfigure
framework.WithImportByID
}

func (*resourcePolicyResource) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) {
response.TypeName = "aws_dynamodb_resource_policy"
}

func (r *resourcePolicyResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) {
response.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"confirm_remove_self_resource_access": schema.BoolAttribute{
Optional: true,
Computed: true,
Default: booldefault.StaticBool(false),
},
names.AttrID: framework.IDAttribute(),
"policy": schema.StringAttribute{
CustomType: fwtypes.IAMPolicyType,
Required: true,
},
"resource_arn": schema.StringAttribute{
CustomType: fwtypes.ARNType,
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"revision_id": schema.StringAttribute{
Computed: true,
},
},
}
}

func (r *resourcePolicyResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) {
var data resourcePolicyResourceModel
response.Diagnostics.Append(request.Plan.Get(ctx, &data)...)
if response.Diagnostics.HasError() {
return
}

conn := r.Meta().DynamoDBClient(ctx)

input := &dynamodb.PutResourcePolicyInput{}
response.Diagnostics.Append(fwflex.Expand(ctx, data, input)...)
if response.Diagnostics.HasError() {
return
}

output, err := conn.PutResourcePolicy(ctx, input)

if err != nil {
response.Diagnostics.AddError(fmt.Sprintf("creating DynamoDB Resource Policy (%s)", data.ResourceARN.ValueString()), err.Error())

return
}

// Set values for unknowns.
data.RevisionID = fwflex.StringToFramework(ctx, output.RevisionId)
data.setID()

_, err = tfresource.RetryWhenNotFound(ctx, propagationTimeout, func() (interface{}, error) {
return findResourcePolicyByARN(ctx, conn, data.ResourceARN.ValueString())
})

if err != nil {
response.Diagnostics.AddError(fmt.Sprintf("waiting for DynamoDB Resource Policy (%s) create", data.ID.ValueString()), err.Error())

return
}

response.Diagnostics.Append(response.State.Set(ctx, &data)...)
}

func (r *resourcePolicyResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) {
var data resourcePolicyResourceModel
response.Diagnostics.Append(request.State.Get(ctx, &data)...)
if response.Diagnostics.HasError() {
return
}

if err := data.InitFromID(); err != nil {
response.Diagnostics.AddError("parsing resource ID", err.Error())

return
}

conn := r.Meta().DynamoDBClient(ctx)

output, err := findResourcePolicyByARN(ctx, conn, data.ResourceARN.ValueString())

if tfresource.NotFound(err) {
response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err))
response.State.RemoveResource(ctx)

return
}

if err != nil {
response.Diagnostics.AddError(fmt.Sprintf("reading DynamoDB Resource Policy (%s)", data.ID.ValueString()), err.Error())

return
}

// Set attributes for import.
response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...)
if response.Diagnostics.HasError() {
return
}

response.Diagnostics.Append(response.State.Set(ctx, &data)...)
}

func (r *resourcePolicyResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) {
var old, new resourcePolicyResourceModel
response.Diagnostics.Append(request.State.Get(ctx, &old)...)
if response.Diagnostics.HasError() {
return
}
response.Diagnostics.Append(request.Plan.Get(ctx, &new)...)
if response.Diagnostics.HasError() {
return
}

conn := r.Meta().DynamoDBClient(ctx)

input := &dynamodb.PutResourcePolicyInput{}
response.Diagnostics.Append(fwflex.Expand(ctx, new, input)...)
if response.Diagnostics.HasError() {
return
}

output, err := conn.PutResourcePolicy(ctx, input)

if err != nil {
response.Diagnostics.AddError(fmt.Sprintf("updating DynamoDB Resource Policy (%s)", new.ID.ValueString()), err.Error())

return
}

// Set values for unknowns.
new.RevisionID = fwflex.StringToFramework(ctx, output.RevisionId)

response.Diagnostics.Append(response.State.Set(ctx, &new)...)
}

func (r *resourcePolicyResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) {
var data resourcePolicyResourceModel
response.Diagnostics.Append(request.State.Get(ctx, &data)...)
if response.Diagnostics.HasError() {
return
}

conn := r.Meta().DynamoDBClient(ctx)

_, err := conn.DeleteResourcePolicy(ctx, &dynamodb.DeleteResourcePolicyInput{
ResourceArn: aws.String(data.ID.ValueString()),
})

if errs.IsA[*awstypes.PolicyNotFoundException](err) || errs.IsA[*awstypes.ResourceNotFoundException](err) {
return
}

if err != nil {
response.Diagnostics.AddError(fmt.Sprintf("deleting DynamoDB Resource Policy (%s)", data.ID.ValueString()), err.Error())

return
}
}

func findResourcePolicyByARN(ctx context.Context, conn *dynamodb.Client, arn string) (*dynamodb.GetResourcePolicyOutput, error) {
input := &dynamodb.GetResourcePolicyInput{
ResourceArn: aws.String(arn),
}

output, err := conn.GetResourcePolicy(ctx, input)

if errs.IsA[*awstypes.PolicyNotFoundException](err) || errs.IsA[*awstypes.ResourceNotFoundException](err) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

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

return output, nil
}

type resourcePolicyResourceModel struct {
ConfirmRemoveSelfResourceAccess types.Bool `tfsdk:"confirm_remove_self_resource_access"`
ID types.String `tfsdk:"id"`
Policy fwtypes.IAMPolicy `tfsdk:"policy"`
ResourceARN fwtypes.ARN `tfsdk:"resource_arn"`
RevisionID types.String `tfsdk:"revision_id"`
}

func (data *resourcePolicyResourceModel) InitFromID() error {
v, err := fwdiag.AsError(fwtypes.ARNValue(data.ID.ValueString()))
if err != nil {
return err
}

data.ResourceARN = v

return nil
}

func (data *resourcePolicyResourceModel) setID() {
data.ID = data.ResourceARN.StringValue
}
Loading

0 comments on commit 78729c3

Please sign in to comment.