Skip to content

Commit

Permalink
feat(cli): support hotswapping Lambda functions that use Docker images (
Browse files Browse the repository at this point in the history
#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*
  • Loading branch information
tmokmss committed Jan 14, 2022
1 parent e01a57a commit 6b553b7
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 4 deletions.
2 changes: 1 addition & 1 deletion packages/aws-cdk/README.md
Expand Up @@ -362,7 +362,7 @@ and that you have the necessary IAM permissions to update the resources that are
Hotswapping is currently supported for the following changes
(additional changes will be supported in the future):

- Code asset and tag changes of AWS Lambda functions.
- Code asset (including Docker image) and tag changes of AWS Lambda functions.
- AWS Lambda Versions and Aliases changes.
- Definition changes of AWS Step Functions State Machines.
- Container asset changes of AWS ECS Services.
Expand Down
13 changes: 10 additions & 3 deletions packages/aws-cdk/lib/api/hotswap/lambda-functions.ts
Expand Up @@ -108,7 +108,7 @@ async function isLambdaFunctionCodeOnlyChange(
switch (updatedPropName) {
case 'Code':
let foundCodeDifference = false;
let s3Bucket = '', s3Key = '';
let s3Bucket, s3Key, imageUri;

for (const newPropName in updatedProp.newValue) {
switch (newPropName) {
Expand All @@ -120,6 +120,10 @@ async function isLambdaFunctionCodeOnlyChange(
foundCodeDifference = true;
s3Key = await evaluateCfnTemplate.evaluateCfnExpression(updatedProp.newValue[newPropName]);
break;
case 'ImageUri':
foundCodeDifference = true;
imageUri = await evaluateCfnTemplate.evaluateCfnExpression(updatedProp.newValue[newPropName]);
break;
default:
return ChangeHotswapImpact.REQUIRES_FULL_DEPLOYMENT;
}
Expand All @@ -128,6 +132,7 @@ async function isLambdaFunctionCodeOnlyChange(
code = {
s3Bucket,
s3Key,
imageUri,
};
}
break;
Expand Down Expand Up @@ -165,8 +170,9 @@ interface CfnDiffTagValue {
}

interface LambdaFunctionCode {
readonly s3Bucket: string;
readonly s3Key: string;
readonly s3Bucket?: string;
readonly s3Key?: string;
readonly imageUri?: string;
}

enum TagDeletion {
Expand Down Expand Up @@ -214,6 +220,7 @@ class LambdaFunctionHotswapOperation implements HotswapOperation {
FunctionName: this.lambdaFunctionResource.physicalName,
S3Bucket: resource.code.s3Bucket,
S3Key: resource.code.s3Key,
ImageUri: resource.code.imageUri,
}).promise();

// only if the code changed is there any point in publishing a new Version
Expand Down
@@ -0,0 +1,67 @@
import { Lambda } from 'aws-sdk';
import * as setup from './hotswap-test-setup';

let mockUpdateLambdaCode: (params: Lambda.Types.UpdateFunctionCodeRequest) => Lambda.Types.FunctionConfiguration;
let mockTagResource: (params: Lambda.Types.TagResourceRequest) => {};
let mockUntagResource: (params: Lambda.Types.UntagResourceRequest) => {};
let hotswapMockSdkProvider: setup.HotswapMockSdkProvider;

beforeEach(() => {
hotswapMockSdkProvider = setup.setupHotswapTests();
mockUpdateLambdaCode = jest.fn();
mockTagResource = jest.fn();
mockUntagResource = jest.fn();
hotswapMockSdkProvider.stubLambda({
updateFunctionCode: mockUpdateLambdaCode,
tagResource: mockTagResource,
untagResource: mockUntagResource,
});
});

test('calls the updateLambdaCode() API when it receives only a code difference in a Lambda function', async () => {
// GIVEN
setup.setCurrentCfnStackTemplate({
Resources: {
Func: {
Type: 'AWS::Lambda::Function',
Properties: {
Code: {
ImageUri: 'current-image',
},
FunctionName: 'my-function',
},
Metadata: {
'aws:asset:path': 'old-path',
},
},
},
});
const cdkStackArtifact = setup.cdkStackArtifactOf({
template: {
Resources: {
Func: {
Type: 'AWS::Lambda::Function',
Properties: {
Code: {
ImageUri: 'new-image',
},
FunctionName: 'my-function',
},
Metadata: {
'aws:asset:path': 'new-path',
},
},
},
},
});

// WHEN
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);

// THEN
expect(deployStackResult).not.toBeUndefined();
expect(mockUpdateLambdaCode).toHaveBeenCalledWith({
FunctionName: 'my-function',
ImageUri: 'new-image',
});
});

0 comments on commit 6b553b7

Please sign in to comment.