Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ecs scheduling strategy #4825

Merged
merged 5 commits into from
Jun 26, 2018
Merged

Conversation

erks
Copy link
Contributor

@erks erks commented Jun 13, 2018

Fixes #4820
Depends on #4823

Changes proposed in this pull request:

Output from acceptance testing: Handled via daily acceptance testing

@ghost ghost added size/XXL Managed by automation to categorize the size of a PR. dependencies Used to indicate dependency changes. labels Jun 13, 2018
@@ -321,6 +328,15 @@ func resourceAwsEcsServiceCreate(d *schema.ResourceData, meta interface{}) error
input.LaunchType = aws.String(v.(string))
}

if v, ok := d.GetOk("scheduling_strategy"); ok {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should deploymentConfiguration be taken into account too?

If deploymentConfiguration is specified, the maximum percent parameter must be 100. The default value for a daemon service for maximumPercent is 100%. The default value for a daemon service for minimumHealthyPercent is 0% for the AWS CLI, the AWS SDKs, and the APIs, and 50% for the AWS Management Console.

https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs_services.html#service_scheduler_daemon

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about that too, but I'm not sure what the general handlings of this are in other places. I'm obviously relying on AWS doing the validation and returning the error for this. But if the best practice here is to do the validation on the terraform side, I can add it. Let me know.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scheduling_strategy attribute is always going to exist since it has a Default -- you can use input.SchedulingStrategy = d.Get("scheduling_strategy").(string) instead of working with d.GetOk() or add it to the CreateEcsService struct directly with the same d.Get()

@bflad
Copy link
Contributor

bflad commented Jun 13, 2018

#4823 has been merged so this is good for rebasing 👍

@bflad bflad added enhancement Requests to existing resources that expand the functionality or scope. service/ecs Issues and PRs that pertain to the ecs service. labels Jun 13, 2018
@ghost ghost added size/L Managed by automation to categorize the size of a PR. and removed size/XXL Managed by automation to categorize the size of a PR. dependencies Used to indicate dependency changes. labels Jun 13, 2018
@erks
Copy link
Contributor Author

erks commented Jun 13, 2018

@bflad do you have any pointer here on how best I can ignore desired_count on create/update/read/etc when scheduling_strategy is DAEMON? Also, should we validate deploymentConfiguration according to https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs_services.html#service_scheduler_daemon ?

@ghost ghost added the size/L Managed by automation to categorize the size of a PR. label Jun 13, 2018
@@ -17,6 +17,8 @@ import (
"github.com/hashicorp/terraform/helper/validation"
)

const schedulingStrategyDaemon = "DAEMON"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should just be able to use ecs.SchedulingStrategyDaemon (and its equivalent ecs.SchedulingStrategyReplica) here instead.

%s
}
`, clusterName, tdName, svcName, schedulingStrategySnippet, desiredCountSnippet)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I waver on this a bit and am personally a little inconsistent but I think I prefer having a bit of repetition in the test config code rather than more complicated dynamic config, particularly when it involves something as slightly convoluted as this.

More of a thought/comment than a critique but I think I find the tests a nice form of documentation about how to use things/how things work but this is a bit harder to follow here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll change it, as it seems other existing functions are also favoring repetition here.

* `launch_type` - (Optional) The launch type on which to run your service. The valid values are `EC2` and `FARGATE`. Defaults to `EC2`.
* `scheduling_strategry` - (Optional) The scheduling strategy to use for the service. The valid values are `REPLICA` and `DAEMON`. Defaults to `REPLICA`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: scheduling_strategry -> scheduling_strategy

Optional: true,
ForceNew: true,
Default: "REPLICA",
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't done consistently but I find https://github.com/terraform-providers/terraform-provider-aws/blob/41a726c851769570036f30cd83ffc2b68a47c8dd/aws/resource_aws_lb_listener.go#L50-L52 is a nice convenience for users.

Not sure if it's worth validating this so we can generate failures at plan time because it comes with the trade off that if AWS adds another scheduling strategy we need a code change and release to support it.

Copy link
Contributor Author

@erks erks Jun 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add the the StateFunc. Thanks for the advice @tomelliff .

Regarding the validation, that's also why I'm a bit hesitant about adding. I think it might come down to consistency, i.e. whether this provider performs validations like this somewhere else.

@ghost ghost added the size/L Managed by automation to categorize the size of a PR. label Jun 14, 2018
@erks
Copy link
Contributor Author

erks commented Jun 18, 2018

@bflad any input on the validation question(s) above? or any overall feedback. happy to address them, if any, so we can move forward.

@tomelliff
Copy link
Contributor

tomelliff commented Jun 19, 2018

I wouldn't bother validating the deployment configuration. You can't test for it at plan time and the AWS API should return a suitable error that explains what's wrong if it fails.

That said, if for some reason the AWS API error message isn't clear (some of them can be a bit opaque) then it might be worth throwing an error or testing for the error code and providing a different error message.

Copy link
Contributor

@bflad bflad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @erks and @tomelliff -- I left some initial feedback/questions below. Please let us know if you have any questions or do not have time to implement the feedback.

* `launch_type` - (Optional) The launch type on which to run your service. The valid values are `EC2` and `FARGATE`. Defaults to `EC2`.
* `scheduling_strategy` - (Optional) The scheduling strategy to use for the service. The valid values are `REPLICA` and `DAEMON`. Defaults to `REPLICA`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add this note from the API documentation: Fargate tasks do not support the DAEMON scheduling strategy.

Config: testAccAWSEcsServiceWithDefaultSchedulingStrategy(clusterName, tdName, svcName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSEcsServiceExists("aws_ecs_service.ghost", &service),
resource.TestCheckResourceAttr("aws_ecs_service.ghost", "scheduling_strategy", "REPLICA"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of a whole new acceptance test and test config for the default value, you can just add this attribute check to the _basic test 👍

Copy link
Contributor Author

@erks erks Jun 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean _basicImport? I can't find the _basic test here. Although _basicImport doesn't seem to be the right place.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry, this resource's testing could use some standardization with everything else. The "basic" test is currently TestAccAWSEcsService_withARN (you'll notice the seemingly odd check for service_registries.# in there - it should really have all the resource attribute default checks).

Optional: true,
ForceNew: true,
Default: ecs.SchedulingStrategyReplica,
StateFunc: func(v interface{}) string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using StateFunc, we should instead prefer to validate the input value with case sensitivity using the below ValidateFunc:

ValidateFunc: validation.StringInSlice([]string{
  ecs.SchedulingStrategyDaemon,
  ecs.SchedulingStrategyReplica,
}, false),

@@ -489,7 +508,11 @@ func resourceAwsEcsServiceRead(d *schema.ResourceData, meta interface{}) error {
d.Set("task_definition", taskDefinition)
}

d.Set("desired_count", service.DesiredCount)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What value for service.DesiredCount gets returned when in DAEMON mode? Is it 0 or the number of container instances? We should generally try to call d.Set() if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my testing, it's the number of container instances, which can change periodically.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding the following DiffSuppressFunc to the desired_count, deployment_minimum_percent, and deployment_maximum_percent attributes, we can continue to always call d.Set("desired_count", service.DesiredCount) (along with the others) and remove the conditional in the read function. This will remove the breaking change for outputs that depend on the desired_count attribute always existing.

DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
	if d.Get("scheduling_strategy").(string) == ecs.SchedulingStrategyDaemon {
		return true
	}
	return false
},

@@ -709,7 +732,9 @@ func resourceAwsEcsServiceUpdate(d *schema.ResourceData, meta interface{}) error
Cluster: aws.String(d.Get("cluster").(string)),
}

if d.HasChange("desired_count") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the DesiredCount returning from the API is nil or 0 when in DAEMON mode, we should be able to leave the old logic here. 👍

Copy link
Contributor Author

@erks erks Jun 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my testing, it's the number of container instances.

@@ -321,6 +328,15 @@ func resourceAwsEcsServiceCreate(d *schema.ResourceData, meta interface{}) error
input.LaunchType = aws.String(v.(string))
}

if v, ok := d.GetOk("scheduling_strategy"); ok {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scheduling_strategy attribute is always going to exist since it has a Default -- you can use input.SchedulingStrategy = d.Get("scheduling_strategy").(string) instead of working with d.GetOk() or add it to the CreateEcsService struct directly with the same d.Get()

@bflad bflad added the waiting-response Maintainers are waiting on response from community or contributor. label Jun 19, 2018
@ghost ghost added the size/L Managed by automation to categorize the size of a PR. label Jun 19, 2018
@bflad bflad removed the waiting-response Maintainers are waiting on response from community or contributor. label Jun 21, 2018
]
DEFINITION
}
resource "aws_ecs_service" "ghost" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test resource needs to reduce the deployment_maximum_percent from the default of 200:

=== RUN   TestAccAWSEcsService_withDaemonSchedulingStrategy
--- FAIL: TestAccAWSEcsService_withDaemonSchedulingStrategy (5.71s)
    testing.go:518: Step 0 error: Error applying: 1 error(s) occurred:
        
        * aws_ecs_service.ghost: 1 error(s) occurred:
        
        * aws_ecs_service.ghost: InvalidParameterException: The daemon scheduling strategy does not support values above 100 for maximumPercent on a deployment configuration. Change the maximumPercent value to 100, and try again

e.g. deployment_maximum_percent = 100

It might also be worth noting this in the attribute documentation and/or adding a daemon example to the documentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done and added the doc/example.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This acceptance test is still failing:

=== RUN   TestAccAWSEcsService_withDaemonSchedulingStrategy
--- FAIL: TestAccAWSEcsService_withDaemonSchedulingStrategy (5.99s)
    testing.go:518: Step 0 error: Error applying: 1 error(s) occurred:
        
        * aws_ecs_service.ghost: 1 error(s) occurred:
        
        * aws_ecs_service.ghost: InvalidParameterException: Both maximumPercent and minimumHealthyPercent cannot be 100 as this will block deployments.
            status code: 400, request id: d5daf50b-7949-11e8-a362-3ff63025fa34 "tf-acc-svc-w-ss-daemon-8yeejuf7"

By changing the create function to never include DeploymentConfiguration when set in DAEMON scheduling strategy, it then received this error during acceptance testing:

=== RUN   TestAccAWSEcsService_withDaemonSchedulingStrategy
--- FAIL: TestAccAWSEcsService_withDaemonSchedulingStrategy (12.56s)
	testing.go:579: Error destroying resource! WARNING: Dangling resources
		may exist. The full state and error is shown below.

		Error: Error applying: 1 error(s) occurred:

		* aws_ecs_service.ghost (destroy): 1 error(s) occurred:

		* aws_ecs_service.ghost: InvalidParameterException: The daemon scheduling strategy does not support a desired count for services. Remove the desired count value and try again
			status code: 400, request id: d91107b6-794b-11e8-b194-535f28f11fde

The deletion function tries to drain any ACTIVE status services by setting their DesiredCount to 0 before deletion. Ignoring DAEMON scheduling strategy for that call, the testing passes as expected:

make testacc TEST=./aws TESTARGS='-run=TestAccAWSEcsService_withDaemonSchedulingStrategy'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./aws -v -run=TestAccAWSEcsService_withDaemonSchedulingStrategy -timeout 120m
=== RUN   TestAccAWSEcsService_withDaemonSchedulingStrategy
--- PASS: TestAccAWSEcsService_withDaemonSchedulingStrategy (15.51s)
PASS
ok  	github.com/terraform-providers/terraform-provider-aws/aws	15.549s

@ghost ghost added the size/L Managed by automation to categorize the size of a PR. label Jun 21, 2018
@TheSimpleZ
Copy link

Hi! What is the status on this PR? Is it going to be merged anytime soon or should i find a workaround for setting up daemons in aws?

@bflad bflad added this to the v1.25.0 milestone Jun 26, 2018
@bflad
Copy link
Contributor

bflad commented Jun 26, 2018

We should be able to get this released tomorrow, more shortly.

Copy link
Contributor

@bflad bflad left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks so much for your work here @erks! This was most of the way there but it turns out needed some additional work to properly support the full Terraform resource lifecycle as found via the acceptance testing while also continuing to support desired_count in outputs. To get this functionality moved ahead, I added an additional commit after yours to finish up the working implementation: aca44f4

Additional comments provided for context. 🚀

21 tests passed (all tests)
=== RUN   TestAccAWSEcsServiceDataSource_basic
--- PASS: TestAccAWSEcsServiceDataSource_basic (12.26s)
=== RUN   TestAccAWSEcsService_basicImport
--- PASS: TestAccAWSEcsService_basicImport (12.67s)
=== RUN   TestAccAWSEcsService_withARN
--- PASS: TestAccAWSEcsService_withARN (13.32s)
=== RUN   TestAccAWSEcsService_withPlacementConstraints_emptyExpression
--- PASS: TestAccAWSEcsService_withPlacementConstraints_emptyExpression (15.50s)
=== RUN   TestAccAWSEcsService_withPlacementConstraints
--- PASS: TestAccAWSEcsService_withPlacementConstraints (15.61s)
=== RUN   TestAccAWSEcsService_withReplicaSchedulingStrategy
--- PASS: TestAccAWSEcsService_withReplicaSchedulingStrategy (15.63s)
=== RUN   TestAccAWSEcsService_withServiceRegistries
--- PASS: TestAccAWSEcsService_withServiceRegistries (21.71s)
=== RUN   TestAccAWSEcsService_withIamRole
--- PASS: TestAccAWSEcsService_withIamRole (31.14s)
=== RUN   TestAccAWSEcsService_withDaemonSchedulingStrategy
--- PASS: TestAccAWSEcsService_withDaemonSchedulingStrategy (33.46s)
=== RUN   TestAccAWSEcsService_withUnnormalizedPlacementStrategy
--- PASS: TestAccAWSEcsService_withUnnormalizedPlacementStrategy (33.62s)
=== RUN   TestAccAWSEcsService_withDeploymentValues
--- PASS: TestAccAWSEcsService_withDeploymentValues (33.66s)
=== RUN   TestAccAWSEcsService_withRenamedCluster
--- PASS: TestAccAWSEcsService_withRenamedCluster (41.34s)
=== RUN   TestAccAWSEcsService_withEcsClusterName
--- PASS: TestAccAWSEcsService_withEcsClusterName (43.46s)
=== RUN   TestAccAWSEcsService_withFamilyAndRevision
--- PASS: TestAccAWSEcsService_withFamilyAndRevision (47.66s)
=== RUN   TestAccAWSEcsService_withServiceRegistries_container
--- PASS: TestAccAWSEcsService_withServiceRegistries_container (47.53s)
=== RUN   TestAccAWSEcsService_withLaunchTypeEC2AndNetworkConfiguration
--- PASS: TestAccAWSEcsService_withLaunchTypeEC2AndNetworkConfiguration (63.54s)
=== RUN   TestAccAWSEcsService_withPlacementStrategy
--- PASS: TestAccAWSEcsService_withPlacementStrategy (71.76s)
=== RUN   TestAccAWSEcsService_withLbChanges
--- PASS: TestAccAWSEcsService_withLbChanges (132.42s)
=== RUN   TestAccAWSEcsService_withAlb
--- PASS: TestAccAWSEcsService_withAlb (224.11s)
=== RUN   TestAccAWSEcsService_healthCheckGracePeriodSeconds
--- PASS: TestAccAWSEcsService_healthCheckGracePeriodSeconds (244.02s)
=== RUN   TestAccAWSEcsService_withLaunchTypeFargate
--- PASS: TestAccAWSEcsService_withLaunchTypeFargate (248.50s)

@@ -489,7 +508,11 @@ func resourceAwsEcsServiceRead(d *schema.ResourceData, meta interface{}) error {
d.Set("task_definition", taskDefinition)
}

d.Set("desired_count", service.DesiredCount)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding the following DiffSuppressFunc to the desired_count, deployment_minimum_percent, and deployment_maximum_percent attributes, we can continue to always call d.Set("desired_count", service.DesiredCount) (along with the others) and remove the conditional in the read function. This will remove the breaking change for outputs that depend on the desired_count attribute always existing.

DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
	if d.Get("scheduling_strategy").(string) == ecs.SchedulingStrategyDaemon {
		return true
	}
	return false
},

]
DEFINITION
}
resource "aws_ecs_service" "ghost" {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This acceptance test is still failing:

=== RUN   TestAccAWSEcsService_withDaemonSchedulingStrategy
--- FAIL: TestAccAWSEcsService_withDaemonSchedulingStrategy (5.99s)
    testing.go:518: Step 0 error: Error applying: 1 error(s) occurred:
        
        * aws_ecs_service.ghost: 1 error(s) occurred:
        
        * aws_ecs_service.ghost: InvalidParameterException: Both maximumPercent and minimumHealthyPercent cannot be 100 as this will block deployments.
            status code: 400, request id: d5daf50b-7949-11e8-a362-3ff63025fa34 "tf-acc-svc-w-ss-daemon-8yeejuf7"

By changing the create function to never include DeploymentConfiguration when set in DAEMON scheduling strategy, it then received this error during acceptance testing:

=== RUN   TestAccAWSEcsService_withDaemonSchedulingStrategy
--- FAIL: TestAccAWSEcsService_withDaemonSchedulingStrategy (12.56s)
	testing.go:579: Error destroying resource! WARNING: Dangling resources
		may exist. The full state and error is shown below.

		Error: Error applying: 1 error(s) occurred:

		* aws_ecs_service.ghost (destroy): 1 error(s) occurred:

		* aws_ecs_service.ghost: InvalidParameterException: The daemon scheduling strategy does not support a desired count for services. Remove the desired count value and try again
			status code: 400, request id: d91107b6-794b-11e8-b194-535f28f11fde

The deletion function tries to drain any ACTIVE status services by setting their DesiredCount to 0 before deletion. Ignoring DAEMON scheduling strategy for that call, the testing passes as expected:

make testacc TEST=./aws TESTARGS='-run=TestAccAWSEcsService_withDaemonSchedulingStrategy'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./aws -v -run=TestAccAWSEcsService_withDaemonSchedulingStrategy -timeout 120m
=== RUN   TestAccAWSEcsService_withDaemonSchedulingStrategy
--- PASS: TestAccAWSEcsService_withDaemonSchedulingStrategy (15.51s)
PASS
ok  	github.com/terraform-providers/terraform-provider-aws/aws	15.549s

cluster = "${aws_ecs_cluster.default.id}"
task_definition = "${aws_ecs_task_definition.ghost.family}:${aws_ecs_task_definition.ghost.revision}"
scheduling_strategy = "DAEMON"
deployment_maximum_percent = 100
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of requiring a special configuration for min/max, we'll setup the resource to properly ignore those configurations and differences 👍

@bflad bflad merged commit fdcbea6 into hashicorp:master Jun 26, 2018
bflad added a commit that referenced this pull request Jun 26, 2018
@erks erks deleted the ecs_scheduling_strategy branch June 26, 2018 16:35
@erks
Copy link
Contributor Author

erks commented Jun 26, 2018

thanks, @bflad

@bflad
Copy link
Contributor

bflad commented Jun 27, 2018

This has been released in version 1.25.0 of the AWS provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading.

@ghost
Copy link

ghost commented Apr 5, 2020

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thanks!

@ghost ghost locked and limited conversation to collaborators Apr 5, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement Requests to existing resources that expand the functionality or scope. service/ecs Issues and PRs that pertain to the ecs service. size/L Managed by automation to categorize the size of a PR.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for scheduling_strategy on aws_ecs_service
5 participants