diff --git a/.changelog/33713.txt b/.changelog/33713.txt new file mode 100644 index 00000000000..8146822e7ea --- /dev/null +++ b/.changelog/33713.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_appautoscaling_scheduled_action: Always send `start_time` and `end_time` values on update when configured +``` \ No newline at end of file diff --git a/internal/service/appautoscaling/scheduled_action.go b/internal/service/appautoscaling/scheduled_action.go index 3d6184bf225..7bc12937a63 100644 --- a/internal/service/appautoscaling/scheduled_action.go +++ b/internal/service/appautoscaling/scheduled_action.go @@ -136,11 +136,9 @@ func resourceScheduledActionPut(ctx context.Context, d *schema.ResourceData, met } input.Timezone = aws.String(d.Get("timezone").(string)) } else { - if d.HasChange("end_time") { - if v, ok := d.GetOk("end_time"); ok { - t, _ := time.Parse(time.RFC3339, v.(string)) - input.EndTime = aws.Time(t) - } + if v, ok := d.GetOk("end_time"); ok { + t, _ := time.Parse(time.RFC3339, v.(string)) + input.EndTime = aws.Time(t) } if d.HasChange("scalable_target_action") { input.ScalableTargetAction = expandScalableTargetAction(d.Get("scalable_target_action").([]interface{})) @@ -148,11 +146,9 @@ func resourceScheduledActionPut(ctx context.Context, d *schema.ResourceData, met if d.HasChange("schedule") { input.Schedule = aws.String(d.Get("schedule").(string)) } - if d.HasChange("start_time") { - if v, ok := d.GetOk("start_time"); ok { - t, _ := time.Parse(time.RFC3339, v.(string)) - input.StartTime = aws.Time(t) - } + if v, ok := d.GetOk("start_time"); ok { + t, _ := time.Parse(time.RFC3339, v.(string)) + input.StartTime = aws.Time(t) } if d.HasChange("timezone") { input.Timezone = aws.String(d.Get("timezone").(string)) diff --git a/internal/service/appautoscaling/scheduled_action_test.go b/internal/service/appautoscaling/scheduled_action_test.go index 0a3c2049cda..039596c2e56 100644 --- a/internal/service/appautoscaling/scheduled_action_test.go +++ b/internal/service/appautoscaling/scheduled_action_test.go @@ -139,6 +139,177 @@ func TestAccAppAutoScalingScheduledAction_ecs(t *testing.T) { }) } +func TestAccAppAutoScalingScheduledAction_ecsUpdateScheduleRetainStartAndEndTime(t *testing.T) { + ctx := acctest.Context(t) + var sa applicationautoscaling.ScheduledAction + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + ts := time.Now().AddDate(0, 0, 1).Format("2006-01-02T15:04:05") + tsUpdate := time.Now().AddDate(0, 0, 2).Format("2006-01-02T15:04:05") + resourceName := "aws_appautoscaling_scheduled_action.test" + autoscalingTargetResourceName := "aws_appautoscaling_target.test" + startTime := time.Now().AddDate(0, 0, 2).Format("2006-01-02T15:04:05Z") + endTime := time.Now().AddDate(0, 0, 8).Format("2006-01-02T15:04:05Z") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.AppAutoScalingServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckScheduledActionDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccScheduledActionConfig_ecsWithStartAndEndTime(rName, ts, startTime, endTime), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckScheduledActionExists(ctx, resourceName, &sa), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrPair(resourceName, "service_namespace", autoscalingTargetResourceName, "service_namespace"), + resource.TestCheckResourceAttrPair(resourceName, "resource_id", autoscalingTargetResourceName, "resource_id"), + resource.TestCheckResourceAttrPair(resourceName, "scalable_dimension", autoscalingTargetResourceName, "scalable_dimension"), + resource.TestCheckResourceAttr(resourceName, "schedule", fmt.Sprintf("at(%s)", ts)), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.0.min_capacity", "1"), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.0.max_capacity", "5"), + resource.TestCheckResourceAttr(resourceName, "timezone", "UTC"), + resource.TestCheckResourceAttr(resourceName, "start_time", startTime), + resource.TestCheckResourceAttr(resourceName, "end_time", endTime), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "autoscaling", regexache.MustCompile(fmt.Sprintf("scheduledAction:.+:scheduledActionName/%s$", rName))), + ), + }, + { + Config: testAccScheduledActionConfig_ecsWithStartAndEndTime(rName, tsUpdate, startTime, endTime), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckScheduledActionExists(ctx, resourceName, &sa), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrPair(resourceName, "service_namespace", autoscalingTargetResourceName, "service_namespace"), + resource.TestCheckResourceAttrPair(resourceName, "resource_id", autoscalingTargetResourceName, "resource_id"), + resource.TestCheckResourceAttrPair(resourceName, "scalable_dimension", autoscalingTargetResourceName, "scalable_dimension"), + resource.TestCheckResourceAttr(resourceName, "schedule", fmt.Sprintf("at(%s)", tsUpdate)), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.0.min_capacity", "1"), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.0.max_capacity", "5"), + resource.TestCheckResourceAttr(resourceName, "timezone", "UTC"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "autoscaling", regexache.MustCompile(fmt.Sprintf("scheduledAction:.+:scheduledActionName/%s$", rName))), + ), + }, + }, + }) +} + +func TestAccAppAutoScalingScheduledAction_ecsUpdateStartAndEndTime(t *testing.T) { + ctx := acctest.Context(t) + var sa applicationautoscaling.ScheduledAction + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + ts := time.Now().AddDate(0, 0, 1).Format("2006-01-02T15:04:05") + tsUpdate := time.Now().AddDate(0, 0, 2).Format("2006-01-02T15:04:05") + resourceName := "aws_appautoscaling_scheduled_action.test" + autoscalingTargetResourceName := "aws_appautoscaling_target.test" + startTime := time.Now().AddDate(0, 0, 2).Format("2006-01-02T15:04:05Z") + endTime := time.Now().AddDate(0, 0, 8).Format("2006-01-02T15:04:05Z") + startTimeUpdate := time.Now().AddDate(0, 0, 4).Format("2006-01-02T15:04:05Z") + endTimeUpdate := time.Now().AddDate(0, 0, 10).Format("2006-01-02T15:04:05Z") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.AppAutoScalingServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckScheduledActionDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccScheduledActionConfig_ecsWithStartAndEndTime(rName, ts, startTime, endTime), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckScheduledActionExists(ctx, resourceName, &sa), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrPair(resourceName, "service_namespace", autoscalingTargetResourceName, "service_namespace"), + resource.TestCheckResourceAttrPair(resourceName, "resource_id", autoscalingTargetResourceName, "resource_id"), + resource.TestCheckResourceAttrPair(resourceName, "scalable_dimension", autoscalingTargetResourceName, "scalable_dimension"), + resource.TestCheckResourceAttr(resourceName, "schedule", fmt.Sprintf("at(%s)", ts)), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.0.min_capacity", "1"), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.0.max_capacity", "5"), + resource.TestCheckResourceAttr(resourceName, "timezone", "UTC"), + resource.TestCheckResourceAttr(resourceName, "start_time", startTime), + resource.TestCheckResourceAttr(resourceName, "end_time", endTime), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "autoscaling", regexache.MustCompile(fmt.Sprintf("scheduledAction:.+:scheduledActionName/%s$", rName))), + ), + }, + { + Config: testAccScheduledActionConfig_ecsWithStartAndEndTime(rName, tsUpdate, startTimeUpdate, endTimeUpdate), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckScheduledActionExists(ctx, resourceName, &sa), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrPair(resourceName, "service_namespace", autoscalingTargetResourceName, "service_namespace"), + resource.TestCheckResourceAttrPair(resourceName, "resource_id", autoscalingTargetResourceName, "resource_id"), + resource.TestCheckResourceAttrPair(resourceName, "scalable_dimension", autoscalingTargetResourceName, "scalable_dimension"), + resource.TestCheckResourceAttr(resourceName, "schedule", fmt.Sprintf("at(%s)", tsUpdate)), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.0.min_capacity", "1"), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.0.max_capacity", "5"), + resource.TestCheckResourceAttr(resourceName, "timezone", "UTC"), + resource.TestCheckResourceAttr(resourceName, "start_time", startTimeUpdate), + resource.TestCheckResourceAttr(resourceName, "end_time", endTimeUpdate), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "autoscaling", regexache.MustCompile(fmt.Sprintf("scheduledAction:.+:scheduledActionName/%s$", rName))), + ), + }, + }, + }) +} + +func TestAccAppAutoScalingScheduledAction_ecsAddStartTimeAndEndTimeAfterResourceCreated(t *testing.T) { + ctx := acctest.Context(t) + var sa applicationautoscaling.ScheduledAction + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + ts := time.Now().AddDate(0, 0, 1).Format("2006-01-02T15:04:05") + tsUpdate := time.Now().AddDate(0, 0, 2).Format("2006-01-02T15:04:05") + resourceName := "aws_appautoscaling_scheduled_action.test" + autoscalingTargetResourceName := "aws_appautoscaling_target.test" + startTime := time.Now().AddDate(0, 0, 2).Format("2006-01-02T15:04:05Z") + endTime := time.Now().AddDate(0, 0, 8).Format("2006-01-02T15:04:05Z") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.AppAutoScalingServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckScheduledActionDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccScheduledActionConfig_ecs(rName, ts), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckScheduledActionExists(ctx, resourceName, &sa), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrPair(resourceName, "service_namespace", autoscalingTargetResourceName, "service_namespace"), + resource.TestCheckResourceAttrPair(resourceName, "resource_id", autoscalingTargetResourceName, "resource_id"), + resource.TestCheckResourceAttrPair(resourceName, "scalable_dimension", autoscalingTargetResourceName, "scalable_dimension"), + resource.TestCheckResourceAttr(resourceName, "schedule", fmt.Sprintf("at(%s)", ts)), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.0.min_capacity", "1"), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.0.max_capacity", "5"), + resource.TestCheckResourceAttr(resourceName, "timezone", "UTC"), + resource.TestCheckNoResourceAttr(resourceName, "start_time"), + resource.TestCheckNoResourceAttr(resourceName, "end_time"), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "autoscaling", regexache.MustCompile(fmt.Sprintf("scheduledAction:.+:scheduledActionName/%s$", rName))), + ), + }, + { + Config: testAccScheduledActionConfig_ecsWithStartAndEndTime(rName, tsUpdate, startTime, endTime), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckScheduledActionExists(ctx, resourceName, &sa), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrPair(resourceName, "service_namespace", autoscalingTargetResourceName, "service_namespace"), + resource.TestCheckResourceAttrPair(resourceName, "resource_id", autoscalingTargetResourceName, "resource_id"), + resource.TestCheckResourceAttrPair(resourceName, "scalable_dimension", autoscalingTargetResourceName, "scalable_dimension"), + resource.TestCheckResourceAttr(resourceName, "schedule", fmt.Sprintf("at(%s)", tsUpdate)), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.0.min_capacity", "1"), + resource.TestCheckResourceAttr(resourceName, "scalable_target_action.0.max_capacity", "5"), + resource.TestCheckResourceAttr(resourceName, "timezone", "UTC"), + resource.TestCheckResourceAttr(resourceName, "start_time", startTime), + resource.TestCheckResourceAttr(resourceName, "end_time", endTime), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "autoscaling", regexache.MustCompile(fmt.Sprintf("scheduledAction:.+:scheduledActionName/%s$", rName))), + ), + }, + }, + }) +} + func TestAccAppAutoScalingScheduledAction_emr(t *testing.T) { ctx := acctest.Context(t) var sa applicationautoscaling.ScheduledAction @@ -784,6 +955,64 @@ resource "aws_ecs_service" "test" { `, rName, ts) } +func testAccScheduledActionConfig_ecsWithStartAndEndTime(rName, ts, startTime, endTime string) string { + return fmt.Sprintf(` +resource "aws_appautoscaling_scheduled_action" "test" { + name = %[1]q + service_namespace = aws_appautoscaling_target.test.service_namespace + resource_id = aws_appautoscaling_target.test.resource_id + scalable_dimension = aws_appautoscaling_target.test.scalable_dimension + schedule = "at(%[2]s)" + + start_time = %[3]q + end_time = %[4]q + + scalable_target_action { + min_capacity = 1 + max_capacity = 5 + } +} + +resource "aws_appautoscaling_target" "test" { + service_namespace = "ecs" + resource_id = "service/${aws_ecs_cluster.test.name}/${aws_ecs_service.test.name}" + scalable_dimension = "ecs:service:DesiredCount" + min_capacity = 1 + max_capacity = 3 +} + +resource "aws_ecs_cluster" "test" { + name = %[1]q +} + +resource "aws_ecs_task_definition" "test" { + family = %[1]q + + container_definitions = <