diff --git a/.changelog/20707.txt b/.changelog/20707.txt new file mode 100644 index 00000000000..250debcf1e3 --- /dev/null +++ b/.changelog/20707.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_ecs_service: Allow `capacity_provider_strategy` changes to be updated in place, when possible +``` \ No newline at end of file diff --git a/internal/service/ecs/service.go b/internal/service/ecs/service.go index 284473cc376..b583c63b6fd 100644 --- a/internal/service/ecs/service.go +++ b/internal/service/ecs/service.go @@ -2,6 +2,7 @@ package ecs import ( "bytes" + "context" "fmt" "log" "math" @@ -12,6 +13,7 @@ import ( "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/ecs" "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "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" @@ -34,8 +36,6 @@ func ResourceService() *schema.Resource { State: resourceServiceImport, }, - CustomizeDiff: verify.SetTagsDiff, - Timeouts: &schema.ResourceTimeout{ Delete: schema.DefaultTimeout(20 * time.Minute), }, @@ -44,27 +44,21 @@ func ResourceService() *schema.Resource { "capacity_provider_strategy": { Type: schema.TypeSet, Optional: true, - ForceNew: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "base": { Type: schema.TypeInt, Optional: true, ValidateFunc: validation.IntBetween(0, 100000), - ForceNew: true, }, - "capacity_provider": { Type: schema.TypeString, Required: true, - ForceNew: true, }, - "weight": { Type: schema.TypeInt, Optional: true, ValidateFunc: validation.IntBetween(0, 1000), - ForceNew: true, }, }, }, @@ -383,7 +377,43 @@ func ResourceService() *schema.Resource { Default: false, }, }, + + CustomizeDiff: customdiff.Sequence( + verify.SetTagsDiff, + capacityProviderStrategyCustomizeDiff, + ), + } +} + +func capacityProviderStrategyCustomizeDiff(_ context.Context, d *schema.ResourceDiff, meta interface{}) error { + // to be backward compatible, should ForceNew almost always (previous behavior), unless: + // force_new_deployment is true and + // neither the old set nor new set is 0 length + if v := d.Get("force_new_deployment").(bool); !v { + return capacityProviderStrategyForceNew(d) } + + old, new := d.GetChange("capacity_provider_strategy") + + ol := old.(*schema.Set).Len() + nl := new.(*schema.Set).Len() + + if (ol == 0 && nl > 0) || (ol > 0 && nl == 0) { + return capacityProviderStrategyForceNew(d) + } + + return nil +} + +func capacityProviderStrategyForceNew(d *schema.ResourceDiff) error { + for _, key := range d.GetChangedKeysPrefix("capacity_provider_strategy") { + if d.HasChange(key) { + if err := d.ForceNew(key); err != nil { + return fmt.Errorf("while attempting to force a new ECS service for capacity_provider_strategy: %w", err) + } + } + } + return nil } func resourceServiceImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { diff --git a/internal/service/ecs/service_test.go b/internal/service/ecs/service_test.go index 2f787c2ce79..4c09de258b5 100644 --- a/internal/service/ecs/service_test.go +++ b/internal/service/ecs/service_test.go @@ -19,7 +19,7 @@ import ( tfecs "github.com/hashicorp/terraform-provider-aws/internal/service/ecs" ) -func TestAccECSService_withARN(t *testing.T) { +func TestAccECSService_basic(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -31,7 +31,7 @@ func TestAccECSService_withARN(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccService(rName), + Config: testAccServiceConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "service_registries.#", "0"), @@ -40,7 +40,7 @@ func TestAccECSService_withARN(t *testing.T) { }, { - Config: testAccServiceModified(rName), + Config: testAccServiceModifiedConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "service_registries.#", "0"), @@ -64,7 +64,7 @@ func TestAccECSService_basicImport(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithFamilyAndRevision(rName), + Config: testAccServiceFamilyAndRevisionConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), ), @@ -102,7 +102,7 @@ func TestAccECSService_disappears(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccService(rName), + Config: testAccServiceConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), acctest.CheckResourceDisappears(acctest.Provider, tfecs.ResourceService(), resourceName), @@ -113,7 +113,7 @@ func TestAccECSService_disappears(t *testing.T) { }) } -func TestAccECSService_withUnnormalizedPlacementStrategy(t *testing.T) { +func TestAccECSService_PlacementStrategy_unnormalized(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -125,7 +125,7 @@ func TestAccECSService_withUnnormalizedPlacementStrategy(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithInterchangeablePlacementStrategy(rName), + Config: testAccServiceInterchangeablePlacementStrategyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), ), @@ -134,7 +134,7 @@ func TestAccECSService_withUnnormalizedPlacementStrategy(t *testing.T) { }) } -func TestAccECSService_withCapacityProviderStrategy(t *testing.T) { +func TestAccECSService_CapacityProviderStrategy_basic(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -146,13 +146,13 @@ func TestAccECSService_withCapacityProviderStrategy(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithCapacityProviderStrategy(rName, 1, 0), + Config: testAccServiceCapacityProviderStrategyConfig(rName, 1, 0, false), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), ), }, { - Config: testAccServiceWithCapacityProviderStrategy(rName, 10, 1), + Config: testAccServiceCapacityProviderStrategyConfig(rName, 10, 1, false), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), ), @@ -161,7 +161,75 @@ func TestAccECSService_withCapacityProviderStrategy(t *testing.T) { }) } -func TestAccECSService_withMultipleCapacityProviderStrategies(t *testing.T) { +func TestAccECSService_CapacityProviderStrategy_forceNewDeployment(t *testing.T) { + var service1, service2 ecs.Service + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_ecs_service.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ecs.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccServiceCapacityProviderStrategyConfig(rName, 1, 0, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(resourceName, &service1), + ), + }, + { + Config: testAccServiceCapacityProviderStrategyConfig(rName, 10, 1, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(resourceName, &service2), + testAccCheckServiceNotRecreated(&service1, &service2), + ), + }, + }, + }) +} + +func TestAccECSService_CapacityProviderStrategy_update(t *testing.T) { + var service1, service2 ecs.Service + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_ecs_service.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ecs.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccServiceUpdateCapacityProviderStrategyRemoveConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(resourceName, &service1), + ), + }, + { + Config: testAccServiceUpdateCapacityProviderStrategyConfig(rName, 1, "FARGATE"), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(resourceName, &service2), + ), + }, + { + Config: testAccServiceUpdateCapacityProviderStrategyConfig(rName, 1, "FARGATE_SPOT"), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(resourceName, &service1), + testAccCheckServiceNotRecreated(&service1, &service2), + ), + }, + { + Config: testAccServiceUpdateCapacityProviderStrategyRemoveConfig(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckServiceExists(resourceName, &service1), + ), + }, + }, + }) +} + +func TestAccECSService_CapacityProviderStrategy_multiple(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -173,7 +241,7 @@ func TestAccECSService_withMultipleCapacityProviderStrategies(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithMultipleCapacityProviderStrategies(rName), + Config: testAccServiceMultipleCapacityProviderStrategiesConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "capacity_provider_strategy.#", "2"), @@ -183,7 +251,7 @@ func TestAccECSService_withMultipleCapacityProviderStrategies(t *testing.T) { }) } -func TestAccECSService_withFamilyAndRevision(t *testing.T) { +func TestAccECSService_familyAndRevision(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -195,14 +263,14 @@ func TestAccECSService_withFamilyAndRevision(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithFamilyAndRevision(rName), + Config: testAccServiceFamilyAndRevisionConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), ), }, { - Config: testAccServiceWithFamilyAndRevisionModified(rName), + Config: testAccServiceFamilyAndRevisionModifiedConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), ), @@ -212,7 +280,7 @@ func TestAccECSService_withFamilyAndRevision(t *testing.T) { } // Regression for https://github.com/hashicorp/terraform/issues/2427 -func TestAccECSService_withRenamedCluster(t *testing.T) { +func TestAccECSService_renamedCluster(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -224,7 +292,7 @@ func TestAccECSService_withRenamedCluster(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithRenamedCluster(rName), + Config: testAccServiceRenamedClusterConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttrPair(resourceName, "cluster", "aws_ecs_cluster.default", "arn"), @@ -232,7 +300,7 @@ func TestAccECSService_withRenamedCluster(t *testing.T) { }, { - Config: testAccServiceWithRenamedCluster(rName), + Config: testAccServiceRenamedClusterConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttrPair(resourceName, "cluster", "aws_ecs_cluster.default", "arn"), @@ -254,29 +322,29 @@ func TestAccECSService_healthCheckGracePeriodSeconds(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccService_healthCheckGracePeriodSeconds(rName, -1), + Config: testAccServiceHealthCheckGracePeriodSecondsConfig(rName, -1), ExpectError: regexp.MustCompile(`expected health_check_grace_period_seconds to be in the range`), }, { - Config: testAccService_healthCheckGracePeriodSeconds(rName, math.MaxInt32+1), + Config: testAccServiceHealthCheckGracePeriodSecondsConfig(rName, math.MaxInt32+1), ExpectError: regexp.MustCompile(`expected health_check_grace_period_seconds to be in the range`), }, { - Config: testAccService_healthCheckGracePeriodSeconds(rName, 300), + Config: testAccServiceHealthCheckGracePeriodSecondsConfig(rName, 300), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "health_check_grace_period_seconds", "300"), ), }, { - Config: testAccService_healthCheckGracePeriodSeconds(rName, 600), + Config: testAccServiceHealthCheckGracePeriodSecondsConfig(rName, 600), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "health_check_grace_period_seconds", "600"), ), }, { - Config: testAccService_healthCheckGracePeriodSeconds(rName, math.MaxInt32), + Config: testAccServiceHealthCheckGracePeriodSecondsConfig(rName, math.MaxInt32), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "health_check_grace_period_seconds", "2147483647"), @@ -286,7 +354,7 @@ func TestAccECSService_healthCheckGracePeriodSeconds(t *testing.T) { }) } -func TestAccECSService_withIAMRole(t *testing.T) { +func TestAccECSService_iamRole(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -298,7 +366,7 @@ func TestAccECSService_withIAMRole(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccService_withIAMRole(rName), + Config: testAccServiceIAMRoleConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), ), @@ -307,7 +375,7 @@ func TestAccECSService_withIAMRole(t *testing.T) { }) } -func TestAccECSService_WithDeploymentControllerType_codeDeploy(t *testing.T) { +func TestAccECSService_DeploymentControllerType_codeDeploy(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -339,7 +407,7 @@ func TestAccECSService_WithDeploymentControllerType_codeDeploy(t *testing.T) { }) } -func TestAccECSService_WithDeploymentControllerType_external(t *testing.T) { +func TestAccECSService_DeploymentControllerType_external(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -370,7 +438,7 @@ func TestAccECSService_WithDeploymentControllerType_external(t *testing.T) { }) } -func TestAccECSService_withDeploymentValues(t *testing.T) { +func TestAccECSService_DeploymentValues_basic(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -382,7 +450,7 @@ func TestAccECSService_withDeploymentValues(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithDeploymentValues(rName), + Config: testAccServiceDeploymentValuesConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "deployment_maximum_percent", "200"), @@ -394,7 +462,7 @@ func TestAccECSService_withDeploymentValues(t *testing.T) { } // Regression for https://github.com/hashicorp/terraform-provider-aws/issues/6315 -func TestAccECSService_withDeploymentMinimumZeroMaximumOneHundred(t *testing.T) { +func TestAccECSService_DeploymentValues_minZeroMaxOneHundred(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -417,7 +485,7 @@ func TestAccECSService_withDeploymentMinimumZeroMaximumOneHundred(t *testing.T) }) } -func TestAccECSService_withDeploymentCircuitBreaker(t *testing.T) { +func TestAccECSService_deploymentCircuitBreaker(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -442,7 +510,7 @@ func TestAccECSService_withDeploymentCircuitBreaker(t *testing.T) { } // Regression for https://github.com/hashicorp/terraform/issues/3444 -func TestAccECSService_withLbChanges(t *testing.T) { +func TestAccECSService_loadBalancerChanges(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -454,13 +522,13 @@ func TestAccECSService_withLbChanges(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccService_withLbChanges(rName), + Config: testAccServiceLBChangesConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), ), }, { - Config: testAccService_withLbChanges_modified(rName), + Config: testAccServiceLBChangesModifiedConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), ), @@ -470,7 +538,7 @@ func TestAccECSService_withLbChanges(t *testing.T) { } // Regression for https://github.com/hashicorp/terraform/issues/3361 -func TestAccECSService_withECSClusterName(t *testing.T) { +func TestAccECSService_clusterName(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -482,7 +550,7 @@ func TestAccECSService_withECSClusterName(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithEcsClusterName(rName), + Config: testAccServiceClusterNameConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "cluster", rName), @@ -492,7 +560,7 @@ func TestAccECSService_withECSClusterName(t *testing.T) { }) } -func TestAccECSService_withAlb(t *testing.T) { +func TestAccECSService_alb(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -504,7 +572,7 @@ func TestAccECSService_withAlb(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithAlb(rName), + Config: testAccServiceALBConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "load_balancer.#", "1"), @@ -514,7 +582,7 @@ func TestAccECSService_withAlb(t *testing.T) { }) } -func TestAccECSService_withMultipleTargetGroups(t *testing.T) { +func TestAccECSService_multipleTargetGroups(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -526,7 +594,7 @@ func TestAccECSService_withMultipleTargetGroups(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithMultipleTargetGroups(rName), + Config: testAccServiceMultipleTargetGroupsConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "load_balancer.#", "2"), @@ -536,7 +604,7 @@ func TestAccECSService_withMultipleTargetGroups(t *testing.T) { }) } -func TestAccECSService_withForceNewDeployment(t *testing.T) { +func TestAccECSService_forceNewDeployment(t *testing.T) { var service1, service2 ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -548,14 +616,14 @@ func TestAccECSService_withForceNewDeployment(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccService(rName), + Config: testAccServiceConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service1), resource.TestCheckResourceAttr(resourceName, "ordered_placement_strategy.#", "0"), ), }, { - Config: testAccServiceWithForceNewDeployment(rName), + Config: testAccServiceForceNewDeploymentConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service2), testAccCheckServiceNotRecreated(&service1, &service2), @@ -568,7 +636,7 @@ func TestAccECSService_withForceNewDeployment(t *testing.T) { }) } -func TestAccECSService_withPlacementStrategy(t *testing.T) { +func TestAccECSService_PlacementStrategy_basic(t *testing.T) { var service1, service2, service3, service4 ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -580,14 +648,14 @@ func TestAccECSService_withPlacementStrategy(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccService(rName), + Config: testAccServiceConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service1), resource.TestCheckResourceAttr(resourceName, "ordered_placement_strategy.#", "0"), ), }, { - Config: testAccServiceWithPlacementStrategy(rName), + Config: testAccServicePlacementStrategyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service2), testAccCheckServiceNotRecreated(&service1, &service2), @@ -597,7 +665,7 @@ func TestAccECSService_withPlacementStrategy(t *testing.T) { ), }, { - Config: testAccServiceWithRandomPlacementStrategy(rName), + Config: testAccServiceRandomPlacementStrategyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service3), testAccCheckServiceNotRecreated(&service2, &service3), @@ -607,7 +675,7 @@ func TestAccECSService_withPlacementStrategy(t *testing.T) { ), }, { - Config: testAccServiceWithMultiplacementStrategy(rName), + Config: testAccServiceMultiplacementStrategyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service4), testAccCheckServiceNotRecreated(&service3, &service4), @@ -623,7 +691,7 @@ func TestAccECSService_withPlacementStrategy(t *testing.T) { } // Reference: https://github.com/hashicorp/terraform-provider-aws/issues/13146 -func TestAccECSService_WithPlacementStrategyType_missing(t *testing.T) { +func TestAccECSService_PlacementStrategy_missing(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resource.ParallelTest(t, resource.TestCase{ @@ -633,14 +701,14 @@ func TestAccECSService_WithPlacementStrategyType_missing(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithPlacementStrategyType(rName, ""), + Config: testAccServicePlacementStrategyTypeConfig(rName, ""), ExpectError: regexp.MustCompile(`expected ordered_placement_strategy.0.type to be one of`), }, }, }) } -func TestAccECSService_withPlacementConstraints(t *testing.T) { +func TestAccECSService_PlacementConstraints_basic(t *testing.T) { var service1, service2 ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -652,14 +720,14 @@ func TestAccECSService_withPlacementConstraints(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithPlacementConstraint(rName), + Config: testAccServicePlacementConstraintConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service1), resource.TestCheckResourceAttr(resourceName, "placement_constraints.#", "1"), ), }, { - Config: testAccServiceWithPlacementConstraintEmptyExpression(rName), + Config: testAccServicePlacementConstraintEmptyExpressionConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service2), testAccCheckServiceNotRecreated(&service1, &service2), @@ -670,7 +738,7 @@ func TestAccECSService_withPlacementConstraints(t *testing.T) { }) } -func TestAccECSService_WithPlacementConstraints_emptyExpression(t *testing.T) { +func TestAccECSService_PlacementConstraints_emptyExpression(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -682,7 +750,7 @@ func TestAccECSService_WithPlacementConstraints_emptyExpression(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithPlacementConstraintEmptyExpression(rName), + Config: testAccServicePlacementConstraintEmptyExpressionConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "placement_constraints.#", "1"), @@ -692,7 +760,7 @@ func TestAccECSService_WithPlacementConstraints_emptyExpression(t *testing.T) { }) } -func TestAccECSService_withLaunchTypeFargate(t *testing.T) { +func TestAccECSService_LaunchTypeFargate_basic(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -704,7 +772,7 @@ func TestAccECSService_withLaunchTypeFargate(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithLaunchTypeFargate(rName, false), + Config: testAccServiceLaunchTypeFargateConfig(rName, false), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "launch_type", "FARGATE"), @@ -715,14 +783,14 @@ func TestAccECSService_withLaunchTypeFargate(t *testing.T) { ), }, { - Config: testAccServiceWithLaunchTypeFargate(rName, true), + Config: testAccServiceLaunchTypeFargateConfig(rName, true), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "network_configuration.0.assign_public_ip", "true"), ), }, { - Config: testAccServiceWithLaunchTypeFargate(rName, false), + Config: testAccServiceLaunchTypeFargateConfig(rName, false), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "network_configuration.0.assign_public_ip", "false"), @@ -732,7 +800,7 @@ func TestAccECSService_withLaunchTypeFargate(t *testing.T) { }) } -func TestAccECSService_withLaunchTypeFargateAndPlatformVersion(t *testing.T) { +func TestAccECSService_LaunchTypeFargate_platformVersion(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -744,21 +812,21 @@ func TestAccECSService_withLaunchTypeFargateAndPlatformVersion(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithLaunchTypeFargateAndPlatformVersion(rName, "1.3.0"), + Config: testAccServiceLaunchTypeFargateAndPlatformVersionConfig(rName, "1.3.0"), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "platform_version", "1.3.0"), ), }, { - Config: testAccServiceWithLaunchTypeFargateAndPlatformVersion(rName, "LATEST"), + Config: testAccServiceLaunchTypeFargateAndPlatformVersionConfig(rName, "LATEST"), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "platform_version", "LATEST"), ), }, { - Config: testAccServiceWithLaunchTypeFargateAndPlatformVersion(rName, "1.4.0"), + Config: testAccServiceLaunchTypeFargateAndPlatformVersionConfig(rName, "1.4.0"), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "platform_version", "1.4.0"), @@ -768,7 +836,7 @@ func TestAccECSService_withLaunchTypeFargateAndPlatformVersion(t *testing.T) { }) } -func TestAccECSService_withLaunchTypeFargateAndWaitForSteadyState(t *testing.T) { +func TestAccECSService_LaunchTypeFargate_waitForSteadyState(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -781,7 +849,7 @@ func TestAccECSService_withLaunchTypeFargateAndWaitForSteadyState(t *testing.T) Steps: []resource.TestStep{ { // Wait for the ECS Cluster to reach a steady state w/specified count - Config: testAccServiceWithLaunchTypeFargateAndWait(rName, 1, true), + Config: testAccServiceLaunchTypeFargateAndWaitConfig(rName, 1, true), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "desired_count", "1"), @@ -801,7 +869,7 @@ func TestAccECSService_withLaunchTypeFargateAndWaitForSteadyState(t *testing.T) }) } -func TestAccECSService_withLaunchTypeFargateAndUpdateWaitForSteadyState(t *testing.T) { +func TestAccECSService_LaunchTypeFargate_updateWaitForSteadyState(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -813,7 +881,7 @@ func TestAccECSService_withLaunchTypeFargateAndUpdateWaitForSteadyState(t *testi CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithLaunchTypeFargateWithoutWait(rName), + Config: testAccServiceLaunchTypeFargateNoWaitConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "desired_count", "1"), @@ -822,7 +890,7 @@ func TestAccECSService_withLaunchTypeFargateAndUpdateWaitForSteadyState(t *testi }, { // Modify desired count and wait for the ECS Cluster to reach steady state - Config: testAccServiceWithLaunchTypeFargateAndWait(rName, 2, true), + Config: testAccServiceLaunchTypeFargateAndWaitConfig(rName, 2, true), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "desired_count", "2"), @@ -831,7 +899,7 @@ func TestAccECSService_withLaunchTypeFargateAndUpdateWaitForSteadyState(t *testi }, { // Modify desired count without wait - Config: testAccServiceWithLaunchTypeFargateAndWait(rName, 1, false), + Config: testAccServiceLaunchTypeFargateAndWaitConfig(rName, 1, false), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "desired_count", "1"), @@ -842,7 +910,7 @@ func TestAccECSService_withLaunchTypeFargateAndUpdateWaitForSteadyState(t *testi }) } -func TestAccECSService_withLaunchTypeEC2AndNetwork(t *testing.T) { +func TestAccECSService_LaunchTypeEC2_network(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -854,7 +922,7 @@ func TestAccECSService_withLaunchTypeEC2AndNetwork(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithNetworkConfiguration(rName), + Config: testAccServiceNetworkConfigurationConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "network_configuration.0.assign_public_ip", "false"), @@ -863,7 +931,7 @@ func TestAccECSService_withLaunchTypeEC2AndNetwork(t *testing.T) { ), }, { - Config: testAccServiceWithNetworkConfiguration_modified(rName), + Config: testAccServiceNetworkConfigurationModifiedConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "network_configuration.0.assign_public_ip", "false"), @@ -875,7 +943,7 @@ func TestAccECSService_withLaunchTypeEC2AndNetwork(t *testing.T) { }) } -func TestAccECSService_withDaemonSchedulingStrategy(t *testing.T) { +func TestAccECSService_DaemonSchedulingStrategy_basic(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -887,7 +955,7 @@ func TestAccECSService_withDaemonSchedulingStrategy(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithDaemonSchedulingStrategy(rName), + Config: testAccServiceDaemonSchedulingStrategyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "scheduling_strategy", "DAEMON"), @@ -897,7 +965,7 @@ func TestAccECSService_withDaemonSchedulingStrategy(t *testing.T) { }) } -func TestAccECSService_withDaemonSchedulingStrategySetDeploymentMinimum(t *testing.T) { +func TestAccECSService_DaemonSchedulingStrategy_setDeploymentMinimum(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -909,7 +977,7 @@ func TestAccECSService_withDaemonSchedulingStrategySetDeploymentMinimum(t *testi CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithDaemonSchedulingStrategySetDeploymentMinimum(rName), + Config: testAccServiceDaemonSchedulingStrategySetDeploymentMinimumConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "scheduling_strategy", "DAEMON"), @@ -919,7 +987,7 @@ func TestAccECSService_withDaemonSchedulingStrategySetDeploymentMinimum(t *testi }) } -func TestAccECSService_withReplicaSchedulingStrategy(t *testing.T) { +func TestAccECSService_replicaSchedulingStrategy(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -931,7 +999,7 @@ func TestAccECSService_withReplicaSchedulingStrategy(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccServiceWithReplicaSchedulingStrategy(rName), + Config: testAccServiceReplicaSchedulingStrategyConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "scheduling_strategy", "REPLICA"), @@ -941,7 +1009,7 @@ func TestAccECSService_withReplicaSchedulingStrategy(t *testing.T) { }) } -func TestAccECSService_withServiceRegistries(t *testing.T) { +func TestAccECSService_ServiceRegistries_basic(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -953,7 +1021,7 @@ func TestAccECSService_withServiceRegistries(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccService_withServiceRegistries(rName), + Config: testAccServiceServiceRegistriesConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "service_registries.#", "1"), @@ -963,7 +1031,7 @@ func TestAccECSService_withServiceRegistries(t *testing.T) { }) } -func TestAccECSService_WithServiceRegistries_container(t *testing.T) { +func TestAccECSService_ServiceRegistries_container(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -975,7 +1043,7 @@ func TestAccECSService_WithServiceRegistries_container(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccService_withServiceRegistries_container(rName), + Config: testAccServiceServiceRegistriesContainerConfig(rName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "service_registries.#", "1"), @@ -985,7 +1053,7 @@ func TestAccECSService_WithServiceRegistries_container(t *testing.T) { }) } -func TestAccECSService_withServiceRegistriesChanges(t *testing.T) { +func TestAccECSService_ServiceRegistries_changes(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) serviceDiscoveryName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -999,14 +1067,14 @@ func TestAccECSService_withServiceRegistriesChanges(t *testing.T) { CheckDestroy: testAccCheckServiceDestroy, Steps: []resource.TestStep{ { - Config: testAccService_withServiceRegistriesChanges(rName, serviceDiscoveryName), + Config: testAccServiceServiceRegistriesChangesConfig(rName, serviceDiscoveryName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "service_registries.#", "1"), ), }, { - Config: testAccService_withServiceRegistriesChanges(rName, updatedServiceDiscoveryName), + Config: testAccServiceServiceRegistriesChangesConfig(rName, updatedServiceDiscoveryName), Check: resource.ComposeTestCheckFunc( testAccCheckServiceExists(resourceName, &service), resource.TestCheckResourceAttr(resourceName, "service_registries.#", "1"), @@ -1016,7 +1084,7 @@ func TestAccECSService_withServiceRegistriesChanges(t *testing.T) { }) } -func TestAccECSService_tags(t *testing.T) { +func TestAccECSService_Tags_basic(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -1065,7 +1133,7 @@ func TestAccECSService_tags(t *testing.T) { }) } -func TestAccECSService_managedTags(t *testing.T) { +func TestAccECSService_Tags_managed(t *testing.T) { var service ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -1088,7 +1156,7 @@ func TestAccECSService_managedTags(t *testing.T) { }) } -func TestAccECSService_propagateTags(t *testing.T) { +func TestAccECSService_Tags_propagate(t *testing.T) { var first, second, third ecs.Service rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_ecs_service.test" @@ -1245,7 +1313,7 @@ func testAccCheckServiceNotRecreated(i, j *ecs.Service) resource.TestCheckFunc { } } -func testAccService(rName string) string { +func testAccServiceConfig(rName string) string { return fmt.Sprintf(` resource "aws_ecs_cluster" "default" { name = %[1]q @@ -1276,7 +1344,7 @@ resource "aws_ecs_service" "test" { `, rName) } -func testAccServiceModified(rName string) string { +func testAccServiceModifiedConfig(rName string) string { return fmt.Sprintf(` resource "aws_ecs_cluster" "default" { name = %[1]q @@ -1307,7 +1375,7 @@ resource "aws_ecs_service" "test" { `, rName) } -func testAccServiceWithLaunchTypeFargateWithoutWait(rName string) string { +func testAccServiceLaunchTypeFargateNoWaitConfig(rName string) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" @@ -1420,7 +1488,7 @@ resource "aws_ecs_service" "test" { `, rName) } -func testAccServiceWithLaunchTypeFargateAndWait(rName string, desiredCount int, waitForSteadyState bool) string { +func testAccServiceLaunchTypeFargateAndWaitConfig(rName string, desiredCount int, waitForSteadyState bool) string { return fmt.Sprintf(` data "aws_availability_zones" "available" { state = "available" @@ -1536,7 +1604,7 @@ resource "aws_ecs_service" "test" { `, rName, desiredCount, waitForSteadyState) } -func testAccServiceWithInterchangeablePlacementStrategy(rName string) string { +func testAccServiceInterchangeablePlacementStrategyConfig(rName string) string { return fmt.Sprintf(` resource "aws_ecs_cluster" "default" { name = %[1]q @@ -1572,7 +1640,7 @@ resource "aws_ecs_service" "test" { `, rName) } -func testAccServiceWithCapacityProviderStrategy(rName string, weight, base int) string { +func testAccServiceCapacityProviderStrategyConfig(rName string, weight, base int, forceNewDeployment bool) string { return acctest.ConfigCompose(testAccCapacityProviderBaseConfig(rName), fmt.Sprintf(` resource "aws_ecs_capacity_provider" "test" { name = %[1]q @@ -1603,10 +1671,11 @@ DEFINITION } resource "aws_ecs_service" "test" { - name = %[1]q - cluster = aws_ecs_cluster.default.id - task_definition = aws_ecs_task_definition.test.arn - desired_count = 1 + name = %[1]q + cluster = aws_ecs_cluster.default.id + task_definition = aws_ecs_task_definition.test.arn + desired_count = 1 + force_new_deployment = %[4]t capacity_provider_strategy { capacity_provider = aws_ecs_capacity_provider.test.name @@ -1614,10 +1683,124 @@ resource "aws_ecs_service" "test" { base = %[3]d } } -`, rName, weight, base)) +`, rName, weight, base, forceNewDeployment)) +} + +func testAccServiceUpdateCapacityProviderStrategyConfig(rName string, weight int, capacityProvider string) string { + return acctest.ConfigCompose( + testAccCapacityProviderBaseConfig(rName), + fmt.Sprintf(` +resource "aws_ecs_cluster" "default" { + name = %[1]q +} + +resource "aws_ecs_task_definition" "test" { + family = %[1]q + network_mode = "awsvpc" + requires_compatibilities = ["FARGATE"] + cpu = "256" + memory = "512" + + container_definitions = <