diff --git a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts index f4736584a065f..7e3f193d45a6b 100644 --- a/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts +++ b/packages/@aws-cdk-testing/cli-integ/tests/cli-integ-tests/cli.integtest.ts @@ -2547,6 +2547,8 @@ integTest( // THEN const expectedSubstring = 'Resource is not in the expected state due to waiter status: TIMEOUT'; expect(deployOutput).toContain(expectedSubstring); + expect(deployOutput).toContain('Observed responses:'); + expect(deployOutput).toContain('200: OK'); expect(deployOutput).not.toContain('hotswapped!'); }), ); diff --git a/packages/aws-cdk/THIRD_PARTY_LICENSES b/packages/aws-cdk/THIRD_PARTY_LICENSES index 0ce635a6c49ac..872df399e0d32 100644 --- a/packages/aws-cdk/THIRD_PARTY_LICENSES +++ b/packages/aws-cdk/THIRD_PARTY_LICENSES @@ -16464,7 +16464,7 @@ Apache License ---------------- -** @smithy/service-error-classification@3.0.8 - https://www.npmjs.com/package/@smithy/service-error-classification/v/3.0.8 | Apache-2.0 +** @smithy/service-error-classification@3.0.11 - https://www.npmjs.com/package/@smithy/service-error-classification/v/3.0.11 | Apache-2.0 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -20570,7 +20570,7 @@ Apache License ---------------- -** @smithy/util-retry@3.0.8 - https://www.npmjs.com/package/@smithy/util-retry/v/3.0.8 | Apache-2.0 +** @smithy/util-retry@3.0.11 - https://www.npmjs.com/package/@smithy/util-retry/v/3.0.11 | Apache-2.0 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ diff --git a/packages/aws-cdk/lib/api/hotswap-deployments.ts b/packages/aws-cdk/lib/api/hotswap-deployments.ts index f0318ae8b74fe..1f3f058314402 100644 --- a/packages/aws-cdk/lib/api/hotswap-deployments.ts +++ b/packages/aws-cdk/lib/api/hotswap-deployments.ts @@ -426,10 +426,7 @@ async function applyHotswappableChange(sdk: SDK, hotswapOperation: HotswappableC } catch (e: any) { if (e.name === 'TimeoutError' || e.name === 'AbortError') { const result: WaiterResult = JSON.parse(formatErrorMessage(e)); - const error = new ToolkitError([ - `Resource is not in the expected state due to waiter status: ${result.state}`, - result.reason ? `${result.reason}.` : '', - ].join('. ')); + const error = new ToolkitError(formatWaiterErrorResult(result)); error.name = e.name; throw error; } @@ -443,6 +440,24 @@ async function applyHotswappableChange(sdk: SDK, hotswapOperation: HotswappableC sdk.removeCustomUserAgent(customUserAgent); } +function formatWaiterErrorResult(result: WaiterResult) { + const main = [ + `Resource is not in the expected state due to waiter status: ${result.state}`, + result.reason ? `${result.reason}.` : '', + ].join('. '); + + if (result.observedResponses != null) { + const observedResponses = Object + .entries(result.observedResponses) + .map(([msg, count]) => ` - ${msg} (${count})`) + .join('\n'); + + return `${main} Observed responses:\n${observedResponses}`; + } + + return main; +} + function logNonHotswappableChanges(nonHotswappableChanges: NonHotswappableChange[], hotswapMode: HotswapMode): void { if (nonHotswappableChanges.length === 0) { return; diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 74d16104b7817..fb1636f107d4d 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -170,9 +170,9 @@ "@smithy/property-provider": "^3.1.10", "@smithy/shared-ini-file-loader": "^3.1.8", "@smithy/types": "^3.5.0", - "@smithy/util-retry": "^3.0.7", - "@smithy/util-stream": "^3.1.9", - "@smithy/util-waiter": "^3.1.6", + "@smithy/util-retry": "^3.0.11", + "@smithy/util-stream": "^3.3.4", + "@smithy/util-waiter": "^3.2.0", "archiver": "^5.3.2", "camelcase": "^6.3.0", "cdk-assets": "^3.0.0-rc.123", diff --git a/packages/aws-cdk/test/api/hotswap/lambda-functions-docker-hotswap-deployments.test.ts b/packages/aws-cdk/test/api/hotswap/lambda-functions-docker-hotswap-deployments.test.ts index 023627a429a04..855c33f0a0150 100644 --- a/packages/aws-cdk/test/api/hotswap/lambda-functions-docker-hotswap-deployments.test.ts +++ b/packages/aws-cdk/test/api/hotswap/lambda-functions-docker-hotswap-deployments.test.ts @@ -1,18 +1,19 @@ -import { UpdateFunctionCodeCommand, waitUntilFunctionUpdatedV2 } from '@aws-sdk/client-lambda'; -import * as setup from './hotswap-test-setup'; -import { HotswapMode } from '../../../lib/api/hotswap/common'; -import { mockLambdaClient } from '../../util/mock-sdk'; -import { silentTest } from '../../util/silent'; - +let mockWaitUntilFunctionUpdatedV2: jest.Mock = jest.fn(); jest.mock('@aws-sdk/client-lambda', () => { const original = jest.requireActual('@aws-sdk/client-lambda'); return { ...original, - waitUntilFunctionUpdatedV2: jest.fn(), + waitUntilFunctionUpdatedV2: mockWaitUntilFunctionUpdatedV2, }; }); +import { UpdateFunctionCodeCommand, waitUntilFunctionUpdatedV2 } from '@aws-sdk/client-lambda'; +import * as setup from './hotswap-test-setup'; +import { HotswapMode } from '../../../lib/api/hotswap/common'; +import { mockLambdaClient } from '../../util/mock-sdk'; +import { silentTest } from '../../util/silent'; + let hotswapMockSdkProvider: setup.HotswapMockSdkProvider; beforeEach(() => { @@ -125,4 +126,61 @@ describe.each([HotswapMode.FALL_BACK, HotswapMode.HOTSWAP_ONLY])('%p mode', (hot { FunctionName: 'my-function' }, ); }); + + silentTest( + 'throws error in case of timeout', + async () => { + // GIVEN + mockWaitUntilFunctionUpdatedV2.mockRejectedValue({ + name: 'TimeoutError', + message: JSON.stringify({ + state: 'TIMEOUT', + reason: 'Function not found', + observedResponses: { + '404: The function with name foo cannot be found.': 5, + }, + }), + }); + 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', + }, + }, + }, + }, + }); + + // THEN + await expect(hotswapMockSdkProvider.tryHotswapDeployment(hotswapMode, cdkStackArtifact)) + .rejects + .toThrow(`Resource is not in the expected state due to waiter status: TIMEOUT. Function not found. Observed responses: + - 404: The function with name foo cannot be found. (5)`); + }, + ); }); diff --git a/yarn.lock b/yarn.lock index c448bcffd7ae0..5b790fdf353fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8582,6 +8582,17 @@ "@smithy/util-base64" "^3.0.0" tslib "^2.6.2" +"@smithy/fetch-http-handler@^4.1.3": + version "4.1.3" + resolved "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-4.1.3.tgz#fc590dea2470d32559ae298306f1277729d24aa9" + integrity sha512-6SxNltSncI8s689nvnzZQc/dPXcpHQ34KUj6gR/HBroytKOd/isMG3gJF/zBE1TBmTT18TXyzhg3O3SOOqGEhA== + dependencies: + "@smithy/protocol-http" "^4.1.8" + "@smithy/querystring-builder" "^3.0.11" + "@smithy/types" "^3.7.2" + "@smithy/util-base64" "^3.0.0" + tslib "^2.6.2" + "@smithy/fetch-http-handler@^5.0.0", "@smithy/fetch-http-handler@^5.0.1": version "5.0.1" resolved "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.0.1.tgz#8463393442ca6a1644204849e42c386066f0df79" @@ -9852,6 +9863,20 @@ "@smithy/util-utf8" "^3.0.0" tslib "^2.6.2" +"@smithy/util-stream@^3.3.4": + version "3.3.4" + resolved "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.3.4.tgz#c506ac41310ebcceb0c3f0ba20755e4fe0a90b8d" + integrity sha512-SGhGBG/KupieJvJSZp/rfHHka8BFgj56eek9px4pp7lZbOF+fRiVr4U7A3y3zJD8uGhxq32C5D96HxsTC9BckQ== + dependencies: + "@smithy/fetch-http-handler" "^4.1.3" + "@smithy/node-http-handler" "^3.3.3" + "@smithy/types" "^3.7.2" + "@smithy/util-base64" "^3.0.0" + "@smithy/util-buffer-from" "^3.0.0" + "@smithy/util-hex-encoding" "^3.0.0" + "@smithy/util-utf8" "^3.0.0" + tslib "^2.6.2" + "@smithy/util-stream@^4.0.0", "@smithy/util-stream@^4.0.2": version "4.0.2" resolved "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.0.2.tgz#63495d3f7fba9d78748d540921136dc4a8d4c067"