Skip to content

Commit

Permalink
provider/aws: Add support to aws_redshift_cluster for iam_roles (
Browse files Browse the repository at this point in the history
  • Loading branch information
stack72 committed May 24, 2016
1 parent 33a7209 commit ce4841e
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 15 deletions.
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

0 comments on commit ce4841e

Please sign in to comment.