Skip to content

Commit

Permalink
Merge pull request #34149 from DrFaust92/redshift-policy-
Browse files Browse the repository at this point in the history
r/redshift_resource_policy - new resource
  • Loading branch information
ewbankkit authored Nov 1, 2023
2 parents a4daa02 + 46ff2f2 commit b1b18e9
Show file tree
Hide file tree
Showing 6 changed files with 373 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/34149.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_redshift_resource_policy
```
25 changes: 25 additions & 0 deletions internal/service/redshift/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -419,3 +419,28 @@ func FindClusterSnapshotByID(ctx context.Context, conn *redshift.Redshift, id st

return output.Snapshots[0], nil
}

func FindResourcePolicyByARN(ctx context.Context, conn *redshift.Redshift, arn string) (*redshift.ResourcePolicy, error) {
input := &redshift.GetResourcePolicyInput{
ResourceArn: aws.String(arn),
}

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

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

if err != nil {
return nil, err
}

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

return output.ResourcePolicy, nil
}
135 changes: 135 additions & 0 deletions internal/service/redshift/resource_policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package redshift

import (
"context"
"log"

"github.com/aws/aws-sdk-go/aws"
"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/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
)

// @SDKResource("aws_redshift_resource_policy")
func ResourceResourcePolicy() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceResourcePolicyPut,
ReadWithoutTimeout: resourceResourcePolicyRead,
UpdateWithoutTimeout: resourceResourcePolicyPut,
DeleteWithoutTimeout: resourceResourcePolicyDelete,

Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: map[string]*schema.Schema{
"policy": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringIsJSON,
DiffSuppressFunc: verify.SuppressEquivalentPolicyDiffs,
StateFunc: func(v interface{}) string {
json, _ := structure.NormalizeJsonString(v)
return json
},
},
"resource_arn": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: verify.ValidARN,
},
},
}
}

func resourceResourcePolicyPut(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).RedshiftConn(ctx)

arn := d.Get("resource_arn").(string)

policy, err := structure.NormalizeJsonString(d.Get("policy").(string))
if err != nil {
return sdkdiag.AppendErrorf(diags, "policy (%s) is invalid JSON: %s", policy, err)
}

input := redshift.PutResourcePolicyInput{
ResourceArn: aws.String(arn),
Policy: aws.String(policy),
}

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

if err != nil {
return sdkdiag.AppendErrorf(diags, "setting Redshift Resource Policy (%s): %s", arn, err)
}

d.SetId(aws.StringValue(out.ResourcePolicy.ResourceArn))

return append(diags, resourceResourcePolicyRead(ctx, d, meta)...)
}

func resourceResourcePolicyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).RedshiftConn(ctx)

out, err := FindResourcePolicyByARN(ctx, conn, d.Id())
if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] Redshift Resource Policy (%s) not found, removing from state", d.Id())
d.SetId("")
return diags
}

if err != nil {
return sdkdiag.AppendErrorf(diags, "reading Redshift Resource Policy (%s): %s", d.Id(), err)
}

d.Set("resource_arn", out.ResourceArn)

policyToSet, err := verify.SecondJSONUnlessEquivalent(d.Get("policy").(string), aws.StringValue(out.Policy))

if err != nil {
return sdkdiag.AppendErrorf(diags, "while setting policy (%s), encountered: %s", policyToSet, err)
}

policyToSet, err = structure.NormalizeJsonString(policyToSet)

if err != nil {
return sdkdiag.AppendErrorf(diags, "policy (%s) is invalid JSON: %s", policyToSet, err)
}

d.Set("policy", policyToSet)

return diags
}

func resourceResourcePolicyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
conn := meta.(*conns.AWSClient).RedshiftConn(ctx)

log.Printf("[DEBUG] Deleting Redshift Resource Policy: %s", d.Id())
_, err := conn.DeleteResourcePolicyWithContext(ctx, &redshift.DeleteResourcePolicyInput{
ResourceArn: aws.String(d.Id()),
})

if tfawserr.ErrCodeEquals(err, redshift.ErrCodeResourceNotFoundFault) {
return diags
}

if err != nil {
return sdkdiag.AppendErrorf(diags, "deleting Redshift Resource Policy (%s): %s", d.Id(), err)
}

return diags
}
145 changes: 145 additions & 0 deletions internal/service/redshift/resource_policy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package redshift_test

import (
"context"
"fmt"
"testing"

"github.com/aws/aws-sdk-go/service/redshift"
sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/terraform"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
tfredshift "github.com/hashicorp/terraform-provider-aws/internal/service/redshift"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
)

func TestAccRedshiftResourcePolicy_basic(t *testing.T) {
ctx := acctest.Context(t)
resourceName := "aws_redshift_resource_policy.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckAlternateAccount(t)
},
ErrorCheck: acctest.ErrorCheck(t, redshift.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5FactoriesAlternate(ctx, t),
CheckDestroy: testAccCheckResourcePolicyDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccResourcePolicyConfig_basic(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckResourcePolicyExists(ctx, resourceName),
resource.TestCheckResourceAttrPair(resourceName, "resource_arn", "aws_redshift_cluster.test", "cluster_namespace_arn"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccRedshiftResourcePolicy_disappears(t *testing.T) {
ctx := acctest.Context(t)
resourceName := "aws_redshift_resource_policy.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckAlternateAccount(t)
},
ErrorCheck: acctest.ErrorCheck(t, redshift.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5FactoriesAlternate(ctx, t),
CheckDestroy: testAccCheckResourcePolicyDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccResourcePolicyConfig_basic(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckResourcePolicyExists(ctx, resourceName),
acctest.CheckResourceDisappears(ctx, acctest.Provider, tfredshift.ResourceResourcePolicy(), resourceName),
),
ExpectNonEmptyPlan: true,
},
},
})
}

func testAccCheckResourcePolicyDestroy(ctx context.Context) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := acctest.Provider.Meta().(*conns.AWSClient).RedshiftConn(ctx)

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_redshift_resource_policy" {
continue
}
_, err := tfredshift.FindResourcePolicyByARN(ctx, conn, rs.Primary.ID)

if tfresource.NotFound(err) {
continue
}

if err != nil {
return err
}

return fmt.Errorf("Redshift Resource Policy %s still exists", rs.Primary.ID)
}

return nil
}
}

func testAccCheckResourcePolicyExists(ctx context.Context, 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 Resource Policy is not set")
}

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

_, err := tfredshift.FindResourcePolicyByARN(ctx, conn, rs.Primary.ID)

return err
}
}

func testAccResourcePolicyConfig_basic(rName string) string {
return acctest.ConfigCompose(testAccClusterConfig_basic(rName), `
data "aws_caller_identity" "test" {
provider = "awsalternate"
}
data "aws_partition" "test" {}
resource "aws_redshift_resource_policy" "test" {
resource_arn = aws_redshift_cluster.test.cluster_namespace_arn
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = {
AWS = "arn:${data.aws_partition.test.partition}:iam::${data.aws_caller_identity.test.account_id}:root"
}
Action = "redshift:CreateInboundIntegration"
Resource = aws_redshift_cluster.test.cluster_namespace_arn
Sid = ""
}]
})
}
`)
}
4 changes: 4 additions & 0 deletions internal/service/redshift/service_package_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 61 additions & 0 deletions website/docs/r/redshift_resource_policy.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
subcategory: "Redshift"
layout: "aws"
page_title: "AWS: aws_redshift_resource_policy"
description: |-
Provides a Redshift Resource Policy resource.
---

# Resource: aws_redshift_resource_policy

Creates a new Amazon Redshift Resource Policy.

## Example Usage

```terraform
resource "aws_redshift_resource_policy" "example" {
resource_arn = aws_redshift_cluster.example.cluster_namespace_arn
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::12345678901:root"
}
Action = "redshift:CreateInboundIntegration"
Resource = aws_redshift_cluster.example.cluster_namespace_arn
Sid = ""
}]
})
}
```

## Argument Reference

This resource supports the following arguments:

* `resource_arn` - (Required) The Amazon Resource Name (ARN) of the account to create or update a resource policy for.
* `policy` - (Required) The content of the resource policy being updated.

## Attribute Reference

This resource exports the following attributes in addition to the arguments above:

* `id` - The Amazon Resource Name (ARN) of the account to create or update a resource policy for.

## Import

In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import Redshift Resource Policies using the `resource_arn`. For example:

```terraform
import {
to = aws_redshift_resource_policy.example
id = "example"
}
```

Using `terraform import`, import Redshift Resource Policies using the `resource_arn`. For example:

```console
% terraform import aws_redshift_resource_policy.example example
```

0 comments on commit b1b18e9

Please sign in to comment.