Skip to content

Commit

Permalink
Merge pull request #27665 from DrFaust92/redshift-partner
Browse files Browse the repository at this point in the history
redshift partner resource
  • Loading branch information
ewbankkit committed Nov 7, 2022
2 parents 382c310 + e5d08e2 commit ba0101b
Show file tree
Hide file tree
Showing 6 changed files with 376 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/27665.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_redshift_partner
```
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -1891,6 +1891,7 @@ func New(_ context.Context) (*schema.Provider, error) {
"aws_redshift_hsm_client_certificate": redshift.ResourceHSMClientCertificate(),
"aws_redshift_hsm_configuration": redshift.ResourceHSMConfiguration(),
"aws_redshift_parameter_group": redshift.ResourceParameterGroup(),
"aws_redshift_partner": redshift.ResourcePartner(),
"aws_redshift_scheduled_action": redshift.ResourceScheduledAction(),
"aws_redshift_security_group": redshift.ResourceSecurityGroup(),
"aws_redshift_snapshot_copy_grant": redshift.ResourceSnapshotCopyGrant(),
Expand Down
37 changes: 37 additions & 0 deletions internal/service/redshift/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,3 +391,40 @@ func FindEndpointAuthorizationById(conn *redshift.Redshift, id string) (*redshif

return output.EndpointAuthorizationList[0], nil
}

func FindPartnerById(conn *redshift.Redshift, id string) (*redshift.PartnerIntegrationInfo, error) {
account, clusterId, dbName, partnerName, err := DecodePartnerID(id)
if err != nil {
return nil, err
}

input := &redshift.DescribePartnersInput{
AccountId: aws.String(account),
ClusterIdentifier: aws.String(clusterId),
DatabaseName: aws.String(dbName),
PartnerName: aws.String(partnerName),
}

output, err := conn.DescribePartners(input)

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

if err != nil {
return nil, err
}

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

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

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

import (
"fmt"
"log"
"strings"

"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/helper/schema"
"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 ResourcePartner() *schema.Resource {
return &schema.Resource{
Create: resourcePartnerCreate,
Read: resourcePartnerRead,
Delete: resourcePartnerDelete,

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

Schema: map[string]*schema.Schema{
"account_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: verify.ValidAccountID,
},
"cluster_identifier": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"database_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"partner_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"status": {
Type: schema.TypeString,
Computed: true,
},
"status_message": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

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

account := d.Get("account_id").(string)
clusterId := d.Get("cluster_identifier").(string)
input := redshift.AddPartnerInput{
AccountId: aws.String(account),
ClusterIdentifier: aws.String(clusterId),
DatabaseName: aws.String(d.Get("database_name").(string)),
PartnerName: aws.String(d.Get("partner_name").(string)),
}

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

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

d.SetId(fmt.Sprintf("%s:%s:%s:%s", account, clusterId, aws.StringValue(out.DatabaseName), aws.StringValue(out.PartnerName)))

return resourcePartnerRead(d, meta)
}

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

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

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

d.Set("account_id", d.Get("account_id").(string))
d.Set("cluster_identifier", d.Get("cluster_identifier").(string))
d.Set("partner_name", out.PartnerName)
d.Set("database_name", out.DatabaseName)
d.Set("status", out.Status)
d.Set("status_message", out.StatusMessage)

return nil
}

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

account, clusterId, dbName, partnerName, err := DecodePartnerID(d.Id())
if err != nil {
return err
}

deleteInput := redshift.DeletePartnerInput{
AccountId: aws.String(account),
ClusterIdentifier: aws.String(clusterId),
DatabaseName: aws.String(dbName),
PartnerName: aws.String(partnerName),
}

_, err = conn.DeletePartner(&deleteInput)

if err != nil {
if tfawserr.ErrCodeEquals(err, redshift.ErrCodePartnerNotFoundFault) {
return nil
}
if err != nil {
return fmt.Errorf("deleting Redshift Partner (%s): %w", d.Id(), err)
}
}

return nil
}

func DecodePartnerID(id string) (string, string, string, string, error) {
idParts := strings.Split(id, ":")
if len(idParts) != 4 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" || idParts[3] == "" {
return "", "", "", "", fmt.Errorf("expected ID to be the form account:cluster_identifier:database_name:partner_name, given: %s", id)
}

return idParts[0], idParts[1], idParts[2], idParts[3], nil
}
144 changes: 144 additions & 0 deletions internal/service/redshift/partner_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
package redshift_test

import (
"fmt"
"testing"

"github.com/aws/aws-sdk-go/service/redshift"
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"
tfredshift "github.com/hashicorp/terraform-provider-aws/internal/service/redshift"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
)

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

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, redshift.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckPartnerDestroy,
Steps: []resource.TestStep{
{
Config: testAccPartnerConfig_basic(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckPartnerExists(resourceName),
resource.TestCheckResourceAttr(resourceName, "partner_name", "Datacoral"),
resource.TestCheckResourceAttrPair(resourceName, "database_name", "aws_redshift_cluster.test", "database_name"),
resource.TestCheckResourceAttrPair(resourceName, "cluster_identifier", "aws_redshift_cluster.test", "id"),
acctest.CheckResourceAttrAccountID(resourceName, "account_id"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"account_id", "cluster_identifier"},
},
},
})
}

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

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, redshift.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckPartnerDestroy,
Steps: []resource.TestStep{
{
Config: testAccPartnerConfig_basic(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckPartnerExists(resourceName),
acctest.CheckResourceDisappears(acctest.Provider, tfredshift.ResourcePartner(), resourceName),
),
ExpectNonEmptyPlan: true,
},
},
})
}

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

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, redshift.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckPartnerDestroy,
Steps: []resource.TestStep{
{
Config: testAccPartnerConfig_basic(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckPartnerExists(resourceName),
acctest.CheckResourceDisappears(acctest.Provider, tfredshift.ResourceCluster(), "aws_redshift_cluster.test"),
),
ExpectNonEmptyPlan: true,
},
},
})
}

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

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

if tfresource.NotFound(err) {
continue
}

if err != nil {
return err
}

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

return nil
}

func testAccCheckPartnerExists(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("No Redshift Partner ID is set")
}

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

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

return err
}
}

func testAccPartnerConfig_basic(rName string) string {
return acctest.ConfigCompose(testAccClusterConfig_basic(rName), `
data "aws_caller_identity" "current" {}
resource "aws_redshift_partner" "test" {
cluster_identifier = aws_redshift_cluster.test.id
account_id = data.aws_caller_identity.current.account_id
database_name = aws_redshift_cluster.test.database_name
partner_name = "Datacoral"
}
`)
}
47 changes: 47 additions & 0 deletions website/docs/r/redshift_partner.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
subcategory: "Redshift"
layout: "aws"
page_title: "AWS: aws_redshift_partner"
description: |-
Provides a Redshift Partner resource.
---

# Resource: aws_redshift_partner

Creates a new Amazon Redshift Partner Integration.

## Example Usage

```terraform
resource "aws_redshift_partner" "example" {
cluster_identifier = aws_redshift_cluster.example.id
account_id = 01234567910
database_name = aws_redshift_cluster.example.database_name
partner_name = "example"
}
```

## Argument Reference

The following arguments are supported:

* `account_id` - (Required) The Amazon Web Services account ID that owns the cluster.
* `cluster_identifier` - (Required) The cluster identifier of the cluster that receives data from the partner.
* `database_name` - (Required) The name of the database that receives data from the partner.
* `partner_name` - (Required) The name of the partner that is authorized to send data.

## Attributes Reference

In addition to all arguments above, the following attributes are exported:

* `id` - The identifier of the Redshift partner, `account_id`, `cluster_identifier`, `database_name`, `partner_name` separated by a colon (`:`).
* `status` - (Optional) The partner integration status.
* `status_message` - (Optional) The status message provided by the partner.

## Import

Redshift usage limits can be imported using the `id`, e.g.,

```
$ terraform import aws_redshift_partner.example 01234567910:cluster-example-id:example:example
```

0 comments on commit ba0101b

Please sign in to comment.