Skip to content

Commit

Permalink
Merge branch 'main' into merge-back/2.134.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] authored Mar 26, 2024
2 parents 265d769 + 5c30255 commit f3b1bf4
Show file tree
Hide file tree
Showing 35 changed files with 7,586 additions and 24 deletions.
2 changes: 2 additions & 0 deletions packages/@aws-cdk-testing/cli-integ/lib/aws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export class AwsClients {
public readonly cloudFormation: AwsCaller<AWS.CloudFormation>;
public readonly s3: AwsCaller<AWS.S3>;
public readonly ecr: AwsCaller<AWS.ECR>;
public readonly ecs: AwsCaller<AWS.ECS>;
public readonly sns: AwsCaller<AWS.SNS>;
public readonly iam: AwsCaller<AWS.IAM>;
public readonly lambda: AwsCaller<AWS.Lambda>;
Expand All @@ -34,6 +35,7 @@ export class AwsClients {
this.cloudFormation = makeAwsCaller(AWS.CloudFormation, this.config);
this.s3 = makeAwsCaller(AWS.S3, this.config);
this.ecr = makeAwsCaller(AWS.ECR, this.config);
this.ecs = makeAwsCaller(AWS.ECS, this.config);
this.sns = makeAwsCaller(AWS.SNS, this.config);
this.iam = makeAwsCaller(AWS.IAM, this.config);
this.lambda = makeAwsCaller(AWS.Lambda, this.config);
Expand Down
57 changes: 57 additions & 0 deletions packages/@aws-cdk-testing/cli-integ/resources/cdk-apps/app/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var constructs = require('constructs');
if (process.env.PACKAGE_LAYOUT_VERSION === '1') {
var cdk = require('@aws-cdk/core');
var ec2 = require('@aws-cdk/aws-ec2');
var ecs = require('@aws-cdk/aws-ecs');
var s3 = require('@aws-cdk/aws-s3');
var ssm = require('@aws-cdk/aws-ssm');
var iam = require('@aws-cdk/aws-iam');
Expand All @@ -17,6 +18,7 @@ if (process.env.PACKAGE_LAYOUT_VERSION === '1') {
DefaultStackSynthesizer,
LegacyStackSynthesizer,
aws_ec2: ec2,
aws_ecs: ecs,
aws_s3: s3,
aws_ssm: ssm,
aws_iam: iam,
Expand Down Expand Up @@ -357,6 +359,60 @@ class LambdaHotswapStack extends cdk.Stack {
}
}

class EcsHotswapStack extends cdk.Stack {
constructor(parent, id, props) {
super(parent, id, props);

// define a simple vpc and cluster
const vpc = new ec2.Vpc(this, 'vpc', {
natGateways: 0,
subnetConfiguration: [
{
cidrMask: 24,
name: 'Public',
subnetType: ec2.SubnetType.PUBLIC,
},
],
maxAzs: 1,
});
const cluster = new ecs.Cluster(this, 'cluster', {
vpc,
});

// allow stack to be used to test failed deployments
const image =
process.env.USE_INVALID_ECS_HOTSWAP_IMAGE == 'true'
? 'nginx:invalidtag'
: 'nginx:alpine';

// deploy basic service
const taskDefinition = new ecs.FargateTaskDefinition(
this,
'task-definition'
);
taskDefinition.addContainer('nginx', {
image: ecs.ContainerImage.fromRegistry(image),
environment: {
SOME_VARIABLE: process.env.DYNAMIC_ECS_PROPERTY_VALUE ?? 'environment',
},
healthCheck: {
command: ['CMD-SHELL', 'exit 0'], // fake health check to speed up deployment
interval: cdk.Duration.seconds(5),
},
});
const service = new ecs.FargateService(this, 'service', {
cluster,
taskDefinition,
assignPublicIp: true, // required without NAT to pull image
circuitBreaker: { rollback: false },
desiredCount: 1,
});

new cdk.CfnOutput(this, 'ClusterName', { value: cluster.clusterName });
new cdk.CfnOutput(this, 'ServiceName', { value: service.serviceName });
}
}

class DockerStack extends cdk.Stack {
constructor(parent, id, props) {
super(parent, id, props);
Expand Down Expand Up @@ -532,6 +588,7 @@ switch (stackSet) {

new LambdaStack(app, `${stackPrefix}-lambda`);
new LambdaHotswapStack(app, `${stackPrefix}-lambda-hotswap`);
new EcsHotswapStack(app, `${stackPrefix}-ecs-hotswap`);
new DockerStack(app, `${stackPrefix}-docker`);
new DockerStackWithCustomFile(app, `${stackPrefix}-docker-with-custom-file`);
const failed = new FailedStack(app, `${stackPrefix}-failed`)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1571,6 +1571,83 @@ integTest('hotswap deployment supports Fn::ImportValue intrinsic', withDefaultFi
}
}));

integTest('hotswap deployment supports ecs service', withDefaultFixture(async (fixture) => {
// GIVEN
const stackArn = await fixture.cdkDeploy('ecs-hotswap', {
captureStderr: false,
});

// WHEN
const deployOutput = await fixture.cdkDeploy('ecs-hotswap', {
options: ['--hotswap'],
captureStderr: true,
onlyStderr: true,
modEnv: {
DYNAMIC_ECS_PROPERTY_VALUE: 'new value',
},
});

const response = await fixture.aws.cloudFormation('describeStacks', {
StackName: stackArn,
});
const serviceName = response.Stacks?.[0].Outputs?.find(output => output.OutputKey == 'ServiceName')?.OutputValue;

// THEN

// The deployment should not trigger a full deployment, thus the stack's status must remains
// "CREATE_COMPLETE"
expect(response.Stacks?.[0].StackStatus).toEqual('CREATE_COMPLETE');
expect(deployOutput).toContain(`ECS Service '${serviceName}' hotswapped!`);
}));

integTest('hotswap deployment for ecs service waits for deployment to complete', withDefaultFixture(async (fixture) => {
// GIVEN
const stackArn = await fixture.cdkDeploy('ecs-hotswap', {
captureStderr: false,
});

// WHEN
await fixture.cdkDeploy('ecs-hotswap', {
options: ['--hotswap'],
modEnv: {
DYNAMIC_ECS_PROPERTY_VALUE: 'new value',
},
});

const describeStacksResponse = await fixture.aws.cloudFormation('describeStacks', {
StackName: stackArn,
});
const clusterName = describeStacksResponse.Stacks?.[0].Outputs?.find(output => output.OutputKey == 'ClusterName')?.OutputValue!;
const serviceName = describeStacksResponse.Stacks?.[0].Outputs?.find(output => output.OutputKey == 'ServiceName')?.OutputValue!;

// THEN

const describeServicesResponse = await fixture.aws.ecs('describeServices', {
cluster: clusterName,
services: [serviceName],
});
expect(describeServicesResponse.services?.[0].deployments).toHaveLength(1); // only one deployment present

}));

integTest('hotswap deployment for ecs service detects failed deployment and errors', withDefaultFixture(async (fixture) => {
// GIVEN
await fixture.cdkDeploy('ecs-hotswap');

// WHEN
const deployOutput = await fixture.cdkDeploy('ecs-hotswap', {
options: ['--hotswap'],
modEnv: {
USE_INVALID_ECS_HOTSWAP_IMAGE: 'true',
},
allowErrExit: true,
});

// THEN
expect(deployOutput).toContain(`❌ ${fixture.stackNamePrefix}-ecs-hotswap failed: ResourceNotReady: Resource is not in the state deploymentCompleted`);
expect(deployOutput).not.toContain('hotswapped!');
}));

async function listChildren(parent: string, pred: (x: string) => Promise<boolean>) {
const ret = new Array<string>();
for (const child of await fs.readdir(parent, { encoding: 'utf-8' })) {
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk-testing/framework-integ/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"dependencies": {
"@aws-cdk/integ-tests-alpha": "0.0.0",
"@aws-cdk/lambda-layer-kubectl-v24": "^2.0.242",
"@aws-cdk/lambda-layer-kubectl-v29": "^2.0.0",
"aws-cdk-lib": "0.0.0",
"aws-sdk": "^2.1583.0",
"aws-sdk-mock": "5.6.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { KubectlV24Layer } from '@aws-cdk/lambda-layer-kubectl-v24';
import { KubectlV29Layer } from '@aws-cdk/lambda-layer-kubectl-v29';
import { Construct } from 'constructs';
import * as eks from 'aws-cdk-lib/aws-eks';

export function getClusterVersionConfig(scope: Construct) {
const versionMap: { [key: string]: any } = {
1.24: KubectlV24Layer,
1.29: KubectlV29Layer,
};

export function getClusterVersionConfig(scope: Construct, version?: eks.KubernetesVersion) {
const _version = version ?? eks.KubernetesVersion.V1_24;
return {
version: eks.KubernetesVersion.V1_24,
version: _version,
// Crazy type-casting is required because KubectlLayer peer depends on
// types from aws-cdk-lib, but we run integration tests in the @aws-cdk/
// v1-style directory, not in the aws-cdk-lib v2-style directory.
kubectlLayer: new KubectlV24Layer(scope, 'KubectlLayer') as unknown as lambda.ILayerVersion,
// kubectlLayer: new KubectlV24Layer(scope, 'KubectlLayer') as unknown as lambda.ILayerVersion,
kubectlLayer: new versionMap[_version.version](scope, 'KubectlLayer') as unknown as lambda.ILayerVersion,
};
};

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit f3b1bf4

Please sign in to comment.