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

rd/redshift_cluster - add missing arguments + attributes #24982

Merged
merged 16 commits into from
May 25, 2022
Merged
7 changes: 7 additions & 0 deletions .changelog/24982.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
resource/aws_redshift_cluster: Add `default_iam_role_arn`, `maintenance_track_name`, and `manual_snapshot_retention_period` arguments.
```

```release-note:enhancement
data-source/aws_redshift_cluster: Add `arn`, `cluster_nodes`, `cluster_nodes`, `maintenance_track_name`, `manual_snapshot_retention_period`, `log_destination_type`, and `log_exports` attributes.
```
49 changes: 46 additions & 3 deletions internal/service/redshift/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ func ResourceCluster() *schema.Resource {
validation.StringMatch(regexp.MustCompile(`(?i)^[a-z_]`), "first character must be a letter or underscore"),
),
},
"default_iam_role_arn": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: verify.ValidARN,
},
"dns_name": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -235,6 +240,17 @@ func ResourceCluster() *schema.Resource {
},
},
},
"maintenance_track_name": {
Type: schema.TypeString,
Optional: true,
Default: "current",
},
"manual_snapshot_retention_period": {
Type: schema.TypeInt,
Optional: true,
Default: -1,
ValidateFunc: validation.IntBetween(-1, 3653),
},
"master_password": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -425,6 +441,11 @@ func resourceClusterCreate(d *schema.ResourceData, meta interface{}) error {
input.ClusterSubnetGroupName = aws.String(v.(string))
}

if v, ok := d.GetOk("default_iam_role_arn"); ok {
backupInput.DefaultIamRoleArn = aws.String(v.(string))
input.DefaultIamRoleArn = aws.String(v.(string))
}

if v, ok := d.GetOk("elastic_ip"); ok {
backupInput.ElasticIp = aws.String(v.(string))
input.ElasticIp = aws.String(v.(string))
Expand All @@ -445,6 +466,16 @@ func resourceClusterCreate(d *schema.ResourceData, meta interface{}) error {
input.KmsKeyId = aws.String(v.(string))
}

if v, ok := d.GetOk("maintenance_track_name"); ok {
backupInput.MaintenanceTrackName = aws.String(v.(string))
input.MaintenanceTrackName = aws.String(v.(string))
}

if v, ok := d.GetOk("manual_snapshot_retention_period"); ok {
backupInput.ManualSnapshotRetentionPeriod = aws.Int64(int64(v.(int)))
input.ManualSnapshotRetentionPeriod = aws.Int64(int64(v.(int)))
}

if v, ok := d.GetOk("number_of_nodes"); ok {
backupInput.NumberOfNodes = aws.Int64(int64(v.(int)))
// NumberOfNodes set below for CreateCluster.
Expand Down Expand Up @@ -566,7 +597,7 @@ func resourceClusterRead(d *schema.ResourceData, meta interface{}) error {
d.Set("allow_version_upgrade", rsc.AllowVersionUpgrade)
arn := arn.ARN{
Partition: meta.(*conns.AWSClient).Partition,
Service: "redshift",
Service: redshift.ServiceName,
Region: meta.(*conns.AWSClient).Region,
AccountID: meta.(*conns.AWSClient).AccountID,
Resource: fmt.Sprintf("cluster:%s", d.Id()),
Expand All @@ -579,7 +610,7 @@ func resourceClusterRead(d *schema.ResourceData, meta interface{}) error {
d.Set("availability_zone", rsc.AvailabilityZone)
azr, err := clusterAvailabilityZoneRelocationStatus(rsc)
if err != nil {
return fmt.Errorf("error reading Redshift Cluster (%s): %w", d.Id(), err)
return err
}
d.Set("availability_zone_relocation_enabled", azr)
d.Set("cluster_identifier", rsc.ClusterIdentifier)
Expand All @@ -597,12 +628,15 @@ func resourceClusterRead(d *schema.ResourceData, meta interface{}) error {
}
d.Set("cluster_version", rsc.ClusterVersion)
d.Set("database_name", rsc.DBName)
d.Set("default_iam_role_arn", rsc.DefaultIamRoleArn)
d.Set("encrypted", rsc.Encrypted)
d.Set("enhanced_vpc_routing", rsc.EnhancedVpcRouting)
d.Set("kms_key_id", rsc.KmsKeyId)
if err := d.Set("logging", flattenLogging(loggingStatus)); err != nil {
return fmt.Errorf("error setting logging: %w", err)
}
d.Set("maintenance_track_name", rsc.MaintenanceTrackName)
d.Set("manual_snapshot_retention_period", rsc.ManualSnapshotRetentionPeriod)
d.Set("master_username", rsc.MasterUsername)
d.Set("node_type", rsc.NodeType)
d.Set("number_of_nodes", rsc.NumberOfNodes)
Expand Down Expand Up @@ -690,6 +724,14 @@ func resourceClusterUpdate(d *schema.ResourceData, meta interface{}) error {
input.ClusterSecurityGroups = flex.ExpandStringSet(d.Get("cluster_security_groups").(*schema.Set))
}

if d.HasChange("maintenance_track_name") {
input.MaintenanceTrackName = aws.String(d.Get("maintenance_track_name").(string))
}

if d.HasChange("manual_snapshot_retention_period") {
input.ManualSnapshotRetentionPeriod = aws.Int64(int64(d.Get("manual_snapshot_retention_period").(int)))
}

// If the cluster type, node type, or number of nodes changed, then the AWS API expects all three
// items to be sent over.
if d.HasChanges("cluster_type", "node_type", "number_of_nodes") {
Expand Down Expand Up @@ -751,7 +793,7 @@ func resourceClusterUpdate(d *schema.ResourceData, meta interface{}) error {
}
}

if d.HasChange("iam_roles") {
if d.HasChanges("iam_roles", "default_iam_role_arn") {
o, n := d.GetChange("iam_roles")
if o == nil {
o = new(schema.Set)
Expand All @@ -769,6 +811,7 @@ func resourceClusterUpdate(d *schema.ResourceData, meta interface{}) error {
AddIamRoles: flex.ExpandStringSet(add),
ClusterIdentifier: aws.String(d.Id()),
RemoveIamRoles: flex.ExpandStringSet(del),
DefaultIamRoleArn: aws.String(d.Get("default_iam_role_arn").(string)),
}

log.Printf("[DEBUG] Modifying Redshift Cluster IAM Roles: %s", input)
Expand Down
118 changes: 81 additions & 37 deletions internal/service/redshift/cluster_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ package redshift

import (
"fmt"
"log"

"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-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/internal/flex"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
)

Expand All @@ -24,6 +25,10 @@ func DataSourceCluster() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"arn": {
Type: schema.TypeString,
Computed: true,
},
"automated_snapshot_retention_period": {
Type: schema.TypeInt,
Computed: true,
Expand All @@ -44,6 +49,26 @@ func DataSourceCluster() *schema.Resource {
Type: schema.TypeString,
Required: true,
},
"cluster_nodes": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"node_role": {
Type: schema.TypeString,
Computed: true,
},
"private_ip_address": {
Type: schema.TypeString,
Computed: true,
},
"public_ip_address": {
Type: schema.TypeString,
Computed: true,
},
},
},
},
"cluster_parameter_group_name": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -77,6 +102,10 @@ func DataSourceCluster() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"default_iam_role_arn": {
Type: schema.TypeString,
Computed: true,
},
"elastic_ip": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -110,6 +139,14 @@ func DataSourceCluster() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"maintenance_track_name": {
Type: schema.TypeString,
Computed: true,
},
"manual_snapshot_retention_period": {
Type: schema.TypeInt,
Computed: true,
},
"node_type": {
Type: schema.TypeString,
Computed: true,
Expand All @@ -134,6 +171,15 @@ func DataSourceCluster() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"log_destination_type": {
Type: schema.TypeString,
Computed: true,
},
"log_exports": {
Type: schema.TypeSet,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"tags": tftags.TagsSchema(),
"vpc_id": {
Type: schema.TypeString,
Expand All @@ -152,37 +198,37 @@ func dataSourceClusterRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).RedshiftConn
ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig

cluster := d.Get("cluster_identifier").(string)

log.Printf("[INFO] Reading Redshift Cluster Information: %s", cluster)

resp, err := conn.DescribeClusters(&redshift.DescribeClustersInput{
ClusterIdentifier: aws.String(cluster),
})
clusterID := d.Get("cluster_identifier").(string)
rsc, err := FindClusterByID(conn, clusterID)

if err != nil {
return fmt.Errorf("Error describing Redshift Cluster: %s, error: %w", cluster, err)
return fmt.Errorf("reading Redshift Cluster (%s): %w", clusterID, err)
}

if resp.Clusters == nil || len(resp.Clusters) == 0 || resp.Clusters[0] == nil {
return fmt.Errorf("Error describing Redshift Cluster: %s, cluster information not found", cluster)
}

rsc := resp.Clusters[0]

d.SetId(cluster)
d.SetId(clusterID)
d.Set("allow_version_upgrade", rsc.AllowVersionUpgrade)
arn := arn.ARN{
Partition: meta.(*conns.AWSClient).Partition,
Service: redshift.ServiceName,
Region: meta.(*conns.AWSClient).Region,
AccountID: meta.(*conns.AWSClient).AccountID,
Resource: fmt.Sprintf("cluster:%s", d.Id()),
}.String()
d.Set("arn", arn)
d.Set("automated_snapshot_retention_period", rsc.AutomatedSnapshotRetentionPeriod)
if rsc.AquaConfiguration != nil {
d.Set("aqua_configuration_status", rsc.AquaConfiguration.AquaConfigurationStatus)
}
d.Set("availability_zone", rsc.AvailabilityZone)
azr, err := clusterAvailabilityZoneRelocationStatus(rsc)
if err != nil {
return fmt.Errorf("error reading Redshift Cluster (%s): %w", d.Id(), err)
return err
}
d.Set("availability_zone_relocation_enabled", azr)
d.Set("cluster_identifier", rsc.ClusterIdentifier)
if err := d.Set("cluster_nodes", flattenClusterNodes(rsc.ClusterNodes)); err != nil {
return fmt.Errorf("setting cluster_nodes: %w", err)
}

if len(rsc.ClusterParameterGroups) > 0 {
d.Set("cluster_parameter_group_name", rsc.ClusterParameterGroups[0].ParameterGroupName)
Expand All @@ -193,18 +239,16 @@ func dataSourceClusterRead(d *schema.ResourceData, meta interface{}) error {

var csg []string
for _, g := range rsc.ClusterSecurityGroups {
csg = append(csg, *g.ClusterSecurityGroupName)
}
if err := d.Set("cluster_security_groups", csg); err != nil {
return fmt.Errorf("Error saving Cluster Security Group Names to state for Redshift Cluster (%s): %w", cluster, err)
csg = append(csg, aws.StringValue(g.ClusterSecurityGroupName))
}
d.Set("cluster_security_groups", csg)

d.Set("cluster_subnet_group_name", rsc.ClusterSubnetGroupName)

if len(rsc.ClusterNodes) > 1 {
d.Set("cluster_type", "multi-node")
d.Set("cluster_type", clusterTypeMultiNode)
} else {
d.Set("cluster_type", "single-node")
d.Set("cluster_type", clusterTypeSingleNode)
}

d.Set("cluster_version", rsc.ClusterVersion)
Expand All @@ -224,11 +268,9 @@ func dataSourceClusterRead(d *schema.ResourceData, meta interface{}) error {

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("Error saving IAM Roles to state for Redshift Cluster (%s): %w", cluster, err)
iamRoles = append(iamRoles, aws.StringValue(i.IamRoleArn))
}
d.Set("iam_roles", iamRoles)

d.Set("kms_key_id", rsc.KmsKeyId)
d.Set("master_username", rsc.MasterUsername)
Expand All @@ -237,34 +279,36 @@ func dataSourceClusterRead(d *schema.ResourceData, meta interface{}) error {
d.Set("port", rsc.Endpoint.Port)
d.Set("preferred_maintenance_window", rsc.PreferredMaintenanceWindow)
d.Set("publicly_accessible", rsc.PubliclyAccessible)
d.Set("default_iam_role_arn", rsc.DefaultIamRoleArn)
d.Set("maintenance_track_name", rsc.MaintenanceTrackName)
d.Set("manual_snapshot_retention_period", rsc.ManualSnapshotRetentionPeriod)

if err := d.Set("tags", KeyValueTags(rsc.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
return fmt.Errorf("error setting tags: %w", err)
return fmt.Errorf("setting tags: %w", err)
}

d.Set("vpc_id", rsc.VpcId)

var vpcg []string
for _, g := range rsc.VpcSecurityGroups {
vpcg = append(vpcg, *g.VpcSecurityGroupId)
}
if err := d.Set("vpc_security_group_ids", vpcg); err != nil {
return fmt.Errorf("Error saving VPC Security Group IDs to state for Redshift Cluster (%s): %w", cluster, err)
vpcg = append(vpcg, aws.StringValue(g.VpcSecurityGroupId))
}
d.Set("vpc_security_group_ids", vpcg)

log.Printf("[INFO] Reading Redshift Cluster Logging Status: %s", cluster)
loggingStatus, loggingErr := conn.DescribeLoggingStatus(&redshift.DescribeLoggingStatusInput{
ClusterIdentifier: aws.String(cluster),
loggingStatus, err := conn.DescribeLoggingStatus(&redshift.DescribeLoggingStatusInput{
ClusterIdentifier: aws.String(clusterID),
})

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

if loggingStatus != nil && aws.BoolValue(loggingStatus.LoggingEnabled) {
d.Set("enable_logging", loggingStatus.LoggingEnabled)
d.Set("bucket_name", loggingStatus.BucketName)
d.Set("s3_key_prefix", loggingStatus.S3KeyPrefix)
d.Set("log_exports", flex.FlattenStringSet(loggingStatus.LogExports))
d.Set("log_destination_type", loggingStatus.LogDestinationType)
}

return nil
Expand Down
Loading