-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(aws-ecs): New CDK constructs for ECS Anywhere task and service d…
…efinitions (#14931) Here is how the user experience will looks like, when using the new constructs for provisioning the `ECS Anywhere` resources: ```typescript // Stack definition const stack = new cdk.Stack(); // ECS Task definition const taskDefinition = new ecs.ExternalTaskDefinition(stack, 'ExternalTaskDef'); // Main container const container = taskDefinition.addContainer('web', { image: ecs.ContainerImage.fromRegistry('amazon/amazon-ecs-sample'), memoryLimitMiB: 512, }); // Port mapping container.addPortMappings({ containerPort: 3000, }); // ECS Service definition new ecs.ExternalService(stack, 'ExternalService', { cluster, taskDefinition, }); ``` > Note: Currently ECS anywhere doesn't support autoscaling, load balancing, `AWS Cloudmap` discovery and attachment of volumes. So validation rules are created part of this pull request. **This is a follow up for the below PR:** [https://github.com/aws/aws-cdk/pull/14811](https://github.com/aws/aws-cdk/pull/14811) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
- Loading branch information
1 parent
eeeec5d
commit 3592b26
Showing
7 changed files
with
1,490 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
190 changes: 190 additions & 0 deletions
190
packages/@aws-cdk/aws-ecs/lib/external/external-service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
import * as appscaling from '@aws-cdk/aws-applicationautoscaling'; | ||
import * as ec2 from '@aws-cdk/aws-ec2'; | ||
import * as elbv2 from '@aws-cdk/aws-elasticloadbalancingv2'; | ||
import * as cloudmap from '@aws-cdk/aws-servicediscovery'; | ||
import { Resource, Stack } from '@aws-cdk/core'; | ||
import { Construct } from 'constructs'; | ||
import { AssociateCloudMapServiceOptions, BaseService, BaseServiceOptions, CloudMapOptions, DeploymentControllerType, EcsTarget, IBaseService, IEcsLoadBalancerTarget, IService, LaunchType, PropagatedTagSource } from '../base/base-service'; | ||
import { fromServiceAtrributes } from '../base/from-service-attributes'; | ||
import { ScalableTaskCount } from '../base/scalable-task-count'; | ||
import { Compatibility, LoadBalancerTargetOptions, TaskDefinition } from '../base/task-definition'; | ||
import { ICluster } from '../cluster'; | ||
/** | ||
* The properties for defining a service using the External launch type. | ||
*/ | ||
export interface ExternalServiceProps extends BaseServiceOptions { | ||
/** | ||
* The task definition to use for tasks in the service. | ||
* | ||
* [disable-awslint:ref-via-interface] | ||
*/ | ||
readonly taskDefinition: TaskDefinition; | ||
|
||
/** | ||
* The security groups to associate with the service. If you do not specify a security group, the default security group for the VPC is used. | ||
* | ||
* | ||
* @default - A new security group is created. | ||
*/ | ||
readonly securityGroups?: ec2.ISecurityGroup[]; | ||
} | ||
|
||
/** | ||
* The interface for a service using the External launch type on an ECS cluster. | ||
*/ | ||
export interface IExternalService extends IService { | ||
|
||
} | ||
|
||
/** | ||
* The properties to import from the service using the External launch type. | ||
*/ | ||
export interface ExternalServiceAttributes { | ||
/** | ||
* The cluster that hosts the service. | ||
*/ | ||
readonly cluster: ICluster; | ||
|
||
/** | ||
* The service ARN. | ||
* | ||
* @default - either this, or {@link serviceName}, is required | ||
*/ | ||
readonly serviceArn?: string; | ||
|
||
/** | ||
* The name of the service. | ||
* | ||
* @default - either this, or {@link serviceArn}, is required | ||
*/ | ||
readonly serviceName?: string; | ||
} | ||
|
||
/** | ||
* This creates a service using the External launch type on an ECS cluster. | ||
* | ||
* @resource AWS::ECS::Service | ||
*/ | ||
export class ExternalService extends BaseService implements IExternalService { | ||
|
||
/** | ||
* Imports from the specified service ARN. | ||
*/ | ||
public static fromExternalServiceArn(scope: Construct, id: string, externalServiceArn: string): IExternalService { | ||
class Import extends Resource implements IExternalService { | ||
public readonly serviceArn = externalServiceArn; | ||
public readonly serviceName = Stack.of(scope).parseArn(externalServiceArn).resourceName as string; | ||
} | ||
return new Import(scope, id); | ||
} | ||
|
||
/** | ||
* Imports from the specified service attrributes. | ||
*/ | ||
public static fromExternalServiceAttributes(scope: Construct, id: string, attrs: ExternalServiceAttributes): IBaseService { | ||
return fromServiceAtrributes(scope, id, attrs); | ||
} | ||
|
||
/** | ||
* Constructs a new instance of the ExternalService class. | ||
*/ | ||
constructor(scope: Construct, id: string, props: ExternalServiceProps) { | ||
if (props.minHealthyPercent !== undefined && props.maxHealthyPercent !== undefined && props.minHealthyPercent >= props.maxHealthyPercent) { | ||
throw new Error('Minimum healthy percent must be less than maximum healthy percent.'); | ||
} | ||
|
||
if (props.taskDefinition.compatibility !== Compatibility.EXTERNAL) { | ||
throw new Error('Supplied TaskDefinition is not configured for compatibility with ECS Anywhere cluster'); | ||
} | ||
|
||
if (props.cluster.defaultCloudMapNamespace !== undefined) { | ||
throw new Error (`Cloud map integration is not supported for External service ${props.cluster.defaultCloudMapNamespace}`); | ||
} | ||
|
||
if (props.cloudMapOptions !== undefined) { | ||
throw new Error ('Cloud map options are not supported for External service'); | ||
} | ||
|
||
if (props.enableExecuteCommand !== undefined) { | ||
throw new Error ('Enable Execute Command options are not supported for External service'); | ||
} | ||
|
||
if (props.capacityProviderStrategies !== undefined) { | ||
throw new Error ('Capacity Providers are not supported for External service'); | ||
} | ||
|
||
const propagateTagsFromSource = props.propagateTags ?? PropagatedTagSource.NONE; | ||
|
||
super(scope, id, { | ||
...props, | ||
desiredCount: props.desiredCount, | ||
maxHealthyPercent: props.maxHealthyPercent === undefined ? 100 : props.maxHealthyPercent, | ||
minHealthyPercent: 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, | ||
}, props.taskDefinition); | ||
|
||
this.node.addValidation({ | ||
validate: () => !this.taskDefinition.defaultContainer ? ['A TaskDefinition must have at least one essential container'] : [], | ||
}); | ||
|
||
this.node.addValidation({ | ||
validate: () => this.networkConfiguration !== undefined ? ['Network configurations not supported for an external service'] : [], | ||
}); | ||
} | ||
|
||
/** | ||
* Overriden method to throw error as `attachToApplicationTargetGroup` is not supported for external service | ||
*/ | ||
public attachToApplicationTargetGroup(_targetGroup: elbv2.IApplicationTargetGroup): elbv2.LoadBalancerTargetProps { | ||
throw new Error ('Application load balancer cannot be attached to an external service'); | ||
} | ||
|
||
/** | ||
* Overriden method to throw error as `loadBalancerTarget` is not supported for external service | ||
*/ | ||
public loadBalancerTarget(_options: LoadBalancerTargetOptions): IEcsLoadBalancerTarget { | ||
throw new Error ('External service cannot be attached as load balancer targets'); | ||
} | ||
|
||
/** | ||
* Overriden method to throw error as `registerLoadBalancerTargets` is not supported for external service | ||
*/ | ||
public registerLoadBalancerTargets(..._targets: EcsTarget[]) { | ||
throw new Error ('External service cannot be registered as load balancer targets'); | ||
} | ||
|
||
/** | ||
* Overriden method to throw error as `configureAwsVpcNetworkingWithSecurityGroups` is not supported for external service | ||
*/ | ||
// eslint-disable-next-line max-len, no-unused-vars | ||
protected configureAwsVpcNetworkingWithSecurityGroups(_vpc: ec2.IVpc, _assignPublicIp?: boolean, _vpcSubnets?: ec2.SubnetSelection, _securityGroups?: ec2.ISecurityGroup[]) { | ||
throw new Error ('Only Bridge network mode is supported for external service'); | ||
} | ||
|
||
/** | ||
* Overriden method to throw error as `autoScaleTaskCount` is not supported for external service | ||
*/ | ||
public autoScaleTaskCount(_props: appscaling.EnableScalingProps): ScalableTaskCount { | ||
throw new Error ('Autoscaling not supported for external service'); | ||
} | ||
|
||
/** | ||
* Overriden method to throw error as `enableCloudMap` is not supported for external service | ||
*/ | ||
public enableCloudMap(_options: CloudMapOptions): cloudmap.Service { | ||
throw new Error ('Cloud map integration not supported for an external service'); | ||
} | ||
|
||
/** | ||
* Overriden method to throw error as `associateCloudMapService` is not supported for external service | ||
*/ | ||
public associateCloudMapService(_options: AssociateCloudMapServiceOptions): void { | ||
throw new Error ('Cloud map service association is not supported for an external service'); | ||
} | ||
} |
91 changes: 91 additions & 0 deletions
91
packages/@aws-cdk/aws-ecs/lib/external/external-task-definition.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { Construct } from 'constructs'; | ||
import { ImportedTaskDefinition } from '../../lib/base/_imported-task-definition'; | ||
import { | ||
CommonTaskDefinitionAttributes, | ||
CommonTaskDefinitionProps, | ||
Compatibility, | ||
InferenceAccelerator, | ||
ITaskDefinition, | ||
NetworkMode, | ||
TaskDefinition, | ||
Volume, | ||
} from '../base/task-definition'; | ||
|
||
/** | ||
* The properties for a task definition run on an External cluster. | ||
*/ | ||
export interface ExternalTaskDefinitionProps extends CommonTaskDefinitionProps { | ||
|
||
} | ||
|
||
/** | ||
* The interface of a task definition run on an External cluster. | ||
*/ | ||
export interface IExternalTaskDefinition extends ITaskDefinition { | ||
|
||
} | ||
|
||
/** | ||
* Attributes used to import an existing External task definition | ||
*/ | ||
export interface ExternalTaskDefinitionAttributes extends CommonTaskDefinitionAttributes { | ||
|
||
} | ||
|
||
/** | ||
* The details of a task definition run on an External cluster. | ||
* | ||
* @resource AWS::ECS::TaskDefinition | ||
*/ | ||
export class ExternalTaskDefinition extends TaskDefinition implements IExternalTaskDefinition { | ||
|
||
/** | ||
* Imports a task definition from the specified task definition ARN. | ||
*/ | ||
public static fromEc2TaskDefinitionArn(scope: Construct, id: string, externalTaskDefinitionArn: string): IExternalTaskDefinition { | ||
return new ImportedTaskDefinition(scope, id, { | ||
taskDefinitionArn: externalTaskDefinitionArn, | ||
}); | ||
} | ||
|
||
/** | ||
* Imports an existing External task definition from its attributes | ||
*/ | ||
public static fromExternalTaskDefinitionAttributes( | ||
scope: Construct, | ||
id: string, | ||
attrs: ExternalTaskDefinitionAttributes, | ||
): IExternalTaskDefinition { | ||
return new ImportedTaskDefinition(scope, id, { | ||
taskDefinitionArn: attrs.taskDefinitionArn, | ||
compatibility: Compatibility.EXTERNAL, | ||
networkMode: NetworkMode.BRIDGE, | ||
taskRole: attrs.taskRole, | ||
}); | ||
} | ||
|
||
/** | ||
* Constructs a new instance of the ExternalTaskDefinition class. | ||
*/ | ||
constructor(scope: Construct, id: string, props: ExternalTaskDefinitionProps = {}) { | ||
super(scope, id, { | ||
...props, | ||
compatibility: Compatibility.EXTERNAL, | ||
networkMode: NetworkMode.BRIDGE, | ||
}); | ||
} | ||
|
||
/** | ||
* Overridden method to throw error, as volumes are not supported for external task definitions | ||
*/ | ||
public addVolume(_volume: Volume) { | ||
throw new Error('External task definitions doesnt support volumes'); | ||
} | ||
|
||
/** | ||
* Overriden method to throw error as interface accelerators are not supported for external tasks | ||
*/ | ||
public addInferenceAccelerator(_inferenceAccelerator: InferenceAccelerator) { | ||
throw new Error('Cannot use inference accelerators on tasks that run on External service'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.