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

redshift partner resource #27665

Merged
merged 4 commits into from
Nov 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -1890,6 +1890,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
```