@fjall/components-infrastructure 0.95.0 → 0.99.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/app.d.ts +90 -107
- package/dist/lib/app.js +149 -139
- package/dist/lib/config/aws/__t17fixture.d.ts +1 -0
- package/dist/lib/config/aws/__t17fixture.js +3 -0
- package/dist/lib/config/aws/__t17fixtureType.d.ts +2 -0
- package/dist/lib/config/aws/__t17fixtureType.js +1 -0
- package/dist/lib/config/aws/alarmTopic.js +8 -4
- package/dist/lib/config/aws/cloudTrail.js +1 -1
- package/dist/lib/config/aws/disasterRecovery.js +11 -16
- package/dist/lib/config/aws/ecrDefaultImage.d.ts +0 -1
- package/dist/lib/config/aws/ecrDefaultImage.js +13 -23
- package/dist/lib/config/aws/identityCenter.d.ts +10 -3
- package/dist/lib/config/aws/identityCenter.js +101 -37
- package/dist/lib/config/aws/identityCenterGroupMembership.js +8 -2
- package/dist/lib/config/aws/identityCenterMembership.d.ts +11 -0
- package/dist/lib/config/aws/identityCenterMembership.js +61 -0
- package/dist/lib/config/aws/index.d.ts +1 -1
- package/dist/lib/config/aws/index.js +1 -1
- package/dist/lib/config/aws/ipam.js +6 -11
- package/dist/lib/config/aws/oidcConnector.js +5 -1
- package/dist/lib/config/aws/scpPreset.js +4 -1
- package/dist/lib/patterns/aws/_eslint_test_tmp/leak.d.ts +1 -0
- package/dist/lib/patterns/aws/_eslint_test_tmp/leak.js +4 -0
- package/dist/lib/patterns/aws/account.js +7 -8
- package/dist/lib/patterns/aws/apexDomainPattern.js +10 -10
- package/dist/lib/patterns/aws/bastionFactory.d.ts +10 -0
- package/dist/lib/patterns/aws/bastionFactory.js +29 -0
- package/dist/lib/patterns/aws/buildkite.d.ts +2 -2
- package/dist/lib/patterns/aws/buildkite.js +51 -97
- package/dist/lib/patterns/aws/cdn.js +1 -1
- package/dist/lib/patterns/aws/clickhouseDatabase.d.ts +172 -0
- package/dist/lib/patterns/aws/clickhouseDatabase.js +600 -0
- package/dist/lib/patterns/aws/compute.d.ts +4 -6
- package/dist/lib/patterns/aws/compute.js +7 -13
- package/dist/lib/patterns/aws/computeEcs.d.ts +95 -396
- package/dist/lib/patterns/aws/computeEcs.js +880 -46
- package/dist/lib/patterns/aws/computeEcsTypes.d.ts +889 -0
- package/dist/lib/patterns/aws/computeEcsTypes.js +12 -0
- package/dist/lib/patterns/aws/computeLambda.d.ts +0 -5
- package/dist/lib/patterns/aws/computeLambda.js +1 -2
- package/dist/lib/patterns/aws/database.d.ts +50 -8
- package/dist/lib/patterns/aws/database.js +183 -27
- package/dist/lib/patterns/aws/domain.js +8 -7
- package/dist/lib/patterns/aws/index.d.ts +3 -0
- package/dist/lib/patterns/aws/index.js +3 -0
- package/dist/lib/patterns/aws/interfaces/compute.d.ts +13 -1
- package/dist/lib/patterns/aws/interfaces/connector.d.ts +1 -1
- package/dist/lib/patterns/aws/interfaces/connector.js +1 -1
- package/dist/lib/patterns/aws/interfaces/database.d.ts +187 -8
- package/dist/lib/patterns/aws/interfaces/database.js +17 -3
- package/dist/lib/patterns/aws/interfaces/index.d.ts +4 -2
- package/dist/lib/patterns/aws/interfaces/index.js +4 -2
- package/dist/lib/patterns/aws/interfaces/messaging.d.ts +7 -0
- package/dist/lib/patterns/aws/interfaces/migrationContributor.d.ts +47 -0
- package/dist/lib/patterns/aws/interfaces/migrationContributor.js +9 -0
- package/dist/lib/patterns/aws/interfaces/vpcPeer.d.ts +7 -0
- package/dist/lib/patterns/aws/interfaces/vpcPeer.js +1 -0
- package/dist/lib/patterns/aws/messaging.d.ts +66 -10
- package/dist/lib/patterns/aws/messaging.js +115 -20
- package/dist/lib/patterns/aws/network.js +16 -7
- package/dist/lib/patterns/aws/organisation.d.ts +4 -0
- package/dist/lib/patterns/aws/organisation.js +24 -5
- package/dist/lib/patterns/aws/storage.d.ts +1 -2
- package/dist/lib/patterns/aws/storage.js +3 -2
- package/dist/lib/patterns/aws/vpcPeer.d.ts +34 -0
- package/dist/lib/patterns/aws/vpcPeer.js +38 -0
- package/dist/lib/patterns/aws/vpcPeerAccepter.d.ts +29 -0
- package/dist/lib/patterns/aws/vpcPeerAccepter.js +196 -0
- package/dist/lib/resources/aws/analytics/clickhouse.js +25 -7
- package/dist/lib/resources/aws/analytics/clickhouseAlarms.d.ts +49 -0
- package/dist/lib/resources/aws/analytics/clickhouseAlarms.js +140 -0
- package/dist/lib/resources/aws/analytics/clickhouseConstants.d.ts +4 -4
- package/dist/lib/resources/aws/analytics/clickhouseConstants.js +6 -4
- package/dist/lib/resources/aws/analytics/clickhouseTypes.d.ts +12 -0
- package/dist/lib/resources/aws/analytics/clickhouseUserData.d.ts +1 -0
- package/dist/lib/resources/aws/analytics/clickhouseUserData.js +56 -5
- package/dist/lib/resources/aws/analytics/index.d.ts +2 -0
- package/dist/lib/resources/aws/analytics/index.js +1 -0
- package/dist/lib/resources/aws/base/awsStack.js +4 -2
- package/dist/lib/resources/aws/compute/__tmp__/regression-shape.d.ts +2 -0
- package/dist/lib/resources/aws/compute/__tmp__/regression-shape.js +11 -0
- package/dist/lib/resources/aws/compute/asgInlineLifecycleHook.d.ts +52 -0
- package/dist/lib/resources/aws/compute/asgInlineLifecycleHook.js +60 -0
- package/dist/lib/resources/aws/compute/blockDeviceVolume.d.ts +8 -0
- package/dist/lib/resources/aws/compute/blockDeviceVolume.js +10 -0
- package/dist/lib/resources/aws/compute/ec2.d.ts +132 -12
- package/dist/lib/resources/aws/compute/ec2.js +163 -23
- package/dist/lib/resources/aws/compute/ec2GracefulTerminationHandler.d.ts +41 -0
- package/dist/lib/resources/aws/compute/ec2GracefulTerminationHandler.js +194 -0
- package/dist/lib/resources/aws/compute/ec2GracefulTerminationLambda.source.cjs +458 -0
- package/dist/lib/resources/aws/compute/ecs.d.ts +27 -1
- package/dist/lib/resources/aws/compute/ecs.js +42 -2
- package/dist/lib/resources/aws/compute/ecsConstants.d.ts +9 -0
- package/dist/lib/resources/aws/compute/ecsConstants.js +16 -0
- package/dist/lib/resources/aws/compute/ecsImages.js +32 -20
- package/dist/lib/resources/aws/compute/ecsLifecycleHookMigration.d.ts +96 -0
- package/dist/lib/resources/aws/compute/ecsLifecycleHookMigration.js +113 -0
- package/dist/lib/resources/aws/compute/ecsNetworking.d.ts +2 -1
- package/dist/lib/resources/aws/compute/ecsNetworking.js +18 -6
- package/dist/lib/resources/aws/compute/ecsRemoteConnections.d.ts +38 -0
- package/dist/lib/resources/aws/compute/ecsRemoteConnections.js +80 -0
- package/dist/lib/resources/aws/compute/ecsServiceFactory.d.ts +13 -4
- package/dist/lib/resources/aws/compute/ecsServiceFactory.js +155 -33
- package/dist/lib/resources/aws/compute/ecsTaskDefinition.d.ts +31 -1
- package/dist/lib/resources/aws/compute/ecsTaskDefinition.js +110 -6
- package/dist/lib/resources/aws/compute/ecsTypes.d.ts +180 -13
- package/dist/lib/resources/aws/compute/ecsValidation.d.ts +9 -0
- package/dist/lib/resources/aws/compute/ecsValidation.js +63 -0
- package/dist/lib/resources/aws/compute/index.d.ts +2 -0
- package/dist/lib/resources/aws/compute/index.js +2 -0
- package/dist/lib/resources/aws/compute/lambda.d.ts +7 -13
- package/dist/lib/resources/aws/compute/lambda.js +30 -38
- package/dist/lib/resources/aws/compute/lifecycleHookLambda.source.cjs +192 -0
- package/dist/lib/resources/aws/compute/persistentDataVolume.d.ts +104 -0
- package/dist/lib/resources/aws/compute/persistentDataVolume.js +245 -0
- package/dist/lib/resources/aws/compute/persistentDataVolumeLambda.source.cjs +398 -0
- package/dist/lib/resources/aws/compute/samApplication.d.ts +15 -0
- package/dist/lib/resources/aws/compute/samApplication.js +27 -0
- package/dist/lib/resources/aws/database/clickhouseConstants.d.ts +159 -0
- package/dist/lib/resources/aws/database/clickhouseConstants.js +181 -0
- package/dist/lib/resources/aws/database/clickhouseSchemas.d.ts +71 -0
- package/dist/lib/resources/aws/database/clickhouseSchemas.js +157 -0
- package/dist/lib/resources/aws/database/clickhouseSecurityGroup.d.ts +14 -0
- package/dist/lib/resources/aws/database/clickhouseSecurityGroup.js +23 -0
- package/dist/lib/resources/aws/database/clickhouseUserData.d.ts +69 -0
- package/dist/lib/resources/aws/database/clickhouseUserData.js +371 -0
- package/dist/lib/resources/aws/database/clickhouseXmlRenderer.d.ts +56 -0
- package/dist/lib/resources/aws/database/clickhouseXmlRenderer.js +112 -0
- package/dist/lib/resources/aws/database/rdsAurora.d.ts +8 -1
- package/dist/lib/resources/aws/database/rdsAurora.js +42 -32
- package/dist/lib/resources/aws/database/rdsAuroraGlobal.d.ts +15 -2
- package/dist/lib/resources/aws/database/rdsAuroraGlobal.js +39 -43
- package/dist/lib/resources/aws/database/rdsDefaults.d.ts +6 -0
- package/dist/lib/resources/aws/database/rdsDefaults.js +7 -1
- package/dist/lib/resources/aws/database/rdsHelpers.d.ts +3 -3
- package/dist/lib/resources/aws/database/rdsHelpers.js +1 -0
- package/dist/lib/resources/aws/database/rdsInstance.d.ts +8 -1
- package/dist/lib/resources/aws/database/rdsInstance.js +51 -34
- package/dist/lib/resources/aws/database/rdsProxyOutput.d.ts +1 -1
- package/dist/lib/resources/aws/database/rdsProxyOutput.js +1 -1
- package/dist/lib/resources/aws/iam/delegationRole.js +12 -5
- package/dist/lib/resources/aws/iam/identityCenter/groupMembership.d.ts +9 -0
- package/dist/lib/resources/aws/iam/identityCenter/groupMembership.js +12 -0
- package/dist/lib/resources/aws/iam/identityCenter/index.d.ts +1 -0
- package/dist/lib/resources/aws/iam/identityCenter/index.js +1 -0
- package/dist/lib/resources/aws/iam/identityCenter/permissionSet.d.ts +1 -0
- package/dist/lib/resources/aws/iam/identityCenter/permissionSet.js +1 -0
- package/dist/lib/resources/aws/logging/logGroup.d.ts +0 -8
- package/dist/lib/resources/aws/logging/logGroup.js +0 -11
- package/dist/lib/resources/aws/messaging/defaultEventBus.d.ts +7 -0
- package/dist/lib/resources/aws/messaging/defaultEventBus.js +21 -0
- package/dist/lib/resources/aws/messaging/eventBridgeRule.d.ts +96 -0
- package/dist/lib/resources/aws/messaging/eventBridgeRule.js +110 -0
- package/dist/lib/resources/aws/messaging/eventTargets.d.ts +84 -0
- package/dist/lib/resources/aws/messaging/eventTargets.js +152 -0
- package/dist/lib/resources/aws/messaging/eventbridge.d.ts +25 -2
- package/dist/lib/resources/aws/messaging/eventbridge.js +22 -10
- package/dist/lib/resources/aws/messaging/index.d.ts +5 -0
- package/dist/lib/resources/aws/messaging/index.js +2 -0
- package/dist/lib/resources/aws/messaging/schedule.d.ts +118 -0
- package/dist/lib/resources/aws/messaging/schedule.js +64 -0
- package/dist/lib/resources/aws/messaging/sns.d.ts +2 -1
- package/dist/lib/resources/aws/messaging/sqs.d.ts +2 -1
- package/dist/lib/resources/aws/messaging/subscription.d.ts +112 -0
- package/dist/lib/resources/aws/messaging/subscription.js +67 -0
- package/dist/lib/resources/aws/messaging/utils.d.ts +6 -0
- package/dist/lib/resources/aws/messaging/utils.js +10 -0
- package/dist/lib/resources/aws/monitoring/clickhouseAlarms.d.ts +60 -0
- package/dist/lib/resources/aws/monitoring/clickhouseAlarms.js +139 -0
- package/dist/lib/resources/aws/monitoring/index.d.ts +2 -0
- package/dist/lib/resources/aws/monitoring/index.js +2 -0
- package/dist/lib/resources/aws/monitoring/scheduleAlarms.d.ts +47 -0
- package/dist/lib/resources/aws/monitoring/scheduleAlarms.js +106 -0
- package/dist/lib/resources/aws/networking/crossAccountDelegationRecord.js +6 -3
- package/dist/lib/resources/aws/networking/crossAccountReturnRoutes.d.ts +40 -0
- package/dist/lib/resources/aws/networking/crossAccountReturnRoutes.js +158 -0
- package/dist/lib/resources/aws/networking/dnsRecord/dnsRecordBase.js +7 -4
- package/dist/lib/resources/aws/networking/domainCertificate.d.ts +2 -2
- package/dist/lib/resources/aws/networking/domainCertificate.js +6 -3
- package/dist/lib/resources/aws/networking/hostedZone.js +6 -4
- package/dist/lib/resources/aws/networking/index.d.ts +3 -0
- package/dist/lib/resources/aws/networking/index.js +3 -0
- package/dist/lib/resources/aws/networking/serviceDiscovery.d.ts +96 -0
- package/dist/lib/resources/aws/networking/serviceDiscovery.js +96 -0
- package/dist/lib/resources/aws/networking/vpc.d.ts +4 -1
- package/dist/lib/resources/aws/networking/vpc.js +10 -3
- package/dist/lib/resources/aws/networking/vpcPeeringAccepterRole.d.ts +18 -0
- package/dist/lib/resources/aws/networking/vpcPeeringAccepterRole.js +61 -0
- package/dist/lib/resources/aws/networking/vpcPeeringConnection.d.ts +49 -0
- package/dist/lib/resources/aws/networking/vpcPeeringConnection.js +106 -0
- package/dist/lib/resources/aws/organisation/costAllocationTagActivator.d.ts +16 -5
- package/dist/lib/resources/aws/organisation/costAllocationTagActivator.js +17 -3
- package/dist/lib/resources/aws/organisation/index.d.ts +1 -1
- package/dist/lib/resources/aws/organisation/organisationPolicy.d.ts +2 -0
- package/dist/lib/resources/aws/organisation/organisationPolicy.js +3 -2
- package/dist/lib/resources/aws/secrets/secret.d.ts +7 -0
- package/dist/lib/resources/aws/secrets/secret.js +4 -3
- package/dist/lib/resources/aws/storage/bucketDeployment.d.ts +16 -0
- package/dist/lib/resources/aws/storage/bucketDeployment.js +17 -0
- package/dist/lib/resources/aws/storage/ecr.js +5 -5
- package/dist/lib/resources/aws/storage/index.d.ts +1 -0
- package/dist/lib/resources/aws/storage/index.js +1 -0
- package/dist/lib/resources/aws/storage/s3.js +10 -3
- package/dist/lib/resources/aws/utilities/customResource.js +18 -9
- package/dist/lib/synth_dump.d.ts +1 -0
- package/dist/lib/synth_dump.js +42 -0
- package/dist/lib/utils/bastionFactory.d.ts +10 -0
- package/dist/lib/utils/bastionFactory.js +29 -0
- package/dist/lib/utils/capitaliseString.d.ts +1 -1
- package/dist/lib/utils/capitaliseString.js +1 -1
- package/dist/lib/utils/cdkContext.d.ts +10 -0
- package/dist/lib/utils/cdkContext.js +13 -0
- package/dist/lib/utils/connections.d.ts +7 -1
- package/dist/lib/utils/connections.js +21 -0
- package/dist/lib/utils/connector.d.ts +30 -2
- package/dist/lib/utils/connector.js +6 -1
- package/dist/lib/utils/costAllocationTags.d.ts +15 -0
- package/dist/lib/utils/costAllocationTags.js +16 -0
- package/dist/lib/utils/databaseTypes.d.ts +14 -0
- package/dist/lib/utils/getConfig.d.ts +2 -0
- package/dist/lib/utils/getConfig.js +2 -0
- package/dist/lib/utils/index.d.ts +4 -0
- package/dist/lib/utils/index.js +4 -0
- package/dist/lib/utils/manifestWriter.d.ts +6 -89
- package/dist/lib/utils/manifestWriter.js +36 -23
- package/dist/lib/utils/migrationVersionResolvers.d.ts +2 -0
- package/dist/lib/utils/migrationVersionResolvers.js +2 -0
- package/dist/lib/utils/orgConfigParser.js +2 -1
- package/dist/lib/utils/resolveAlertsTopic.d.ts +14 -0
- package/dist/lib/utils/resolveAlertsTopic.js +30 -0
- package/dist/lib/utils/validationLogger.js +6 -3
- package/dist/lib/utils/vpcPeerInterface.d.ts +22 -0
- package/dist/lib/utils/vpcPeerInterface.js +1 -0
- package/package.json +22 -18
|
@@ -1,14 +1,29 @@
|
|
|
1
|
-
import { FargateService, Ec2Service, PropagatedTagSource, PlacementStrategy, AsgCapacityProvider, EcsOptimizedImage, AmiHardwareType } from "aws-cdk-lib/aws-ecs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { FargateService, Ec2Service, PropagatedTagSource, PlacementStrategy, AsgCapacityProvider, EcsOptimizedImage, AmiHardwareType, NetworkMode } from "aws-cdk-lib/aws-ecs";
|
|
2
|
+
import { Peer, Port, SubnetType, UserData } from "aws-cdk-lib/aws-ec2";
|
|
3
|
+
import { ServicePrincipal } from "aws-cdk-lib/aws-iam";
|
|
4
|
+
import { Role } from "../iam/role.js";
|
|
5
|
+
import { CfnOutput, Duration, Token } from "aws-cdk-lib";
|
|
4
6
|
import { PredefinedMetric, ScalableTarget, ServiceNamespace, TargetTrackingScalingPolicy } from "aws-cdk-lib/aws-applicationautoscaling";
|
|
5
|
-
import {
|
|
7
|
+
import { Monitoring } from "aws-cdk-lib/aws-autoscaling";
|
|
6
8
|
import { SecurityGroup } from "../networking/securityGroup.js";
|
|
9
|
+
import { Ec2Instance } from "./ec2.js";
|
|
7
10
|
import { vpcHasNatGateways } from "../../../utils/vpcUtils.js";
|
|
8
11
|
import { toPascalCase } from "../../../utils/capitaliseString.js";
|
|
9
|
-
import { DEFAULT_EC2_INSTANCE_TYPE, DEFAULT_WARM_POOL_MIN_SIZE, DEFAULT_WARM_POOL_REUSE_ON_SCALE_IN, inferAmiHardwareType } from "./ecsConstants.js";
|
|
12
|
+
import { DEFAULT_EC2_INSTANCE_TYPE, DEFAULT_WARM_POOL_MIN_SIZE, DEFAULT_WARM_POOL_REUSE_ON_SCALE_IN, DEFAULT_HEALTH_CHECK_GRACE_SECONDS, DEFAULT_MIN_HEALTHY_PERCENT, DEFAULT_MAX_HEALTHY_PERCENT, DEFAULT_DESIRED_COUNT, inferAmiHardwareType } from "./ecsConstants.js";
|
|
10
13
|
import { ScalingType } from "./ecsTypes.js";
|
|
11
14
|
import { isServiceFargate, isServiceEc2 } from "./ecsTaskDefinition.js";
|
|
15
|
+
/**
|
|
16
|
+
* Resolves the user's `circuitBreaker` config to the CDK
|
|
17
|
+
* `DeploymentCircuitBreaker` shape. `undefined` resolves to the safe default
|
|
18
|
+
* `{ enable: true, rollback: true }`; `false` resolves to `undefined` (CDK
|
|
19
|
+
* omits the breaker block from CFN output entirely).
|
|
20
|
+
*/
|
|
21
|
+
export function resolveCircuitBreaker(config) {
|
|
22
|
+
if (config === false)
|
|
23
|
+
return undefined;
|
|
24
|
+
const rollback = config?.rollback ?? true;
|
|
25
|
+
return { enable: true, rollback };
|
|
26
|
+
}
|
|
12
27
|
/**
|
|
13
28
|
* Generates a unique key for EC2 config so services with matching
|
|
14
29
|
* configurations share an ASG.
|
|
@@ -22,7 +37,26 @@ export function getEc2ConfigKey(ec2Config) {
|
|
|
22
37
|
const warmPoolKey = ec2Config.warmPool
|
|
23
38
|
? `wp${ec2Config.warmPool.minSize ?? DEFAULT_WARM_POOL_MIN_SIZE}-${ec2Config.warmPool.reuseOnScaleIn ?? DEFAULT_WARM_POOL_REUSE_ON_SCALE_IN}`
|
|
24
39
|
: "nowp";
|
|
25
|
-
|
|
40
|
+
const baseKey = `${instanceType}-${amiHardwareType}-${warmPoolKey}`;
|
|
41
|
+
// PDV services are implicit singletons — sharing an ASG would let two tasks race for the same EBS volume.
|
|
42
|
+
const pdv = ec2Config.persistentDataVolume;
|
|
43
|
+
const extras = [];
|
|
44
|
+
if (pdv !== undefined) {
|
|
45
|
+
extras.push(`pdv-${pdv.deviceName}-${pdv.sizeGb}-${stableAzSegment(pdv.availabilityZone)}`);
|
|
46
|
+
}
|
|
47
|
+
// Serialise actual AZ names — `az${length}` would let services pinned to different AZs collide on `az1`.
|
|
48
|
+
// CDK Tokens (env-agnostic stacks) substitute a stable sentinel to keep logical IDs deterministic.
|
|
49
|
+
if (ec2Config.availabilityZones !== undefined) {
|
|
50
|
+
const azKey = [...ec2Config.availabilityZones]
|
|
51
|
+
.map(stableAzSegment)
|
|
52
|
+
.sort()
|
|
53
|
+
.join(",");
|
|
54
|
+
extras.push(`az-${azKey}`);
|
|
55
|
+
}
|
|
56
|
+
return extras.length === 0 ? baseKey : `${baseKey}-${extras.join("-")}`;
|
|
57
|
+
}
|
|
58
|
+
function stableAzSegment(az) {
|
|
59
|
+
return Token.isUnresolved(az) ? "synthAz" : az;
|
|
26
60
|
}
|
|
27
61
|
/**
|
|
28
62
|
* Gets or creates an ASG capacity provider for an EC2-backed service.
|
|
@@ -46,10 +80,11 @@ export function getOrCreateAsgCapacityProvider(ctx, serviceProps, state) {
|
|
|
46
80
|
: inferAmiHardwareType(instanceType);
|
|
47
81
|
const minCapacity = ec2Config.minCapacity ?? 2;
|
|
48
82
|
const maxCapacity = ec2Config.maxCapacity ?? 3;
|
|
49
|
-
const asgSecurityGroup =
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
83
|
+
const asgSecurityGroup = ctx.props.cluster?.securityGroup ??
|
|
84
|
+
new SecurityGroup(ctx.scope, `${safeKey}AsgSecurityGroup`, {
|
|
85
|
+
vpc: ctx.cluster.vpc,
|
|
86
|
+
description: `Security group for ${key} auto scaling group`
|
|
87
|
+
});
|
|
53
88
|
if (ctx.directAccessEnabled) {
|
|
54
89
|
for (const service of ctx.props.services) {
|
|
55
90
|
if (isServiceEc2(service)) {
|
|
@@ -62,29 +97,61 @@ export function getOrCreateAsgCapacityProvider(ctx, serviceProps, state) {
|
|
|
62
97
|
}
|
|
63
98
|
}
|
|
64
99
|
const hasNat = vpcHasNatGateways(ctx.cluster.vpc);
|
|
65
|
-
const
|
|
66
|
-
|
|
100
|
+
const resolvedWarmPool = ec2Config.warmPool
|
|
101
|
+
? {
|
|
102
|
+
minSize: ec2Config.warmPool.minSize ?? DEFAULT_WARM_POOL_MIN_SIZE,
|
|
103
|
+
reuseOnScaleIn: ec2Config.warmPool.reuseOnScaleIn ??
|
|
104
|
+
DEFAULT_WARM_POOL_REUSE_ON_SCALE_IN
|
|
105
|
+
}
|
|
106
|
+
: undefined;
|
|
107
|
+
// userData + role must be set on the LaunchTemplate or AsgCapacityProvider
|
|
108
|
+
// throws at synth (ProvidedLaunchTemplateExposeUser/ExposeDefine).
|
|
109
|
+
const instanceRole = new Role(ctx.scope, `${safeKey}InstanceRole`, {
|
|
110
|
+
assumedBy: new ServicePrincipal("ec2.amazonaws.com"),
|
|
111
|
+
description: `EC2 instance role for ${key} ECS capacity`
|
|
112
|
+
});
|
|
113
|
+
const ec2Instance = new Ec2Instance(ctx.scope, `${safeKey}Ec2Instance`, {
|
|
114
|
+
serviceName: `${ctx.props.clusterName}${safeKey}`,
|
|
67
115
|
vpc: ctx.cluster.vpc,
|
|
68
116
|
vpcSubnets: {
|
|
69
|
-
subnetType: hasNat ? SubnetType.PRIVATE_WITH_EGRESS : SubnetType.PUBLIC
|
|
117
|
+
subnetType: hasNat ? SubnetType.PRIVATE_WITH_EGRESS : SubnetType.PUBLIC,
|
|
118
|
+
...(ec2Config.availabilityZones !== undefined && {
|
|
119
|
+
availabilityZones: ec2Config.availabilityZones
|
|
120
|
+
})
|
|
70
121
|
},
|
|
71
122
|
securityGroup: asgSecurityGroup,
|
|
72
123
|
minCapacity,
|
|
73
124
|
maxCapacity,
|
|
74
|
-
instanceType
|
|
125
|
+
instanceType,
|
|
126
|
+
machineImage: ec2Config.machineImage ??
|
|
127
|
+
EcsOptimizedImage.amazonLinux2023(amiHardwareType),
|
|
128
|
+
userData: ec2Config.userData ?? UserData.forLinux(),
|
|
129
|
+
role: instanceRole,
|
|
130
|
+
instanceMonitoring: ec2Config.instanceMonitoring ?? Monitoring.BASIC,
|
|
75
131
|
capacityRebalance: true,
|
|
76
|
-
|
|
77
|
-
|
|
132
|
+
ecsClusterArn: ctx.cluster.clusterArn,
|
|
133
|
+
...(ec2Config.desiredCapacity !== undefined && {
|
|
134
|
+
desiredCapacity: ec2Config.desiredCapacity
|
|
135
|
+
}),
|
|
136
|
+
...(ec2Config.blockDevices !== undefined && {
|
|
137
|
+
blockDevices: ec2Config.blockDevices
|
|
138
|
+
}),
|
|
139
|
+
...(ec2Config.associatePublicIpAddress !== undefined && {
|
|
140
|
+
associatePublicIpAddress: ec2Config.associatePublicIpAddress
|
|
141
|
+
}),
|
|
142
|
+
...(resolvedWarmPool !== undefined && { warmPool: resolvedWarmPool }),
|
|
143
|
+
...(ec2Config.persistentDataVolume !== undefined && {
|
|
144
|
+
persistentDataVolume: ec2Config.persistentDataVolume
|
|
145
|
+
}),
|
|
146
|
+
...(ec2Config.tags !== undefined && { tags: ec2Config.tags })
|
|
78
147
|
});
|
|
79
|
-
|
|
80
|
-
asg.addWarmPool({
|
|
81
|
-
minSize: ec2Config.warmPool.minSize ?? DEFAULT_WARM_POOL_MIN_SIZE,
|
|
82
|
-
reuseOnScaleIn: ec2Config.warmPool.reuseOnScaleIn ?? DEFAULT_WARM_POOL_REUSE_ON_SCALE_IN
|
|
83
|
-
});
|
|
84
|
-
}
|
|
148
|
+
const asg = ec2Instance.getAutoScalingGroup();
|
|
85
149
|
const provider = new AsgCapacityProvider(ctx.scope, `${safeKey}AsgCapacityProvider`, {
|
|
86
150
|
autoScalingGroup: asg,
|
|
87
151
|
enableManagedDraining: true,
|
|
152
|
+
// MTP's ProtectedFromScaleIn flag does NOT clear on CP deletion, so
|
|
153
|
+
// CFN rollback wedges on a stranded protected instance. The drain
|
|
154
|
+
// path is Ec2GracefulTerminationHandler instead.
|
|
88
155
|
enableManagedTerminationProtection: false
|
|
89
156
|
});
|
|
90
157
|
ctx.cluster.addAsgCapacityProvider(provider);
|
|
@@ -101,8 +168,13 @@ export function getOrCreateAsgCapacityProvider(ctx, serviceProps, state) {
|
|
|
101
168
|
* Creates a Fargate or EC2 service and emits a CfnOutput for its ARN.
|
|
102
169
|
*/
|
|
103
170
|
export function createService(ctx, serviceName, serviceProps, taskDefinition, asgState) {
|
|
104
|
-
const desiredCount = serviceProps.desiredCount ??
|
|
171
|
+
const desiredCount = serviceProps.desiredCount ?? DEFAULT_DESIRED_COUNT;
|
|
105
172
|
let service;
|
|
173
|
+
// CDK's Ec2Service rejects `securityGroups` unless networkMode is AWS_VPC
|
|
174
|
+
// (HOST/BRIDGE share the instance ENI). FargateService is always awsvpc.
|
|
175
|
+
const explicitSecurityGroups = serviceProps.securityGroups && serviceProps.securityGroups.length > 0
|
|
176
|
+
? serviceProps.securityGroups
|
|
177
|
+
: undefined;
|
|
106
178
|
if (isServiceFargate(serviceProps)) {
|
|
107
179
|
const hasNat = vpcHasNatGateways(ctx.cluster.vpc);
|
|
108
180
|
service = new FargateService(ctx.scope, `${serviceName}Service`, {
|
|
@@ -121,12 +193,17 @@ export function createService(ctx, serviceName, serviceProps, taskDefinition, as
|
|
|
121
193
|
}
|
|
122
194
|
],
|
|
123
195
|
propagateTags: PropagatedTagSource.SERVICE,
|
|
124
|
-
circuitBreaker:
|
|
196
|
+
circuitBreaker: resolveCircuitBreaker(serviceProps.circuitBreaker),
|
|
125
197
|
enableECSManagedTags: true,
|
|
126
198
|
enableExecuteCommand: true,
|
|
127
|
-
healthCheckGracePeriod: Duration.seconds(
|
|
128
|
-
minHealthyPercent:
|
|
129
|
-
|
|
199
|
+
healthCheckGracePeriod: Duration.seconds(DEFAULT_HEALTH_CHECK_GRACE_SECONDS),
|
|
200
|
+
minHealthyPercent: serviceProps.deployment?.minHealthyPercent ??
|
|
201
|
+
DEFAULT_MIN_HEALTHY_PERCENT,
|
|
202
|
+
maxHealthyPercent: serviceProps.deployment?.maxHealthyPercent ??
|
|
203
|
+
DEFAULT_MAX_HEALTHY_PERCENT,
|
|
204
|
+
...(explicitSecurityGroups !== undefined && {
|
|
205
|
+
securityGroups: explicitSecurityGroups
|
|
206
|
+
})
|
|
130
207
|
});
|
|
131
208
|
}
|
|
132
209
|
else {
|
|
@@ -143,15 +220,59 @@ export function createService(ctx, serviceName, serviceProps, taskDefinition, as
|
|
|
143
220
|
}
|
|
144
221
|
],
|
|
145
222
|
propagateTags: PropagatedTagSource.SERVICE,
|
|
146
|
-
circuitBreaker:
|
|
223
|
+
circuitBreaker: resolveCircuitBreaker(serviceProps.circuitBreaker),
|
|
147
224
|
placementStrategies: [PlacementStrategy.spreadAcrossInstances()],
|
|
148
225
|
enableECSManagedTags: true,
|
|
149
226
|
enableExecuteCommand: true,
|
|
150
|
-
healthCheckGracePeriod: Duration.seconds(
|
|
151
|
-
minHealthyPercent:
|
|
152
|
-
|
|
227
|
+
healthCheckGracePeriod: Duration.seconds(DEFAULT_HEALTH_CHECK_GRACE_SECONDS),
|
|
228
|
+
minHealthyPercent: serviceProps.deployment?.minHealthyPercent ??
|
|
229
|
+
DEFAULT_MIN_HEALTHY_PERCENT,
|
|
230
|
+
maxHealthyPercent: serviceProps.deployment?.maxHealthyPercent ??
|
|
231
|
+
DEFAULT_MAX_HEALTHY_PERCENT,
|
|
232
|
+
...(explicitSecurityGroups !== undefined && {
|
|
233
|
+
securityGroups: explicitSecurityGroups
|
|
234
|
+
})
|
|
153
235
|
});
|
|
154
236
|
}
|
|
237
|
+
if (serviceProps.cloudMapService !== undefined) {
|
|
238
|
+
const isSrv = serviceProps.cloudMapDnsRecordType === "SRV";
|
|
239
|
+
const isHostOrBridge = taskDefinition.networkMode === NetworkMode.HOST ||
|
|
240
|
+
taskDefinition.networkMode === NetworkMode.BRIDGE;
|
|
241
|
+
// AWS forbids A-typed serviceRegistries under HOST/BRIDGE networkMode.
|
|
242
|
+
if (isHostOrBridge && !isSrv) {
|
|
243
|
+
throw new Error(`Service '${serviceName}': cloudMapDnsRecordType '${serviceProps.cloudMapDnsRecordType ?? "A"}' ` +
|
|
244
|
+
`is not supported with networkMode '${taskDefinition.networkMode}'. ` +
|
|
245
|
+
'Use dnsRecordType: "SRV" or change networkMode to AWS_VPC.');
|
|
246
|
+
}
|
|
247
|
+
const primaryWithPort = serviceProps.containers.find((c) => c.port !== undefined);
|
|
248
|
+
const primaryWithMappings = serviceProps.containers.find((c) => c.portMappings !== undefined &&
|
|
249
|
+
c.portMappings[0]?.containerPort !== undefined);
|
|
250
|
+
const primary = primaryWithPort ?? primaryWithMappings;
|
|
251
|
+
const primaryPort = primaryWithPort?.port ??
|
|
252
|
+
primaryWithMappings?.portMappings?.[0]?.containerPort;
|
|
253
|
+
if (isSrv && (primary === undefined || primaryPort === undefined)) {
|
|
254
|
+
throw new Error(`Service '${serviceName}': cloudMapDnsRecordType: "SRV" requires at ` +
|
|
255
|
+
"least one container with a port — SRV records carry the published " +
|
|
256
|
+
"port and cannot be registered without one.");
|
|
257
|
+
}
|
|
258
|
+
if (primary !== undefined && primaryPort !== undefined) {
|
|
259
|
+
const containerDef = taskDefinition.findContainer(primary.name);
|
|
260
|
+
if (containerDef === undefined) {
|
|
261
|
+
throw new Error(`Service '${serviceName}': could not resolve container '${primary.name}' ` +
|
|
262
|
+
"from task definition for Cloud Map registration.");
|
|
263
|
+
}
|
|
264
|
+
service.associateCloudMapService({
|
|
265
|
+
service: serviceProps.cloudMapService,
|
|
266
|
+
container: containerDef,
|
|
267
|
+
containerPort: primaryPort
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
service.associateCloudMapService({
|
|
272
|
+
service: serviceProps.cloudMapService
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
155
276
|
new CfnOutput(ctx.scope, `${ctx.outputName}${toPascalCase(serviceName)}ServiceArn`, {
|
|
156
277
|
key: `${ctx.outputName}${toPascalCase(serviceName)}ServiceArn`,
|
|
157
278
|
exportName: `${ctx.props.clusterName}${serviceName}ServiceArn`,
|
|
@@ -164,12 +285,13 @@ export function createService(ctx, serviceName, serviceProps, taskDefinition, as
|
|
|
164
285
|
* Adds auto-scaling to an ECS service based on CPU or memory utilisation.
|
|
165
286
|
*/
|
|
166
287
|
export function addServiceScaling(ctx, serviceName, serviceProps, service) {
|
|
288
|
+
const desiredCount = serviceProps.desiredCount ?? DEFAULT_DESIRED_COUNT;
|
|
167
289
|
const scalableTarget = new ScalableTarget(ctx.scope, `${serviceName}ScalableTarget`, {
|
|
168
290
|
serviceNamespace: ServiceNamespace.ECS,
|
|
169
291
|
resourceId: `service/${ctx.cluster.clusterName}/${service.serviceName}`,
|
|
170
292
|
scalableDimension: "ecs:service:DesiredCount",
|
|
171
|
-
minCapacity: serviceProps.minCapacity ??
|
|
172
|
-
maxCapacity: serviceProps.maxCapacity ??
|
|
293
|
+
minCapacity: serviceProps.minCapacity ?? desiredCount,
|
|
294
|
+
maxCapacity: serviceProps.maxCapacity ?? Math.max(desiredCount + 1, 3)
|
|
173
295
|
});
|
|
174
296
|
return new TargetTrackingScalingPolicy(ctx.scope, `${serviceName}ScalingPolicy`, {
|
|
175
297
|
scalingTarget: scalableTarget,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { FargateTaskDefinition, Ec2TaskDefinition, type ContainerDefinition } from "aws-cdk-lib/aws-ecs";
|
|
1
|
+
import { FargateTaskDefinition, Ec2TaskDefinition, NetworkMode, type ContainerDefinition } from "aws-cdk-lib/aws-ecs";
|
|
2
|
+
import type { Construct } from "constructs";
|
|
2
3
|
import { type Role } from "aws-cdk-lib/aws-iam";
|
|
3
4
|
import type { EcsConstructContext } from "./ecsContext.js";
|
|
4
5
|
import type { EcsClusterProps, EcsServiceProps, EcsCapacityProvider } from "./ecsTypes.js";
|
|
@@ -24,6 +25,35 @@ export declare function collectSecretsManagerSecretNames(props: EcsClusterProps,
|
|
|
24
25
|
*/
|
|
25
26
|
export declare function deriveSsmSecretsPath(props: EcsClusterProps, serviceName: string, explicitPath?: string): string;
|
|
26
27
|
export declare function createTaskDefinition(ctx: EcsConstructContext, serviceName: string, serviceProps: EcsServiceProps, executionRole: Role, taskRole: Role): FargateTaskDefinition | Ec2TaskDefinition;
|
|
28
|
+
/**
|
|
29
|
+
* Routing point for `Ec2TaskDefinition`s used by EventBridge-triggered scheduled
|
|
30
|
+
* tasks (per `EcsClusterConfig.scheduledTasks`). Pattern-layer callers MUST
|
|
31
|
+
* reach `Ec2TaskDefinition` through this wrapper rather than instantiating the
|
|
32
|
+
* raw CDK class — a future SOC2-relevant default (encryption, retention,
|
|
33
|
+
* uniform tags) added here propagates to every scheduled-task task def at once.
|
|
34
|
+
*
|
|
35
|
+
* Compare with `createTaskDefinition()` above, which is the per-service path;
|
|
36
|
+
* this is the per-schedule path and intentionally kept narrow (no execution /
|
|
37
|
+
* task roles — scheduled tasks use task-definition defaults).
|
|
38
|
+
*/
|
|
39
|
+
export declare function createScheduledTaskDefinition(scope: Construct, id: string, props: {
|
|
40
|
+
family: string;
|
|
41
|
+
networkMode?: NetworkMode;
|
|
42
|
+
}): Ec2TaskDefinition;
|
|
43
|
+
/**
|
|
44
|
+
* Routing point for `FargateTaskDefinition`s used by the lifecycle-hook
|
|
45
|
+
* migration runner when `migrations.separateTaskDef` is set. Synthesises a
|
|
46
|
+
* dedicated Fargate task definition with caller-supplied CPU/memory and the
|
|
47
|
+
* supplied execution + task roles. Runtime platform pinned to ARM64/Linux to
|
|
48
|
+
* match the service task def default.
|
|
49
|
+
*/
|
|
50
|
+
export declare function createMigrationTaskDefinition(scope: Construct, id: string, props: {
|
|
51
|
+
family: string;
|
|
52
|
+
cpu: number;
|
|
53
|
+
memoryLimitMiB: number;
|
|
54
|
+
executionRole: Role;
|
|
55
|
+
taskRole: Role;
|
|
56
|
+
}): FargateTaskDefinition;
|
|
27
57
|
export declare function addContainersToTask(ctx: EcsConstructContext, serviceName: string, serviceProps: EcsServiceProps, taskDefinition: FargateTaskDefinition | Ec2TaskDefinition): {
|
|
28
58
|
containers: ContainerDefinition[];
|
|
29
59
|
primaryContainer?: ContainerDefinition;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { AwsLogDriver, FargateTaskDefinition, Ec2TaskDefinition, NetworkMode, CpuArchitecture, OperatingSystemFamily } from "aws-cdk-lib/aws-ecs";
|
|
1
|
+
import { AwsLogDriver, ContainerDependencyCondition, FargateTaskDefinition, Ec2TaskDefinition, NetworkMode, CpuArchitecture, OperatingSystemFamily } from "aws-cdk-lib/aws-ecs";
|
|
2
2
|
import { Duration } from "aws-cdk-lib";
|
|
3
3
|
import { Secret as EcsSecret } from "aws-cdk-lib/aws-ecs";
|
|
4
4
|
import { Secret } from "aws-cdk-lib/aws-secretsmanager";
|
|
5
5
|
import { StringParameter } from "aws-cdk-lib/aws-ssm";
|
|
6
|
+
import { resolveOrgId } from "../../../utils/cdkContext.js";
|
|
6
7
|
import { validateSsmPathComponent } from "./ecsValidation.js";
|
|
7
|
-
import { DEFAULT_LOG_RETENTION_DAYS } from "./ecsConstants.js";
|
|
8
|
+
import { DEFAULT_LOG_RETENTION_DAYS, DEFAULT_FARGATE_CPU, DEFAULT_FARGATE_MEMORY_MIB, DEFAULT_EC2_CONTAINER_MEMORY_MIB } from "./ecsConstants.js";
|
|
8
9
|
import { getContainerImage } from "./ecsImages.js";
|
|
10
|
+
import { resolveRemoteConnections } from "./ecsRemoteConnections.js";
|
|
9
11
|
// Re-export extracted functions so existing consumers are not broken
|
|
10
12
|
export { createExecutionRole, createTaskRole } from "./ecsRoles.js";
|
|
11
13
|
export { getContainerImage } from "./ecsImages.js";
|
|
@@ -64,8 +66,8 @@ export function deriveSsmSecretsPath(props, serviceName, explicitPath) {
|
|
|
64
66
|
return `/${appName}/${props.clusterName}/${serviceName}`;
|
|
65
67
|
}
|
|
66
68
|
export function createTaskDefinition(ctx, serviceName, serviceProps, executionRole, taskRole) {
|
|
67
|
-
const cpu = serviceProps.cpu ??
|
|
68
|
-
const memoryLimitMiB = serviceProps.memoryLimitMiB ??
|
|
69
|
+
const cpu = serviceProps.cpu ?? DEFAULT_FARGATE_CPU;
|
|
70
|
+
const memoryLimitMiB = serviceProps.memoryLimitMiB ?? DEFAULT_FARGATE_MEMORY_MIB;
|
|
69
71
|
if (isServiceFargate(serviceProps)) {
|
|
70
72
|
return new FargateTaskDefinition(ctx.scope, `${serviceName}TaskDefinition`, {
|
|
71
73
|
family: `${ctx.props.clusterName}-${serviceName}`,
|
|
@@ -80,17 +82,66 @@ export function createTaskDefinition(ctx, serviceName, serviceProps, executionRo
|
|
|
80
82
|
});
|
|
81
83
|
}
|
|
82
84
|
else {
|
|
85
|
+
const networkMode = serviceProps.networkMode ??
|
|
86
|
+
(ctx.directAccessEnabled ? NetworkMode.HOST : NetworkMode.AWS_VPC);
|
|
83
87
|
return new Ec2TaskDefinition(ctx.scope, `${serviceName}TaskDefinition`, {
|
|
84
88
|
family: `${ctx.props.clusterName}-${serviceName}`,
|
|
85
89
|
executionRole,
|
|
86
90
|
taskRole,
|
|
87
|
-
...(
|
|
91
|
+
...(networkMode !== undefined && { networkMode })
|
|
88
92
|
});
|
|
89
93
|
}
|
|
90
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Routing point for `Ec2TaskDefinition`s used by EventBridge-triggered scheduled
|
|
97
|
+
* tasks (per `EcsClusterConfig.scheduledTasks`). Pattern-layer callers MUST
|
|
98
|
+
* reach `Ec2TaskDefinition` through this wrapper rather than instantiating the
|
|
99
|
+
* raw CDK class — a future SOC2-relevant default (encryption, retention,
|
|
100
|
+
* uniform tags) added here propagates to every scheduled-task task def at once.
|
|
101
|
+
*
|
|
102
|
+
* Compare with `createTaskDefinition()` above, which is the per-service path;
|
|
103
|
+
* this is the per-schedule path and intentionally kept narrow (no execution /
|
|
104
|
+
* task roles — scheduled tasks use task-definition defaults).
|
|
105
|
+
*/
|
|
106
|
+
export function createScheduledTaskDefinition(scope, id, props) {
|
|
107
|
+
return new Ec2TaskDefinition(scope, id, {
|
|
108
|
+
family: props.family,
|
|
109
|
+
...(props.networkMode !== undefined && { networkMode: props.networkMode })
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Routing point for `FargateTaskDefinition`s used by the lifecycle-hook
|
|
114
|
+
* migration runner when `migrations.separateTaskDef` is set. Synthesises a
|
|
115
|
+
* dedicated Fargate task definition with caller-supplied CPU/memory and the
|
|
116
|
+
* supplied execution + task roles. Runtime platform pinned to ARM64/Linux to
|
|
117
|
+
* match the service task def default.
|
|
118
|
+
*/
|
|
119
|
+
export function createMigrationTaskDefinition(scope, id, props) {
|
|
120
|
+
return new FargateTaskDefinition(scope, id, {
|
|
121
|
+
family: props.family,
|
|
122
|
+
cpu: props.cpu,
|
|
123
|
+
memoryLimitMiB: props.memoryLimitMiB,
|
|
124
|
+
executionRole: props.executionRole,
|
|
125
|
+
taskRole: props.taskRole,
|
|
126
|
+
runtimePlatform: {
|
|
127
|
+
cpuArchitecture: CpuArchitecture.ARM64,
|
|
128
|
+
operatingSystemFamily: OperatingSystemFamily.LINUX
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
const CONTAINER_DEPENDENCY_CONDITIONS = {
|
|
133
|
+
START: ContainerDependencyCondition.START,
|
|
134
|
+
COMPLETE: ContainerDependencyCondition.COMPLETE,
|
|
135
|
+
SUCCESS: ContainerDependencyCondition.SUCCESS,
|
|
136
|
+
HEALTHY: ContainerDependencyCondition.HEALTHY
|
|
137
|
+
};
|
|
91
138
|
export function addContainersToTask(ctx, serviceName, serviceProps, taskDefinition) {
|
|
92
139
|
const containers = [];
|
|
140
|
+
const containerByName = new Map();
|
|
93
141
|
let primaryContainer;
|
|
142
|
+
const orgId = resolveOrgId(ctx.scope.node);
|
|
143
|
+
const remoteEnvByService = resolveRemoteConnections([serviceProps], ctx.scope, orgId);
|
|
144
|
+
const remoteEnv = remoteEnvByService[serviceName] ?? {};
|
|
94
145
|
for (const containerConfig of serviceProps.containers) {
|
|
95
146
|
const image = getContainerImage(ctx, serviceName, containerConfig, serviceProps);
|
|
96
147
|
const isFirstWithPort = !primaryContainer && containerConfig.port !== undefined;
|
|
@@ -125,8 +176,11 @@ export function addContainersToTask(ctx, serviceName, serviceProps, taskDefiniti
|
|
|
125
176
|
streamPrefix: `/ecs/${ctx.props.clusterName}/${serviceName}`,
|
|
126
177
|
logRetention: DEFAULT_LOG_RETENTION_DAYS
|
|
127
178
|
}),
|
|
179
|
+
// remoteEnv (cross-app `${PREFIX}_HOST/_PORT`) intentionally overrides user
|
|
180
|
+
// values — a stale manual setting must not mask the resolved peer.
|
|
128
181
|
environment: {
|
|
129
182
|
...containerConfig.environment,
|
|
183
|
+
...remoteEnv,
|
|
130
184
|
...(containerConfig.port
|
|
131
185
|
? { PORT: String(containerConfig.port) }
|
|
132
186
|
: {})
|
|
@@ -150,19 +204,69 @@ export function addContainersToTask(ctx, serviceName, serviceProps, taskDefiniti
|
|
|
150
204
|
: undefined
|
|
151
205
|
}
|
|
152
206
|
: undefined,
|
|
207
|
+
stopTimeout: containerConfig.stopTimeout !== undefined
|
|
208
|
+
? Duration.seconds(containerConfig.stopTimeout)
|
|
209
|
+
: undefined,
|
|
153
210
|
...(isServiceEc2(serviceProps) && {
|
|
154
|
-
memoryLimitMiB: serviceProps.ec2Config?.memoryLimitMiB ??
|
|
211
|
+
memoryLimitMiB: serviceProps.ec2Config?.memoryLimitMiB ??
|
|
212
|
+
DEFAULT_EC2_CONTAINER_MEMORY_MIB
|
|
155
213
|
})
|
|
156
214
|
});
|
|
215
|
+
if (containerConfig.port !== undefined &&
|
|
216
|
+
containerConfig.portMappings !== undefined &&
|
|
217
|
+
containerConfig.portMappings.length > 0) {
|
|
218
|
+
throw new Error(`Container '${containerConfig.name}' in service '${serviceName}': ` +
|
|
219
|
+
`"port" and "portMappings" are mutually exclusive on EcsContainerConfig — supply one or the other, not both.`);
|
|
220
|
+
}
|
|
157
221
|
if (containerConfig.port) {
|
|
158
222
|
container.addPortMappings({
|
|
159
223
|
containerPort: containerConfig.port
|
|
160
224
|
});
|
|
161
225
|
}
|
|
226
|
+
else if (containerConfig.portMappings &&
|
|
227
|
+
containerConfig.portMappings.length > 0) {
|
|
228
|
+
container.addPortMappings(...containerConfig.portMappings);
|
|
229
|
+
}
|
|
230
|
+
if (containerConfig.volumes && containerConfig.volumes.length > 0) {
|
|
231
|
+
for (const volume of containerConfig.volumes) {
|
|
232
|
+
taskDefinition.addVolume({
|
|
233
|
+
name: volume.name,
|
|
234
|
+
...(volume.hostSourcePath !== undefined && {
|
|
235
|
+
host: { sourcePath: volume.hostSourcePath }
|
|
236
|
+
})
|
|
237
|
+
});
|
|
238
|
+
container.addMountPoints({
|
|
239
|
+
sourceVolume: volume.name,
|
|
240
|
+
containerPath: volume.mountPath,
|
|
241
|
+
readOnly: volume.readOnly ?? false
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
162
245
|
if (isFirstWithPort) {
|
|
163
246
|
primaryContainer = container;
|
|
164
247
|
}
|
|
165
248
|
containers.push(container);
|
|
249
|
+
containerByName.set(containerConfig.name, container);
|
|
250
|
+
}
|
|
251
|
+
for (const containerConfig of serviceProps.containers) {
|
|
252
|
+
if (!containerConfig.dependsOn || containerConfig.dependsOn.length === 0) {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
const dependent = containerByName.get(containerConfig.name);
|
|
256
|
+
if (!dependent)
|
|
257
|
+
continue;
|
|
258
|
+
for (const dep of containerConfig.dependsOn) {
|
|
259
|
+
const target = containerByName.get(dep.container);
|
|
260
|
+
if (!target) {
|
|
261
|
+
const available = [...containerByName.keys()].join(", ");
|
|
262
|
+
throw new Error(`Service '${serviceName}': container '${containerConfig.name}' dependsOn ` +
|
|
263
|
+
`unknown container '${dep.container}'. Available containers: ${available}.`);
|
|
264
|
+
}
|
|
265
|
+
dependent.addContainerDependencies({
|
|
266
|
+
container: target,
|
|
267
|
+
condition: CONTAINER_DEPENDENCY_CONDITIONS[dep.condition]
|
|
268
|
+
});
|
|
269
|
+
}
|
|
166
270
|
}
|
|
167
271
|
return { containers, primaryContainer };
|
|
168
272
|
}
|