From ae1e10ac4089e7c85174490a6d928ced04d37311 Mon Sep 17 00:00:00 2001 From: hitofuji Date: Sun, 10 May 2020 15:49:15 +0900 Subject: [PATCH 01/27] add schema --- aws/resource_aws_redshift_scheduled_action.go | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 aws/resource_aws_redshift_scheduled_action.go diff --git a/aws/resource_aws_redshift_scheduled_action.go b/aws/resource_aws_redshift_scheduled_action.go new file mode 100644 index 00000000000..d0a366316e5 --- /dev/null +++ b/aws/resource_aws_redshift_scheduled_action.go @@ -0,0 +1,97 @@ +package aws + +import ( + "github.com/aws/aws-sdk-go/service/glue" + "github.com/aws/aws-sdk-go/service/redshift" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" +) + +func resourceAwsRedshiftScheduledAction() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsRedshiftScheduledActionCreate, + Read: resourceAwsRedshiftScheduledActionRead, + Update: resourceAwsRedshiftScheduledActionUpdate, + Delete: resourceAwsRedshiftScheduledActionDelete, + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + ForceNew: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + "active": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "start_time": { + Type: schema.TypeString, + Optional: true, + }, + "end_time": { + Type: schema.TypeString, + Optional: true, + }, + "schedule": { + Type: schema.TypeString, + Required: true, + }, + "iam_role": { + Type: schema.TypeString, + Required: true, + }, + "target_action": { + Type: schema.TypeMap, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "PauseClusterMessage", + "ResizeCluster", + "ResumeCluster", + }, false), + }, + "cluster_identifier": { + Type: schema.TypeString, + Required: true, + }, + "classic": { + Type: schema.TypeBool, + Optional: true, + }, + "cluster_type": { + Type: schema.TypeString, + Optional: true, + }, + "node_type": { + Type: schema.TypeString, + Optional: true, + }, + "number_of_nodes": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + }, + } + +} From dc6c8c126958e05715e94a357b8438db6418017a Mon Sep 17 00:00:00 2001 From: hitofuji Date: Mon, 11 May 2020 09:33:32 +0900 Subject: [PATCH 02/27] add create method excepted target_action --- aws/resource_aws_redshift_scheduled_action.go | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/aws/resource_aws_redshift_scheduled_action.go b/aws/resource_aws_redshift_scheduled_action.go index d0a366316e5..6174aa88e79 100644 --- a/aws/resource_aws_redshift_scheduled_action.go +++ b/aws/resource_aws_redshift_scheduled_action.go @@ -1,10 +1,14 @@ package aws import ( + "fmt" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/glue" "github.com/aws/aws-sdk-go/service/redshift" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "time" ) func resourceAwsRedshiftScheduledAction() *schema.Resource { @@ -31,7 +35,6 @@ func resourceAwsRedshiftScheduledAction() *schema.Resource { "description": { Type: schema.TypeString, Optional: true, - ForceNew: true, }, "active": { Type: schema.TypeBool, @@ -93,5 +96,32 @@ func resourceAwsRedshiftScheduledAction() *schema.Resource { }, }, } +} +func resourceAwsRedshiftScheduledActionCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).redshiftconn + var name string + if v, ok := d.GetOk("name"); ok { + name = v.(string) + } else { + name = resource.UniqueId() + } + createOpts := &redshift.CreateScheduledActionInput{ + ScheduledActionName: aws.String(name), + Schedule: aws.String(d.Get("schedule").(string)), + IamRole: aws.String(d.Get("iam_role").(string)), + } + // TODO: add target_action + if attr, ok := d.GetOk("description"); ok { + createOpts.ScheduledActionDescription = aws.String(attr.(string)) + } + if attr, ok := d.GetOk("active"); ok { + createOpts.Enable = aws.Bool(attr.(bool)) + } + if attr, ok := d.GetOk("start_time"); ok { + createOpts.StartTime = aws.Time(attr.(time.Time)) + } + if attr, ok := d.GetOk("end_time"); ok { + createOpts.EndTime = aws.Time(attr.(time.Time)) + } } From ddc1775c072aaffe6f24407e375ab867c4c7601f Mon Sep 17 00:00:00 2001 From: hitofuji Date: Sun, 17 May 2020 15:47:49 +0900 Subject: [PATCH 03/27] create resource file --- aws/resource_aws_redshift_scheduled_action.go | 158 ++++++++++++++++-- 1 file changed, 148 insertions(+), 10 deletions(-) diff --git a/aws/resource_aws_redshift_scheduled_action.go b/aws/resource_aws_redshift_scheduled_action.go index 6174aa88e79..6110d191267 100644 --- a/aws/resource_aws_redshift_scheduled_action.go +++ b/aws/resource_aws_redshift_scheduled_action.go @@ -3,11 +3,11 @@ package aws import ( "fmt" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/glue" "github.com/aws/aws-sdk-go/service/redshift" "github.com/hashicorp/terraform-plugin-sdk/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "log" "time" ) @@ -22,11 +22,6 @@ func resourceAwsRedshiftScheduledAction() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "arn": { - Type: schema.TypeString, - Computed: true, - ForceNew: true, - }, "name": { Type: schema.TypeString, Required: true, @@ -66,9 +61,9 @@ func resourceAwsRedshiftScheduledAction() *schema.Resource { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringInSlice([]string{ - "PauseClusterMessage", - "ResizeCluster", - "ResumeCluster", + redshift.ScheduledActionTypeValuesResumeCluster, + redshift.ScheduledActionTypeValuesPauseCluster, + redshift.ScheduledActionTypeValuesResizeCluster, }, false), }, "cluster_identifier": { @@ -110,8 +105,8 @@ func resourceAwsRedshiftScheduledActionCreate(d *schema.ResourceData, meta inter ScheduledActionName: aws.String(name), Schedule: aws.String(d.Get("schedule").(string)), IamRole: aws.String(d.Get("iam_role").(string)), + TargetAction: expandRedshiftScheduledActionTargetAction(d.Get("target_action")), } - // TODO: add target_action if attr, ok := d.GetOk("description"); ok { createOpts.ScheduledActionDescription = aws.String(attr.(string)) } @@ -124,4 +119,147 @@ func resourceAwsRedshiftScheduledActionCreate(d *schema.ResourceData, meta inter if attr, ok := d.GetOk("end_time"); ok { createOpts.EndTime = aws.Time(attr.(time.Time)) } + + log.Printf("[DEBUG] Creating Glue Connection: %s", createOpts) + _, err := conn.CreateScheduledAction(createOpts) + if err != nil { + return fmt.Errorf("error creating Glue Connection (%s): %s", name, err) + } + + d.SetId(name) + + return resourceAwsRedshiftScheduledActionRead(d, meta) +} + +func resourceAwsRedshiftScheduledActionRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).redshiftconn + + descOpts := &redshift.DescribeScheduledActionsInput{ + ScheduledActionName: aws.String(d.Id()), + } + + resp, err := conn.DescribeScheduledActions(descOpts) + if err != nil { + return fmt.Errorf("Error describing Redshift Scheduled Action %s: %s", d.Id(), err) + } + + if resp.ScheduledActions == nil || len(resp.ScheduledActions) != 1 { + log.Printf("[WARN] Unable to find Redshift Scheduled Action (%s)", d.Id()) + d.SetId("") + return nil + } + + scheduledAction := resp.ScheduledActions[0] + + d.Set("name", scheduledAction.ScheduledActionName) + d.Set("description", scheduledAction.ScheduledActionDescription) + d.Set("active", scheduledAction.State) + d.Set("start_time", scheduledAction.StartTime) + d.Set("end_time", scheduledAction.EndTime) + d.Set("schedule", scheduledAction.Schedule) + d.Set("iam_role", scheduledAction.IamRole) + + if err := d.Set("target_action", flattenRedshiftScheduledActionType(scheduledAction.TargetAction)); err != nil { + return fmt.Errorf("Error setting definitions: %s", err) + } + + return nil +} + +func resourceAwsRedshiftScheduledActionUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).redshiftconn + + modifyOpts := &redshift.ModifyScheduledActionInput{ + ScheduledActionName: aws.String(d.Id()), + Schedule: aws.String(d.Get("schedule").(string)), + IamRole: aws.String(d.Get("iam_role").(string)), + TargetAction: expandRedshiftScheduledActionTargetAction(d.Get("target_action")), + Enable: aws.Bool(d.Get("active").(bool)), + StartTime: aws.Time(d.Get("start_time").(time.Time)), + EndTime: aws.Time(d.Get("end_time").(time.Time)), + ScheduledActionDescription: aws.String(d.Get("description").(string)), + } + + log.Printf("[DEBUG] Updating Redshift Scheduled Action: %s", modifyOpts) + _, err := conn.ModifyScheduledAction(modifyOpts) + if err != nil { + return fmt.Errorf("error updating Redshift Scheduled Action (%s): %s", d.Id(), err) + } + + return nil +} + +func resourceAwsRedshiftScheduledActionDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).redshiftconn + + deleteOpts := &redshift.DeleteScheduledActionInput{ + ScheduledActionName: aws.String(d.Id()), + } + + log.Printf("[DEBUG] Deleting Redshift Scheduled Action: %s", deleteOpts) + _, err := conn.DeleteScheduledAction(deleteOpts) + if err != nil { + return fmt.Errorf("error deleting Redshift Scheduled Action (%s): %s", d.Id(), err) + } + + return nil +} + +func expandRedshiftScheduledActionTargetAction(configured interface{}) *redshift.ScheduledActionType { + if configured == nil { + return nil + } + if configured.([]interface{}) == nil || len(configured.([]interface{})) == 0 { + return nil + } + + p := configured.(map[string]interface{}) + targetAction := &redshift.ScheduledActionType{} + + switch p["action"].(string) { + case redshift.ScheduledActionTypeValuesPauseCluster: + targetAction.PauseCluster.ClusterIdentifier = p["cluster_identifier"].(*string) + case redshift.ScheduledActionTypeValuesResumeCluster: + targetAction.ResumeCluster.ClusterIdentifier = p["cluster_identifier"].(*string) + case redshift.ScheduledActionTypeValuesResizeCluster: + targetAction.ResizeCluster.ClusterIdentifier = p["cluster_identifier"].(*string) + targetAction.ResizeCluster.Classic = p["classic"].(*bool) + targetAction.ResizeCluster.ClusterType = p["cluster_type"].(*string) + targetAction.ResizeCluster.NodeType = p["node_type"].(*string) + targetAction.ResizeCluster.NumberOfNodes = p["number_of_nodes"].(*int64) + } + + return targetAction +} + +func flattenRedshiftScheduledActionType(scheduledActionType *redshift.ScheduledActionType) map[string]interface{} { + if scheduledActionType == nil { + return map[string]interface{}{} + } + + m := map[string]interface{}{} + + if scheduledActionType.ResumeCluster != nil { + m = map[string]interface{}{ + "action": redshift.ScheduledActionTypeValuesResumeCluster, + "cluster_identifier": aws.StringValue(scheduledActionType.ResumeCluster.ClusterIdentifier), + } + } + if scheduledActionType.PauseCluster != nil { + m = map[string]interface{}{ + "action": redshift.ScheduledActionTypeValuesPauseCluster, + "cluster_identifier": aws.StringValue(scheduledActionType.PauseCluster.ClusterIdentifier), + } + } + if scheduledActionType.ResizeCluster != nil { + m = map[string]interface{}{ + "action": redshift.ScheduledActionTypeValuesResizeCluster, + "cluster_identifier": aws.StringValue(scheduledActionType.ResizeCluster.ClusterIdentifier), + "classic": aws.BoolValue(scheduledActionType.ResizeCluster.Classic), + "cluster_type": aws.StringValue(scheduledActionType.ResizeCluster.ClusterType), + "node_type": aws.StringValue(scheduledActionType.ResizeCluster.NodeType), + "number_of_nodes": aws.Int64Value(scheduledActionType.ResizeCluster.NumberOfNodes), + } + } + return m } From b43dcbaeb5da0b41aa0dfb7fca35c8ef7b76bf0b Mon Sep 17 00:00:00 2001 From: hitofuji Date: Sun, 17 May 2020 16:01:54 +0900 Subject: [PATCH 04/27] update provider.go --- aws/provider.go | 1 + 1 file changed, 1 insertion(+) diff --git a/aws/provider.go b/aws/provider.go index 6e990105ddf..ffc11c05617 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -1010,6 +1010,7 @@ func Provider() *schema.Provider { "aws_redshift_snapshot_schedule": resourceAwsRedshiftSnapshotSchedule(), "aws_redshift_snapshot_schedule_association": resourceAwsRedshiftSnapshotScheduleAssociation(), "aws_redshift_event_subscription": resourceAwsRedshiftEventSubscription(), + "aws_redshift_scheduled_action": resourceAwsRedshiftScheduledAction(), "aws_resourcegroups_group": resourceAwsResourceGroupsGroup(), "aws_route53_delegation_set": resourceAwsRoute53DelegationSet(), "aws_route53_hosted_zone_dnssec": resourceAwsRoute53HostedZoneDnssec(), From 7ef41f842928abe3a62393c8302d7ef9abd0fd46 Mon Sep 17 00:00:00 2001 From: hitofuji Date: Sun, 24 May 2020 00:34:00 +0900 Subject: [PATCH 05/27] fix bugs --- aws/resource_aws_redshift_scheduled_action.go | 53 ++++++++++++------- 1 file changed, 34 insertions(+), 19 deletions(-) diff --git a/aws/resource_aws_redshift_scheduled_action.go b/aws/resource_aws_redshift_scheduled_action.go index 6110d191267..c08dbfa7264 100644 --- a/aws/resource_aws_redshift_scheduled_action.go +++ b/aws/resource_aws_redshift_scheduled_action.go @@ -114,16 +114,18 @@ func resourceAwsRedshiftScheduledActionCreate(d *schema.ResourceData, meta inter createOpts.Enable = aws.Bool(attr.(bool)) } if attr, ok := d.GetOk("start_time"); ok { - createOpts.StartTime = aws.Time(attr.(time.Time)) + t, _ := time.Parse("2006-01-02T15:04:05-0700", attr.(string)) + createOpts.StartTime = aws.Time(t) } if attr, ok := d.GetOk("end_time"); ok { - createOpts.EndTime = aws.Time(attr.(time.Time)) + t, _ := time.Parse("2006-01-02T15:04:05-0700", attr.(string)) + createOpts.EndTime = aws.Time(t) } - log.Printf("[DEBUG] Creating Glue Connection: %s", createOpts) + log.Printf("[DEBUG] Creating Redshift Scheduled Action: %s", createOpts) _, err := conn.CreateScheduledAction(createOpts) if err != nil { - return fmt.Errorf("error creating Glue Connection (%s): %s", name, err) + return fmt.Errorf("error creating Redshift Scheduled Action (%s): %s", name, err) } d.SetId(name) @@ -175,11 +177,18 @@ func resourceAwsRedshiftScheduledActionUpdate(d *schema.ResourceData, meta inter IamRole: aws.String(d.Get("iam_role").(string)), TargetAction: expandRedshiftScheduledActionTargetAction(d.Get("target_action")), Enable: aws.Bool(d.Get("active").(bool)), - StartTime: aws.Time(d.Get("start_time").(time.Time)), - EndTime: aws.Time(d.Get("end_time").(time.Time)), ScheduledActionDescription: aws.String(d.Get("description").(string)), } + if attr, ok := d.GetOk("start_time"); ok { + t, _ := time.Parse("2006-01-02T15:04:05-0700", attr.(string)) + modifyOpts.StartTime = aws.Time(t) + } + if attr, ok := d.GetOk("end_time"); ok { + t, _ := time.Parse("2006-01-02T15:04:05-0700", attr.(string)) + modifyOpts.EndTime = aws.Time(t) + } + log.Printf("[DEBUG] Updating Redshift Scheduled Action: %s", modifyOpts) _, err := conn.ModifyScheduledAction(modifyOpts) if err != nil { @@ -209,27 +218,33 @@ func expandRedshiftScheduledActionTargetAction(configured interface{}) *redshift if configured == nil { return nil } - if configured.([]interface{}) == nil || len(configured.([]interface{})) == 0 { - return nil - } p := configured.(map[string]interface{}) - targetAction := &redshift.ScheduledActionType{} switch p["action"].(string) { case redshift.ScheduledActionTypeValuesPauseCluster: - targetAction.PauseCluster.ClusterIdentifier = p["cluster_identifier"].(*string) + pauseCluster := redshift.PauseClusterMessage{ClusterIdentifier: aws.String(p["cluster_identifier"].(string))} + return &redshift.ScheduledActionType{ + PauseCluster: &pauseCluster, + } case redshift.ScheduledActionTypeValuesResumeCluster: - targetAction.ResumeCluster.ClusterIdentifier = p["cluster_identifier"].(*string) + resumeCluster := redshift.ResumeClusterMessage{ClusterIdentifier: aws.String(p["cluster_identifier"].(string))} + return &redshift.ScheduledActionType{ + ResumeCluster: &resumeCluster, + } case redshift.ScheduledActionTypeValuesResizeCluster: - targetAction.ResizeCluster.ClusterIdentifier = p["cluster_identifier"].(*string) - targetAction.ResizeCluster.Classic = p["classic"].(*bool) - targetAction.ResizeCluster.ClusterType = p["cluster_type"].(*string) - targetAction.ResizeCluster.NodeType = p["node_type"].(*string) - targetAction.ResizeCluster.NumberOfNodes = p["number_of_nodes"].(*int64) + resizeCluster := redshift.ResizeClusterMessage{ + ClusterIdentifier: aws.String(p["cluster_identifier"].(string)), + Classic: aws.Bool(p["classic"].(bool)), + ClusterType: aws.String(p["cluster_type"].(string)), + NodeType: aws.String(p["node_type"].(string)), + NumberOfNodes: aws.Int64(p["number_of_nodes"].(int64)), + } + return &redshift.ScheduledActionType{ + ResizeCluster: &resizeCluster, + } } - - return targetAction + return nil } func flattenRedshiftScheduledActionType(scheduledActionType *redshift.ScheduledActionType) map[string]interface{} { From 5cb3e05d517e420253ed4f9209589266aac0cb05 Mon Sep 17 00:00:00 2001 From: hitofuji Date: Sat, 30 May 2020 17:40:46 +0900 Subject: [PATCH 06/27] TypeMap to TypeList, Use const, set arn to id --- aws/resource_aws_redshift_scheduled_action.go | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/aws/resource_aws_redshift_scheduled_action.go b/aws/resource_aws_redshift_scheduled_action.go index c08dbfa7264..5703c31bde7 100644 --- a/aws/resource_aws_redshift_scheduled_action.go +++ b/aws/resource_aws_redshift_scheduled_action.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "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/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" @@ -37,12 +38,14 @@ func resourceAwsRedshiftScheduledAction() *schema.Resource { Default: true, }, "start_time": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsRFC3339Time, }, "end_time": { - Type: schema.TypeString, - Optional: true, + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsRFC3339Time, }, "schedule": { Type: schema.TypeString, @@ -53,8 +56,9 @@ func resourceAwsRedshiftScheduledAction() *schema.Resource { Required: true, }, "target_action": { - Type: schema.TypeMap, + Type: schema.TypeList, Required: true, + MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "action": { @@ -114,11 +118,11 @@ func resourceAwsRedshiftScheduledActionCreate(d *schema.ResourceData, meta inter createOpts.Enable = aws.Bool(attr.(bool)) } if attr, ok := d.GetOk("start_time"); ok { - t, _ := time.Parse("2006-01-02T15:04:05-0700", attr.(string)) + t, _ := time.Parse(time.RFC3339, attr.(string)) createOpts.StartTime = aws.Time(t) } if attr, ok := d.GetOk("end_time"); ok { - t, _ := time.Parse("2006-01-02T15:04:05-0700", attr.(string)) + t, _ := time.Parse(time.RFC3339, attr.(string)) createOpts.EndTime = aws.Time(t) } @@ -128,16 +132,25 @@ func resourceAwsRedshiftScheduledActionCreate(d *schema.ResourceData, meta inter return fmt.Errorf("error creating Redshift Scheduled Action (%s): %s", name, err) } - d.SetId(name) + id := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Service: "redshift", + Region: meta.(*AWSClient).region, + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("scheduledaction:%s", name), + }.String() + + d.SetId(id) return resourceAwsRedshiftScheduledActionRead(d, meta) } func resourceAwsRedshiftScheduledActionRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).redshiftconn + name := d.Get("name") descOpts := &redshift.DescribeScheduledActionsInput{ - ScheduledActionName: aws.String(d.Id()), + ScheduledActionName: aws.String(name.(string)), } resp, err := conn.DescribeScheduledActions(descOpts) @@ -156,8 +169,8 @@ func resourceAwsRedshiftScheduledActionRead(d *schema.ResourceData, meta interfa d.Set("name", scheduledAction.ScheduledActionName) d.Set("description", scheduledAction.ScheduledActionDescription) d.Set("active", scheduledAction.State) - d.Set("start_time", scheduledAction.StartTime) - d.Set("end_time", scheduledAction.EndTime) + d.Set("start_time", aws.TimeValue(scheduledAction.StartTime).Format(time.RFC3339)) + d.Set("end_time", aws.TimeValue(scheduledAction.EndTime).Format(time.RFC3339)) d.Set("schedule", scheduledAction.Schedule) d.Set("iam_role", scheduledAction.IamRole) @@ -172,7 +185,7 @@ func resourceAwsRedshiftScheduledActionUpdate(d *schema.ResourceData, meta inter conn := meta.(*AWSClient).redshiftconn modifyOpts := &redshift.ModifyScheduledActionInput{ - ScheduledActionName: aws.String(d.Id()), + ScheduledActionName: aws.String(d.Get("name").(string)), Schedule: aws.String(d.Get("schedule").(string)), IamRole: aws.String(d.Get("iam_role").(string)), TargetAction: expandRedshiftScheduledActionTargetAction(d.Get("target_action")), @@ -181,11 +194,11 @@ func resourceAwsRedshiftScheduledActionUpdate(d *schema.ResourceData, meta inter } if attr, ok := d.GetOk("start_time"); ok { - t, _ := time.Parse("2006-01-02T15:04:05-0700", attr.(string)) + t, _ := time.Parse(time.RFC3339, attr.(string)) modifyOpts.StartTime = aws.Time(t) } if attr, ok := d.GetOk("end_time"); ok { - t, _ := time.Parse("2006-01-02T15:04:05-0700", attr.(string)) + t, _ := time.Parse(time.RFC3339, attr.(string)) modifyOpts.EndTime = aws.Time(t) } @@ -215,11 +228,11 @@ func resourceAwsRedshiftScheduledActionDelete(d *schema.ResourceData, meta inter } func expandRedshiftScheduledActionTargetAction(configured interface{}) *redshift.ScheduledActionType { - if configured == nil { + if configured == nil || len(configured.([]interface{})) == 0 { return nil } - p := configured.(map[string]interface{}) + p := configured.([]interface{})[0].(map[string]interface{}) switch p["action"].(string) { case redshift.ScheduledActionTypeValuesPauseCluster: @@ -247,9 +260,9 @@ func expandRedshiftScheduledActionTargetAction(configured interface{}) *redshift return nil } -func flattenRedshiftScheduledActionType(scheduledActionType *redshift.ScheduledActionType) map[string]interface{} { +func flattenRedshiftScheduledActionType(scheduledActionType *redshift.ScheduledActionType) []map[string]interface{} { if scheduledActionType == nil { - return map[string]interface{}{} + return []map[string]interface{}{} } m := map[string]interface{}{} @@ -276,5 +289,5 @@ func flattenRedshiftScheduledActionType(scheduledActionType *redshift.ScheduledA "number_of_nodes": aws.Int64Value(scheduledActionType.ResizeCluster.NumberOfNodes), } } - return m + return []map[string]interface{}{m} } From 519757d0c72acdf9684b062315338efd79a066c2 Mon Sep 17 00:00:00 2001 From: hitofuji Date: Sun, 31 May 2020 11:55:46 +0900 Subject: [PATCH 07/27] set back id to name --- aws/resource_aws_redshift_scheduled_action.go | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/aws/resource_aws_redshift_scheduled_action.go b/aws/resource_aws_redshift_scheduled_action.go index 5703c31bde7..631e8b68f45 100644 --- a/aws/resource_aws_redshift_scheduled_action.go +++ b/aws/resource_aws_redshift_scheduled_action.go @@ -3,7 +3,6 @@ package aws import ( "fmt" "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/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/helper/schema" @@ -132,25 +131,17 @@ func resourceAwsRedshiftScheduledActionCreate(d *schema.ResourceData, meta inter return fmt.Errorf("error creating Redshift Scheduled Action (%s): %s", name, err) } - id := arn.ARN{ - Partition: meta.(*AWSClient).partition, - Service: "redshift", - Region: meta.(*AWSClient).region, - AccountID: meta.(*AWSClient).accountid, - Resource: fmt.Sprintf("scheduledaction:%s", name), - }.String() - - d.SetId(id) + d.SetId(name) return resourceAwsRedshiftScheduledActionRead(d, meta) } func resourceAwsRedshiftScheduledActionRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).redshiftconn - name := d.Get("name") + name := d.Id() descOpts := &redshift.DescribeScheduledActionsInput{ - ScheduledActionName: aws.String(name.(string)), + ScheduledActionName: aws.String(name), } resp, err := conn.DescribeScheduledActions(descOpts) From f8c8cdbd79610160ece4a006609b526226b1e56f Mon Sep 17 00:00:00 2001 From: hitofuji Date: Thu, 4 Jun 2020 23:25:39 +0900 Subject: [PATCH 08/27] add retry in create and update, add basic test --- aws/resource_aws_redshift_scheduled_action.go | 45 ++- ...urce_aws_redshift_scheduled_action_test.go | 325 ++++++++++++++++++ 2 files changed, 366 insertions(+), 4 deletions(-) create mode 100644 aws/resource_aws_redshift_scheduled_action_test.go diff --git a/aws/resource_aws_redshift_scheduled_action.go b/aws/resource_aws_redshift_scheduled_action.go index 631e8b68f45..b04752d1cd4 100644 --- a/aws/resource_aws_redshift_scheduled_action.go +++ b/aws/resource_aws_redshift_scheduled_action.go @@ -126,7 +126,23 @@ func resourceAwsRedshiftScheduledActionCreate(d *schema.ResourceData, meta inter } log.Printf("[DEBUG] Creating Redshift Scheduled Action: %s", createOpts) - _, err := conn.CreateScheduledAction(createOpts) + + // Retry for IAM eventual consistency + err := resource.Retry(1*time.Minute, func() *resource.RetryError { + _, err := conn.CreateScheduledAction(createOpts) + + // InvalidParameterValue: If you create iam role same time, you must wait the role will be valid + if isAWSErr(err, "InvalidParameterValue", "The IAM role must delegate access to Amazon Redshift scheduler") { + return resource.RetryableError(err) + } + + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + if err != nil { return fmt.Errorf("error creating Redshift Scheduled Action (%s): %s", name, err) } @@ -160,11 +176,17 @@ func resourceAwsRedshiftScheduledActionRead(d *schema.ResourceData, meta interfa d.Set("name", scheduledAction.ScheduledActionName) d.Set("description", scheduledAction.ScheduledActionDescription) d.Set("active", scheduledAction.State) - d.Set("start_time", aws.TimeValue(scheduledAction.StartTime).Format(time.RFC3339)) - d.Set("end_time", aws.TimeValue(scheduledAction.EndTime).Format(time.RFC3339)) d.Set("schedule", scheduledAction.Schedule) d.Set("iam_role", scheduledAction.IamRole) + if aws.TimeValue(scheduledAction.StartTime).Format(time.RFC3339) != "0001-01-01T00:00:00Z" { + d.Set("start_time", aws.TimeValue(scheduledAction.StartTime).Format(time.RFC3339)) + } + + if aws.TimeValue(scheduledAction.EndTime).Format(time.RFC3339) != "0001-01-01T00:00:00Z" { + d.Set("start_time", aws.TimeValue(scheduledAction.EndTime).Format(time.RFC3339)) + } + if err := d.Set("target_action", flattenRedshiftScheduledActionType(scheduledAction.TargetAction)); err != nil { return fmt.Errorf("Error setting definitions: %s", err) } @@ -194,7 +216,22 @@ func resourceAwsRedshiftScheduledActionUpdate(d *schema.ResourceData, meta inter } log.Printf("[DEBUG] Updating Redshift Scheduled Action: %s", modifyOpts) - _, err := conn.ModifyScheduledAction(modifyOpts) + + err := resource.Retry(1*time.Minute, func() *resource.RetryError { + _, err := conn.ModifyScheduledAction(modifyOpts) + + // InvalidParameterValue: If you create iam role same time, you must wait the role will be valid + if isAWSErr(err, "InvalidParameterValue", "The IAM role must delegate access to Amazon Redshift scheduler") { + return resource.RetryableError(err) + } + + if err != nil { + return resource.NonRetryableError(err) + } + + return nil + }) + if err != nil { return fmt.Errorf("error updating Redshift Scheduled Action (%s): %s", d.Id(), err) } diff --git a/aws/resource_aws_redshift_scheduled_action_test.go b/aws/resource_aws_redshift_scheduled_action_test.go new file mode 100644 index 00000000000..1777dcb50f3 --- /dev/null +++ b/aws/resource_aws_redshift_scheduled_action_test.go @@ -0,0 +1,325 @@ +package aws + +import ( + "fmt" + "log" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/redshift" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func init() { + resource.AddTestSweepers("aws_redshift_scheduled_action", &resource.Sweeper{ + Name: "aws_redshift_scheduled_action", + Dependencies: []string{ + "aws_iam_role", + "aws_iam_policy", + "aws_iam_role_policy_attachment", + }, + F: testSweepRedshiftScheduledActions, + }) +} + +func testSweepRedshiftScheduledActions(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + conn := client.(*AWSClient).redshiftconn + + req := &redshift.DescribeScheduledActionsInput{} + + resp, err := conn.DescribeScheduledActions(req) + if err != nil { + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping Redshift Regional Scheduled Actions sweep for %s: %s", region, err) + return nil + } + return fmt.Errorf("Error describing Redshift Regional Scheduled Actions: %s", err) + } + + if len(resp.ScheduledActions) == 0 { + log.Print("[DEBUG] No AWS Redshift Regional Scheduled Actions to sweep") + return nil + } + + for _, ScheduledActions := range resp.ScheduledActions { + identifier := aws.StringValue(ScheduledActions.ScheduledActionName) + + hasPrefix := false + prefixes := []string{"tf-test-"} + + for _, prefix := range prefixes { + if strings.HasPrefix(identifier, prefix) { + hasPrefix = true + break + } + } + + if !hasPrefix { + log.Printf("[INFO] Skipping Delete Redshift Scheduled Action: %s", identifier) + continue + } + + _, err := conn.DeleteScheduledAction(&redshift.DeleteScheduledActionInput{ + ScheduledActionName: ScheduledActions.ScheduledActionName, + }) + if isAWSErr(err, redshift.ErrCodeScheduledActionNotFoundFault, "") { + return nil + } + if err != nil { + return fmt.Errorf("Error deleting Redshift Scheduled Action %s: %s", identifier, err) + } + } + + return nil +} + +func TestAccAWSRedshiftScheduledAction_basic(t *testing.T) { + var v redshift.ScheduledAction + + rName := acctest.RandString(8) + resourceName := "aws_redshift_scheduled_action.default" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSRedshiftScheduledActionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSRedshiftScheduledActionConfigPauseCluster(rName, "cron(00 23 * * ? *)"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), + resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "schedule", "cron(00 23 * * ? *)"), + ), + }, + { + Config: testAccAWSRedshiftScheduledActionConfigPauseCluster(rName, "at(2060-03-04T17:27:00)"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), + resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "schedule", "at(2060-03-04T17:27:00)"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "active", + }, + }, + }, + }) +} + +func testAccCheckAWSRedshiftScheduledActionDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_redshift_scheduled_action" { + continue + } + + conn := testAccProvider.Meta().(*AWSClient).redshiftconn + resp, err := conn.DescribeScheduledActions(&redshift.DescribeScheduledActionsInput{ + ScheduledActionName: aws.String(rs.Primary.ID), + }) + + if isAWSErr(err, "ScheduledActionNotFound", "was not found.") { + continue + } + + if err == nil { + if len(resp.ScheduledActions) != 0 { + for _, s := range resp.ScheduledActions { + if *s.ScheduledActionName == rs.Primary.ID { + return fmt.Errorf("Redshift Cluster Scheduled Action %s still exists", rs.Primary.ID) + } + } + } + } + + return err + } + + return nil +} + +func testAccCheckAWSRedshiftScheduledActionExists(n string, v *redshift.ScheduledAction) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No Redshift Cluster Scheduled Action ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).redshiftconn + resp, err := conn.DescribeScheduledActions(&redshift.DescribeScheduledActionsInput{ + ScheduledActionName: aws.String(rs.Primary.ID), + }) + + if err != nil { + return err + } + + for _, s := range resp.ScheduledActions { + if *s.ScheduledActionName == rs.Primary.ID { + *v = *s + return nil + } + } + + return fmt.Errorf("Redshift Scheduled Action (%s) not found", rs.Primary.ID) + } +} + +func testAccAWSRedshiftScheduledActionConfigDependentResource(rName string) string { + return fmt.Sprintf(` +resource "aws_iam_role" "default" { + name = "tf-test-%s" + assume_role_policy = < Date: Sat, 6 Jun 2020 16:58:15 +0900 Subject: [PATCH 09/27] fix test, delete creating random name --- aws/resource_aws_redshift_scheduled_action.go | 9 +- ...urce_aws_redshift_scheduled_action_test.go | 240 +++++++++++++++--- 2 files changed, 207 insertions(+), 42 deletions(-) diff --git a/aws/resource_aws_redshift_scheduled_action.go b/aws/resource_aws_redshift_scheduled_action.go index b04752d1cd4..f6b1f94c208 100644 --- a/aws/resource_aws_redshift_scheduled_action.go +++ b/aws/resource_aws_redshift_scheduled_action.go @@ -99,11 +99,6 @@ func resourceAwsRedshiftScheduledAction() *schema.Resource { func resourceAwsRedshiftScheduledActionCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).redshiftconn var name string - if v, ok := d.GetOk("name"); ok { - name = v.(string) - } else { - name = resource.UniqueId() - } createOpts := &redshift.CreateScheduledActionInput{ ScheduledActionName: aws.String(name), Schedule: aws.String(d.Get("schedule").(string)), @@ -184,7 +179,7 @@ func resourceAwsRedshiftScheduledActionRead(d *schema.ResourceData, meta interfa } if aws.TimeValue(scheduledAction.EndTime).Format(time.RFC3339) != "0001-01-01T00:00:00Z" { - d.Set("start_time", aws.TimeValue(scheduledAction.EndTime).Format(time.RFC3339)) + d.Set("end_time", aws.TimeValue(scheduledAction.EndTime).Format(time.RFC3339)) } if err := d.Set("target_action", flattenRedshiftScheduledActionType(scheduledAction.TargetAction)); err != nil { @@ -279,7 +274,7 @@ func expandRedshiftScheduledActionTargetAction(configured interface{}) *redshift Classic: aws.Bool(p["classic"].(bool)), ClusterType: aws.String(p["cluster_type"].(string)), NodeType: aws.String(p["node_type"].(string)), - NumberOfNodes: aws.Int64(p["number_of_nodes"].(int64)), + NumberOfNodes: aws.Int64(int64(p["number_of_nodes"].(int))), } return &redshift.ScheduledActionType{ ResizeCluster: &resizeCluster, diff --git a/aws/resource_aws_redshift_scheduled_action_test.go b/aws/resource_aws_redshift_scheduled_action_test.go index 1777dcb50f3..dcb1f7d9d0b 100644 --- a/aws/resource_aws_redshift_scheduled_action_test.go +++ b/aws/resource_aws_redshift_scheduled_action_test.go @@ -5,6 +5,7 @@ import ( "log" "strings" "testing" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/redshift" @@ -80,7 +81,7 @@ func testSweepRedshiftScheduledActions(region string) error { return nil } -func TestAccAWSRedshiftScheduledAction_basic(t *testing.T) { +func TestAccAWSRedshiftScheduledActionPauseCluster_basic(t *testing.T) { var v redshift.ScheduledAction rName := acctest.RandString(8) @@ -98,6 +99,8 @@ func TestAccAWSRedshiftScheduledAction_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), resource.TestCheckResourceAttr(resourceName, "schedule", "cron(00 23 * * ? *)"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.action", "PauseCluster"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.cluster_identifier", "tf-test-identifier"), ), }, { @@ -107,6 +110,169 @@ func TestAccAWSRedshiftScheduledAction_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), resource.TestCheckResourceAttr(resourceName, "schedule", "at(2060-03-04T17:27:00)"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.action", "PauseCluster"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.cluster_identifier", "tf-test-identifier"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "active", + }, + }, + }, + }) +} + +func TestAccAWSRedshiftScheduledActionPauseCluster_WithOptions(t *testing.T) { + var v redshift.ScheduledAction + + rName := acctest.RandString(8) + resourceName := "aws_redshift_scheduled_action.default" + startTime := time.Now().UTC().Add(1 * time.Hour).Format(time.RFC3339) + endTime := time.Now().UTC().Add(2 * time.Hour).Format(time.RFC3339) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSRedshiftScheduledActionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSRedshiftScheduledActionConfigPauseClusterWithFullOption(rName, "cron(00 * * * ? *)", "This is test action", "true", startTime, endTime), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), + resource.TestCheckResourceAttr(resourceName, "description", "This is test action"), + resource.TestCheckResourceAttr(resourceName, "active", "true"), + resource.TestCheckResourceAttr(resourceName, "start_time", startTime), + resource.TestCheckResourceAttr(resourceName, "end_time", endTime), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "active", + }, + }, + }, + }) +} + +func TestAccAWSRedshiftScheduledActionResumeCluster_basic(t *testing.T) { + var v redshift.ScheduledAction + + rName := acctest.RandString(8) + resourceName := "aws_redshift_scheduled_action.default" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSRedshiftScheduledActionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSRedshiftScheduledActionConfigResumeCluster(rName, "cron(00 23 * * ? *)"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), + resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "schedule", "cron(00 23 * * ? *)"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.action", "ResumeCluster"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.cluster_identifier", "tf-test-identifier"), + ), + }, + { + Config: testAccAWSRedshiftScheduledActionConfigResumeCluster(rName, "at(2060-03-04T17:27:00)"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), + resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "schedule", "at(2060-03-04T17:27:00)"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.action", "ResumeCluster"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.cluster_identifier", "tf-test-identifier"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "active", + }, + }, + }, + }) +} + +func TestAccAWSRedshiftScheduledActionResizeCluster_basic(t *testing.T) { + var v redshift.ScheduledAction + + rName := acctest.RandString(8) + resourceName := "aws_redshift_scheduled_action.default" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSRedshiftScheduledActionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSRedshiftScheduledActionConfigResizeClusterBasic(rName, "cron(00 23 * * ? *)"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), + resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "schedule", "cron(00 23 * * ? *)"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.action", "ResizeCluster"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.cluster_identifier", "tf-test-identifier"), + ), + }, + { + Config: testAccAWSRedshiftScheduledActionConfigResizeClusterBasic(rName, "at(2060-03-04T17:27:00)"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), + resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "schedule", "at(2060-03-04T17:27:00)"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.action", "ResizeCluster"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.cluster_identifier", "tf-test-identifier"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "active", + }, + }, + }, + }) +} + +func TestAccAWSRedshiftScheduledActionResizeCluster_WithOptions(t *testing.T) { + var v redshift.ScheduledAction + + rName := acctest.RandString(8) + resourceName := "aws_redshift_scheduled_action.default" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSRedshiftScheduledActionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSRedshiftScheduledActionConfigResizeClusterWithFullOption(rName, "cron(00 23 * * ? *)", "true", "multi-node", "dc1.large", "2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), + resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.classic", "true"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.cluster_type", "multi-node"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.node_type", "dc1.large"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.number_of_nodes", "2"), ), }, { @@ -252,74 +418,78 @@ resource "aws_redshift_scheduled_action" "default" { `, testAccAWSRedshiftScheduledActionConfigDependentResource(rName), rName, schedule) } -func testAccAWSRedshiftScheduledActionConfigResumeCluster(rName, schedule string) string { +func testAccAWSRedshiftScheduledActionConfigPauseClusterWithFullOption(rName, schedule, description, active, startTime, endTime string) string { return fmt.Sprintf(` + +%s + resource "aws_redshift_scheduled_action" "default" { - name = "%s" + name = "tf-test-%s" + description = "%s" + active = %s + start_time = "%s" + end_time = "%s" schedule = "%s" + iam_role = aws_iam_role.default.arn target_action { - action = "ResumeCluster" + action = "PauseCluster" cluster_identifier = "tf-test-identifier" } } - `, rName, schedule) + `, testAccAWSRedshiftScheduledActionConfigDependentResource(rName), rName, description, active, startTime, endTime, schedule) } -func testAccAWSRedshiftScheduledActionConfigResizeClusterBasic(rName, schedule string) string { +func testAccAWSRedshiftScheduledActionConfigResumeCluster(rName, schedule string) string { return fmt.Sprintf(` + +%s + resource "aws_redshift_scheduled_action" "default" { - name = "%s" + name = "tf-test-%s" schedule = "%s" + iam_role = aws_iam_role.default.arn target_action { - action = "ResizeCluster" + action = "ResumeCluster" cluster_identifier = "tf-test-identifier" } } - `, rName, schedule) + `, testAccAWSRedshiftScheduledActionConfigDependentResource(rName), rName, schedule) } -func testAccAWSRedshiftScheduledActionConfigResizeClusterWithFullOption(rName, schedule, classic, clusterType, nodeType, numberOfNodes string) string { +func testAccAWSRedshiftScheduledActionConfigResizeClusterBasic(rName, schedule string) string { return fmt.Sprintf(` + +%s + resource "aws_redshift_scheduled_action" "default" { - name = "%s" + name = "tf-test-%s" schedule = "%s" + iam_role = aws_iam_role.default.arn target_action { action = "ResizeCluster" cluster_identifier = "tf-test-identifier" - classic = %s - cluster_type = "%s" - node_type = "%s" - number_of_nodes = %s } } - `, rName, schedule, classic, clusterType, nodeType, numberOfNodes) + `, testAccAWSRedshiftScheduledActionConfigDependentResource(rName), rName, schedule) } -func testAccAWSRedshiftScheduledActionConfigPauseClusterWithFullOption(rName, schedule, description, active, startTime, endTime string) string { +func testAccAWSRedshiftScheduledActionConfigResizeClusterWithFullOption(rName, schedule, classic, clusterType, nodeType, numberOfNodes string) string { return fmt.Sprintf(` -resource "aws_redshift_scheduled_action" "default" { - name = "%s" - description = "%s" - active = %s - start_time = "%s" - end_time = "%s" - schedule = "%s" - target_action { - action = "PauseCluster" - cluster_identifier = "tf-test-identifier" - } -} - `, rName, description, active, startTime, endTime, schedule) -} -func testAccAWSRedshiftScheduledActionConfigPauseClusterWithNoName(schedule string) string { - return fmt.Sprintf(` +%s + resource "aws_redshift_scheduled_action" "default" { + name = "tf-test-%s" schedule = "%s" + iam_role = aws_iam_role.default.arn target_action { - action = "PauseCluster" + action = "ResizeCluster" cluster_identifier = "tf-test-identifier" + classic = %s + cluster_type = "%s" + node_type = "%s" + number_of_nodes = %s } } - `, schedule) + `, testAccAWSRedshiftScheduledActionConfigDependentResource(rName), rName, schedule, classic, clusterType, nodeType, numberOfNodes) } From 2eead9650118d5775ab908a7b164528a84272558 Mon Sep 17 00:00:00 2001 From: hitofuji Date: Sat, 6 Jun 2020 17:05:35 +0900 Subject: [PATCH 10/27] fix bug --- aws/resource_aws_redshift_scheduled_action.go | 2 +- .../r/redshift_scheduled_action.html.markdown | 49 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 website/docs/r/redshift_scheduled_action.html.markdown diff --git a/aws/resource_aws_redshift_scheduled_action.go b/aws/resource_aws_redshift_scheduled_action.go index f6b1f94c208..e9d3c6e2cc0 100644 --- a/aws/resource_aws_redshift_scheduled_action.go +++ b/aws/resource_aws_redshift_scheduled_action.go @@ -98,7 +98,7 @@ func resourceAwsRedshiftScheduledAction() *schema.Resource { func resourceAwsRedshiftScheduledActionCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).redshiftconn - var name string + name := d.Get("name").(string) createOpts := &redshift.CreateScheduledActionInput{ ScheduledActionName: aws.String(name), Schedule: aws.String(d.Get("schedule").(string)), diff --git a/website/docs/r/redshift_scheduled_action.html.markdown b/website/docs/r/redshift_scheduled_action.html.markdown new file mode 100644 index 00000000000..8652cbc19de --- /dev/null +++ b/website/docs/r/redshift_scheduled_action.html.markdown @@ -0,0 +1,49 @@ +--- +layout: "aws" +page_title: "AWS: aws_redshift_snapshot_schedule_association" +sidebar_current: "docs-aws-resource-redshift-snapshot-schedule-association" +description: |- + Provides an Association Redshift Cluster and Snapshot Schedule resource. +--- + +# Resource: aws_redshift_snapshot_schedule_association + +## Example Usage + +```hcl +resource "aws_redshift_cluster" "default" { + cluster_identifier = "tf-redshift-cluster" + database_name = "mydb" + master_username = "foo" + master_password = "Mustbe8characters" + node_type = "dc1.large" + cluster_type = "single-node" +} + +resource "aws_redshift_snapshot_schedule" "default" { + identifier = "tf-redshift-snapshot-schedule" + definitions = [ + "rate(12 hours)", + ] +} + +resource "aws_redshift_snapshot_schedule_association" "default" { + cluster_identifier = "${aws_redshift_cluster.default.id}" + schedule_identifier = "${aws_redshift_snapshot_schedule.default.id}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `cluster_identifier` - (Required, Forces new resource) The cluster identifier. +* `schedule_identifier` - (Required, Forces new resource) The snapshot schedule identifier. + +## Import + +Redshift Snapshot Schedule Association can be imported using the `/`, e.g. + +``` +$ terraform import aws_redshift_snapshot_schedule_association.default tf-redshift-cluster/tf-redshift-snapshot-schedule +``` \ No newline at end of file From 86f9d775e18da6d991e61572fffd4f4e7dc35823 Mon Sep 17 00:00:00 2001 From: hitofuji Date: Sun, 7 Jun 2020 00:23:55 +0900 Subject: [PATCH 11/27] add document --- .../r/redshift_scheduled_action.html.markdown | 121 ++++++++++++++---- 1 file changed, 97 insertions(+), 24 deletions(-) diff --git a/website/docs/r/redshift_scheduled_action.html.markdown b/website/docs/r/redshift_scheduled_action.html.markdown index 8652cbc19de..a92d39b4bbd 100644 --- a/website/docs/r/redshift_scheduled_action.html.markdown +++ b/website/docs/r/redshift_scheduled_action.html.markdown @@ -1,35 +1,91 @@ --- layout: "aws" -page_title: "AWS: aws_redshift_snapshot_schedule_association" -sidebar_current: "docs-aws-resource-redshift-snapshot-schedule-association" +page_title: "AWS: aws_redshift_scheduled_action" +sidebar_current: "docs-aws-resource-redshift-scheduled-action" description: |- - Provides an Association Redshift Cluster and Snapshot Schedule resource. + Provides a Redshift Scheduled Action resource. --- -# Resource: aws_redshift_snapshot_schedule_association +# Resource: aws_redshift_scheduled_action -## Example Usage +## Example Pause Cluster ```hcl -resource "aws_redshift_cluster" "default" { - cluster_identifier = "tf-redshift-cluster" - database_name = "mydb" - master_username = "foo" - master_password = "Mustbe8characters" - node_type = "dc1.large" - cluster_type = "single-node" +resource "aws_iam_role" "redshift_scheduled_action" { + name = "redshift_scheduled_action" + assume_role_policy = </`, e.g. +Redshift Scheduled Action can be imported using the `name`, e.g. ``` -$ terraform import aws_redshift_snapshot_schedule_association.default tf-redshift-cluster/tf-redshift-snapshot-schedule +$ terraform import aws_redshift_scheduled_action.default tf-redshift-scheduled-action ``` \ No newline at end of file From 192abd392befae7624d2d09fefdcef563c228fa5 Mon Sep 17 00:00:00 2001 From: hitofuji Date: Sun, 7 Jun 2020 09:38:14 +0900 Subject: [PATCH 12/27] remove sidebar_current --- website/docs/r/redshift_scheduled_action.html.markdown | 1 - 1 file changed, 1 deletion(-) diff --git a/website/docs/r/redshift_scheduled_action.html.markdown b/website/docs/r/redshift_scheduled_action.html.markdown index a92d39b4bbd..e07171f151d 100644 --- a/website/docs/r/redshift_scheduled_action.html.markdown +++ b/website/docs/r/redshift_scheduled_action.html.markdown @@ -1,7 +1,6 @@ --- layout: "aws" page_title: "AWS: aws_redshift_scheduled_action" -sidebar_current: "docs-aws-resource-redshift-scheduled-action" description: |- Provides a Redshift Scheduled Action resource. --- From 7c13b052636cd98fa88b8adc4aa23d9c2a7b68a6 Mon Sep 17 00:00:00 2001 From: hitofuji Date: Sun, 7 Jun 2020 09:54:24 +0900 Subject: [PATCH 13/27] add subcategory --- website/docs/r/redshift_scheduled_action.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/redshift_scheduled_action.html.markdown b/website/docs/r/redshift_scheduled_action.html.markdown index e07171f151d..0912e4c31a5 100644 --- a/website/docs/r/redshift_scheduled_action.html.markdown +++ b/website/docs/r/redshift_scheduled_action.html.markdown @@ -1,4 +1,5 @@ --- +subcategory: "Redshift" layout: "aws" page_title: "AWS: aws_redshift_scheduled_action" description: |- From 5fa2668f9657a525681e17e9ab3ef73923ae8b7d Mon Sep 17 00:00:00 2001 From: hitofuji Date: Sun, 7 Jun 2020 11:02:31 +0900 Subject: [PATCH 14/27] lint fix --- .../r/redshift_scheduled_action.html.markdown | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/website/docs/r/redshift_scheduled_action.html.markdown b/website/docs/r/redshift_scheduled_action.html.markdown index 0912e4c31a5..5311e744f45 100644 --- a/website/docs/r/redshift_scheduled_action.html.markdown +++ b/website/docs/r/redshift_scheduled_action.html.markdown @@ -12,7 +12,7 @@ description: |- ```hcl resource "aws_iam_role" "redshift_scheduled_action" { - name = "redshift_scheduled_action" + name = "redshift_scheduled_action" assume_role_policy = < Date: Wed, 17 Jun 2020 20:29:25 +0900 Subject: [PATCH 15/27] refactor --- aws/resource_aws_redshift_scheduled_action.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_redshift_scheduled_action.go b/aws/resource_aws_redshift_scheduled_action.go index e9d3c6e2cc0..ebfe1fbe318 100644 --- a/aws/resource_aws_redshift_scheduled_action.go +++ b/aws/resource_aws_redshift_scheduled_action.go @@ -174,11 +174,11 @@ func resourceAwsRedshiftScheduledActionRead(d *schema.ResourceData, meta interfa d.Set("schedule", scheduledAction.Schedule) d.Set("iam_role", scheduledAction.IamRole) - if aws.TimeValue(scheduledAction.StartTime).Format(time.RFC3339) != "0001-01-01T00:00:00Z" { + if scheduledAction.StartTime != nil { d.Set("start_time", aws.TimeValue(scheduledAction.StartTime).Format(time.RFC3339)) } - if aws.TimeValue(scheduledAction.EndTime).Format(time.RFC3339) != "0001-01-01T00:00:00Z" { + if scheduledAction.EndTime != nil { d.Set("end_time", aws.TimeValue(scheduledAction.EndTime).Format(time.RFC3339)) } From 853e69c667dc879f2a4e493f0695e63146eca247 Mon Sep 17 00:00:00 2001 From: hitofuji Date: Sun, 6 Sep 2020 15:12:25 +0900 Subject: [PATCH 16/27] update to terraform-plugin-sdk/v2 --- aws/resource_aws_redshift_scheduled_action.go | 13 +++++++++---- aws/resource_aws_redshift_scheduled_action_test.go | 6 +++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_redshift_scheduled_action.go b/aws/resource_aws_redshift_scheduled_action.go index ebfe1fbe318..76a0f8098e4 100644 --- a/aws/resource_aws_redshift_scheduled_action.go +++ b/aws/resource_aws_redshift_scheduled_action.go @@ -4,9 +4,9 @@ import ( "fmt" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/redshift" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "log" "time" ) @@ -170,10 +170,15 @@ func resourceAwsRedshiftScheduledActionRead(d *schema.ResourceData, meta interfa d.Set("name", scheduledAction.ScheduledActionName) d.Set("description", scheduledAction.ScheduledActionDescription) - d.Set("active", scheduledAction.State) d.Set("schedule", scheduledAction.Schedule) d.Set("iam_role", scheduledAction.IamRole) + if aws.StringValue(scheduledAction.State) == redshift.ScheduledActionStateActive { + d.Set("active", true) + } else { + d.Set("active", false) + } + if scheduledAction.StartTime != nil { d.Set("start_time", aws.TimeValue(scheduledAction.StartTime).Format(time.RFC3339)) } diff --git a/aws/resource_aws_redshift_scheduled_action_test.go b/aws/resource_aws_redshift_scheduled_action_test.go index dcb1f7d9d0b..f957198de3c 100644 --- a/aws/resource_aws_redshift_scheduled_action_test.go +++ b/aws/resource_aws_redshift_scheduled_action_test.go @@ -9,9 +9,9 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/redshift" - "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" - "github.com/hashicorp/terraform-plugin-sdk/helper/resource" - "github.com/hashicorp/terraform-plugin-sdk/terraform" + "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" ) func init() { From ae915b5e36481b76989a9b3575dd0bfab5d88d32 Mon Sep 17 00:00:00 2001 From: hitofuji Date: Sun, 6 Sep 2020 15:14:41 +0900 Subject: [PATCH 17/27] fix go.mod --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 1c4383d0d97..f59af0f777c 100644 --- a/go.mod +++ b/go.mod @@ -25,4 +25,4 @@ require ( gopkg.in/yaml.v2 v2.4.0 ) -replace github.com/hashicorp/terraform-plugin-sdk/v2 => github.com/gdavison/terraform-plugin-sdk/v2 v2.7.1-0.20210913224932-c7c2dbd9e010 +replace github.com/hashicorp/terraform-plugin-sdk/v2 => github.com/gdavison/terraform-plugin-sdk/v2 v2.7.1-0.20210913224932-c7c2dbd9e010 \ No newline at end of file From 28910e420b577bac61eec1fdb2416bdc222afee5 Mon Sep 17 00:00:00 2001 From: hitofuji Date: Sun, 6 Sep 2020 15:18:46 +0900 Subject: [PATCH 18/27] lint fix --- website/docs/r/redshift_scheduled_action.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/redshift_scheduled_action.html.markdown b/website/docs/r/redshift_scheduled_action.html.markdown index 5311e744f45..c6afab46ae5 100644 --- a/website/docs/r/redshift_scheduled_action.html.markdown +++ b/website/docs/r/redshift_scheduled_action.html.markdown @@ -99,7 +99,7 @@ The following arguments are supported: * `start_time` - (Optional) The start time in UTC when the schedule is active, in UTC RFC3339 format(for example, YYYY-MM-DDTHH:MM:SSZ). * `end_time` - (Optional) The end time in UTC when the schedule is active, in UTC RFC3339 format(for example, YYYY-MM-DDTHH:MM:SSZ). * `schedule` - (Required) The schedule of action. The schedule is defined format of "at expression" or "cron expression", for example `at(2016-03-04T17:27:00)` or `cron(0 10 ? * MON *)`. See [Scheduled Action](https://docs.aws.amazon.com/redshift/latest/APIReference/API_ScheduledAction.html) for more information. -* `iam_role` - (Required) The IAM role to assume to run the scheduled action. +* `iam_role` - (Required) The IAM role to assume to run the scheduled action. * `target_action` - (Required) Target action, documented below. ### Nested Blocks From 549e97eab591a7948a0bda0b7e28e1fb3545637d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 28 Sep 2021 12:13:40 -0400 Subject: [PATCH 19/27] Add CHANGELOG entry. --- .changelog/13474.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/13474.txt diff --git a/.changelog/13474.txt b/.changelog/13474.txt new file mode 100644 index 00000000000..04eccad08e9 --- /dev/null +++ b/.changelog/13474.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_redshift_scheduled_action +``` \ No newline at end of file From a485a09deb09cb086d6518971ab204aab8ff8417 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 29 Sep 2021 08:40:38 -0400 Subject: [PATCH 20/27] Add and use 'finder.ScheduledActionByName'. --- .../service/redshift/finder/finder.go | 29 ++++ aws/resource_aws_redshift_scheduled_action.go | 156 +++++++++++------- 2 files changed, 129 insertions(+), 56 deletions(-) diff --git a/aws/internal/service/redshift/finder/finder.go b/aws/internal/service/redshift/finder/finder.go index 10cf6fabee6..2688b090b88 100644 --- a/aws/internal/service/redshift/finder/finder.go +++ b/aws/internal/service/redshift/finder/finder.go @@ -36,3 +36,32 @@ func ClusterByID(conn *redshift.Redshift, id string) (*redshift.Cluster, error) return output.Clusters[0], nil } + +func ScheduledActionByName(conn *redshift.Redshift, name string) (*redshift.ScheduledAction, error) { + input := &redshift.DescribeScheduledActionsInput{ + ScheduledActionName: aws.String(name), + } + + output, err := conn.DescribeScheduledActions(input) + + if tfawserr.ErrCodeEquals(err, redshift.ErrCodeScheduledActionNotFoundFault) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || len(output.ScheduledActions) == 0 || output.ScheduledActions[0] == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + if count := len(output.ScheduledActions); count > 1 { + return nil, tfresource.NewTooManyResultsError(count, input) + } + + return output.ScheduledActions[0], nil +} diff --git a/aws/resource_aws_redshift_scheduled_action.go b/aws/resource_aws_redshift_scheduled_action.go index 76a0f8098e4..c2cb0e8b340 100644 --- a/aws/resource_aws_redshift_scheduled_action.go +++ b/aws/resource_aws_redshift_scheduled_action.go @@ -2,13 +2,17 @@ package aws import ( "fmt" + "log" + "time" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/redshift" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "log" - "time" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/redshift/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsRedshiftScheduledAction() *schema.Resource { @@ -17,77 +21,120 @@ func resourceAwsRedshiftScheduledAction() *schema.Resource { Read: resourceAwsRedshiftScheduledActionRead, Update: resourceAwsRedshiftScheduledActionUpdate, Delete: resourceAwsRedshiftScheduledActionDelete, + Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, "description": { Type: schema.TypeString, Optional: true, }, - "active": { + "enable": { Type: schema.TypeBool, Optional: true, Default: true, }, - "start_time": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.IsRFC3339Time, - }, "end_time": { Type: schema.TypeString, Optional: true, ValidateFunc: validation.IsRFC3339Time, }, - "schedule": { + "iam_role": { Type: schema.TypeString, Required: true, }, - "iam_role": { + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "schedule": { Type: schema.TypeString, Required: true, }, + "start_time": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsRFC3339Time, + }, "target_action": { Type: schema.TypeList, Required: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "action": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - redshift.ScheduledActionTypeValuesResumeCluster, - redshift.ScheduledActionTypeValuesPauseCluster, - redshift.ScheduledActionTypeValuesResizeCluster, - }, false), - }, - "cluster_identifier": { - Type: schema.TypeString, - Required: true, - }, - "classic": { - Type: schema.TypeBool, - Optional: true, - }, - "cluster_type": { - Type: schema.TypeString, + "pause_cluster": { + Type: schema.TypeList, Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster_identifier": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + ExactlyOneOf: []string{ + "target_action.0.pause_cluster", + "target_action.0.resize_cluster", + "target_action.0.resume_cluster", + }, }, - "node_type": { - Type: schema.TypeString, + "resize_cluster": { + Type: schema.TypeList, Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "classic": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "cluster_identifier": { + Type: schema.TypeString, + Required: true, + }, + "cluster_type": { + Type: schema.TypeString, + Optional: true, + }, + "node_type": { + Type: schema.TypeString, + Optional: true, + }, + "number_of_nodes": { + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + ExactlyOneOf: []string{ + "target_action.0.pause_cluster", + "target_action.0.resize_cluster", + "target_action.0.resume_cluster", + }, }, - "number_of_nodes": { - Type: schema.TypeInt, + "resume_cluster": { + Type: schema.TypeList, Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster_identifier": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + ExactlyOneOf: []string{ + "target_action.0.pause_cluster", + "target_action.0.resize_cluster", + "target_action.0.resume_cluster", + }, }, }, }, @@ -149,29 +196,23 @@ func resourceAwsRedshiftScheduledActionCreate(d *schema.ResourceData, meta inter func resourceAwsRedshiftScheduledActionRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).redshiftconn - name := d.Id() - - descOpts := &redshift.DescribeScheduledActionsInput{ - ScheduledActionName: aws.String(name), - } - resp, err := conn.DescribeScheduledActions(descOpts) - if err != nil { - return fmt.Errorf("Error describing Redshift Scheduled Action %s: %s", d.Id(), err) - } + scheduledAction, err := finder.ScheduledActionByName(conn, d.Id()) - if resp.ScheduledActions == nil || len(resp.ScheduledActions) != 1 { - log.Printf("[WARN] Unable to find Redshift Scheduled Action (%s)", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Redshift Scheduled Action (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - scheduledAction := resp.ScheduledActions[0] + if err != nil { + return fmt.Errorf("error reading Redshift Scheduled Action (%s): %w", d.Id(), err) + } - d.Set("name", scheduledAction.ScheduledActionName) d.Set("description", scheduledAction.ScheduledActionDescription) - d.Set("schedule", scheduledAction.Schedule) d.Set("iam_role", scheduledAction.IamRole) + d.Set("name", scheduledAction.ScheduledActionName) + d.Set("schedule", scheduledAction.Schedule) if aws.StringValue(scheduledAction.State) == redshift.ScheduledActionStateActive { d.Set("active", true) @@ -242,14 +283,17 @@ func resourceAwsRedshiftScheduledActionUpdate(d *schema.ResourceData, meta inter func resourceAwsRedshiftScheduledActionDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).redshiftconn - deleteOpts := &redshift.DeleteScheduledActionInput{ + log.Printf("[DEBUG] Deleting Redshift Scheduled Action: %s", d.Id()) + _, err := conn.DeleteScheduledAction(&redshift.DeleteScheduledActionInput{ ScheduledActionName: aws.String(d.Id()), + }) + + if tfawserr.ErrCodeEquals(err, redshift.ErrCodeScheduledActionNotFoundFault) { + return nil } - log.Printf("[DEBUG] Deleting Redshift Scheduled Action: %s", deleteOpts) - _, err := conn.DeleteScheduledAction(deleteOpts) if err != nil { - return fmt.Errorf("error deleting Redshift Scheduled Action (%s): %s", d.Id(), err) + return fmt.Errorf("error deleting Redshift Scheduled Action (%s): %w", d.Id(), err) } return nil From c7d5afe0c81266a482bc22589b4ae72f82a82d52 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 29 Sep 2021 09:06:49 -0400 Subject: [PATCH 21/27] r/aws_redshift_scheduled_action: Update documentation. --- .../r/redshift_scheduled_action.html.markdown | 62 ++++++++++++------- 1 file changed, 38 insertions(+), 24 deletions(-) diff --git a/website/docs/r/redshift_scheduled_action.html.markdown b/website/docs/r/redshift_scheduled_action.html.markdown index c6afab46ae5..4d566b10b2d 100644 --- a/website/docs/r/redshift_scheduled_action.html.markdown +++ b/website/docs/r/redshift_scheduled_action.html.markdown @@ -10,8 +10,8 @@ description: |- ## Example Pause Cluster -```hcl -resource "aws_iam_role" "redshift_scheduled_action" { +```terraform +resource "aws_iam_role" "example" { name = "redshift_scheduled_action" assume_role_policy = < Date: Wed, 29 Sep 2021 11:48:37 -0400 Subject: [PATCH 22/27] r/aws_redshift_scheduled_action: Modify acceptance tests. --- aws/internal/service/redshift/errors.go | 5 + aws/resource_aws_iam_role_test.go | 1 + aws/resource_aws_redshift_scheduled_action.go | 350 ++++++++----- ...urce_aws_redshift_scheduled_action_test.go | 471 +++++++++--------- 4 files changed, 480 insertions(+), 347 deletions(-) create mode 100644 aws/internal/service/redshift/errors.go diff --git a/aws/internal/service/redshift/errors.go b/aws/internal/service/redshift/errors.go new file mode 100644 index 00000000000..53a43bd1d80 --- /dev/null +++ b/aws/internal/service/redshift/errors.go @@ -0,0 +1,5 @@ +package redshift + +const ( + ErrCodeInvalidParameterValue = "InvalidParameterValue" +) diff --git a/aws/resource_aws_iam_role_test.go b/aws/resource_aws_iam_role_test.go index 7d0fab32827..2b664b958ed 100644 --- a/aws/resource_aws_iam_role_test.go +++ b/aws/resource_aws_iam_role_test.go @@ -42,6 +42,7 @@ func init() { "aws_lambda_function", "aws_launch_configuration", "aws_redshift_cluster", + "aws_redshift_scheduled_action", "aws_spot_fleet_request", }, F: testSweepIamRoles, diff --git a/aws/resource_aws_redshift_scheduled_action.go b/aws/resource_aws_redshift_scheduled_action.go index c2cb0e8b340..697d9136029 100644 --- a/aws/resource_aws_redshift_scheduled_action.go +++ b/aws/resource_aws_redshift_scheduled_action.go @@ -8,9 +8,10 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/redshift" "github.com/hashicorp/aws-sdk-go-base/tfawserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + iamwaiter "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/iam/waiter" + tfredshift "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/redshift" "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/redshift/finder" "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) @@ -145,51 +146,52 @@ func resourceAwsRedshiftScheduledAction() *schema.Resource { func resourceAwsRedshiftScheduledActionCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).redshiftconn + name := d.Get("name").(string) - createOpts := &redshift.CreateScheduledActionInput{ - ScheduledActionName: aws.String(name), - Schedule: aws.String(d.Get("schedule").(string)), + input := &redshift.CreateScheduledActionInput{ + Enable: aws.Bool(d.Get("enable").(bool)), IamRole: aws.String(d.Get("iam_role").(string)), - TargetAction: expandRedshiftScheduledActionTargetAction(d.Get("target_action")), - } - if attr, ok := d.GetOk("description"); ok { - createOpts.ScheduledActionDescription = aws.String(attr.(string)) - } - if attr, ok := d.GetOk("active"); ok { - createOpts.Enable = aws.Bool(attr.(bool)) - } - if attr, ok := d.GetOk("start_time"); ok { - t, _ := time.Parse(time.RFC3339, attr.(string)) - createOpts.StartTime = aws.Time(t) + Schedule: aws.String(d.Get("schedule").(string)), + ScheduledActionName: aws.String(name), + TargetAction: expandRedshiftScheduledActionType(d.Get("target_action").([]interface{})[0].(map[string]interface{})), } - if attr, ok := d.GetOk("end_time"); ok { - t, _ := time.Parse(time.RFC3339, attr.(string)) - createOpts.EndTime = aws.Time(t) + + if v, ok := d.GetOk("description"); ok { + input.ScheduledActionDescription = aws.String(v.(string)) } - log.Printf("[DEBUG] Creating Redshift Scheduled Action: %s", createOpts) + if v, ok := d.GetOk("end_time"); ok { + t, _ := time.Parse(time.RFC3339, v.(string)) - // Retry for IAM eventual consistency - err := resource.Retry(1*time.Minute, func() *resource.RetryError { - _, err := conn.CreateScheduledAction(createOpts) + input.EndTime = aws.Time(t) + } - // InvalidParameterValue: If you create iam role same time, you must wait the role will be valid - if isAWSErr(err, "InvalidParameterValue", "The IAM role must delegate access to Amazon Redshift scheduler") { - return resource.RetryableError(err) - } + if v, ok := d.GetOk("start_time"); ok { + t, _ := time.Parse(time.RFC3339, v.(string)) - if err != nil { - return resource.NonRetryableError(err) - } + input.StartTime = aws.Time(t) + } - return nil - }) + log.Printf("[DEBUG] Creating Redshift Scheduled Action: %s", input) + outputRaw, err := tfresource.RetryWhen( + iamwaiter.PropagationTimeout, + func() (interface{}, error) { + return conn.CreateScheduledAction(input) + }, + func(err error) (bool, error) { + if tfawserr.ErrMessageContains(err, tfredshift.ErrCodeInvalidParameterValue, "The IAM role must delegate access to Amazon Redshift scheduler") { + return true, err + } + + return false, err + }, + ) if err != nil { - return fmt.Errorf("error creating Redshift Scheduled Action (%s): %s", name, err) + return fmt.Errorf("error creating Redshift Scheduled Action (%s): %w", name, err) } - d.SetId(name) + d.SetId(aws.StringValue(outputRaw.(*redshift.CreateScheduledActionOutput).ScheduledActionName)) return resourceAwsRedshiftScheduledActionRead(d, meta) } @@ -210,26 +212,31 @@ func resourceAwsRedshiftScheduledActionRead(d *schema.ResourceData, meta interfa } d.Set("description", scheduledAction.ScheduledActionDescription) - d.Set("iam_role", scheduledAction.IamRole) - d.Set("name", scheduledAction.ScheduledActionName) - d.Set("schedule", scheduledAction.Schedule) - if aws.StringValue(scheduledAction.State) == redshift.ScheduledActionStateActive { - d.Set("active", true) + d.Set("enable", true) } else { - d.Set("active", false) - } - - if scheduledAction.StartTime != nil { - d.Set("start_time", aws.TimeValue(scheduledAction.StartTime).Format(time.RFC3339)) + d.Set("enable", false) } - if scheduledAction.EndTime != nil { d.Set("end_time", aws.TimeValue(scheduledAction.EndTime).Format(time.RFC3339)) + } else { + d.Set("end_time", nil) + } + d.Set("iam_role", scheduledAction.IamRole) + d.Set("name", scheduledAction.ScheduledActionName) + d.Set("schedule", scheduledAction.Schedule) + if scheduledAction.StartTime != nil { + d.Set("start_time", aws.TimeValue(scheduledAction.StartTime).Format(time.RFC3339)) + } else { + d.Set("start_time", nil) } - if err := d.Set("target_action", flattenRedshiftScheduledActionType(scheduledAction.TargetAction)); err != nil { - return fmt.Errorf("Error setting definitions: %s", err) + if scheduledAction.TargetAction != nil { + if err := d.Set("target_action", []interface{}{flattenRedshiftScheduledActionType(scheduledAction.TargetAction)}); err != nil { + return fmt.Errorf("error setting target_action: %w", err) + } + } else { + d.Set("target_action", nil) } return nil @@ -238,43 +245,47 @@ func resourceAwsRedshiftScheduledActionRead(d *schema.ResourceData, meta interfa func resourceAwsRedshiftScheduledActionUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).redshiftconn - modifyOpts := &redshift.ModifyScheduledActionInput{ - ScheduledActionName: aws.String(d.Get("name").(string)), - Schedule: aws.String(d.Get("schedule").(string)), - IamRole: aws.String(d.Get("iam_role").(string)), - TargetAction: expandRedshiftScheduledActionTargetAction(d.Get("target_action")), - Enable: aws.Bool(d.Get("active").(bool)), - ScheduledActionDescription: aws.String(d.Get("description").(string)), + input := &redshift.ModifyScheduledActionInput{ + ScheduledActionName: aws.String(d.Get("name").(string)), } - if attr, ok := d.GetOk("start_time"); ok { - t, _ := time.Parse(time.RFC3339, attr.(string)) - modifyOpts.StartTime = aws.Time(t) + if d.HasChange("description") { + input.ScheduledActionDescription = aws.String(d.Get("description").(string)) } - if attr, ok := d.GetOk("end_time"); ok { - t, _ := time.Parse(time.RFC3339, attr.(string)) - modifyOpts.EndTime = aws.Time(t) + + if d.HasChange("enable") { + input.Enable = aws.Bool(d.Get("enable").(bool)) } - log.Printf("[DEBUG] Updating Redshift Scheduled Action: %s", modifyOpts) + if hasChange, v := d.HasChange("end_time"), d.Get("end_time").(string); hasChange && v != "" { + t, _ := time.Parse(time.RFC3339, v) - err := resource.Retry(1*time.Minute, func() *resource.RetryError { - _, err := conn.ModifyScheduledAction(modifyOpts) + input.EndTime = aws.Time(t) + } - // InvalidParameterValue: If you create iam role same time, you must wait the role will be valid - if isAWSErr(err, "InvalidParameterValue", "The IAM role must delegate access to Amazon Redshift scheduler") { - return resource.RetryableError(err) - } + if d.HasChange("iam_role") { + input.IamRole = aws.String(d.Get("iam_role").(string)) + } - if err != nil { - return resource.NonRetryableError(err) - } + if d.HasChange("schedule") { + input.Schedule = aws.String(d.Get("schedule").(string)) + } - return nil - }) + if hasChange, v := d.HasChange("start_time"), d.Get("start_time").(string); hasChange && v != "" { + t, _ := time.Parse(time.RFC3339, v) + + input.StartTime = aws.Time(t) + } + + if d.HasChange("target_action") { + input.TargetAction = expandRedshiftScheduledActionType(d.Get("target_action").([]interface{})[0].(map[string]interface{})) + } + + log.Printf("[DEBUG] Updating Redshift Scheduled Action: %s", input) + _, err := conn.ModifyScheduledAction(input) if err != nil { - return fmt.Errorf("error updating Redshift Scheduled Action (%s): %s", d.Id(), err) + return fmt.Errorf("error updating Redshift Scheduled Action (%s): %w", d.Id(), err) } return nil @@ -299,67 +310,162 @@ func resourceAwsRedshiftScheduledActionDelete(d *schema.ResourceData, meta inter return nil } -func expandRedshiftScheduledActionTargetAction(configured interface{}) *redshift.ScheduledActionType { - if configured == nil || len(configured.([]interface{})) == 0 { +func expandRedshiftScheduledActionType(tfMap map[string]interface{}) *redshift.ScheduledActionType { + if tfMap == nil { return nil } - p := configured.([]interface{})[0].(map[string]interface{}) + apiObject := &redshift.ScheduledActionType{} - switch p["action"].(string) { - case redshift.ScheduledActionTypeValuesPauseCluster: - pauseCluster := redshift.PauseClusterMessage{ClusterIdentifier: aws.String(p["cluster_identifier"].(string))} - return &redshift.ScheduledActionType{ - PauseCluster: &pauseCluster, - } - case redshift.ScheduledActionTypeValuesResumeCluster: - resumeCluster := redshift.ResumeClusterMessage{ClusterIdentifier: aws.String(p["cluster_identifier"].(string))} - return &redshift.ScheduledActionType{ - ResumeCluster: &resumeCluster, - } - case redshift.ScheduledActionTypeValuesResizeCluster: - resizeCluster := redshift.ResizeClusterMessage{ - ClusterIdentifier: aws.String(p["cluster_identifier"].(string)), - Classic: aws.Bool(p["classic"].(bool)), - ClusterType: aws.String(p["cluster_type"].(string)), - NodeType: aws.String(p["node_type"].(string)), - NumberOfNodes: aws.Int64(int64(p["number_of_nodes"].(int))), - } - return &redshift.ScheduledActionType{ - ResizeCluster: &resizeCluster, - } + if v, ok := tfMap["pause_cluster"].([]interface{}); ok && len(v) > 0 { + apiObject.PauseCluster = expandRedshiftPauseClusterMessage(v[0].(map[string]interface{})) } - return nil + + if v, ok := tfMap["resize_cluster"].([]interface{}); ok && len(v) > 0 { + apiObject.ResizeCluster = expandRedshiftResizeClusterMessage(v[0].(map[string]interface{})) + } + + if v, ok := tfMap["resume_cluster"].([]interface{}); ok && len(v) > 0 { + apiObject.ResumeCluster = expandRedshiftResumeClusterMessage(v[0].(map[string]interface{})) + } + + return apiObject } -func flattenRedshiftScheduledActionType(scheduledActionType *redshift.ScheduledActionType) []map[string]interface{} { - if scheduledActionType == nil { - return []map[string]interface{}{} +func expandRedshiftPauseClusterMessage(tfMap map[string]interface{}) *redshift.PauseClusterMessage { + if tfMap == nil { + return nil } - m := map[string]interface{}{} + apiObject := &redshift.PauseClusterMessage{} - if scheduledActionType.ResumeCluster != nil { - m = map[string]interface{}{ - "action": redshift.ScheduledActionTypeValuesResumeCluster, - "cluster_identifier": aws.StringValue(scheduledActionType.ResumeCluster.ClusterIdentifier), - } + if v, ok := tfMap["cluster_identifier"].(string); ok && v != "" { + apiObject.ClusterIdentifier = aws.String(v) } - if scheduledActionType.PauseCluster != nil { - m = map[string]interface{}{ - "action": redshift.ScheduledActionTypeValuesPauseCluster, - "cluster_identifier": aws.StringValue(scheduledActionType.PauseCluster.ClusterIdentifier), - } + + return apiObject +} + +func expandRedshiftResizeClusterMessage(tfMap map[string]interface{}) *redshift.ResizeClusterMessage { + if tfMap == nil { + return nil } - if scheduledActionType.ResizeCluster != nil { - m = map[string]interface{}{ - "action": redshift.ScheduledActionTypeValuesResizeCluster, - "cluster_identifier": aws.StringValue(scheduledActionType.ResizeCluster.ClusterIdentifier), - "classic": aws.BoolValue(scheduledActionType.ResizeCluster.Classic), - "cluster_type": aws.StringValue(scheduledActionType.ResizeCluster.ClusterType), - "node_type": aws.StringValue(scheduledActionType.ResizeCluster.NodeType), - "number_of_nodes": aws.Int64Value(scheduledActionType.ResizeCluster.NumberOfNodes), - } + + apiObject := &redshift.ResizeClusterMessage{} + + if v, ok := tfMap["classic"].(bool); ok { + apiObject.Classic = aws.Bool(v) + } + + if v, ok := tfMap["cluster_identifier"].(string); ok && v != "" { + apiObject.ClusterIdentifier = aws.String(v) + } + + if v, ok := tfMap["cluster_type"].(string); ok && v != "" { + apiObject.ClusterType = aws.String(v) + } + + if v, ok := tfMap["node_type"].(string); ok && v != "" { + apiObject.NodeType = aws.String(v) + } + + if v, ok := tfMap["number_of_nodes"].(int); ok && v != 0 { + apiObject.NumberOfNodes = aws.Int64(int64(v)) + } + + return apiObject +} + +func expandRedshiftResumeClusterMessage(tfMap map[string]interface{}) *redshift.ResumeClusterMessage { + if tfMap == nil { + return nil } - return []map[string]interface{}{m} + + apiObject := &redshift.ResumeClusterMessage{} + + if v, ok := tfMap["cluster_identifier"].(string); ok && v != "" { + apiObject.ClusterIdentifier = aws.String(v) + } + + return apiObject +} + +func flattenRedshiftScheduledActionType(apiObject *redshift.ScheduledActionType) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.PauseCluster; v != nil { + tfMap["pause_cluster"] = []interface{}{flattenRedshiftPauseClusterMessage(v)} + } + + if v := apiObject.ResizeCluster; v != nil { + tfMap["resize_cluster"] = []interface{}{flattenRedshiftResizeClusterMessage(v)} + } + + if v := apiObject.ResumeCluster; v != nil { + tfMap["resume_cluster"] = []interface{}{flattenRedshiftResumeClusterMessage(v)} + } + + return tfMap +} + +func flattenRedshiftPauseClusterMessage(apiObject *redshift.PauseClusterMessage) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.ClusterIdentifier; v != nil { + tfMap["cluster_identifier"] = aws.StringValue(v) + } + + return tfMap +} + +func flattenRedshiftResizeClusterMessage(apiObject *redshift.ResizeClusterMessage) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.Classic; v != nil { + tfMap["classic"] = aws.BoolValue(v) + } + + if v := apiObject.ClusterIdentifier; v != nil { + tfMap["cluster_identifier"] = aws.StringValue(v) + } + + if v := apiObject.ClusterType; v != nil { + tfMap["cluster_type"] = aws.StringValue(v) + } + + if v := apiObject.NodeType; v != nil { + tfMap["node_type"] = aws.StringValue(v) + } + + if v := apiObject.NumberOfNodes; v != nil { + tfMap["number_of_nodes"] = aws.Int64Value(v) + } + + return tfMap +} + +func flattenRedshiftResumeClusterMessage(apiObject *redshift.ResumeClusterMessage) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.ClusterIdentifier; v != nil { + tfMap["cluster_identifier"] = aws.StringValue(v) + } + + return tfMap } diff --git a/aws/resource_aws_redshift_scheduled_action_test.go b/aws/resource_aws_redshift_scheduled_action_test.go index f957198de3c..25091d1ca5f 100644 --- a/aws/resource_aws_redshift_scheduled_action_test.go +++ b/aws/resource_aws_redshift_scheduled_action_test.go @@ -3,7 +3,6 @@ package aws import ( "fmt" "log" - "strings" "testing" "time" @@ -12,17 +11,14 @@ import ( "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/terraform-providers/terraform-provider-aws/aws/internal/service/redshift/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func init() { resource.AddTestSweepers("aws_redshift_scheduled_action", &resource.Sweeper{ Name: "aws_redshift_scheduled_action", - Dependencies: []string{ - "aws_iam_role", - "aws_iam_policy", - "aws_iam_role_policy_attachment", - }, - F: testSweepRedshiftScheduledActions, + F: testSweepRedshiftScheduledActions, }) } @@ -32,60 +28,47 @@ func testSweepRedshiftScheduledActions(region string) error { return fmt.Errorf("error getting client: %s", err) } conn := client.(*AWSClient).redshiftconn + input := &redshift.DescribeScheduledActionsInput{} + sweepResources := make([]*testSweepResource, 0) - req := &redshift.DescribeScheduledActionsInput{} + err = conn.DescribeScheduledActionsPages(input, func(page *redshift.DescribeScheduledActionsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } - resp, err := conn.DescribeScheduledActions(req) - if err != nil { - if testSweepSkipSweepError(err) { - log.Printf("[WARN] Skipping Redshift Regional Scheduled Actions sweep for %s: %s", region, err) - return nil + for _, scheduledAction := range page.ScheduledActions { + r := resourceAwsRedshiftScheduledAction() + d := r.Data(nil) + d.SetId(aws.StringValue(scheduledAction.ScheduledActionName)) + + sweepResources = append(sweepResources, NewTestSweepResource(r, d, client)) } - return fmt.Errorf("Error describing Redshift Regional Scheduled Actions: %s", err) - } - if len(resp.ScheduledActions) == 0 { - log.Print("[DEBUG] No AWS Redshift Regional Scheduled Actions to sweep") + return !lastPage + }) + + if testSweepSkipSweepError(err) { + log.Printf("[WARN] Skipping Redshift Scheduled Action sweep for %s: %s", region, err) return nil } - for _, ScheduledActions := range resp.ScheduledActions { - identifier := aws.StringValue(ScheduledActions.ScheduledActionName) - - hasPrefix := false - prefixes := []string{"tf-test-"} - - for _, prefix := range prefixes { - if strings.HasPrefix(identifier, prefix) { - hasPrefix = true - break - } - } + if err != nil { + return fmt.Errorf("error listing Redshift Scheduled Actions (%s): %w", region, err) + } - if !hasPrefix { - log.Printf("[INFO] Skipping Delete Redshift Scheduled Action: %s", identifier) - continue - } + err = testSweepResourceOrchestrator(sweepResources) - _, err := conn.DeleteScheduledAction(&redshift.DeleteScheduledActionInput{ - ScheduledActionName: ScheduledActions.ScheduledActionName, - }) - if isAWSErr(err, redshift.ErrCodeScheduledActionNotFoundFault, "") { - return nil - } - if err != nil { - return fmt.Errorf("Error deleting Redshift Scheduled Action %s: %s", identifier, err) - } + if err != nil { + return fmt.Errorf("error sweeping Redshift Scheduled Actions (%s): %w", region, err) } return nil } -func TestAccAWSRedshiftScheduledActionPauseCluster_basic(t *testing.T) { +func TestAccAWSRedshiftScheduledAction_basicPauseCluster(t *testing.T) { var v redshift.ScheduledAction - - rName := acctest.RandString(8) - resourceName := "aws_redshift_scheduled_action.default" + resourceName := "aws_redshift_scheduled_action.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -96,41 +79,49 @@ func TestAccAWSRedshiftScheduledActionPauseCluster_basic(t *testing.T) { Config: testAccAWSRedshiftScheduledActionConfigPauseCluster(rName, "cron(00 23 * * ? *)"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), - resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "enable", "true"), + resource.TestCheckResourceAttr(resourceName, "end_time", ""), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "schedule", "cron(00 23 * * ? *)"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.action", "PauseCluster"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.cluster_identifier", "tf-test-identifier"), + resource.TestCheckResourceAttr(resourceName, "start_time", ""), + resource.TestCheckResourceAttr(resourceName, "target_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.pause_cluster.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resume_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.pause_cluster.0.cluster_identifier", "tf-test-identifier"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, { Config: testAccAWSRedshiftScheduledActionConfigPauseCluster(rName, "at(2060-03-04T17:27:00)"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), - resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "enable", "true"), + resource.TestCheckResourceAttr(resourceName, "end_time", ""), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "schedule", "at(2060-03-04T17:27:00)"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.action", "PauseCluster"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.cluster_identifier", "tf-test-identifier"), + resource.TestCheckResourceAttr(resourceName, "start_time", ""), + resource.TestCheckResourceAttr(resourceName, "target_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.pause_cluster.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resume_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.pause_cluster.0.cluster_identifier", "tf-test-identifier"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "active", - }, - }, }, }) } -func TestAccAWSRedshiftScheduledActionPauseCluster_WithOptions(t *testing.T) { +func TestAccAWSRedshiftScheduledAction_PauseClusterWithOptions(t *testing.T) { var v redshift.ScheduledAction - - rName := acctest.RandString(8) - resourceName := "aws_redshift_scheduled_action.default" + resourceName := "aws_redshift_scheduled_action.test" + rName := acctest.RandomWithPrefix("tf-acc-test") startTime := time.Now().UTC().Add(1 * time.Hour).Format(time.RFC3339) endTime := time.Now().UTC().Add(2 * time.Hour).Format(time.RFC3339) @@ -140,33 +131,35 @@ func TestAccAWSRedshiftScheduledActionPauseCluster_WithOptions(t *testing.T) { CheckDestroy: testAccCheckAWSRedshiftScheduledActionDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSRedshiftScheduledActionConfigPauseClusterWithFullOption(rName, "cron(00 * * * ? *)", "This is test action", "true", startTime, endTime), + Config: testAccAWSRedshiftScheduledActionConfigPauseClusterWithFullOptions(rName, "cron(00 * * * ? *)", "This is test action", true, startTime, endTime), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), resource.TestCheckResourceAttr(resourceName, "description", "This is test action"), - resource.TestCheckResourceAttr(resourceName, "active", "true"), - resource.TestCheckResourceAttr(resourceName, "start_time", startTime), + resource.TestCheckResourceAttr(resourceName, "enable", "true"), resource.TestCheckResourceAttr(resourceName, "end_time", endTime), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "schedule", "cron(00 * * * ? *)"), + resource.TestCheckResourceAttr(resourceName, "start_time", startTime), + resource.TestCheckResourceAttr(resourceName, "target_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.pause_cluster.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resume_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.pause_cluster.0.cluster_identifier", "tf-test-identifier"), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "active", - }, }, }, }) } -func TestAccAWSRedshiftScheduledActionResumeCluster_basic(t *testing.T) { +func TestAccAWSRedshiftScheduledAction_basicResumeCluster(t *testing.T) { var v redshift.ScheduledAction - - rName := acctest.RandString(8) - resourceName := "aws_redshift_scheduled_action.default" + resourceName := "aws_redshift_scheduled_action.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -177,41 +170,49 @@ func TestAccAWSRedshiftScheduledActionResumeCluster_basic(t *testing.T) { Config: testAccAWSRedshiftScheduledActionConfigResumeCluster(rName, "cron(00 23 * * ? *)"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), - resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "enable", "true"), + resource.TestCheckResourceAttr(resourceName, "end_time", ""), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "schedule", "cron(00 23 * * ? *)"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.action", "ResumeCluster"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.cluster_identifier", "tf-test-identifier"), + resource.TestCheckResourceAttr(resourceName, "start_time", ""), + resource.TestCheckResourceAttr(resourceName, "target_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.pause_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resume_cluster.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resume_cluster.0.cluster_identifier", "tf-test-identifier"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, { Config: testAccAWSRedshiftScheduledActionConfigResumeCluster(rName, "at(2060-03-04T17:27:00)"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), - resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "enable", "true"), + resource.TestCheckResourceAttr(resourceName, "end_time", ""), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "schedule", "at(2060-03-04T17:27:00)"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.action", "ResumeCluster"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.cluster_identifier", "tf-test-identifier"), + resource.TestCheckResourceAttr(resourceName, "start_time", ""), + resource.TestCheckResourceAttr(resourceName, "target_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.pause_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resume_cluster.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resume_cluster.0.cluster_identifier", "tf-test-identifier"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "active", - }, - }, }, }) } -func TestAccAWSRedshiftScheduledActionResizeCluster_basic(t *testing.T) { +func TestAccAWSRedshiftScheduledAction_basicResizeCluster(t *testing.T) { var v redshift.ScheduledAction - - rName := acctest.RandString(8) - resourceName := "aws_redshift_scheduled_action.default" + resourceName := "aws_redshift_scheduled_action.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -222,41 +223,49 @@ func TestAccAWSRedshiftScheduledActionResizeCluster_basic(t *testing.T) { Config: testAccAWSRedshiftScheduledActionConfigResizeClusterBasic(rName, "cron(00 23 * * ? *)"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), - resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "enable", "true"), + resource.TestCheckResourceAttr(resourceName, "end_time", ""), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "schedule", "cron(00 23 * * ? *)"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.action", "ResizeCluster"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.cluster_identifier", "tf-test-identifier"), + resource.TestCheckResourceAttr(resourceName, "start_time", ""), + resource.TestCheckResourceAttr(resourceName, "target_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.pause_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resume_cluster.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.0.cluster_identifier", "tf-test-identifier"), ), }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, { Config: testAccAWSRedshiftScheduledActionConfigResizeClusterBasic(rName, "at(2060-03-04T17:27:00)"), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), - resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "enable", "true"), + resource.TestCheckResourceAttr(resourceName, "end_time", ""), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "schedule", "at(2060-03-04T17:27:00)"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.action", "ResizeCluster"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.cluster_identifier", "tf-test-identifier"), + resource.TestCheckResourceAttr(resourceName, "start_time", ""), + resource.TestCheckResourceAttr(resourceName, "target_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.pause_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resume_cluster.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.0.cluster_identifier", "tf-test-identifier"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "active", - }, - }, }, }) } -func TestAccAWSRedshiftScheduledActionResizeCluster_WithOptions(t *testing.T) { +func TestAccAWSRedshiftScheduledAction_ResizeClusterWithOptions(t *testing.T) { var v redshift.ScheduledAction - - rName := acctest.RandString(8) - resourceName := "aws_redshift_scheduled_action.default" + resourceName := "aws_redshift_scheduled_action.test" + rName := acctest.RandomWithPrefix("tf-acc-test") resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -264,55 +273,76 @@ func TestAccAWSRedshiftScheduledActionResizeCluster_WithOptions(t *testing.T) { CheckDestroy: testAccCheckAWSRedshiftScheduledActionDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSRedshiftScheduledActionConfigResizeClusterWithFullOption(rName, "cron(00 23 * * ? *)", "true", "multi-node", "dc1.large", "2"), + Config: testAccAWSRedshiftScheduledActionConfigResizeClusterWithFullOptions(rName, "cron(00 23 * * ? *)", true, "multi-node", "dc1.large", 2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), - resource.TestCheckResourceAttr(resourceName, "name", fmt.Sprintf("tf-test-%s", rName)), - resource.TestCheckResourceAttrPair(resourceName, "name", resourceName, "id"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.classic", "true"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.cluster_type", "multi-node"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.node_type", "dc1.large"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.number_of_nodes", "2"), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "enable", "true"), + resource.TestCheckResourceAttr(resourceName, "end_time", ""), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "schedule", "cron(00 23 * * ? *)"), + resource.TestCheckResourceAttr(resourceName, "start_time", ""), + resource.TestCheckResourceAttr(resourceName, "target_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.pause_cluster.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resume_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.0.classic", "true"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.0.cluster_identifier", "tf-test-identifier"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.0.cluster_type", "multi-node"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.0.node_type", "dc1.large"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.0.number_of_nodes", "2"), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "active", - }, + }, + }, + }) +} + +func TestAccAWSRedshiftScheduledAction_disappears(t *testing.T) { + var v redshift.ScheduledAction + resourceName := "aws_redshift_scheduled_action.test" + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSRedshiftScheduledActionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSRedshiftScheduledActionConfigPauseCluster(rName, "cron(00 23 * * ? *)"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSRedshiftScheduledActionExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsRedshiftScheduledAction(), resourceName), + ), + ExpectNonEmptyPlan: true, }, }, }) } func testAccCheckAWSRedshiftScheduledActionDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).redshiftconn + for _, rs := range s.RootModule().Resources { if rs.Type != "aws_redshift_scheduled_action" { continue } - conn := testAccProvider.Meta().(*AWSClient).redshiftconn - resp, err := conn.DescribeScheduledActions(&redshift.DescribeScheduledActionsInput{ - ScheduledActionName: aws.String(rs.Primary.ID), - }) + _, err := finder.ScheduledActionByName(conn, rs.Primary.ID) - if isAWSErr(err, "ScheduledActionNotFound", "was not found.") { + if tfresource.NotFound(err) { continue } - if err == nil { - if len(resp.ScheduledActions) != 0 { - for _, s := range resp.ScheduledActions { - if *s.ScheduledActionName == rs.Primary.ID { - return fmt.Errorf("Redshift Cluster Scheduled Action %s still exists", rs.Primary.ID) - } - } - } + if err != nil { + return err } - return err + return fmt.Errorf("Redshift Scheduled Action %s still exists", rs.Primary.ID) } return nil @@ -326,33 +356,28 @@ func testAccCheckAWSRedshiftScheduledActionExists(n string, v *redshift.Schedule } if rs.Primary.ID == "" { - return fmt.Errorf("No Redshift Cluster Scheduled Action ID is set") + return fmt.Errorf("No Redshift Scheduled Action ID is set") } conn := testAccProvider.Meta().(*AWSClient).redshiftconn - resp, err := conn.DescribeScheduledActions(&redshift.DescribeScheduledActionsInput{ - ScheduledActionName: aws.String(rs.Primary.ID), - }) + + output, err := finder.ScheduledActionByName(conn, rs.Primary.ID) if err != nil { return err } - for _, s := range resp.ScheduledActions { - if *s.ScheduledActionName == rs.Primary.ID { - *v = *s - return nil - } - } + *v = *output - return fmt.Errorf("Redshift Scheduled Action (%s) not found", rs.Primary.ID) + return nil } } -func testAccAWSRedshiftScheduledActionConfigDependentResource(rName string) string { +func testAccAWSRedshiftScheduledActionConfigBase(rName string) string { return fmt.Sprintf(` -resource "aws_iam_role" "default" { - name = "tf-test-%s" +resource "aws_iam_role" "test" { + name = %[1]q + assume_role_policy = < Date: Wed, 29 Sep 2021 11:57:08 -0400 Subject: [PATCH 23/27] Add acceptance test 'ErrorCheck's. --- aws/resource_aws_redshift_scheduled_action_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/aws/resource_aws_redshift_scheduled_action_test.go b/aws/resource_aws_redshift_scheduled_action_test.go index 25091d1ca5f..c8acd407614 100644 --- a/aws/resource_aws_redshift_scheduled_action_test.go +++ b/aws/resource_aws_redshift_scheduled_action_test.go @@ -72,6 +72,7 @@ func TestAccAWSRedshiftScheduledAction_basicPauseCluster(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, redshift.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSRedshiftScheduledActionDestroy, Steps: []resource.TestStep{ @@ -127,6 +128,7 @@ func TestAccAWSRedshiftScheduledAction_PauseClusterWithOptions(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, redshift.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSRedshiftScheduledActionDestroy, Steps: []resource.TestStep{ @@ -163,6 +165,7 @@ func TestAccAWSRedshiftScheduledAction_basicResumeCluster(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, redshift.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSRedshiftScheduledActionDestroy, Steps: []resource.TestStep{ @@ -216,6 +219,7 @@ func TestAccAWSRedshiftScheduledAction_basicResizeCluster(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, redshift.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSRedshiftScheduledActionDestroy, Steps: []resource.TestStep{ @@ -269,6 +273,7 @@ func TestAccAWSRedshiftScheduledAction_ResizeClusterWithOptions(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, redshift.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSRedshiftScheduledActionDestroy, Steps: []resource.TestStep{ @@ -309,6 +314,7 @@ func TestAccAWSRedshiftScheduledAction_disappears(t *testing.T) { resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, + ErrorCheck: testAccErrorCheck(t, redshift.EndpointsID), Providers: testAccProviders, CheckDestroy: testAccCheckAWSRedshiftScheduledActionDestroy, Steps: []resource.TestStep{ From 667ea7f0444d454bcf69e7b4f35677e4764c637d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 29 Sep 2021 11:59:47 -0400 Subject: [PATCH 24/27] Fix tfproviderdocs error. --- website/docs/r/redshift_scheduled_action.html.markdown | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/website/docs/r/redshift_scheduled_action.html.markdown b/website/docs/r/redshift_scheduled_action.html.markdown index 4d566b10b2d..6507c121ab7 100644 --- a/website/docs/r/redshift_scheduled_action.html.markdown +++ b/website/docs/r/redshift_scheduled_action.html.markdown @@ -8,7 +8,9 @@ description: |- # Resource: aws_redshift_scheduled_action -## Example Pause Cluster +## Example Usage + +### Pause Cluster Action ```terraform resource "aws_iam_role" "example" { @@ -71,7 +73,7 @@ resource "aws_redshift_scheduled_action" "example" { } ``` -## Example Resize Cluster +### Resize Cluster Action ```terraform resource "aws_redshift_scheduled_action" "example" { From 26d923863b0163fb6552eed9cf28fea336cbf272 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 29 Sep 2021 12:02:39 -0400 Subject: [PATCH 25/27] Fix terrafmt error. --- aws/resource_aws_redshift_scheduled_action_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aws/resource_aws_redshift_scheduled_action_test.go b/aws/resource_aws_redshift_scheduled_action_test.go index c8acd407614..2115bac9e07 100644 --- a/aws/resource_aws_redshift_scheduled_action_test.go +++ b/aws/resource_aws_redshift_scheduled_action_test.go @@ -511,7 +511,7 @@ resource "aws_redshift_scheduled_action" "test" { target_action { resize_cluster { cluster_identifier = "tf-test-identifier" - classic = %[3]t + classic = %[3]t cluster_type = %[4]q node_type = %[5]q number_of_nodes = %[6]d From 19de093865d5802ef979244641dfaa7925ff0bed Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 29 Sep 2021 12:07:37 -0400 Subject: [PATCH 26/27] Correct acceptance test checks. --- aws/resource_aws_redshift_scheduled_action_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/aws/resource_aws_redshift_scheduled_action_test.go b/aws/resource_aws_redshift_scheduled_action_test.go index 2115bac9e07..28dd1294f88 100644 --- a/aws/resource_aws_redshift_scheduled_action_test.go +++ b/aws/resource_aws_redshift_scheduled_action_test.go @@ -235,8 +235,8 @@ func TestAccAWSRedshiftScheduledAction_basicResizeCluster(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "start_time", ""), resource.TestCheckResourceAttr(resourceName, "target_action.#", "1"), resource.TestCheckResourceAttr(resourceName, "target_action.0.pause_cluster.#", "0"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.#", "0"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.resume_cluster.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resume_cluster.#", "0"), resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.0.cluster_identifier", "tf-test-identifier"), ), }, @@ -257,8 +257,8 @@ func TestAccAWSRedshiftScheduledAction_basicResizeCluster(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "start_time", ""), resource.TestCheckResourceAttr(resourceName, "target_action.#", "1"), resource.TestCheckResourceAttr(resourceName, "target_action.0.pause_cluster.#", "0"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.#", "0"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.resume_cluster.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.#", "1"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resume_cluster.#", "0"), resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.0.cluster_identifier", "tf-test-identifier"), ), }, @@ -288,8 +288,8 @@ func TestAccAWSRedshiftScheduledAction_ResizeClusterWithOptions(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "schedule", "cron(00 23 * * ? *)"), resource.TestCheckResourceAttr(resourceName, "start_time", ""), resource.TestCheckResourceAttr(resourceName, "target_action.#", "1"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.pause_cluster.#", "1"), - resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.pause_cluster.#", "0"), + resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.#", "1"), resource.TestCheckResourceAttr(resourceName, "target_action.0.resume_cluster.#", "0"), resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.0.classic", "true"), resource.TestCheckResourceAttr(resourceName, "target_action.0.resize_cluster.0.cluster_identifier", "tf-test-identifier"), From 1f75e4c24f854890e751f05f1509a2891defebf7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 29 Sep 2021 12:24:27 -0400 Subject: [PATCH 27/27] Add 'Attributes Reference' section. --- .../r/redshift_scheduled_action.html.markdown | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/website/docs/r/redshift_scheduled_action.html.markdown b/website/docs/r/redshift_scheduled_action.html.markdown index 6507c121ab7..cfae369a912 100644 --- a/website/docs/r/redshift_scheduled_action.html.markdown +++ b/website/docs/r/redshift_scheduled_action.html.markdown @@ -115,19 +115,25 @@ The following arguments are supported: ### `pause_cluster` -* `cluster_identifier` - (Required) The target identifier for the redshift cluster of the scheduled action. +* `cluster_identifier` - (Required) The identifier of the cluster to be paused. ### `resize_cluster` -* `cluster_identifier` - (Required) The target identifier for the redshift cluster of the scheduled action. -* `classic` - (Optional) Indicate resize operation is using the classic resize process. Default is `false`. +* `cluster_identifier` - (Required) The unique identifier for the cluster to resize. +* `classic` - (Optional) A boolean value indicating whether the resize operation is using the classic resize process. Default: `false`. * `cluster_type` - (Optional) The new cluster type for the specified cluster. -* `node_type` - (Optional) The new node type for the nodes you are addingThe new node type for the nodes you are adding. +* `node_type` - (Optional) The new node type for the nodes you are adding. * `number_of_nodes` - (Optional) The new number of nodes for the cluster. ### `resume_cluster` -* `cluster_identifier` - (Required) The target identifier for the redshift cluster of the scheduled action. +* `cluster_identifier` - (Required) The identifier of the cluster to be resumed. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The Redshift Scheduled Action name. ## Import