Skip to content

Commit 6b553b7

Browse files
authored
feat(cli): support hotswapping Lambda functions that use Docker images (#18319)
closes #18302 We must just update `ImageUri` with the new ECR image url. PR for `InlineCode` hotswap: #18408 `----` *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent e01a57a commit 6b553b7

File tree

3 files changed

+78
-4
lines changed

3 files changed

+78
-4
lines changed

packages/aws-cdk/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ and that you have the necessary IAM permissions to update the resources that are
362362
Hotswapping is currently supported for the following changes
363363
(additional changes will be supported in the future):
364364

365-
- Code asset and tag changes of AWS Lambda functions.
365+
- Code asset (including Docker image) and tag changes of AWS Lambda functions.
366366
- AWS Lambda Versions and Aliases changes.
367367
- Definition changes of AWS Step Functions State Machines.
368368
- Container asset changes of AWS ECS Services.

packages/aws-cdk/lib/api/hotswap/lambda-functions.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ async function isLambdaFunctionCodeOnlyChange(
108108
switch (updatedPropName) {
109109
case 'Code':
110110
let foundCodeDifference = false;
111-
let s3Bucket = '', s3Key = '';
111+
let s3Bucket, s3Key, imageUri;
112112

113113
for (const newPropName in updatedProp.newValue) {
114114
switch (newPropName) {
@@ -120,6 +120,10 @@ async function isLambdaFunctionCodeOnlyChange(
120120
foundCodeDifference = true;
121121
s3Key = await evaluateCfnTemplate.evaluateCfnExpression(updatedProp.newValue[newPropName]);
122122
break;
123+
case 'ImageUri':
124+
foundCodeDifference = true;
125+
imageUri = await evaluateCfnTemplate.evaluateCfnExpression(updatedProp.newValue[newPropName]);
126+
break;
123127
default:
124128
return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT;
125129
}
@@ -128,6 +132,7 @@ async function isLambdaFunctionCodeOnlyChange(
128132
code = {
129133
s3Bucket,
130134
s3Key,
135+
imageUri,
131136
};
132137
}
133138
break;
@@ -165,8 +170,9 @@ interface CfnDiffTagValue {
165170
}
166171

167172
interface LambdaFunctionCode {
168-
readonly s3Bucket: string;
169-
readonly s3Key: string;
173+
readonly s3Bucket?: string;
174+
readonly s3Key?: string;
175+
readonly imageUri?: string;
170176
}
171177

172178
enum TagDeletion {
@@ -214,6 +220,7 @@ class LambdaFunctionHotswapOperation implements HotswapOperation {
214220
FunctionName: this.lambdaFunctionResource.physicalName,
215221
S3Bucket: resource.code.s3Bucket,
216222
S3Key: resource.code.s3Key,
223+
ImageUri: resource.code.imageUri,
217224
}).promise();
218225

219226
// only if the code changed is there any point in publishing a new Version
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import { Lambda } from 'aws-sdk';
2+
import * as setup from './hotswap-test-setup';
3+
4+
let mockUpdateLambdaCode: (params: Lambda.Types.UpdateFunctionCodeRequest) => Lambda.Types.FunctionConfiguration;
5+
let mockTagResource: (params: Lambda.Types.TagResourceRequest) => {};
6+
let mockUntagResource: (params: Lambda.Types.UntagResourceRequest) => {};
7+
let hotswapMockSdkProvider: setup.HotswapMockSdkProvider;
8+
9+
beforeEach(() => {
10+
hotswapMockSdkProvider = setup.setupHotswapTests();
11+
mockUpdateLambdaCode = jest.fn();
12+
mockTagResource = jest.fn();
13+
mockUntagResource = jest.fn();
14+
hotswapMockSdkProvider.stubLambda({
15+
updateFunctionCode: mockUpdateLambdaCode,
16+
tagResource: mockTagResource,
17+
untagResource: mockUntagResource,
18+
});
19+
});
20+
21+
test('calls the updateLambdaCode() API when it receives only a code difference in a Lambda function', async () => {
22+
// GIVEN
23+
setup.setCurrentCfnStackTemplate({
24+
Resources: {
25+
Func: {
26+
Type: 'AWS::Lambda::Function',
27+
Properties: {
28+
Code: {
29+
ImageUri: 'current-image',
30+
},
31+
FunctionName: 'my-function',
32+
},
33+
Metadata: {
34+
'aws:asset:path': 'old-path',
35+
},
36+
},
37+
},
38+
});
39+
const cdkStackArtifact = setup.cdkStackArtifactOf({
40+
template: {
41+
Resources: {
42+
Func: {
43+
Type: 'AWS::Lambda::Function',
44+
Properties: {
45+
Code: {
46+
ImageUri: 'new-image',
47+
},
48+
FunctionName: 'my-function',
49+
},
50+
Metadata: {
51+
'aws:asset:path': 'new-path',
52+
},
53+
},
54+
},
55+
},
56+
});
57+
58+
// WHEN
59+
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
60+
61+
// THEN
62+
expect(deployStackResult).not.toBeUndefined();
63+
expect(mockUpdateLambdaCode).toHaveBeenCalledWith({
64+
FunctionName: 'my-function',
65+
ImageUri: 'new-image',
66+
});
67+
});

0 commit comments

Comments
 (0)