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

Add tags attribute support for redshift parameter group #8894

29 changes: 20 additions & 9 deletions aws/resource_aws_redshift_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ func resourceAwsRedshiftCluster() *schema.Resource {
},

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},

"database_name": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -610,29 +615,34 @@ func resourceAwsRedshiftClusterRead(d *schema.ResourceData, meta interface{}) er

d.Set("cluster_public_key", rsc.ClusterPublicKey)
d.Set("cluster_revision_number", rsc.ClusterRevisionNumber)
d.Set("tags", tagsToMapRedshift(rsc.Tags))
if err := d.Set("tags", tagsToMapRedshift(rsc.Tags)); err != nil {
return fmt.Errorf("Error setting Redshift Cluster Tags: %#v", err)
}

d.Set("snapshot_copy", flattenRedshiftSnapshotCopy(rsc.ClusterSnapshotCopyStatus))

if err := d.Set("logging", flattenRedshiftLogging(loggingStatus)); err != nil {
return fmt.Errorf("error setting logging: %s", err)
}

return nil
}

func resourceAwsRedshiftClusterUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).redshiftconn
d.Partial(true)

arn := arn.ARN{
Partition: meta.(*AWSClient).partition,
Service: "redshift",
Region: meta.(*AWSClient).region,
AccountID: meta.(*AWSClient).accountid,
Resource: fmt.Sprintf("cluster:%s", d.Id()),
}.String()
if tagErr := setTagsRedshift(conn, d, arn); tagErr != nil {

d.Set("arn", arn)

return nil
}

func resourceAwsRedshiftClusterUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).redshiftconn
d.Partial(true)

if tagErr := setTagsRedshift(conn, d); tagErr != nil {
return tagErr
} else {
d.SetPartial("tags")
Expand Down Expand Up @@ -878,6 +888,7 @@ func resourceAwsRedshiftClusterDelete(d *schema.ResourceData, meta interface{})
}

log.Printf("[DEBUG] Deleting Redshift Cluster: %s", deleteOpts)
log.Printf("[DEBUG] schema.TimeoutDelete: %+v", d.Timeout(schema.TimeoutDelete))
err := deleteAwsRedshiftCluster(&deleteOpts, conn, d.Timeout(schema.TimeoutDelete))
if err != nil {
return err
Expand Down
32 changes: 27 additions & 5 deletions aws/resource_aws_redshift_event_subscription.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/service/redshift"
"github.com/hashicorp/terraform/helper/schema"
)
Expand All @@ -25,6 +26,11 @@ func resourceAwsRedshiftEventSubscription() *schema.Resource {
Update: schema.DefaultTimeout(40 * time.Minute),
},
Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},

"name": {
Type: schema.TypeString,
Required: true,
Expand Down Expand Up @@ -68,11 +74,7 @@ func resourceAwsRedshiftEventSubscription() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"tags": {
Type: schema.TypeMap,
Optional: true,
ForceNew: true,
},
"tags": tagsSchema(),
},
}
}
Expand Down Expand Up @@ -106,6 +108,16 @@ func resourceAwsRedshiftEventSubscriptionCreate(d *schema.ResourceData, meta int
func resourceAwsRedshiftEventSubscriptionRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).redshiftconn

arn := arn.ARN{
Partition: meta.(*AWSClient).partition,
Service: "redshift",
Region: meta.(*AWSClient).region,
AccountID: meta.(*AWSClient).accountid,
Resource: fmt.Sprintf("eventsubscription:%s", d.Id()),
}.String()

d.Set("arn", arn)

sub, err := resourceAwsRedshiftEventSubscriptionRetrieve(d.Id(), conn)
if err != nil {
return fmt.Errorf("Error retrieving Redshift Event Subscription %s: %s", d.Id(), err)
Expand Down Expand Up @@ -175,6 +187,8 @@ func resourceAwsRedshiftEventSubscriptionRetrieve(name string, conn *redshift.Re
func resourceAwsRedshiftEventSubscriptionUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).redshiftconn

d.Partial(true)

req := &redshift.ModifyEventSubscriptionInput{
SubscriptionName: aws.String(d.Id()),
SnsTopicArn: aws.String(d.Get("sns_topic_arn").(string)),
Expand All @@ -191,6 +205,14 @@ func resourceAwsRedshiftEventSubscriptionUpdate(d *schema.ResourceData, meta int
return fmt.Errorf("Modifying Redshift Event Subscription %s failed: %s", d.Id(), err)
}

if tagErr := setTagsRedshift(conn, d); tagErr != nil {
return tagErr
} else {
d.SetPartial("tags")
}

d.Partial(false)

return nil
}

Expand Down
75 changes: 75 additions & 0 deletions aws/resource_aws_redshift_event_subscription_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,54 @@ func TestAccAWSRedshiftEventSubscription_categoryUpdate(t *testing.T) {
})
}

func TestAccAWSRedshiftEventSubscription_tagsUpdate(t *testing.T) {
var v redshift.EventSubscription
rInt := acctest.RandInt()
resourceName := "aws_redshift_event_subscription.bar"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSRedshiftEventSubscriptionDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSRedshiftEventSubscriptionConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRedshiftEventSubscriptionExists(resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "tags.%", "1"),
resource.TestCheckResourceAttr(resourceName, "tags.Name", "name"),
),
},
{
Config: testAccAWSRedshiftEventSubscriptionConfigUpdateTags(rInt, "aaaaa"),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRedshiftEventSubscriptionExists(resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "tags.%", "2"),
resource.TestCheckResourceAttr(resourceName, "tags.Name", "name"),
resource.TestCheckResourceAttr(resourceName, "tags.Test", "aaaaa"),
),
},
{
Config: testAccAWSRedshiftEventSubscriptionConfigUpdateTags(rInt, "bbbbb"),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRedshiftEventSubscriptionExists(resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "tags.%", "2"),
resource.TestCheckResourceAttr(resourceName, "tags.Name", "name"),
resource.TestCheckResourceAttr(resourceName, "tags.Test", "bbbbb"),
),
},
{
Config: testAccAWSRedshiftEventSubscriptionConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRedshiftEventSubscriptionExists(resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "tags.%", "1"),
resource.TestCheckResourceAttr(resourceName, "tags.Name", "name"),
),
},
},
})
}

func testAccCheckAWSRedshiftEventSubscriptionExists(n string, v *redshift.EventSubscription) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
Expand Down Expand Up @@ -382,3 +430,30 @@ resource "aws_redshift_event_subscription" "bar" {
}
`, rInt, rInt)
}

func testAccAWSRedshiftEventSubscriptionConfigUpdateTags(rInt int, rString string) string {
return fmt.Sprintf(`
resource "aws_sns_topic" "aws_sns_topic" {
name = "tf-acc-test-redshift-event-subs-sns-topic-%d"
}

resource "aws_redshift_event_subscription" "bar" {
name = "tf-acc-test-redshift-event-subs-%d"
sns_topic_arn = "${aws_sns_topic.aws_sns_topic.arn}"
source_type = "cluster"
severity = "INFO"

event_categories = [
"configuration",
"management",
"monitoring",
"security",
]

tags = {
Name = "name"
Test = "%s"
}
}
`, rInt, rInt, rString)
}
28 changes: 28 additions & 0 deletions aws/resource_aws_redshift_parameter_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/arn"
"github.com/aws/aws-sdk-go/service/redshift"
"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/schema"
Expand All @@ -24,6 +25,11 @@ func resourceAwsRedshiftParameterGroup() *schema.Resource {
},

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},

"name": {
Type: schema.TypeString,
ForceNew: true,
Expand Down Expand Up @@ -62,6 +68,8 @@ func resourceAwsRedshiftParameterGroup() *schema.Resource {
},
Set: resourceAwsRedshiftParameterHash,
},

"tags": tagsSchema(),
},
}
}
Expand All @@ -73,6 +81,7 @@ func resourceAwsRedshiftParameterGroupCreate(d *schema.ResourceData, meta interf
ParameterGroupName: aws.String(d.Get("name").(string)),
ParameterGroupFamily: aws.String(d.Get("family").(string)),
Description: aws.String(d.Get("description").(string)),
Tags: tagsFromMapRedshift(d.Get("tags").(map[string]interface{})),
}

log.Printf("[DEBUG] Create Redshift Parameter Group: %#v", createOpts)
Expand Down Expand Up @@ -105,9 +114,22 @@ func resourceAwsRedshiftParameterGroupRead(d *schema.ResourceData, meta interfac
return fmt.Errorf("Unable to find Parameter Group: %#v", describeResp.ParameterGroups)
}

arn := arn.ARN{
Partition: meta.(*AWSClient).partition,
Service: "redshift",
Region: meta.(*AWSClient).region,
AccountID: meta.(*AWSClient).accountid,
Resource: fmt.Sprintf("parametergroup:%s", d.Id()),
}.String()

d.Set("arn", arn)

d.Set("name", describeResp.ParameterGroups[0].ParameterGroupName)
d.Set("family", describeResp.ParameterGroups[0].ParameterGroupFamily)
d.Set("description", describeResp.ParameterGroups[0].Description)
if err := d.Set("tags", tagsToMapRedshift(describeResp.ParameterGroups[0].Tags)); err != nil {
return fmt.Errorf("Error setting Redshift Parameter Group Tags: %#v", err)
}

describeParametersOpts := redshift.DescribeClusterParametersInput{
ParameterGroupName: aws.String(d.Id()),
Expand Down Expand Up @@ -161,6 +183,12 @@ func resourceAwsRedshiftParameterGroupUpdate(d *schema.ResourceData, meta interf
d.SetPartial("parameter")
}

if tagErr := setTagsRedshift(conn, d); tagErr != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There was a subtle bug introduced here as the handling of the tags argument would trigger an error because it was not protected by an if d.IsNewResource() conditional and the arn attribute was not set yet (which showed as a * resource ARN in the Redshift error):

--- FAIL: TestAccAWSRedshiftParameterGroup_withTags (8.02s)
    testing.go:568: Step 0 error: errors during apply:

        Error: AccessDenied: User: arn:aws:iam::--OMITTED--:user/bflad is not authorized to perform: redshift:CreateTags on resource: *

To fix this, opted to switch resourceAwsRedshiftParameterGroupCreate from returning resourceAwsRedshiftParameterGroupUpdate to instead return resourceAwsRedshiftParameterGroupRead and implement setting parameters during creation:

	if v := d.Get("parameter").(*schema.Set); v.Len() > 0 {
		parameters, err := expandRedshiftParameters(v.List())

		if err != nil {
			return fmt.Errorf("error expanding parameter: %s", err)
		}

		modifyOpts := redshift.ModifyClusterParameterGroupInput{
			ParameterGroupName: aws.String(d.Id()),
			Parameters:         parameters,
		}

		if _, err := conn.ModifyClusterParameterGroup(&modifyOpts); err != nil {
			return fmt.Errorf("error adding Redshift Parameter Group (%s) parameters: %s", d.Id(), err)
		}
	}

return tagErr
} else {
d.SetPartial("tags")
}

d.Partial(false)
return resourceAwsRedshiftParameterGroupRead(d, meta)
}
Expand Down
74 changes: 74 additions & 0 deletions aws/resource_aws_redshift_parameter_group_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,50 @@ func TestAccAWSRedshiftParameterGroup_withoutParameters(t *testing.T) {
})
}

func TestAccAWSRedshiftParameterGroup_withTags(t *testing.T) {
var v redshift.ClusterParameterGroup

rInt := acctest.RandInt()
resourceName := "aws_redshift_parameter_group.default"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSRedshiftParameterGroupDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSRedshiftParameterGroupConfigWithTags(rInt, "aaa"),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRedshiftParameterGroupExists(resourceName, &v),
resource.TestCheckResourceAttr(
resourceName, "tags.%", "3"),
resource.TestCheckResourceAttr(resourceName, "tags.name", fmt.Sprintf("test-terraform-%d", rInt)),
resource.TestCheckResourceAttr(resourceName, "tags.environment", "Production"),
resource.TestCheckResourceAttr(resourceName, "tags.description", fmt.Sprintf("Test parameter group for terraform %s", "aaa")),
),
},
{
Config: testAccAWSRedshiftParameterGroupConfigWithTags(rInt, "bbb"),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRedshiftParameterGroupExists(resourceName, &v),
resource.TestCheckResourceAttr(
resourceName, "tags.%", "3"),
resource.TestCheckResourceAttr(resourceName, "tags.description", fmt.Sprintf("Test parameter group for terraform %s", "bbb")),
),
},
{
Config: testAccAWSRedshiftParameterGroupConfigWithTagsUpdate(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRedshiftParameterGroupExists(resourceName, &v),
resource.TestCheckResourceAttr(
resourceName, "tags.%", "1"),
resource.TestCheckResourceAttr(resourceName, "tags.name", fmt.Sprintf("test-terraform-%d", rInt)),
),
},
},
})
}

func TestResourceAWSRedshiftParameterGroupNameValidation(t *testing.T) {
cases := []struct {
Value string
Expand Down Expand Up @@ -237,3 +281,33 @@ resource "aws_redshift_parameter_group" "bar" {
}
`, rInt)
}

func testAccAWSRedshiftParameterGroupConfigWithTags(rInt int, rString string) string {
return fmt.Sprintf(`
resource "aws_redshift_parameter_group" "default" {
name = "test-terraform-%[1]d"
family = "redshift-1.0"
description = "Test parameter group for terraform"

tags = {
environment = "Production"
name = "test-terraform-%[1]d"
description = "Test parameter group for terraform %[2]s"
}
}
`, rInt, rString)
}

func testAccAWSRedshiftParameterGroupConfigWithTagsUpdate(rInt int) string {
return fmt.Sprintf(`
resource "aws_redshift_parameter_group" "default" {
name = "test-terraform-%[1]d"
family = "redshift-1.0"
description = "Test parameter group for terraform"

tags = {
name = "test-terraform-%[1]d"
}
}
`, rInt)
}
Loading