@aws-cdk/aws-ecs
Version:
The CDK Construct Library for AWS::ECS
728 lines • 109 kB
JavaScript
"use strict";
var _a, _b;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PropagatedTagSource = exports.DeploymentControllerType = exports.LaunchType = exports.BaseService = exports.ListenerConfig = void 0;
const jsiiDeprecationWarnings = require("../../.warnings.jsii.js");
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const appscaling = require("@aws-cdk/aws-applicationautoscaling");
const cloudwatch = require("@aws-cdk/aws-cloudwatch");
const ec2 = require("@aws-cdk/aws-ec2");
const elbv2 = require("@aws-cdk/aws-elasticloadbalancingv2");
const iam = require("@aws-cdk/aws-iam");
const cloudmap = require("@aws-cdk/aws-servicediscovery");
const core_1 = require("@aws-cdk/core");
const task_definition_1 = require("../base/task-definition");
const cluster_1 = require("../cluster");
const ecs_generated_1 = require("../ecs.generated");
const scalable_task_count_1 = require("./scalable-task-count");
/**
* Base class for configuring listener when registering targets.
*/
class ListenerConfig {
/**
* Create a config for adding target group to ALB listener.
*/
static applicationListener(listener, props) {
return new ApplicationListenerConfig(listener, props);
}
/**
* Create a config for adding target group to NLB listener.
*/
static networkListener(listener, props) {
return new NetworkListenerConfig(listener, props);
}
}
exports.ListenerConfig = ListenerConfig;
_a = JSII_RTTI_SYMBOL_1;
ListenerConfig[_a] = { fqn: "@aws-cdk/aws-ecs.ListenerConfig", version: "1.149.0" };
/**
* Class for configuring application load balancer listener when registering targets.
*/
class ApplicationListenerConfig extends ListenerConfig {
constructor(listener, props) {
super();
this.listener = listener;
this.props = props;
}
/**
* Create and attach a target group to listener.
*/
addTargets(id, target, service) {
var _c;
const props = this.props || {};
const protocol = props.protocol;
const port = (_c = props.port) !== null && _c !== void 0 ? _c : (protocol === elbv2.ApplicationProtocol.HTTPS ? 443 : 80);
this.listener.addTargets(id, {
...props,
targets: [
service.loadBalancerTarget({
...target,
}),
],
port,
});
}
}
/**
* Class for configuring network load balancer listener when registering targets.
*/
class NetworkListenerConfig extends ListenerConfig {
constructor(listener, props) {
super();
this.listener = listener;
this.props = props;
}
/**
* Create and attach a target group to listener.
*/
addTargets(id, target, service) {
var _c, _d;
const port = (_d = (_c = this.props) === null || _c === void 0 ? void 0 : _c.port) !== null && _d !== void 0 ? _d : 80;
this.listener.addTargets(id, {
...this.props,
targets: [
service.loadBalancerTarget({
...target,
}),
],
port,
});
}
}
/**
* The base class for Ec2Service and FargateService services.
*/
class BaseService extends core_1.Resource {
/**
* Constructs a new instance of the BaseService class.
*/
constructor(scope, id, props, additionalProps, taskDefinition) {
var _c, _d, _e, _f, _g, _h, _j, _k, _l;
super(scope, id, {
physicalName: props.serviceName,
});
/**
* The security groups which manage the allowed network traffic for the service.
*/
this.connections = new ec2.Connections();
/**
* A list of Elastic Load Balancing load balancer objects, containing the load balancer name, the container
* name (as it appears in a container definition), and the container port to access from the load balancer.
*/
this.loadBalancers = new Array();
/**
* The details of the service discovery registries to assign to this service.
* For more information, see Service Discovery.
*/
this.serviceRegistries = new Array();
jsiiDeprecationWarnings._aws_cdk_aws_ecs_BaseServiceProps(props);
jsiiDeprecationWarnings._aws_cdk_aws_ecs_TaskDefinition(taskDefinition);
if (props.propagateTags && props.propagateTaskTagsFrom) {
throw new Error('You can only specify either propagateTags or propagateTaskTagsFrom. Alternatively, you can leave both blank');
}
this.taskDefinition = taskDefinition;
// launchType will set to undefined if using external DeploymentController or capacityProviderStrategies
const launchType = ((_c = props.deploymentController) === null || _c === void 0 ? void 0 : _c.type) === DeploymentControllerType.EXTERNAL ||
props.capacityProviderStrategies !== undefined ?
undefined : props.launchType;
const propagateTagsFromSource = (_e = (_d = props.propagateTaskTagsFrom) !== null && _d !== void 0 ? _d : props.propagateTags) !== null && _e !== void 0 ? _e : PropagatedTagSource.NONE;
this.resource = new ecs_generated_1.CfnService(this, 'Service', {
desiredCount: props.desiredCount,
serviceName: this.physicalName,
loadBalancers: core_1.Lazy.any({ produce: () => this.loadBalancers }, { omitEmptyArray: true }),
deploymentConfiguration: {
maximumPercent: props.maxHealthyPercent || 200,
minimumHealthyPercent: props.minHealthyPercent === undefined ? 50 : props.minHealthyPercent,
deploymentCircuitBreaker: props.circuitBreaker ? {
enable: true,
rollback: (_f = props.circuitBreaker.rollback) !== null && _f !== void 0 ? _f : false,
} : undefined,
},
propagateTags: propagateTagsFromSource === PropagatedTagSource.NONE ? undefined : props.propagateTags,
enableEcsManagedTags: (_g = props.enableECSManagedTags) !== null && _g !== void 0 ? _g : false,
deploymentController: props.circuitBreaker ? {
type: DeploymentControllerType.ECS,
} : props.deploymentController,
launchType: launchType,
enableExecuteCommand: props.enableExecuteCommand,
capacityProviderStrategy: props.capacityProviderStrategies,
healthCheckGracePeriodSeconds: this.evaluateHealthGracePeriod(props.healthCheckGracePeriod),
/* role: never specified, supplanted by Service Linked Role */
networkConfiguration: core_1.Lazy.any({ produce: () => this.networkConfiguration }, { omitEmptyArray: true }),
serviceRegistries: core_1.Lazy.any({ produce: () => this.serviceRegistries }, { omitEmptyArray: true }),
...additionalProps,
});
if (((_h = props.deploymentController) === null || _h === void 0 ? void 0 : _h.type) === DeploymentControllerType.EXTERNAL) {
core_1.Annotations.of(this).addWarning('taskDefinition and launchType are blanked out when using external deployment controller.');
}
this.serviceArn = this.getResourceArnAttribute(this.resource.ref, {
service: 'ecs',
resource: 'service',
resourceName: `${props.cluster.clusterName}/${this.physicalName}`,
});
this.serviceName = this.getResourceNameAttribute(this.resource.attrName);
this.cluster = props.cluster;
if (props.cloudMapOptions) {
this.enableCloudMap(props.cloudMapOptions);
}
if (props.enableExecuteCommand) {
this.enableExecuteCommand();
const logging = (_k = (_j = this.cluster.executeCommandConfiguration) === null || _j === void 0 ? void 0 : _j.logging) !== null && _k !== void 0 ? _k : cluster_1.ExecuteCommandLogging.DEFAULT;
if ((_l = this.cluster.executeCommandConfiguration) === null || _l === void 0 ? void 0 : _l.kmsKey) {
this.enableExecuteCommandEncryption(logging);
}
if (logging !== cluster_1.ExecuteCommandLogging.NONE) {
this.executeCommandLogConfiguration();
}
}
this.node.defaultChild = this.resource;
}
/**
* Import an existing ECS/Fargate Service using the service cluster format.
* The format is the "new" format "arn:aws:ecs:region:aws_account_id:service/cluster-name/service-name".
* @see https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-account-settings.html#ecs-resource-ids
*/
static fromServiceArnWithCluster(scope, id, serviceArn) {
const stack = core_1.Stack.of(scope);
const arn = stack.splitArn(serviceArn, core_1.ArnFormat.SLASH_RESOURCE_NAME);
const resourceName = arn.resourceName;
if (!resourceName) {
throw new Error('Missing resource Name from service ARN: ${serviceArn}');
}
const resourceNameParts = resourceName.split('/');
if (resourceNameParts.length !== 2) {
throw new Error(`resource name ${resourceName} from service ARN: ${serviceArn} is not using the ARN cluster format`);
}
const clusterName = resourceNameParts[0];
const serviceName = resourceNameParts[1];
const clusterArn = core_1.Stack.of(scope).formatArn({
partition: arn.partition,
region: arn.region,
account: arn.account,
service: 'ecs',
resource: 'cluster',
resourceName: clusterName,
});
const cluster = cluster_1.Cluster.fromClusterArn(scope, `${id}Cluster`, clusterArn);
class Import extends core_1.Resource {
constructor() {
super(...arguments);
this.serviceArn = serviceArn;
this.serviceName = serviceName;
this.cluster = cluster;
}
}
return new Import(scope, id, {
environmentFromArn: serviceArn,
});
}
/**
* The CloudMap service created for this service, if any.
*/
get cloudMapService() {
return this.cloudmapService;
}
executeCommandLogConfiguration() {
var _c, _d;
const logConfiguration = (_c = this.cluster.executeCommandConfiguration) === null || _c === void 0 ? void 0 : _c.logConfiguration;
this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({
actions: [
'logs:DescribeLogGroups',
],
resources: ['*'],
}));
const logGroupArn = (logConfiguration === null || logConfiguration === void 0 ? void 0 : logConfiguration.cloudWatchLogGroup) ? `arn:${this.stack.partition}:logs:${this.stack.region}:${this.stack.account}:log-group:${logConfiguration.cloudWatchLogGroup.logGroupName}:*` : '*';
this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({
actions: [
'logs:CreateLogStream',
'logs:DescribeLogStreams',
'logs:PutLogEvents',
],
resources: [logGroupArn],
}));
if ((_d = logConfiguration === null || logConfiguration === void 0 ? void 0 : logConfiguration.s3Bucket) === null || _d === void 0 ? void 0 : _d.bucketName) {
this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({
actions: [
's3:GetBucketLocation',
],
resources: ['*'],
}));
this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({
actions: [
's3:PutObject',
],
resources: [`arn:${this.stack.partition}:s3:::${logConfiguration.s3Bucket.bucketName}/*`],
}));
if (logConfiguration.s3EncryptionEnabled) {
this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({
actions: [
's3:GetEncryptionConfiguration',
],
resources: [`arn:${this.stack.partition}:s3:::${logConfiguration.s3Bucket.bucketName}`],
}));
}
}
}
enableExecuteCommandEncryption(logging) {
var _c, _d, _e, _f, _g, _h, _j, _k;
this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({
actions: [
'kms:Decrypt',
'kms:GenerateDataKey',
],
resources: [`${(_d = (_c = this.cluster.executeCommandConfiguration) === null || _c === void 0 ? void 0 : _c.kmsKey) === null || _d === void 0 ? void 0 : _d.keyArn}`],
}));
(_f = (_e = this.cluster.executeCommandConfiguration) === null || _e === void 0 ? void 0 : _e.kmsKey) === null || _f === void 0 ? void 0 : _f.addToResourcePolicy(new iam.PolicyStatement({
actions: [
'kms:*',
],
resources: ['*'],
principals: [new iam.ArnPrincipal(`arn:${this.stack.partition}:iam::${this.stack.account}:root`)],
}));
if (logging === cluster_1.ExecuteCommandLogging.DEFAULT || ((_h = (_g = this.cluster.executeCommandConfiguration) === null || _g === void 0 ? void 0 : _g.logConfiguration) === null || _h === void 0 ? void 0 : _h.cloudWatchEncryptionEnabled)) {
(_k = (_j = this.cluster.executeCommandConfiguration) === null || _j === void 0 ? void 0 : _j.kmsKey) === null || _k === void 0 ? void 0 : _k.addToResourcePolicy(new iam.PolicyStatement({
actions: [
'kms:Encrypt*',
'kms:Decrypt*',
'kms:ReEncrypt*',
'kms:GenerateDataKey*',
'kms:Describe*',
],
resources: ['*'],
principals: [new iam.ServicePrincipal(`logs.${this.stack.region}.amazonaws.com`)],
conditions: {
ArnLike: { 'kms:EncryptionContext:aws:logs:arn': `arn:${this.stack.partition}:logs:${this.stack.region}:${this.stack.account}:*` },
},
}));
}
}
/**
* This method is called to attach this service to an Application Load Balancer.
*
* Don't call this function directly. Instead, call `listener.addTargets()`
* to add this service to a load balancer.
*/
attachToApplicationTargetGroup(targetGroup) {
return this.defaultLoadBalancerTarget.attachToApplicationTargetGroup(targetGroup);
}
/**
* Registers the service as a target of a Classic Load Balancer (CLB).
*
* Don't call this. Call `loadBalancer.addTarget()` instead.
*/
attachToClassicLB(loadBalancer) {
return this.defaultLoadBalancerTarget.attachToClassicLB(loadBalancer);
}
/**
* Return a load balancing target for a specific container and port.
*
* Use this function to create a load balancer target if you want to load balance to
* another container than the first essential container or the first mapped port on
* the container.
*
* Use the return value of this function where you would normally use a load balancer
* target, instead of the `Service` object itself.
*
* @example
*
* declare const listener: elbv2.ApplicationListener;
* declare const service: ecs.BaseService;
* listener.addTargets('ECS', {
* port: 80,
* targets: [service.loadBalancerTarget({
* containerName: 'MyContainer',
* containerPort: 1234,
* })],
* });
*/
loadBalancerTarget(options) {
jsiiDeprecationWarnings._aws_cdk_aws_ecs_LoadBalancerTargetOptions(options);
const self = this;
const target = this.taskDefinition._validateTarget(options);
const connections = self.connections;
return {
attachToApplicationTargetGroup(targetGroup) {
targetGroup.registerConnectable(self, self.taskDefinition._portRangeFromPortMapping(target.portMapping));
return self.attachToELBv2(targetGroup, target.containerName, target.portMapping.containerPort);
},
attachToNetworkTargetGroup(targetGroup) {
return self.attachToELBv2(targetGroup, target.containerName, target.portMapping.containerPort);
},
connections,
attachToClassicLB(loadBalancer) {
return self.attachToELB(loadBalancer, target.containerName, target.portMapping.containerPort);
},
};
}
/**
* Use this function to create all load balancer targets to be registered in this service, add them to
* target groups, and attach target groups to listeners accordingly.
*
* Alternatively, you can use `listener.addTargets()` to create targets and add them to target groups.
*
* @example
*
* declare const listener: elbv2.ApplicationListener;
* declare const service: ecs.BaseService;
* service.registerLoadBalancerTargets(
* {
* containerName: 'web',
* containerPort: 80,
* newTargetGroupId: 'ECS',
* listener: ecs.ListenerConfig.applicationListener(listener, {
* protocol: elbv2.ApplicationProtocol.HTTPS
* }),
* },
* )
*/
registerLoadBalancerTargets(...targets) {
jsiiDeprecationWarnings._aws_cdk_aws_ecs_EcsTarget(targets);
for (const target of targets) {
target.listener.addTargets(target.newTargetGroupId, {
containerName: target.containerName,
containerPort: target.containerPort,
protocol: target.protocol,
}, this);
}
}
/**
* This method is called to attach this service to a Network Load Balancer.
*
* Don't call this function directly. Instead, call `listener.addTargets()`
* to add this service to a load balancer.
*/
attachToNetworkTargetGroup(targetGroup) {
return this.defaultLoadBalancerTarget.attachToNetworkTargetGroup(targetGroup);
}
/**
* An attribute representing the minimum and maximum task count for an AutoScalingGroup.
*/
autoScaleTaskCount(props) {
if (this.scalableTaskCount) {
throw new Error('AutoScaling of task count already enabled for this service');
}
return this.scalableTaskCount = new scalable_task_count_1.ScalableTaskCount(this, 'TaskCount', {
serviceNamespace: appscaling.ServiceNamespace.ECS,
resourceId: `service/${this.cluster.clusterName}/${this.serviceName}`,
dimension: 'ecs:service:DesiredCount',
role: this.makeAutoScalingRole(),
...props,
});
}
/**
* Enable CloudMap service discovery for the service
*
* @returns The created CloudMap service
*/
enableCloudMap(options) {
var _c;
jsiiDeprecationWarnings._aws_cdk_aws_ecs_CloudMapOptions(options);
const sdNamespace = (_c = options.cloudMapNamespace) !== null && _c !== void 0 ? _c : this.cluster.defaultCloudMapNamespace;
if (sdNamespace === undefined) {
throw new Error('Cannot enable service discovery if a Cloudmap Namespace has not been created in the cluster.');
}
// Determine DNS type based on network mode
const networkMode = this.taskDefinition.networkMode;
if (networkMode === task_definition_1.NetworkMode.NONE) {
throw new Error('Cannot use a service discovery if NetworkMode is None. Use Bridge, Host or AwsVpc instead.');
}
// Bridge or host network mode requires SRV records
let dnsRecordType = options.dnsRecordType;
if (networkMode === task_definition_1.NetworkMode.BRIDGE || networkMode === task_definition_1.NetworkMode.HOST) {
if (dnsRecordType === undefined) {
dnsRecordType = cloudmap.DnsRecordType.SRV;
}
if (dnsRecordType !== cloudmap.DnsRecordType.SRV) {
throw new Error('SRV records must be used when network mode is Bridge or Host.');
}
}
// Default DNS record type for AwsVpc network mode is A Records
if (networkMode === task_definition_1.NetworkMode.AWS_VPC) {
if (dnsRecordType === undefined) {
dnsRecordType = cloudmap.DnsRecordType.A;
}
}
const { containerName, containerPort } = determineContainerNameAndPort({
taskDefinition: this.taskDefinition,
dnsRecordType: dnsRecordType,
container: options.container,
containerPort: options.containerPort,
});
const cloudmapService = new cloudmap.Service(this, 'CloudmapService', {
namespace: sdNamespace,
name: options.name,
dnsRecordType: dnsRecordType,
customHealthCheck: { failureThreshold: options.failureThreshold || 1 },
dnsTtl: options.dnsTtl,
});
const serviceArn = cloudmapService.serviceArn;
// add Cloudmap service to the ECS Service's serviceRegistry
this.addServiceRegistry({
arn: serviceArn,
containerName,
containerPort,
});
this.cloudmapService = cloudmapService;
return cloudmapService;
}
/**
* Associates this service with a CloudMap service
*/
associateCloudMapService(options) {
jsiiDeprecationWarnings._aws_cdk_aws_ecs_AssociateCloudMapServiceOptions(options);
const service = options.service;
const { containerName, containerPort } = determineContainerNameAndPort({
taskDefinition: this.taskDefinition,
dnsRecordType: service.dnsRecordType,
container: options.container,
containerPort: options.containerPort,
});
// add Cloudmap service to the ECS Service's serviceRegistry
this.addServiceRegistry({
arn: service.serviceArn,
containerName,
containerPort,
});
}
/**
* This method returns the specified CloudWatch metric name for this service.
*/
metric(metricName, props) {
return new cloudwatch.Metric({
namespace: 'AWS/ECS',
metricName,
dimensionsMap: { ClusterName: this.cluster.clusterName, ServiceName: this.serviceName },
...props,
}).attachTo(this);
}
/**
* This method returns the CloudWatch metric for this service's memory utilization.
*
* @default average over 5 minutes
*/
metricMemoryUtilization(props) {
return this.metric('MemoryUtilization', props);
}
/**
* This method returns the CloudWatch metric for this service's CPU utilization.
*
* @default average over 5 minutes
*/
metricCpuUtilization(props) {
return this.metric('CPUUtilization', props);
}
/**
* This method is called to create a networkConfiguration.
* @deprecated use configureAwsVpcNetworkingWithSecurityGroups instead.
*/
// eslint-disable-next-line max-len
configureAwsVpcNetworking(vpc, assignPublicIp, vpcSubnets, securityGroup) {
jsiiDeprecationWarnings.print("@aws-cdk/aws-ecs.BaseService#configureAwsVpcNetworking", "use configureAwsVpcNetworkingWithSecurityGroups instead.");
if (vpcSubnets === undefined) {
vpcSubnets = assignPublicIp ? { subnetType: ec2.SubnetType.PUBLIC } : {};
}
if (securityGroup === undefined) {
securityGroup = new ec2.SecurityGroup(this, 'SecurityGroup', { vpc });
}
this.connections.addSecurityGroup(securityGroup);
this.networkConfiguration = {
awsvpcConfiguration: {
assignPublicIp: assignPublicIp ? 'ENABLED' : 'DISABLED',
subnets: vpc.selectSubnets(vpcSubnets).subnetIds,
securityGroups: core_1.Lazy.list({ produce: () => [securityGroup.securityGroupId] }),
},
};
}
/**
* This method is called to create a networkConfiguration.
*/
// eslint-disable-next-line max-len
configureAwsVpcNetworkingWithSecurityGroups(vpc, assignPublicIp, vpcSubnets, securityGroups) {
if (vpcSubnets === undefined) {
vpcSubnets = assignPublicIp ? { subnetType: ec2.SubnetType.PUBLIC } : {};
}
if (securityGroups === undefined || securityGroups.length === 0) {
securityGroups = [new ec2.SecurityGroup(this, 'SecurityGroup', { vpc })];
}
securityGroups.forEach((sg) => { this.connections.addSecurityGroup(sg); }, this);
this.networkConfiguration = {
awsvpcConfiguration: {
assignPublicIp: assignPublicIp ? 'ENABLED' : 'DISABLED',
subnets: vpc.selectSubnets(vpcSubnets).subnetIds,
securityGroups: securityGroups.map((sg) => sg.securityGroupId),
},
};
}
renderServiceRegistry(registry) {
return {
registryArn: registry.arn,
containerName: registry.containerName,
containerPort: registry.containerPort,
};
}
/**
* Shared logic for attaching to an ELB
*/
attachToELB(loadBalancer, containerName, containerPort) {
if (this.taskDefinition.networkMode === task_definition_1.NetworkMode.AWS_VPC) {
throw new Error('Cannot use a Classic Load Balancer if NetworkMode is AwsVpc. Use Host or Bridge instead.');
}
if (this.taskDefinition.networkMode === task_definition_1.NetworkMode.NONE) {
throw new Error('Cannot use a Classic Load Balancer if NetworkMode is None. Use Host or Bridge instead.');
}
this.loadBalancers.push({
loadBalancerName: loadBalancer.loadBalancerName,
containerName,
containerPort,
});
}
/**
* Shared logic for attaching to an ELBv2
*/
attachToELBv2(targetGroup, containerName, containerPort) {
if (this.taskDefinition.networkMode === task_definition_1.NetworkMode.NONE) {
throw new Error('Cannot use a load balancer if NetworkMode is None. Use Bridge, Host or AwsVpc instead.');
}
this.loadBalancers.push({
targetGroupArn: targetGroup.targetGroupArn,
containerName,
containerPort,
});
// Service creation can only happen after the load balancer has
// been associated with our target group(s), so add ordering dependency.
this.resource.node.addDependency(targetGroup.loadBalancerAttached);
const targetType = this.taskDefinition.networkMode === task_definition_1.NetworkMode.AWS_VPC ? elbv2.TargetType.IP : elbv2.TargetType.INSTANCE;
return { targetType };
}
get defaultLoadBalancerTarget() {
return this.loadBalancerTarget({
containerName: this.taskDefinition.defaultContainer.containerName,
});
}
/**
* Generate the role that will be used for autoscaling this service
*/
makeAutoScalingRole() {
// Use a Service Linked Role.
return iam.Role.fromRoleArn(this, 'ScalingRole', core_1.Stack.of(this).formatArn({
region: '',
service: 'iam',
resource: 'role/aws-service-role/ecs.application-autoscaling.amazonaws.com',
resourceName: 'AWSServiceRoleForApplicationAutoScaling_ECSService',
}));
}
/**
* Associate Service Discovery (Cloud Map) service
*/
addServiceRegistry(registry) {
if (this.serviceRegistries.length >= 1) {
throw new Error('Cannot associate with the given service discovery registry. ECS supports at most one service registry per service.');
}
const sr = this.renderServiceRegistry(registry);
this.serviceRegistries.push(sr);
}
/**
* Return the default grace period when load balancers are configured and
* healthCheckGracePeriod is not already set
*/
evaluateHealthGracePeriod(providedHealthCheckGracePeriod) {
return core_1.Lazy.any({
produce: () => { var _c; return (_c = providedHealthCheckGracePeriod === null || providedHealthCheckGracePeriod === void 0 ? void 0 : providedHealthCheckGracePeriod.toSeconds()) !== null && _c !== void 0 ? _c : (this.loadBalancers.length > 0 ? 60 : undefined); },
});
}
enableExecuteCommand() {
this.taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({
actions: [
'ssmmessages:CreateControlChannel',
'ssmmessages:CreateDataChannel',
'ssmmessages:OpenControlChannel',
'ssmmessages:OpenDataChannel',
],
resources: ['*'],
}));
}
}
exports.BaseService = BaseService;
_b = JSII_RTTI_SYMBOL_1;
BaseService[_b] = { fqn: "@aws-cdk/aws-ecs.BaseService", version: "1.149.0" };
/**
* The launch type of an ECS service
*/
var LaunchType;
(function (LaunchType) {
/**
* The service will be launched using the EC2 launch type
*/
LaunchType["EC2"] = "EC2";
/**
* The service will be launched using the FARGATE launch type
*/
LaunchType["FARGATE"] = "FARGATE";
/**
* The service will be launched using the EXTERNAL launch type
*/
LaunchType["EXTERNAL"] = "EXTERNAL";
})(LaunchType = exports.LaunchType || (exports.LaunchType = {}));
/**
* The deployment controller type to use for the service.
*/
var DeploymentControllerType;
(function (DeploymentControllerType) {
/**
* The rolling update (ECS) deployment type involves replacing the current
* running version of the container with the latest version.
*/
DeploymentControllerType["ECS"] = "ECS";
/**
* The blue/green (CODE_DEPLOY) deployment type uses the blue/green deployment model powered by AWS CodeDeploy
*/
DeploymentControllerType["CODE_DEPLOY"] = "CODE_DEPLOY";
/**
* The external (EXTERNAL) deployment type enables you to use any third-party deployment controller
*/
DeploymentControllerType["EXTERNAL"] = "EXTERNAL";
})(DeploymentControllerType = exports.DeploymentControllerType || (exports.DeploymentControllerType = {}));
/**
* Propagate tags from either service or task definition
*/
var PropagatedTagSource;
(function (PropagatedTagSource) {
/**
* Propagate tags from service
*/
PropagatedTagSource["SERVICE"] = "SERVICE";
/**
* Propagate tags from task definition
*/
PropagatedTagSource["TASK_DEFINITION"] = "TASK_DEFINITION";
/**
* Do not propagate
*/
PropagatedTagSource["NONE"] = "NONE";
})(PropagatedTagSource = exports.PropagatedTagSource || (exports.PropagatedTagSource = {}));
/**
* Determine the name of the container and port to target for the service registry.
*/
function determineContainerNameAndPort(options) {
var _c, _d;
// If the record type is SRV, then provide the containerName and containerPort to target.
// We use the name of the default container and the default port of the default container
// unless the user specifies otherwise.
if (options.dnsRecordType === cloudmap.DnsRecordType.SRV) {
// Ensure the user-provided container is from the right task definition.
if (options.container && options.container.taskDefinition != options.taskDefinition) {
throw new Error('Cannot add discovery for a container from another task definition');
}
const container = (_c = options.container) !== null && _c !== void 0 ? _c : options.taskDefinition.defaultContainer;
// Ensure that any port given by the user is mapped.
if (options.containerPort && !container.portMappings.some(mapping => mapping.containerPort === options.containerPort)) {
throw new Error('Cannot add discovery for a container port that has not been mapped');
}
return {
containerName: container.containerName,
containerPort: (_d = options.containerPort) !== null && _d !== void 0 ? _d : options.taskDefinition.defaultContainer.containerPort,
};
}
return {};
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS1zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYmFzZS1zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLGtFQUFrRTtBQUNsRSxzREFBc0Q7QUFDdEQsd0NBQXdDO0FBRXhDLDZEQUE2RDtBQUM3RCx3Q0FBd0M7QUFDeEMsMERBQTBEO0FBQzFELHdDQUFnSDtBQUVoSCw2REFBaUc7QUFDakcsd0NBQWdHO0FBRWhHLG9EQUE4QztBQUM5QywrREFBMEQ7QUFxTjFEOztHQUVHO0FBQ0gsTUFBc0IsY0FBYztJQUNsQzs7T0FFRztJQUNJLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxRQUFtQyxFQUFFLEtBQXdDO1FBQzdHLE9BQU8sSUFBSSx5QkFBeUIsQ0FBQyxRQUFRLEVBQUUsS0FBSyxDQUFDLENBQUM7S0FDdkQ7SUFFRDs7T0FFRztJQUNJLE1BQU0sQ0FBQyxlQUFlLENBQUMsUUFBK0IsRUFBRSxLQUFvQztRQUNqRyxPQUFPLElBQUkscUJBQXFCLENBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxDQUFDO0tBQ25EOztBQWJILHdDQW1CQzs7O0FBRUQ7O0dBRUc7QUFDSCxNQUFNLHlCQUEwQixTQUFRLGNBQWM7SUFDcEQsWUFBNkIsUUFBbUMsRUFBbUIsS0FBd0M7UUFDekgsS0FBSyxFQUFFLENBQUM7UUFEbUIsYUFBUSxHQUFSLFFBQVEsQ0FBMkI7UUFBbUIsVUFBSyxHQUFMLEtBQUssQ0FBbUM7S0FFMUg7SUFFRDs7T0FFRztJQUNJLFVBQVUsQ0FBQyxFQUFVLEVBQUUsTUFBaUMsRUFBRSxPQUFvQjs7UUFDbkYsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUM7UUFDL0IsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLFFBQVEsQ0FBQztRQUNoQyxNQUFNLElBQUksU0FBRyxLQUFLLENBQUMsSUFBSSxtQ0FBSSxDQUFDLFFBQVEsS0FBSyxLQUFLLENBQUMsbUJBQW1CLENBQUMs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