Skip to content

Commit f3b1bf4

Browse files
authored
Merge branch 'main' into merge-back/2.134.0
2 parents 265d769 + 5c30255 commit f3b1bf4

File tree

35 files changed

+7586
-24
lines changed

35 files changed

+7586
-24
lines changed

packages/@aws-cdk-testing/cli-integ/lib/aws.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export class AwsClients {
1818
public readonly cloudFormation: AwsCaller<AWS.CloudFormation>;
1919
public readonly s3: AwsCaller<AWS.S3>;
2020
public readonly ecr: AwsCaller<AWS.ECR>;
21+
public readonly ecs: AwsCaller<AWS.ECS>;
2122
public readonly sns: AwsCaller<AWS.SNS>;
2223
public readonly iam: AwsCaller<AWS.IAM>;
2324
public readonly lambda: AwsCaller<AWS.Lambda>;
@@ -34,6 +35,7 @@ export class AwsClients {
3435
this.cloudFormation = makeAwsCaller(AWS.CloudFormation, this.config);
3536
this.s3 = makeAwsCaller(AWS.S3, this.config);
3637
this.ecr = makeAwsCaller(AWS.ECR, this.config);
38+
this.ecs = makeAwsCaller(AWS.ECS, this.config);
3739
this.sns = makeAwsCaller(AWS.SNS, this.config);
3840
this.iam = makeAwsCaller(AWS.IAM, this.config);
3941
this.lambda = makeAwsCaller(AWS.Lambda, this.config);

packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/app/app.js

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ var constructs = require('constructs');
44
if (process.env.PACKAGE_LAYOUT_VERSION === '1') {
55
var cdk = require('@aws-cdk/core');
66
var ec2 = require('@aws-cdk/aws-ec2');
7+
var ecs = require('@aws-cdk/aws-ecs');
78
var s3 = require('@aws-cdk/aws-s3');
89
var ssm = require('@aws-cdk/aws-ssm');
910
var iam = require('@aws-cdk/aws-iam');
@@ -17,6 +18,7 @@ if (process.env.PACKAGE_LAYOUT_VERSION === '1') {
1718
DefaultStackSynthesizer,
1819
LegacyStackSynthesizer,
1920
aws_ec2: ec2,
21+
aws_ecs: ecs,
2022
aws_s3: s3,
2123
aws_ssm: ssm,
2224
aws_iam: iam,
@@ -357,6 +359,60 @@ class LambdaHotswapStack extends cdk.Stack {
357359
}
358360
}
359361

362+
class EcsHotswapStack extends cdk.Stack {
363+
constructor(parent, id, props) {
364+
super(parent, id, props);
365+
366+
// define a simple vpc and cluster
367+
const vpc = new ec2.Vpc(this, 'vpc', {
368+
natGateways: 0,
369+
subnetConfiguration: [
370+
{
371+
cidrMask: 24,
372+
name: 'Public',
373+
subnetType: ec2.SubnetType.PUBLIC,
374+
},
375+
],
376+
maxAzs: 1,
377+
});
378+
const cluster = new ecs.Cluster(this, 'cluster', {
379+
vpc,
380+
});
381+
382+
// allow stack to be used to test failed deployments
383+
const image =
384+
process.env.USE_INVALID_ECS_HOTSWAP_IMAGE == 'true'
385+
? 'nginx:invalidtag'
386+
: 'nginx:alpine';
387+
388+
// deploy basic service
389+
const taskDefinition = new ecs.FargateTaskDefinition(
390+
this,
391+
'task-definition'
392+
);
393+
taskDefinition.addContainer('nginx', {
394+
image: ecs.ContainerImage.fromRegistry(image),
395+
environment: {
396+
SOME_VARIABLE: process.env.DYNAMIC_ECS_PROPERTY_VALUE ?? 'environment',
397+
},
398+
healthCheck: {
399+
command: ['CMD-SHELL', 'exit 0'], // fake health check to speed up deployment
400+
interval: cdk.Duration.seconds(5),
401+
},
402+
});
403+
const service = new ecs.FargateService(this, 'service', {
404+
cluster,
405+
taskDefinition,
406+
assignPublicIp: true, // required without NAT to pull image
407+
circuitBreaker: { rollback: false },
408+
desiredCount: 1,
409+
});
410+
411+
new cdk.CfnOutput(this, 'ClusterName', { value: cluster.clusterName });
412+
new cdk.CfnOutput(this, 'ServiceName', { value: service.serviceName });
413+
}
414+
}
415+
360416
class DockerStack extends cdk.Stack {
361417
constructor(parent, id, props) {
362418
super(parent, id, props);
@@ -532,6 +588,7 @@ switch (stackSet) {
532588

533589
new LambdaStack(app, `${stackPrefix}-lambda`);
534590
new LambdaHotswapStack(app, `${stackPrefix}-lambda-hotswap`);
591+
new EcsHotswapStack(app, `${stackPrefix}-ecs-hotswap`);
535592
new DockerStack(app, `${stackPrefix}-docker`);
536593
new DockerStackWithCustomFile(app, `${stackPrefix}-docker-with-custom-file`);
537594
const failed = new FailedStack(app, `${stackPrefix}-failed`)

packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1571,6 +1571,83 @@ integTest('hotswap deployment supports Fn::ImportValue intrinsic', withDefaultFi
15711571
}
15721572
}));
15731573

1574+
integTest('hotswap deployment supports ecs service', withDefaultFixture(async (fixture) => {
1575+
// GIVEN
1576+
const stackArn = await fixture.cdkDeploy('ecs-hotswap', {
1577+
captureStderr: false,
1578+
});
1579+
1580+
// WHEN
1581+
const deployOutput = await fixture.cdkDeploy('ecs-hotswap', {
1582+
options: ['--hotswap'],
1583+
captureStderr: true,
1584+
onlyStderr: true,
1585+
modEnv: {
1586+
DYNAMIC_ECS_PROPERTY_VALUE: 'new value',
1587+
},
1588+
});
1589+
1590+
const response = await fixture.aws.cloudFormation('describeStacks', {
1591+
StackName: stackArn,
1592+
});
1593+
const serviceName = response.Stacks?.[0].Outputs?.find(output => output.OutputKey == 'ServiceName')?.OutputValue;
1594+
1595+
// THEN
1596+
1597+
// The deployment should not trigger a full deployment, thus the stack's status must remains
1598+
// "CREATE_COMPLETE"
1599+
expect(response.Stacks?.[0].StackStatus).toEqual('CREATE_COMPLETE');
1600+
expect(deployOutput).toContain(`ECS Service '${serviceName}' hotswapped!`);
1601+
}));
1602+
1603+
integTest('hotswap deployment for ecs service waits for deployment to complete', withDefaultFixture(async (fixture) => {
1604+
// GIVEN
1605+
const stackArn = await fixture.cdkDeploy('ecs-hotswap', {
1606+
captureStderr: false,
1607+
});
1608+
1609+
// WHEN
1610+
await fixture.cdkDeploy('ecs-hotswap', {
1611+
options: ['--hotswap'],
1612+
modEnv: {
1613+
DYNAMIC_ECS_PROPERTY_VALUE: 'new value',
1614+
},
1615+
});
1616+
1617+
const describeStacksResponse = await fixture.aws.cloudFormation('describeStacks', {
1618+
StackName: stackArn,
1619+
});
1620+
const clusterName = describeStacksResponse.Stacks?.[0].Outputs?.find(output => output.OutputKey == 'ClusterName')?.OutputValue!;
1621+
const serviceName = describeStacksResponse.Stacks?.[0].Outputs?.find(output => output.OutputKey == 'ServiceName')?.OutputValue!;
1622+
1623+
// THEN
1624+
1625+
const describeServicesResponse = await fixture.aws.ecs('describeServices', {
1626+
cluster: clusterName,
1627+
services: [serviceName],
1628+
});
1629+
expect(describeServicesResponse.services?.[0].deployments).toHaveLength(1); // only one deployment present
1630+
1631+
}));
1632+
1633+
integTest('hotswap deployment for ecs service detects failed deployment and errors', withDefaultFixture(async (fixture) => {
1634+
// GIVEN
1635+
await fixture.cdkDeploy('ecs-hotswap');
1636+
1637+
// WHEN
1638+
const deployOutput = await fixture.cdkDeploy('ecs-hotswap', {
1639+
options: ['--hotswap'],
1640+
modEnv: {
1641+
USE_INVALID_ECS_HOTSWAP_IMAGE: 'true',
1642+
},
1643+
allowErrExit: true,
1644+
});
1645+
1646+
// THEN
1647+
expect(deployOutput).toContain(`❌ ${fixture.stackNamePrefix}-ecs-hotswap failed: ResourceNotReady: Resource is not in the state deploymentCompleted`);
1648+
expect(deployOutput).not.toContain('hotswapped!');
1649+
}));
1650+
15741651
async function listChildren(parent: string, pred: (x: string) => Promise<boolean>) {
15751652
const ret = new Array<string>();
15761653
for (const child of await fs.readdir(parent, { encoding: 'utf-8' })) {

packages/@aws-cdk-testing/framework-integ/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"dependencies": {
4141
"@aws-cdk/integ-tests-alpha": "0.0.0",
4242
"@aws-cdk/lambda-layer-kubectl-v24": "^2.0.242",
43+
"@aws-cdk/lambda-layer-kubectl-v29": "^2.0.0",
4344
"aws-cdk-lib": "0.0.0",
4445
"aws-sdk": "^2.1583.0",
4546
"aws-sdk-mock": "5.6.0",
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
import * as lambda from 'aws-cdk-lib/aws-lambda';
22
import { KubectlV24Layer } from '@aws-cdk/lambda-layer-kubectl-v24';
3+
import { KubectlV29Layer } from '@aws-cdk/lambda-layer-kubectl-v29';
34
import { Construct } from 'constructs';
45
import * as eks from 'aws-cdk-lib/aws-eks';
56

6-
export function getClusterVersionConfig(scope: Construct) {
7+
const versionMap: { [key: string]: any } = {
8+
1.24: KubectlV24Layer,
9+
1.29: KubectlV29Layer,
10+
};
11+
12+
export function getClusterVersionConfig(scope: Construct, version?: eks.KubernetesVersion) {
13+
const _version = version ?? eks.KubernetesVersion.V1_24;
714
return {
8-
version: eks.KubernetesVersion.V1_24,
15+
version: _version,
916
// Crazy type-casting is required because KubectlLayer peer depends on
1017
// types from aws-cdk-lib, but we run integration tests in the @aws-cdk/
1118
// v1-style directory, not in the aws-cdk-lib v2-style directory.
12-
kubectlLayer: new KubectlV24Layer(scope, 'KubectlLayer') as unknown as lambda.ILayerVersion,
19+
// kubectlLayer: new KubectlV24Layer(scope, 'KubectlLayer') as unknown as lambda.ILayerVersion,
20+
kubectlLayer: new versionMap[_version.version](scope, 'KubectlLayer') as unknown as lambda.ILayerVersion,
1321
};
1422
};

packages/@aws-cdk-testing/framework-integ/test/aws-eks/test/integ.eks-al2023-nodegroup.js.snapshot/asset.1471fa6f2876749a13de79989efc6651c9768d3173ef5904947e87504f8d7069/apply/__init__.py

Lines changed: 95 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)