Skip to content

Commit

Permalink
ECS ExternalService support daemon
Browse files Browse the repository at this point in the history
  • Loading branch information
phuhung273 committed Dec 22, 2024
1 parent 0546ec2 commit 713fadd
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 2 deletions.
23 changes: 21 additions & 2 deletions packages/aws-cdk-lib/aws-ecs/lib/external/external-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ export interface ExternalServiceProps extends BaseServiceOptions {
* @default - A new security group is created.
*/
readonly securityGroups?: ec2.ISecurityGroup[];

/**
* Specifies whether the service will use the daemon scheduling strategy.
* If true, the service scheduler deploys exactly one task on each container instance in your cluster.
*
* When you are using this strategy, do not specify a desired number of tasks or any task placement strategies.
*
* @default false
*/
readonly daemon?: boolean;
}

/**
Expand Down Expand Up @@ -89,6 +99,14 @@ export class ExternalService extends BaseService implements IExternalService {
* Constructs a new instance of the ExternalService class.
*/
constructor(scope: Construct, id: string, props: ExternalServiceProps) {
if (props.daemon && props.desiredCount !== undefined) {
throw new Error('Daemon mode launches one task on every instance. Don\'t supply desiredCount.');
}

if (props.daemon && props.maxHealthyPercent !== undefined && props.maxHealthyPercent !== 100) {
throw new Error('Maximum percent must be 100 for daemon mode.');
}

if (props.minHealthyPercent !== undefined && props.maxHealthyPercent !== undefined && props.minHealthyPercent >= props.maxHealthyPercent) {
throw new Error('Minimum healthy percent must be less than maximum healthy percent.');
}
Expand All @@ -114,15 +132,16 @@ export class ExternalService extends BaseService implements IExternalService {
super(scope, id, {
...props,
desiredCount: props.desiredCount,
maxHealthyPercent: props.maxHealthyPercent === undefined ? 100 : props.maxHealthyPercent,
minHealthyPercent: props.minHealthyPercent === undefined ? 0 : props.minHealthyPercent,
maxHealthyPercent: props.daemon || props.maxHealthyPercent === undefined ? 100 : props.maxHealthyPercent,
minHealthyPercent: props.daemon || props.minHealthyPercent === undefined ? 0 : props.minHealthyPercent,
launchType: LaunchType.EXTERNAL,
propagateTags: propagateTagsFromSource,
enableECSManagedTags: props.enableECSManagedTags,
},
{
cluster: props.cluster.clusterName,
taskDefinition: props.deploymentController?.type === DeploymentControllerType.EXTERNAL ? undefined : props.taskDefinition.taskDefinitionArn,
schedulingStrategy: props.daemon ? 'DAEMON' : 'REPLICA',
}, props.taskDefinition);

this.node.addValidation({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,85 @@ describe('external service', () => {

});

test('errors if daemon and desiredCount both specified', () => {
// GIVEN
const stack = new cdk.Stack();
const vpc = new ec2.Vpc(stack, 'MyVpc', {});
const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc });
addDefaultCapacityProvider(cluster, stack, vpc);
const taskDefinition = new ecs.ExternalTaskDefinition(stack, 'TaskDef');
taskDefinition.addContainer('BaseContainer', {
image: ecs.ContainerImage.fromRegistry('test'),
memoryReservationMiB: 10,
});

// THEN
expect(() => {
new ecs.ExternalService(stack, 'ExternalService', {
cluster,
taskDefinition,
daemon: true,
desiredCount: 2,
});
}).toThrow(/Don't supply desiredCount/);

});

test('errors if daemon and maximumPercent not 100', () => {
// GIVEN
const stack = new cdk.Stack();
const vpc = new ec2.Vpc(stack, 'MyVpc', {});
const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc });
addDefaultCapacityProvider(cluster, stack, vpc);
const taskDefinition = new ecs.ExternalTaskDefinition(stack, 'TaskDef');
taskDefinition.addContainer('BaseContainer', {
image: ecs.ContainerImage.fromRegistry('test'),
memoryReservationMiB: 10,
});

// THEN
expect(() => {
new ecs.ExternalService(stack, 'ExternalService', {
cluster,
taskDefinition,
daemon: true,
maxHealthyPercent: 300,
});
}).toThrow(/Maximum percent must be 100 for daemon mode./);

});

test('sets daemon scheduling strategy', () => {
// GIVEN
const stack = new cdk.Stack();
const vpc = new ec2.Vpc(stack, 'MyVpc', {});
const cluster = new ecs.Cluster(stack, 'EcsCluster', { vpc });
addDefaultCapacityProvider(cluster, stack, vpc);
const taskDefinition = new ecs.ExternalTaskDefinition(stack, 'TaskDef');
taskDefinition.addContainer('BaseContainer', {
image: ecs.ContainerImage.fromRegistry('test'),
memoryReservationMiB: 10,
});

new ecs.ExternalService(stack, 'ExternalService', {
cluster,
taskDefinition,
daemon: true,
});

// THEN
Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', {
SchedulingStrategy: 'DAEMON',
DeploymentConfiguration: {
MaximumPercent: 100,
MinimumHealthyPercent: 0,
},
EnableECSManagedTags: false,
LaunchType: LaunchType.EXTERNAL,
});

});

test('errors if minimum not less than maximum', () => {
// GIVEN
const stack = new cdk.Stack();
Expand Down

0 comments on commit 713fadd

Please sign in to comment.