Skip to content

Commit bf334a2

Browse files
lejiatiPatMyron
andauthored
Validate scheduling strategy for Fargate services (#2559)
* Validate scheduling strategy for Fargate services * Update test/fixtures/templates/good/resources/ecs/test_fargate_scheduling_strategy.yaml Co-authored-by: Pat Myron <[email protected]> * Fix Fargate strategy rule to handle non string properties Change: Intrinsic functions can be used for resource properties and previously this rule checker doesn't handle such scenario. --------- Co-authored-by: Pat Myron <[email protected]>
1 parent bf30a9b commit bf334a2

File tree

6 files changed

+95
-2
lines changed

6 files changed

+95
-2
lines changed

docs/rules.md

+1
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ The following **151** rules are applied by this linter:
132132
| [E3041<a name="E3041"></a>](../src/cfnlint/rules/resources/route53/RecordSetName.py) | RecordSet HostedZoneName is a superdomain of Name | In a RecordSet, the HostedZoneName must be a superdomain of the Name being validated | | [Source](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset.html#cfn-route53-recordset-name) | `resource`,`properties`,`route53` |
133133
| [E3042<a name="E3042"></a>](../src/cfnlint/rules/resources/ecs/TaskDefinitionEssentialContainer.py) | Check at least one essential container is specified | Check that every TaskDefinition specifies at least one essential container | | [Source](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-containerdefinitions.html#cfn-ecs-taskdefinition-containerdefinition-essential) | `properties`,`ecs`,`task`,`container`,`fargate` |
134134
| [E3043<a name="E3043"></a>](../src/cfnlint/rules/resources/cloudformation/NestedStackParameters.py) | Validate parameters for in a nested stack | Evalute if parameters for a nested stack are specified and if parameters are specified for a nested stack that aren't required. | | [Source](https://github.com/awslabs/cfn-python-lint) | `resources`,`cloudformation` |
135+
| [E3044<a name="E3044"></a>](../src/cfnlint/rules/resources/ecs/FargateDeploymentSchedulingStrategy.py) | Validate scheduling strategy for Fargate services | Fargate services currently only support REPLICA scheduling strategy | | [Source](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-schedulingstrategy) | `resources`,`container`, `fargate`, `service` |
135136
| [E3050<a name="E3050"></a>](../src/cfnlint/rules/resources/iam/RefWithPath.py) | Check if REFing to a IAM resource with path set | Some resources don't support looking up the IAM resource by name. This check validates when a REF is being used and the Path is not '/' | | [Source](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements.html) | `properties`,`iam` |
136137
| [E3502<a name="E3502"></a>](../src/cfnlint/rules/resources/properties/JsonSize.py) | Check if a JSON Object is within size limits | Validate properties that are JSON values so that their length is within the limits | | [Source](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html) | `resources`,`limits`,`json` |
137138
| [E3503<a name="E3503"></a>](../src/cfnlint/rules/resources/certificatemanager/DomainValidationOptions.py) | ValidationDomain is superdomain of DomainName | In ValidationDomainOptions, the ValidationDomain must be a superdomain of the DomainName being validated | | [Source](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-certificatemanager-certificate-domainvalidationoption.html#cfn-certificatemanager-certificate-domainvalidationoption-validationdomain) | `certificate`,`certificatemanager`,`domainvalidationoptions`,`validationdomain` |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
"""
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: MIT-0
4+
"""
5+
from cfnlint.rules import CloudFormationLintRule, RuleMatch
6+
7+
8+
class FargateDeploymentSchedulingStrategy(CloudFormationLintRule):
9+
id = "E3044"
10+
shortdesc = "Check Fargate service scheduling strategy"
11+
description = "Check that Fargate service scheduling strategy is REPLICA"
12+
source_url = "https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-ecs-service.html#cfn-ecs-service-schedulingstrategy"
13+
tags = ["properties", "ecs", "service", "container", "fargate"]
14+
15+
def match(self, cfn):
16+
matches = []
17+
ecs_services = cfn.get_resource_properties(["AWS::ECS::Service"])
18+
19+
for ecs_service in ecs_services:
20+
path = ecs_service["Path"]
21+
properties = ecs_service["Value"]
22+
if isinstance(properties, dict):
23+
launch_type = properties.get("LaunchType", None)
24+
if isinstance(launch_type, str) and launch_type == "Fargate":
25+
scheduling_strategy = properties.get("SchedulingStrategy", None)
26+
if (
27+
isinstance(scheduling_strategy, str)
28+
and scheduling_strategy != "REPLICA"
29+
):
30+
error_message = f"Fargate service only support REPLICA as scheduling strategy at {'/'.join(map(str, path))}"
31+
matches.append(RuleMatch(path, error_message))
32+
return matches

src/cfnlint/rules/resources/ecs/TaskDefinitionEssentialContainer.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ def match(self, cfn):
4141
has_essential_container = True
4242

4343
if not has_essential_container:
44-
message = "No essential containers defined for {0}"
45-
rule_match = RuleMatch(path, message.format("/".join(map(str, path))))
44+
error_message = (
45+
f"No essential containers defined for {'/'.join(map(str, path))}"
46+
)
47+
rule_match = RuleMatch(path, error_message)
4648
matches.append(rule_match)
4749

4850
return matches
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Resources:
2+
Service1:
3+
Type: AWS::ECS::Service
4+
Properties:
5+
LaunchType: Fargate
6+
SchedulingStrategy: DAEMON
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Resources:
2+
Service1:
3+
Type: AWS::ECS::Service
4+
Properties:
5+
LaunchType: Fargate
6+
SchedulingStrategy: REPLICA
7+
Service2:
8+
Type: AWS::ECS::Service
9+
Properties:
10+
LaunchType: EC2
11+
SchedulingStrategy: DAEMON
12+
Service3:
13+
Type: AWS::ECS::Service
14+
Properties:
15+
LaunchType: EXTERNAL
16+
SchedulingStrategy: DAEMON
17+
Service4:
18+
Type: AWS::ECS::Service
19+
Properties:
20+
LaunchType: !Join ["", ["FAR", "GATE"]]
21+
SchedulingStrategy: DAEMON
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
"""
2+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
SPDX-License-Identifier: MIT-0
4+
"""
5+
from test.unit.rules import BaseRuleTestCase
6+
7+
from cfnlint.rules.resources.ecs.FargateDeploymentSchedulingStrategy import (
8+
FargateDeploymentSchedulingStrategy,
9+
)
10+
11+
12+
class TestFargateServiceSchedulingStrategy(BaseRuleTestCase):
13+
"""
14+
Test that Fargate service has correct scheduling strategy (REPLICA)
15+
"""
16+
17+
def setUp(self):
18+
super(TestFargateServiceSchedulingStrategy, self).setUp()
19+
self.collection.register(FargateDeploymentSchedulingStrategy())
20+
self.success_templates = [
21+
"test/fixtures/templates/good/resources/ecs/test_fargate_scheduling_strategy.yaml"
22+
]
23+
24+
def test_file_positive(self):
25+
self.helper_file_positive()
26+
27+
def test_file_negative(self):
28+
self.helper_file_negative(
29+
"test/fixtures/templates/bad/resources/ecs/test_fargate_scheduling_strategy.yaml",
30+
1,
31+
)

0 commit comments

Comments
 (0)