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

provider/aws: Add support to aws_redshift_cluster for iam_roles #6647

Merged
merged 1 commit into from
May 24, 2016
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
57 changes: 56 additions & 1 deletion builtin/providers/aws/resource_aws_redshift_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,14 @@ func resourceAwsRedshiftCluster() *schema.Resource {
Computed: true,
},

"iam_roles": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},

"tags": tagsSchema(),
},
}
Expand Down Expand Up @@ -263,6 +271,10 @@ func resourceAwsRedshiftClusterCreate(d *schema.ResourceData, meta interface{})
createOpts.ElasticIp = aws.String(v.(string))
}

if v, ok := d.GetOk("iam_roles"); ok {
createOpts.IamRoles = expandStringList(v.(*schema.Set).List())
}

log.Printf("[DEBUG] Redshift Cluster create options: %s", createOpts)
resp, err := conn.CreateCluster(createOpts)
if err != nil {
Expand Down Expand Up @@ -359,6 +371,14 @@ func resourceAwsRedshiftClusterRead(d *schema.ResourceData, meta interface{}) er
return fmt.Errorf("[DEBUG] Error saving Cluster Security Group Names to state for Redshift Cluster (%s): %s", d.Id(), err)
}

var iamRoles []string
for _, i := range rsc.IamRoles {
iamRoles = append(iamRoles, *i.IamRoleArn)
}
if err := d.Set("iam_roles", iamRoles); err != nil {
return fmt.Errorf("[DEBUG] Error saving IAM Roles to state for Redshift Cluster (%s): %s", d.Id(), err)
}

d.Set("cluster_public_key", rsc.ClusterPublicKey)
d.Set("cluster_revision_number", rsc.ClusterRevisionNumber)
d.Set("tags", tagsToMapRedshift(rsc.Tags))
Expand Down Expand Up @@ -461,6 +481,41 @@ func resourceAwsRedshiftClusterUpdate(d *schema.ResourceData, meta interface{})
if err != nil {
return fmt.Errorf("[WARN] Error modifying Redshift Cluster (%s): %s", d.Id(), err)
}
}

if d.HasChange("iam_roles") {
o, n := d.GetChange("iam_roles")
if o == nil {
o = new(schema.Set)
}
if n == nil {
n = new(schema.Set)
}

os := o.(*schema.Set)
ns := n.(*schema.Set)

removeIams := os.Difference(ns).List()
addIams := ns.Difference(os).List()

log.Printf("[INFO] Building Redshift Modify Cluster IAM Role Options")
req := &redshift.ModifyClusterIamRolesInput{
ClusterIdentifier: aws.String(d.Id()),
AddIamRoles: expandStringList(addIams),
RemoveIamRoles: expandStringList(removeIams),
}

log.Printf("[INFO] Modifying Redshift Cluster IAM Roles: %s", d.Id())
log.Printf("[DEBUG] Redshift Cluster Modify IAM Role options: %s", req)
_, err := conn.ModifyClusterIamRoles(req)
if err != nil {
return fmt.Errorf("[WARN] Error modifying Redshift Cluster IAM Roles (%s): %s", d.Id(), err)
}

d.SetPartial("iam_roles")
}

if requestUpdate || d.HasChange("iam_roles") {

stateConf := &resource.StateChangeConf{
Pending: []string{"creating", "deleting", "rebooting", "resizing", "renaming", "modifying"},
Expand All @@ -471,7 +526,7 @@ func resourceAwsRedshiftClusterUpdate(d *schema.ResourceData, meta interface{})
}

// Wait, catching any errors
_, err = stateConf.WaitForState()
_, err := stateConf.WaitForState()
if err != nil {
return fmt.Errorf("[WARN] Error Modifying Redshift Cluster (%s): %s", d.Id(), err)
}
Expand Down
97 changes: 83 additions & 14 deletions builtin/providers/aws/resource_aws_redshift_cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,39 @@ func TestAccAWSRedshiftCluster_basic(t *testing.T) {
})
}

func TestAccAWSRedshiftCluster_iamRoles(t *testing.T) {
var v redshift.Cluster

ri := rand.New(rand.NewSource(time.Now().UnixNano())).Int()
preConfig := fmt.Sprintf(testAccAWSRedshiftClusterConfig_iamRoles, ri, ri, ri)
postConfig := fmt.Sprintf(testAccAWSRedshiftClusterConfig_updateIamRoles, ri, ri, ri)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSRedshiftClusterDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: preConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
resource.TestCheckResourceAttr(
"aws_redshift_cluster.default", "iam_roles.#", "2"),
),
},

resource.TestStep{
Config: postConfig,
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSRedshiftClusterExists("aws_redshift_cluster.default", &v),
resource.TestCheckResourceAttr(
"aws_redshift_cluster.default", "iam_roles.#", "1"),
),
},
},
})
}

func TestAccAWSRedshiftCluster_publiclyAccessible(t *testing.T) {
var v redshift.Cluster

Expand Down Expand Up @@ -376,7 +409,6 @@ resource "aws_redshift_cluster" "default" {
node_type = "dc1.large"
automated_snapshot_retention_period = 7
allow_version_upgrade = false

tags {
environment = "Production"
cluster = "reader"
Expand All @@ -394,7 +426,6 @@ resource "aws_redshift_cluster" "default" {
node_type = "dc1.large"
automated_snapshot_retention_period = 7
allow_version_upgrade = false

tags {
environment = "Production"
}
Expand All @@ -404,14 +435,12 @@ var testAccAWSRedshiftClusterConfig_notPubliclyAccessible = `
resource "aws_vpc" "foo" {
cidr_block = "10.1.0.0/16"
}

resource "aws_internet_gateway" "foo" {
vpc_id = "${aws_vpc.foo.id}"
tags {
foo = "bar"
}
}

resource "aws_subnet" "foo" {
cidr_block = "10.1.1.0/24"
availability_zone = "us-west-2a"
Expand All @@ -420,7 +449,6 @@ resource "aws_subnet" "foo" {
Name = "tf-dbsubnet-test-1"
}
}

resource "aws_subnet" "bar" {
cidr_block = "10.1.2.0/24"
availability_zone = "us-west-2b"
Expand All @@ -429,7 +457,6 @@ resource "aws_subnet" "bar" {
Name = "tf-dbsubnet-test-2"
}
}

resource "aws_subnet" "foobar" {
cidr_block = "10.1.3.0/24"
availability_zone = "us-west-2c"
Expand All @@ -438,13 +465,11 @@ resource "aws_subnet" "foobar" {
Name = "tf-dbsubnet-test-3"
}
}

resource "aws_redshift_subnet_group" "foo" {
name = "foo"
description = "foo description"
subnet_ids = ["${aws_subnet.foo.id}", "${aws_subnet.bar.id}", "${aws_subnet.foobar.id}"]
}

resource "aws_redshift_cluster" "default" {
cluster_identifier = "tf-redshift-cluster-%d"
availability_zone = "us-west-2a"
Expand All @@ -462,14 +487,12 @@ var testAccAWSRedshiftClusterConfig_updatePubliclyAccessible = `
resource "aws_vpc" "foo" {
cidr_block = "10.1.0.0/16"
}

resource "aws_internet_gateway" "foo" {
vpc_id = "${aws_vpc.foo.id}"
tags {
foo = "bar"
}
}

resource "aws_subnet" "foo" {
cidr_block = "10.1.1.0/24"
availability_zone = "us-west-2a"
Expand All @@ -478,7 +501,6 @@ resource "aws_subnet" "foo" {
Name = "tf-dbsubnet-test-1"
}
}

resource "aws_subnet" "bar" {
cidr_block = "10.1.2.0/24"
availability_zone = "us-west-2b"
Expand All @@ -487,7 +509,6 @@ resource "aws_subnet" "bar" {
Name = "tf-dbsubnet-test-2"
}
}

resource "aws_subnet" "foobar" {
cidr_block = "10.1.3.0/24"
availability_zone = "us-west-2c"
Expand All @@ -496,13 +517,11 @@ resource "aws_subnet" "foobar" {
Name = "tf-dbsubnet-test-3"
}
}

resource "aws_redshift_subnet_group" "foo" {
name = "foo"
description = "foo description"
subnet_ids = ["${aws_subnet.foo.id}", "${aws_subnet.bar.id}", "${aws_subnet.foobar.id}"]
}

resource "aws_redshift_cluster" "default" {
cluster_identifier = "tf-redshift-cluster-%d"
availability_zone = "us-west-2a"
Expand All @@ -515,3 +534,53 @@ resource "aws_redshift_cluster" "default" {
cluster_subnet_group_name = "${aws_redshift_subnet_group.foo.name}"
publicly_accessible = true
}`

var testAccAWSRedshiftClusterConfig_iamRoles = `
resource "aws_iam_role" "ec2-role" {
name = "test-role-ec2-%d"
path = "/"
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"
}

resource "aws_iam_role" "lambda-role" {
name = "test-role-lambda-%d"
path = "/"
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"lambda.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"
}

resource "aws_redshift_cluster" "default" {
cluster_identifier = "tf-redshift-cluster-%d"
availability_zone = "us-west-2a"
database_name = "mydb"
master_username = "foo_test"
master_password = "Mustbe8characters"
node_type = "dc1.large"
automated_snapshot_retention_period = 0
allow_version_upgrade = false
iam_roles = ["${aws_iam_role.ec2-role.arn}", "${aws_iam_role.lambda-role.arn}"]
}`

var testAccAWSRedshiftClusterConfig_updateIamRoles = `
resource "aws_iam_role" "ec2-role" {
name = "test-role-ec2-%d"
path = "/"
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"ec2.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"
}

resource "aws_iam_role" "lambda-role" {
name = "test-role-lambda-%d"
path = "/"
assume_role_policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"Service\":[\"lambda.amazonaws.com\"]},\"Action\":[\"sts:AssumeRole\"]}]}"
}

resource "aws_redshift_cluster" "default" {
cluster_identifier = "tf-redshift-cluster-%d"
availability_zone = "us-west-2a"
database_name = "mydb"
master_username = "foo_test"
master_password = "Mustbe8characters"
node_type = "dc1.large"
automated_snapshot_retention_period = 0
allow_version_upgrade = false
iam_roles = ["${aws_iam_role.ec2-role.arn}"]
}`
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ string.
* `elastic_ip` - (Optional) The Elastic IP (EIP) address for the cluster.
* `skip_final_snapshot` - (Optional) Determines whether a final snapshot of the cluster is created before Amazon Redshift deletes the cluster. If true , a final cluster snapshot is not created. If false , a final cluster snapshot is created before the cluster is deleted. Default is true.
* `final_snapshot_identifier` - (Optional) The identifier of the final snapshot that is to be created immediately before deleting the cluster. If this parameter is provided, `skip_final_snapshot` must be false.
* `iam_roles` - (Optional) A list of IAM Role ARNs to associate with the cluster. A Maximum of 10 can be associated to the cluster at any time.
* `tags` - (Optional) A mapping of tags to assign to the resource.


## Attributes Reference

The following attributes are exported:
Expand Down