From 298131312b513c0e73865e6fff74c189ee99e328 Mon Sep 17 00:00:00 2001 From: Rizxcviii Date: Tue, 27 Dec 2022 17:06:16 +0000 Subject: [PATCH 1/8] fix(aws-redshift): Columns are not dropped on removal from array (#23011) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When attempting to a drop a column from the array, this would cause an error similar to that of the following ```Received response status [FAILED] from custom resource. Message returned: Statement status was FAILED: ERROR: column "column" of relation "tableā€ already exists``` fixes #22208 ---- ### All Submissions: * [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Unconventional Dependencies: * [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies) ### New Features * [ ] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [ ] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)? *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../private/database-query-provider/table.ts | 7 +- packages/@aws-cdk/aws-redshift/lib/table.ts | 4 +- .../database-query-provider/table.test.ts | 11 +- .../cfn-response.js | 83 ------ .../outbound.js | 45 ---- .../util.js | 17 -- .../handler-name.js | 0 .../index.js | 0 .../privileges.js | 0 .../redshift-data.js | 0 .../table.js | 117 +++++++++ .../types.js | 0 .../user.js | 0 .../util.js | 0 .../cfn-response.js | 87 +++++++ .../consts.js | 0 .../framework.js | 0 .../outbound.js | 69 +++++ .../util.js | 39 +++ .../table.js | 116 --------- ...-cdk-redshift-cluster-database.assets.json | 18 +- ...dk-redshift-cluster-database.template.json | 78 +++--- .../test/integ.database.js.snapshot/cdk.out | 2 +- .../integ.database.js.snapshot/integ.json | 12 +- .../integ.database.js.snapshot/manifest.json | 80 ++++-- ...efaultTestDeployAssert4339FB48.assets.json | 19 ++ ...aultTestDeployAssert4339FB48.template.json | 36 +++ .../test/integ.database.js.snapshot/tree.json | 236 +++++++++++++----- .../aws-redshift/test/integ.database.ts | 9 +- 29 files changed, 672 insertions(+), 413 deletions(-) delete mode 100644 packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/cfn-response.js delete mode 100644 packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/outbound.js delete mode 100644 packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/util.js rename packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/{asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3 => asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415}/handler-name.js (100%) rename packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/{asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3 => asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415}/index.js (100%) rename packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/{asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3 => asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415}/privileges.js (100%) rename packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/{asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3 => asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415}/redshift-data.js (100%) create mode 100644 packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/table.js rename packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/{asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3 => asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415}/types.js (100%) rename packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/{asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3 => asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415}/user.js (100%) rename packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/{asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3 => asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415}/util.js (100%) create mode 100644 packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/cfn-response.js rename packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/{asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671 => asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585}/consts.js (100%) rename packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/{asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671 => asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585}/framework.js (100%) create mode 100644 packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/outbound.js create mode 100644 packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/util.js delete mode 100644 packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/table.js create mode 100644 packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48.assets.json create mode 100644 packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48.template.json diff --git a/packages/@aws-cdk/aws-redshift/lib/private/database-query-provider/table.ts b/packages/@aws-cdk/aws-redshift/lib/private/database-query-provider/table.ts index 0716477eb54f..18a9dec63429 100644 --- a/packages/@aws-cdk/aws-redshift/lib/private/database-query-provider/table.ts +++ b/packages/@aws-cdk/aws-redshift/lib/private/database-query-provider/table.ts @@ -88,8 +88,11 @@ async function updateTable( } const oldTableColumns = oldResourceProperties.tableColumns; - if (!oldTableColumns.every(oldColumn => tableColumns.some(column => column.name === oldColumn.name && column.dataType === oldColumn.dataType))) { - return createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps); + const columnDeletions = oldTableColumns.filter(oldColumn => ( + tableColumns.every(column => oldColumn.name !== column.name) + )); + if (columnDeletions.length > 0) { + alterationStatements.push(...columnDeletions.map(column => `ALTER TABLE ${tableName} DROP COLUMN ${column.name}`)); } const columnAdditions = tableColumns.filter(column => { diff --git a/packages/@aws-cdk/aws-redshift/lib/table.ts b/packages/@aws-cdk/aws-redshift/lib/table.ts index 58b39c1b88bf..168fd06b5989 100644 --- a/packages/@aws-cdk/aws-redshift/lib/table.ts +++ b/packages/@aws-cdk/aws-redshift/lib/table.ts @@ -55,7 +55,9 @@ export enum TableAction { */ export interface Column { /** - * The name of the column. + * The unique name/identifier of the column. + * + * **NOTE**. After deploying this column, you cannot change its name. Doing so will cause the column to be dropped and recreated. */ readonly name: string; diff --git a/packages/@aws-cdk/aws-redshift/test/database-query-provider/table.test.ts b/packages/@aws-cdk/aws-redshift/test/database-query-provider/table.test.ts index 7c5534d59a78..4839416fc8fa 100644 --- a/packages/@aws-cdk/aws-redshift/test/database-query-provider/table.test.ts +++ b/packages/@aws-cdk/aws-redshift/test/database-query-provider/table.test.ts @@ -225,20 +225,17 @@ describe('update', () => { })); }); - test('replaces if table columns change', async () => { - const newTableColumnName = 'col2'; - const newTableColumnDataType = 'varchar(1)'; - const newTableColumns = [{ name: newTableColumnName, dataType: newTableColumnDataType }]; + test('does not replace if table columns removed', async () => { const newResourceProperties = { ...resourceProperties, - tableColumns: newTableColumns, + tableColumns: [], }; - await expect(manageTable(newResourceProperties, event)).resolves.not.toMatchObject({ + await expect(manageTable(newResourceProperties, event)).resolves.toMatchObject({ PhysicalResourceId: physicalResourceId, }); expect(mockExecuteStatement).toHaveBeenCalledWith(expect.objectContaining({ - Sql: `CREATE TABLE ${tableNamePrefix}${requestIdTruncated} (${newTableColumnName} ${newTableColumnDataType})`, + Sql: `ALTER TABLE ${physicalResourceId} DROP COLUMN col1`, })); }); diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/cfn-response.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/cfn-response.js deleted file mode 100644 index 6319e06391de..000000000000 --- a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/cfn-response.js +++ /dev/null @@ -1,83 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.Retry = exports.safeHandler = exports.includeStackTraces = exports.submitResponse = exports.MISSING_PHYSICAL_ID_MARKER = exports.CREATE_FAILED_PHYSICAL_ID_MARKER = void 0; -/* eslint-disable max-len */ -/* eslint-disable no-console */ -const url = require("url"); -const outbound_1 = require("./outbound"); -const util_1 = require("./util"); -exports.CREATE_FAILED_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::CREATE_FAILED'; -exports.MISSING_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID'; -async function submitResponse(status, event, options = {}) { - const json = { - Status: status, - Reason: options.reason || status, - StackId: event.StackId, - RequestId: event.RequestId, - PhysicalResourceId: event.PhysicalResourceId || exports.MISSING_PHYSICAL_ID_MARKER, - LogicalResourceId: event.LogicalResourceId, - NoEcho: options.noEcho, - Data: event.Data, - }; - util_1.log('submit response to cloudformation', json); - const responseBody = JSON.stringify(json); - const parsedUrl = url.parse(event.ResponseURL); - await outbound_1.httpRequest({ - hostname: parsedUrl.hostname, - path: parsedUrl.path, - method: 'PUT', - headers: { - 'content-type': '', - 'content-length': responseBody.length, - }, - }, responseBody); -} -exports.submitResponse = submitResponse; -exports.includeStackTraces = true; // for unit tests -function safeHandler(block) { - return async (event) => { - // ignore DELETE event when the physical resource ID is the marker that - // indicates that this DELETE is a subsequent DELETE to a failed CREATE - // operation. - if (event.RequestType === 'Delete' && event.PhysicalResourceId === exports.CREATE_FAILED_PHYSICAL_ID_MARKER) { - util_1.log('ignoring DELETE event caused by a failed CREATE event'); - await submitResponse('SUCCESS', event); - return; - } - try { - await block(event); - } - catch (e) { - // tell waiter state machine to retry - if (e instanceof Retry) { - util_1.log('retry requested by handler'); - throw e; - } - if (!event.PhysicalResourceId) { - // special case: if CREATE fails, which usually implies, we usually don't - // have a physical resource id. in this case, the subsequent DELETE - // operation does not have any meaning, and will likely fail as well. to - // address this, we use a marker so the provider framework can simply - // ignore the subsequent DELETE. - if (event.RequestType === 'Create') { - util_1.log('CREATE failed, responding with a marker physical resource id so that the subsequent DELETE will be ignored'); - event.PhysicalResourceId = exports.CREATE_FAILED_PHYSICAL_ID_MARKER; - } - else { - // otherwise, if PhysicalResourceId is not specified, something is - // terribly wrong because all other events should have an ID. - util_1.log(`ERROR: Malformed event. "PhysicalResourceId" is required: ${JSON.stringify({ ...event, ResponseURL: '...' })}`); - } - } - // this is an actual error, fail the activity altogether and exist. - await submitResponse('FAILED', event, { - reason: exports.includeStackTraces ? e.stack : e.message, - }); - } - }; -} -exports.safeHandler = safeHandler; -class Retry extends Error { -} -exports.Retry = Retry; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2ZuLXJlc3BvbnNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiY2ZuLXJlc3BvbnNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDRCQUE0QjtBQUM1QiwrQkFBK0I7QUFDL0IsMkJBQTJCO0FBQzNCLHlDQUF5QztBQUN6QyxpQ0FBNkI7QUFFaEIsUUFBQSxnQ0FBZ0MsR0FBRyx3REFBd0QsQ0FBQztBQUM1RixRQUFBLDBCQUEwQixHQUFHLDhEQUE4RCxDQUFDO0FBZ0JsRyxLQUFLLFVBQVUsY0FBYyxDQUFDLE1BQTRCLEVBQUUsS0FBaUMsRUFBRSxVQUF5QyxFQUFHO0lBQ2hKLE1BQU0sSUFBSSxHQUFtRDtRQUMzRCxNQUFNLEVBQUUsTUFBTTtRQUNkLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTSxJQUFJLE1BQU07UUFDaEMsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPO1FBQ3RCLFNBQVMsRUFBRSxLQUFLLENBQUMsU0FBUztRQUMxQixrQkFBa0IsRUFBRSxLQUFLLENBQUMsa0JBQWtCLElBQUksa0NBQTBCO1FBQzFFLGlCQUFpQixFQUFFLEtBQUssQ0FBQyxpQkFBaUI7UUFDMUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNO1FBQ3RCLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSTtLQUNqQixDQUFDO0lBRUYsVUFBRyxDQUFDLG1DQUFtQyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBRS9DLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7SUFFMUMsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDL0MsTUFBTSxzQkFBVyxDQUFDO1FBQ2hCLFFBQVEsRUFBRSxTQUFTLENBQUMsUUFBUTtRQUM1QixJQUFJLEVBQUUsU0FBUyxDQUFDLElBQUk7UUFDcEIsTUFBTSxFQUFFLEtBQUs7UUFDYixPQUFPLEVBQUU7WUFDUCxjQUFjLEVBQUUsRUFBRTtZQUNsQixnQkFBZ0IsRUFBRSxZQUFZLENBQUMsTUFBTTtTQUN0QztLQUNGLEVBQUUsWUFBWSxDQUFDLENBQUM7QUFDbkIsQ0FBQztBQTFCRCx3Q0EwQkM7QUFFVSxRQUFBLGtCQUFrQixHQUFHLElBQUksQ0FBQyxDQUFDLGlCQUFpQjtBQUV2RCxTQUFnQixXQUFXLENBQUMsS0FBb0M7SUFDOUQsT0FBTyxLQUFLLEVBQUUsS0FBVSxFQUFFLEVBQUU7UUFFMUIsdUVBQXVFO1FBQ3ZFLHVFQUF1RTtRQUN2RSxhQUFhO1FBQ2IsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsa0JBQWtCLEtBQUssd0NBQWdDLEVBQUU7WUFDbkcsVUFBRyxDQUFDLHVEQUF1RCxDQUFDLENBQUM7WUFDN0QsTUFBTSxjQUFjLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ3ZDLE9BQU87U0FDUjtRQUVELElBQUk7WUFDRixNQUFNLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUNwQjtRQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ1YscUNBQXFDO1lBQ3JDLElBQUksQ0FBQyxZQUFZLEtBQUssRUFBRTtnQkFDdEIsVUFBRyxDQUFDLDRCQUE0QixDQUFDLENBQUM7Z0JBQ2xDLE1BQU0sQ0FBQyxDQUFDO2FBQ1Q7WUFFRCxJQUFJLENBQUMsS0FBSyxDQUFDLGtCQUFrQixFQUFFO2dCQUM3Qix5RUFBeUU7Z0JBQ3pFLG1FQUFtRTtnQkFDbkUsd0VBQXdFO2dCQUN4RSxxRUFBcUU7Z0JBQ3JFLGdDQUFnQztnQkFDaEMsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFBRTtvQkFDbEMsVUFBRyxDQUFDLDRHQUE0RyxDQUFDLENBQUM7b0JBQ2xILEtBQUssQ0FBQyxrQkFBa0IsR0FBRyx3Q0FBZ0MsQ0FBQztpQkFDN0Q7cUJBQU07b0JBQ0wsa0VBQWtFO29CQUNsRSw2REFBNkQ7b0JBQzdELFVBQUcsQ0FBQyw2REFBNkQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEdBQUcsS0FBSyxFQUFFLFdBQVcsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztpQkFDdEg7YUFDRjtZQUVELG1FQUFtRTtZQUNuRSxNQUFNLGNBQWMsQ0FBQyxRQUFRLEVBQUUsS0FBSyxFQUFFO2dCQUNwQyxNQUFNLEVBQUUsMEJBQWtCLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPO2FBQ2pELENBQUMsQ0FBQztTQUNKO0lBQ0gsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQTNDRCxrQ0EyQ0M7QUFFRCxNQUFhLEtBQU0sU0FBUSxLQUFLO0NBQUk7QUFBcEMsc0JBQW9DIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgbWF4LWxlbiAqL1xuLyogZXNsaW50LWRpc2FibGUgbm8tY29uc29sZSAqL1xuaW1wb3J0ICogYXMgdXJsIGZyb20gJ3VybCc7XG5pbXBvcnQgeyBodHRwUmVxdWVzdCB9IGZyb20gJy4vb3V0Ym91bmQnO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi91dGlsJztcblxuZXhwb3J0IGNvbnN0IENSRUFURV9GQUlMRURfUEhZU0lDQUxfSURfTUFSS0VSID0gJ0FXU0NESzo6Q3VzdG9tUmVzb3VyY2VQcm92aWRlckZyYW1ld29yazo6Q1JFQVRFX0ZBSUxFRCc7XG5leHBvcnQgY29uc3QgTUlTU0lOR19QSFlTSUNBTF9JRF9NQVJLRVIgPSAnQVdTQ0RLOjpDdXN0b21SZXNvdXJjZVByb3ZpZGVyRnJhbWV3b3JrOjpNSVNTSU5HX1BIWVNJQ0FMX0lEJztcblxuZXhwb3J0IGludGVyZmFjZSBDbG91ZEZvcm1hdGlvblJlc3BvbnNlT3B0aW9ucyB7XG4gIHJlYWRvbmx5IHJlYXNvbj86IHN0cmluZztcbiAgcmVhZG9ubHkgbm9FY2hvPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDbG91ZEZvcm1hdGlvbkV2ZW50Q29udGV4dCB7XG4gIFN0YWNrSWQ6IHN0cmluZztcbiAgUmVxdWVzdElkOiBzdHJpbmc7XG4gIFBoeXNpY2FsUmVzb3VyY2VJZD86IHN0cmluZztcbiAgTG9naWNhbFJlc291cmNlSWQ6IHN0cmluZztcbiAgUmVzcG9uc2VVUkw6IHN0cmluZztcbiAgRGF0YT86IGFueVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3VibWl0UmVzcG9uc2Uoc3RhdHVzOiAnU1VDQ0VTUycgfCAnRkFJTEVEJywgZXZlbnQ6IENsb3VkRm9ybWF0aW9uRXZlbnRDb250ZXh0LCBvcHRpb25zOiBDbG91ZEZvcm1hdGlvblJlc3BvbnNlT3B0aW9ucyA9IHsgfSkge1xuICBjb25zdCBqc29uOiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZVJlc3BvbnNlID0ge1xuICAgIFN0YXR1czogc3RhdHVzLFxuICAgIFJlYXNvbjogb3B0aW9ucy5yZWFzb24gfHwgc3RhdHVzLFxuICAgIFN0YWNrSWQ6IGV2ZW50LlN0YWNrSWQsXG4gICAgUmVxdWVzdElkOiBldmVudC5SZXF1ZXN0SWQsXG4gICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBldmVudC5QaHlzaWNhbFJlc291cmNlSWQgfHwgTUlTU0lOR19QSFlTSUNBTF9JRF9NQVJLRVIsXG4gICAgTG9naWNhbFJlc291cmNlSWQ6IGV2ZW50LkxvZ2ljYWxSZXNvdXJjZUlkLFxuICAgIE5vRWNobzogb3B0aW9ucy5ub0VjaG8sXG4gICAgRGF0YTogZXZlbnQuRGF0YSxcbiAgfTtcblxuICBsb2coJ3N1Ym1pdCByZXNwb25zZSB0byBjbG91ZGZvcm1hdGlvbicsIGpzb24pO1xuXG4gIGNvbnN0IHJlc3BvbnNlQm9keSA9IEpTT04uc3RyaW5naWZ5KGpzb24pO1xuXG4gIGNvbnN0IHBhcnNlZFVybCA9IHVybC5wYXJzZShldmVudC5SZXNwb25zZVVSTCk7XG4gIGF3YWl0IGh0dHBSZXF1ZXN0KHtcbiAgICBob3N0bmFtZTogcGFyc2VkVXJsLmhvc3RuYW1lLFxuICAgIHBhdGg6IHBhcnNlZFVybC5wYXRoLFxuICAgIG1ldGhvZDogJ1BVVCcsXG4gICAgaGVhZGVyczoge1xuICAgICAgJ2NvbnRlbnQtdHlwZSc6ICcnLFxuICAgICAgJ2NvbnRlbnQtbGVuZ3RoJzogcmVzcG9uc2VCb2R5Lmxlbmd0aCxcbiAgICB9LFxuICB9LCByZXNwb25zZUJvZHkpO1xufVxuXG5leHBvcnQgbGV0IGluY2x1ZGVTdGFja1RyYWNlcyA9IHRydWU7IC8vIGZvciB1bml0IHRlc3RzXG5cbmV4cG9ydCBmdW5jdGlvbiBzYWZlSGFuZGxlcihibG9jazogKGV2ZW50OiBhbnkpID0+IFByb21pc2U8dm9pZD4pIHtcbiAgcmV0dXJuIGFzeW5jIChldmVudDogYW55KSA9PiB7XG5cbiAgICAvLyBpZ25vcmUgREVMRVRFIGV2ZW50IHdoZW4gdGhlIHBoeXNpY2FsIHJlc291cmNlIElEIGlzIHRoZSBtYXJrZXIgdGhhdFxuICAgIC8vIGluZGljYXRlcyB0aGF0IHRoaXMgREVMRVRFIGlzIGEgc3Vic2VxdWVudCBERUxFVEUgdG8gYSBmYWlsZWQgQ1JFQVRFXG4gICAgLy8gb3BlcmF0aW9uLlxuICAgIGlmIChldmVudC5SZXF1ZXN0VHlwZSA9PT0gJ0RlbGV0ZScgJiYgZXZlbnQuUGh5c2ljYWxSZXNvdXJjZUlkID09PSBDUkVBVEVfRkFJTEVEX1BIWVNJQ0FMX0lEX01BUktFUikge1xuICAgICAgbG9nKCdpZ25vcmluZyBERUxFVEUgZXZlbnQgY2F1c2VkIGJ5IGEgZmFpbGVkIENSRUFURSBldmVudCcpO1xuICAgICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCBldmVudCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGJsb2NrKGV2ZW50KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvLyB0ZWxsIHdhaXRlciBzdGF0ZSBtYWNoaW5lIHRvIHJldHJ5XG4gICAgICBpZiAoZSBpbnN0YW5jZW9mIFJldHJ5KSB7XG4gICAgICAgIGxvZygncmV0cnkgcmVxdWVzdGVkIGJ5IGhhbmRsZXInKTtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFldmVudC5QaHlzaWNhbFJlc291cmNlSWQpIHtcbiAgICAgICAgLy8gc3BlY2lhbCBjYXNlOiBpZiBDUkVBVEUgZmFpbHMsIHdoaWNoIHVzdWFsbHkgaW1wbGllcywgd2UgdXN1YWxseSBkb24ndFxuICAgICAgICAvLyBoYXZlIGEgcGh5c2ljYWwgcmVzb3VyY2UgaWQuIGluIHRoaXMgY2FzZSwgdGhlIHN1YnNlcXVlbnQgREVMRVRFXG4gICAgICAgIC8vIG9wZXJhdGlvbiBkb2VzIG5vdCBoYXZlIGFueSBtZWFuaW5nLCBhbmQgd2lsbCBsaWtlbHkgZmFpbCBhcyB3ZWxsLiB0b1xuICAgICAgICAvLyBhZGRyZXNzIHRoaXMsIHdlIHVzZSBhIG1hcmtlciBzbyB0aGUgcHJvdmlkZXIgZnJhbWV3b3JrIGNhbiBzaW1wbHlcbiAgICAgICAgLy8gaWdub3JlIHRoZSBzdWJzZXF1ZW50IERFTEVURS5cbiAgICAgICAgaWYgKGV2ZW50LlJlcXVlc3RUeXBlID09PSAnQ3JlYXRlJykge1xuICAgICAgICAgIGxvZygnQ1JFQVRFIGZhaWxlZCwgcmVzcG9uZGluZyB3aXRoIGEgbWFya2VyIHBoeXNpY2FsIHJlc291cmNlIGlkIHNvIHRoYXQgdGhlIHN1YnNlcXVlbnQgREVMRVRFIHdpbGwgYmUgaWdub3JlZCcpO1xuICAgICAgICAgIGV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCA9IENSRUFURV9GQUlMRURfUEhZU0lDQUxfSURfTUFSS0VSO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIG90aGVyd2lzZSwgaWYgUGh5c2ljYWxSZXNvdXJjZUlkIGlzIG5vdCBzcGVjaWZpZWQsIHNvbWV0aGluZyBpc1xuICAgICAgICAgIC8vIHRlcnJpYmx5IHdyb25nIGJlY2F1c2UgYWxsIG90aGVyIGV2ZW50cyBzaG91bGQgaGF2ZSBhbiBJRC5cbiAgICAgICAgICBsb2coYEVSUk9SOiBNYWxmb3JtZWQgZXZlbnQuIFwiUGh5c2ljYWxSZXNvdXJjZUlkXCIgaXMgcmVxdWlyZWQ6ICR7SlNPTi5zdHJpbmdpZnkoeyAuLi5ldmVudCwgUmVzcG9uc2VVUkw6ICcuLi4nIH0pfWApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIHRoaXMgaXMgYW4gYWN0dWFsIGVycm9yLCBmYWlsIHRoZSBhY3Rpdml0eSBhbHRvZ2V0aGVyIGFuZCBleGlzdC5cbiAgICAgIGF3YWl0IHN1Ym1pdFJlc3BvbnNlKCdGQUlMRUQnLCBldmVudCwge1xuICAgICAgICByZWFzb246IGluY2x1ZGVTdGFja1RyYWNlcyA/IGUuc3RhY2sgOiBlLm1lc3NhZ2UsXG4gICAgICB9KTtcbiAgICB9XG4gIH07XG59XG5cbmV4cG9ydCBjbGFzcyBSZXRyeSBleHRlbmRzIEVycm9yIHsgfVxuIl19 \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/outbound.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/outbound.js deleted file mode 100644 index 70203dcc42f3..000000000000 --- a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/outbound.js +++ /dev/null @@ -1,45 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.httpRequest = exports.invokeFunction = exports.startExecution = void 0; -/* istanbul ignore file */ -const https = require("https"); -// eslint-disable-next-line import/no-extraneous-dependencies -const AWS = require("aws-sdk"); -const FRAMEWORK_HANDLER_TIMEOUT = 900000; // 15 minutes -// In order to honor the overall maximum timeout set for the target process, -// the default 2 minutes from AWS SDK has to be overriden: -// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Config.html#httpOptions-property -const awsSdkConfig = { - httpOptions: { timeout: FRAMEWORK_HANDLER_TIMEOUT }, -}; -async function defaultHttpRequest(options, responseBody) { - return new Promise((resolve, reject) => { - try { - const request = https.request(options, resolve); - request.on('error', reject); - request.write(responseBody); - request.end(); - } - catch (e) { - reject(e); - } - }); -} -let sfn; -let lambda; -async function defaultStartExecution(req) { - if (!sfn) { - sfn = new AWS.StepFunctions(awsSdkConfig); - } - return sfn.startExecution(req).promise(); -} -async function defaultInvokeFunction(req) { - if (!lambda) { - lambda = new AWS.Lambda(awsSdkConfig); - } - return lambda.invoke(req).promise(); -} -exports.startExecution = defaultStartExecution; -exports.invokeFunction = defaultInvokeFunction; -exports.httpRequest = defaultHttpRequest; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3V0Ym91bmQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJvdXRib3VuZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwwQkFBMEI7QUFDMUIsK0JBQStCO0FBQy9CLDZEQUE2RDtBQUM3RCwrQkFBK0I7QUFJL0IsTUFBTSx5QkFBeUIsR0FBRyxNQUFNLENBQUMsQ0FBQyxhQUFhO0FBRXZELDRFQUE0RTtBQUM1RSwwREFBMEQ7QUFDMUQsMkZBQTJGO0FBQzNGLE1BQU0sWUFBWSxHQUF5QjtJQUN6QyxXQUFXLEVBQUUsRUFBRSxPQUFPLEVBQUUseUJBQXlCLEVBQUU7Q0FDcEQsQ0FBQztBQUVGLEtBQUssVUFBVSxrQkFBa0IsQ0FBQyxPQUE2QixFQUFFLFlBQW9CO0lBQ25GLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7UUFDckMsSUFBSTtZQUNGLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQ2hELE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQzVCLE9BQU8sQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDNUIsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO1NBQ2Y7UUFBQyxPQUFPLENBQUMsRUFBRTtZQUNWLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUNYO0lBQ0gsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsSUFBSSxHQUFzQixDQUFDO0FBQzNCLElBQUksTUFBa0IsQ0FBQztBQUV2QixLQUFLLFVBQVUscUJBQXFCLENBQUMsR0FBMEM7SUFDN0UsSUFBSSxDQUFDLEdBQUcsRUFBRTtRQUNSLEdBQUcsR0FBRyxJQUFJLEdBQUcsQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDLENBQUM7S0FDM0M7SUFFRCxPQUFPLEdBQUcsQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7QUFDM0MsQ0FBQztBQUVELEtBQUssVUFBVSxxQkFBcUIsQ0FBQyxHQUFpQztJQUNwRSxJQUFJLENBQUMsTUFBTSxFQUFFO1FBQ1gsTUFBTSxHQUFHLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztLQUN2QztJQUVELE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztBQUN0QyxDQUFDO0FBRVUsUUFBQSxjQUFjLEdBQUcscUJBQXFCLENBQUM7QUFDdkMsUUFBQSxjQUFjLEdBQUcscUJBQXFCLENBQUM7QUFDdkMsUUFBQSxXQUFXLEdBQUcsa0JBQWtCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBpc3RhbmJ1bCBpZ25vcmUgZmlsZSAqL1xuaW1wb3J0ICogYXMgaHR0cHMgZnJvbSAnaHR0cHMnO1xuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llc1xuaW1wb3J0ICogYXMgQVdTIGZyb20gJ2F3cy1zZGsnO1xuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1leHRyYW5lb3VzLWRlcGVuZGVuY2llc1xuaW1wb3J0IHR5cGUgeyBDb25maWd1cmF0aW9uT3B0aW9ucyB9IGZyb20gJ2F3cy1zZGsvbGliL2NvbmZpZy1iYXNlJztcblxuY29uc3QgRlJBTUVXT1JLX0hBTkRMRVJfVElNRU9VVCA9IDkwMDAwMDsgLy8gMTUgbWludXRlc1xuXG4vLyBJbiBvcmRlciB0byBob25vciB0aGUgb3ZlcmFsbCBtYXhpbXVtIHRpbWVvdXQgc2V0IGZvciB0aGUgdGFyZ2V0IHByb2Nlc3MsXG4vLyB0aGUgZGVmYXVsdCAyIG1pbnV0ZXMgZnJvbSBBV1MgU0RLIGhhcyB0byBiZSBvdmVycmlkZW46XG4vLyBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQVdTSmF2YVNjcmlwdFNESy9sYXRlc3QvQVdTL0NvbmZpZy5odG1sI2h0dHBPcHRpb25zLXByb3BlcnR5XG5jb25zdCBhd3NTZGtDb25maWc6IENvbmZpZ3VyYXRpb25PcHRpb25zID0ge1xuICBodHRwT3B0aW9uczogeyB0aW1lb3V0OiBGUkFNRVdPUktfSEFORExFUl9USU1FT1VUIH0sXG59O1xuXG5hc3luYyBmdW5jdGlvbiBkZWZhdWx0SHR0cFJlcXVlc3Qob3B0aW9uczogaHR0cHMuUmVxdWVzdE9wdGlvbnMsIHJlc3BvbnNlQm9keTogc3RyaW5nKSB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlcXVlc3QgPSBodHRwcy5yZXF1ZXN0KG9wdGlvbnMsIHJlc29sdmUpO1xuICAgICAgcmVxdWVzdC5vbignZXJyb3InLCByZWplY3QpO1xuICAgICAgcmVxdWVzdC53cml0ZShyZXNwb25zZUJvZHkpO1xuICAgICAgcmVxdWVzdC5lbmQoKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICByZWplY3QoZSk7XG4gICAgfVxuICB9KTtcbn1cblxubGV0IHNmbjogQVdTLlN0ZXBGdW5jdGlvbnM7XG5sZXQgbGFtYmRhOiBBV1MuTGFtYmRhO1xuXG5hc3luYyBmdW5jdGlvbiBkZWZhdWx0U3RhcnRFeGVjdXRpb24ocmVxOiBBV1MuU3RlcEZ1bmN0aW9ucy5TdGFydEV4ZWN1dGlvbklucHV0KTogUHJvbWlzZTxBV1MuU3RlcEZ1bmN0aW9ucy5TdGFydEV4ZWN1dGlvbk91dHB1dD4ge1xuICBpZiAoIXNmbikge1xuICAgIHNmbiA9IG5ldyBBV1MuU3RlcEZ1bmN0aW9ucyhhd3NTZGtDb25maWcpO1xuICB9XG5cbiAgcmV0dXJuIHNmbi5zdGFydEV4ZWN1dGlvbihyZXEpLnByb21pc2UoKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZGVmYXVsdEludm9rZUZ1bmN0aW9uKHJlcTogQVdTLkxhbWJkYS5JbnZvY2F0aW9uUmVxdWVzdCk6IFByb21pc2U8QVdTLkxhbWJkYS5JbnZvY2F0aW9uUmVzcG9uc2U+IHtcbiAgaWYgKCFsYW1iZGEpIHtcbiAgICBsYW1iZGEgPSBuZXcgQVdTLkxhbWJkYShhd3NTZGtDb25maWcpO1xuICB9XG5cbiAgcmV0dXJuIGxhbWJkYS5pbnZva2UocmVxKS5wcm9taXNlKCk7XG59XG5cbmV4cG9ydCBsZXQgc3RhcnRFeGVjdXRpb24gPSBkZWZhdWx0U3RhcnRFeGVjdXRpb247XG5leHBvcnQgbGV0IGludm9rZUZ1bmN0aW9uID0gZGVmYXVsdEludm9rZUZ1bmN0aW9uO1xuZXhwb3J0IGxldCBodHRwUmVxdWVzdCA9IGRlZmF1bHRIdHRwUmVxdWVzdDtcbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/util.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/util.js deleted file mode 100644 index ee4c6e9c9dde..000000000000 --- a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/util.js +++ /dev/null @@ -1,17 +0,0 @@ -"use strict"; -/* eslint-disable no-console */ -Object.defineProperty(exports, "__esModule", { value: true }); -exports.log = exports.getEnv = void 0; -function getEnv(name) { - const value = process.env[name]; - if (!value) { - throw new Error(`The environment variable "${name}" is not defined`); - } - return value; -} -exports.getEnv = getEnv; -function log(title, ...args) { - console.log('[provider-framework]', title, ...args.map(x => typeof (x) === 'object' ? JSON.stringify(x, undefined, 2) : x)); -} -exports.log = log; -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInV0aWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtCQUErQjs7O0FBRS9CLFNBQWdCLE1BQU0sQ0FBQyxJQUFZO0lBQ2pDLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDaEMsSUFBSSxDQUFDLEtBQUssRUFBRTtRQUNWLE1BQU0sSUFBSSxLQUFLLENBQUMsNkJBQTZCLElBQUksa0JBQWtCLENBQUMsQ0FBQztLQUN0RTtJQUNELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQU5ELHdCQU1DO0FBRUQsU0FBZ0IsR0FBRyxDQUFDLEtBQVUsRUFBRSxHQUFHLElBQVc7SUFDNUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxzQkFBc0IsRUFBRSxLQUFLLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsT0FBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQzdILENBQUM7QUFGRCxrQkFFQyIsInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIG5vLWNvbnNvbGUgKi9cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEVudihuYW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICBjb25zdCB2YWx1ZSA9IHByb2Nlc3MuZW52W25hbWVdO1xuICBpZiAoIXZhbHVlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBUaGUgZW52aXJvbm1lbnQgdmFyaWFibGUgXCIke25hbWV9XCIgaXMgbm90IGRlZmluZWRgKTtcbiAgfVxuICByZXR1cm4gdmFsdWU7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBsb2codGl0bGU6IGFueSwgLi4uYXJnczogYW55W10pIHtcbiAgY29uc29sZS5sb2coJ1twcm92aWRlci1mcmFtZXdvcmtdJywgdGl0bGUsIC4uLmFyZ3MubWFwKHggPT4gdHlwZW9mKHgpID09PSAnb2JqZWN0JyA/IEpTT04uc3RyaW5naWZ5KHgsIHVuZGVmaW5lZCwgMikgOiB4KSk7XG59XG4iXX0= \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/handler-name.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/handler-name.js similarity index 100% rename from packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/handler-name.js rename to packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/handler-name.js diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/index.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/index.js similarity index 100% rename from packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/index.js rename to packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/index.js diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/privileges.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/privileges.js similarity index 100% rename from packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/privileges.js rename to packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/privileges.js diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/redshift-data.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/redshift-data.js similarity index 100% rename from packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/redshift-data.js rename to packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/redshift-data.js diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/table.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/table.js new file mode 100644 index 000000000000..16942fad1cb3 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/table.js @@ -0,0 +1,117 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.handler = void 0; +const redshift_data_1 = require("./redshift-data"); +const types_1 = require("./types"); +const util_1 = require("./util"); +async function handler(props, event) { + const tableNamePrefix = props.tableName.prefix; + const tableNameSuffix = props.tableName.generateSuffix === 'true' ? `${event.RequestId.substring(0, 8)}` : ''; + const tableColumns = props.tableColumns; + const tableAndClusterProps = props; + if (event.RequestType === 'Create') { + const tableName = await createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps); + return { PhysicalResourceId: tableName }; + } + else if (event.RequestType === 'Delete') { + await dropTable(event.PhysicalResourceId, tableAndClusterProps); + return; + } + else if (event.RequestType === 'Update') { + const tableName = await updateTable(event.PhysicalResourceId, tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps, event.OldResourceProperties); + return { PhysicalResourceId: tableName }; + } + else { + /* eslint-disable-next-line dot-notation */ + throw new Error(`Unrecognized event type: ${event['RequestType']}`); + } +} +exports.handler = handler; +async function createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps) { + const tableName = tableNamePrefix + tableNameSuffix; + const tableColumnsString = tableColumns.map(column => `${column.name} ${column.dataType}`).join(); + let statement = `CREATE TABLE ${tableName} (${tableColumnsString})`; + if (tableAndClusterProps.distStyle) { + statement += ` DISTSTYLE ${tableAndClusterProps.distStyle}`; + } + const distKeyColumn = util_1.getDistKeyColumn(tableColumns); + if (distKeyColumn) { + statement += ` DISTKEY(${distKeyColumn.name})`; + } + const sortKeyColumns = util_1.getSortKeyColumns(tableColumns); + if (sortKeyColumns.length > 0) { + const sortKeyColumnsString = getSortKeyColumnsString(sortKeyColumns); + statement += ` ${tableAndClusterProps.sortStyle} SORTKEY(${sortKeyColumnsString})`; + } + await redshift_data_1.executeStatement(statement, tableAndClusterProps); + return tableName; +} +async function dropTable(tableName, clusterProps) { + await redshift_data_1.executeStatement(`DROP TABLE ${tableName}`, clusterProps); +} +async function updateTable(tableName, tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps, oldResourceProperties) { + const alterationStatements = []; + const oldClusterProps = oldResourceProperties; + if (tableAndClusterProps.clusterName !== oldClusterProps.clusterName || tableAndClusterProps.databaseName !== oldClusterProps.databaseName) { + return createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps); + } + const oldTableNamePrefix = oldResourceProperties.tableName.prefix; + if (tableNamePrefix !== oldTableNamePrefix) { + return createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps); + } + const oldTableColumns = oldResourceProperties.tableColumns; + const columnDeletions = oldTableColumns.filter(oldColumn => (tableColumns.every(column => oldColumn.name !== column.name))); + if (columnDeletions.length > 0) { + alterationStatements.push(...columnDeletions.map(column => `ALTER TABLE ${tableName} DROP COLUMN ${column.name}`)); + } + const columnAdditions = tableColumns.filter(column => { + return !oldTableColumns.some(oldColumn => column.name === oldColumn.name && column.dataType === oldColumn.dataType); + }).map(column => `ADD ${column.name} ${column.dataType}`); + if (columnAdditions.length > 0) { + alterationStatements.push(...columnAdditions.map(addition => `ALTER TABLE ${tableName} ${addition}`)); + } + const oldDistStyle = oldResourceProperties.distStyle; + if ((!oldDistStyle && tableAndClusterProps.distStyle) || + (oldDistStyle && !tableAndClusterProps.distStyle)) { + return createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps); + } + else if (oldDistStyle !== tableAndClusterProps.distStyle) { + alterationStatements.push(`ALTER TABLE ${tableName} ALTER DISTSTYLE ${tableAndClusterProps.distStyle}`); + } + const oldDistKey = util_1.getDistKeyColumn(oldTableColumns)?.name; + const newDistKey = util_1.getDistKeyColumn(tableColumns)?.name; + if ((!oldDistKey && newDistKey) || (oldDistKey && !newDistKey)) { + return createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps); + } + else if (oldDistKey !== newDistKey) { + alterationStatements.push(`ALTER TABLE ${tableName} ALTER DISTKEY ${newDistKey}`); + } + const oldSortKeyColumns = util_1.getSortKeyColumns(oldTableColumns); + const newSortKeyColumns = util_1.getSortKeyColumns(tableColumns); + const oldSortStyle = oldResourceProperties.sortStyle; + const newSortStyle = tableAndClusterProps.sortStyle; + if ((oldSortStyle === newSortStyle && !util_1.areColumnsEqual(oldSortKeyColumns, newSortKeyColumns)) + || (oldSortStyle !== newSortStyle)) { + switch (newSortStyle) { + case types_1.TableSortStyle.INTERLEAVED: + // INTERLEAVED sort key addition requires replacement. + // https://docs.aws.amazon.com/redshift/latest/dg/r_ALTER_TABLE.html + return createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps); + case types_1.TableSortStyle.COMPOUND: { + const sortKeyColumnsString = getSortKeyColumnsString(newSortKeyColumns); + alterationStatements.push(`ALTER TABLE ${tableName} ALTER ${newSortStyle} SORTKEY(${sortKeyColumnsString})`); + break; + } + case types_1.TableSortStyle.AUTO: { + alterationStatements.push(`ALTER TABLE ${tableName} ALTER SORTKEY ${newSortStyle}`); + break; + } + } + } + await Promise.all(alterationStatements.map(statement => redshift_data_1.executeStatement(statement, tableAndClusterProps))); + return tableName; +} +function getSortKeyColumnsString(sortKeyColumns) { + return sortKeyColumns.map(column => column.name).join(); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ0YWJsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFHQSxtREFBbUQ7QUFDbkQsbUNBQTZFO0FBQzdFLGlDQUE4RTtBQUV2RSxLQUFLLFVBQVUsT0FBTyxDQUFDLEtBQTJCLEVBQUUsS0FBa0Q7SUFDM0csTUFBTSxlQUFlLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7SUFDL0MsTUFBTSxlQUFlLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQyxjQUFjLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7SUFDOUcsTUFBTSxZQUFZLEdBQUcsS0FBSyxDQUFDLFlBQVksQ0FBQztJQUN4QyxNQUFNLG9CQUFvQixHQUFHLEtBQUssQ0FBQztJQUVuQyxJQUFJLEtBQUssQ0FBQyxXQUFXLEtBQUssUUFBUSxFQUFFO1FBQ2xDLE1BQU0sU0FBUyxHQUFHLE1BQU0sV0FBVyxDQUFDLGVBQWUsRUFBRSxlQUFlLEVBQUUsWUFBWSxFQUFFLG9CQUFvQixDQUFDLENBQUM7UUFDMUcsT0FBTyxFQUFFLGtCQUFrQixFQUFFLFNBQVMsRUFBRSxDQUFDO0tBQzFDO1NBQU0sSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFBRTtRQUN6QyxNQUFNLFNBQVMsQ0FBQyxLQUFLLENBQUMsa0JBQWtCLEVBQUUsb0JBQW9CLENBQUMsQ0FBQztRQUNoRSxPQUFPO0tBQ1I7U0FBTSxJQUFJLEtBQUssQ0FBQyxXQUFXLEtBQUssUUFBUSxFQUFFO1FBQ3pDLE1BQU0sU0FBUyxHQUFHLE1BQU0sV0FBVyxDQUNqQyxLQUFLLENBQUMsa0JBQWtCLEVBQ3hCLGVBQWUsRUFDZixlQUFlLEVBQ2YsWUFBWSxFQUNaLG9CQUFvQixFQUNwQixLQUFLLENBQUMscUJBQTZDLENBQ3BELENBQUM7UUFDRixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsU0FBUyxFQUFFLENBQUM7S0FDMUM7U0FBTTtRQUNMLDJDQUEyQztRQUMzQyxNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixLQUFLLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0tBQ3JFO0FBQ0gsQ0FBQztBQTFCRCwwQkEwQkM7QUFFRCxLQUFLLFVBQVUsV0FBVyxDQUN4QixlQUF1QixFQUN2QixlQUF1QixFQUN2QixZQUFzQixFQUN0QixvQkFBMEM7SUFFMUMsTUFBTSxTQUFTLEdBQUcsZUFBZSxHQUFHLGVBQWUsQ0FBQztJQUNwRCxNQUFNLGtCQUFrQixHQUFHLFlBQVksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxJQUFJLElBQUksTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7SUFFbEcsSUFBSSxTQUFTLEdBQUcsZ0JBQWdCLFNBQVMsS0FBSyxrQkFBa0IsR0FBRyxDQUFDO0lBRXBFLElBQUksb0JBQW9CLENBQUMsU0FBUyxFQUFFO1FBQ2xDLFNBQVMsSUFBSSxjQUFjLG9CQUFvQixDQUFDLFNBQVMsRUFBRSxDQUFDO0tBQzdEO0lBRUQsTUFBTSxhQUFhLEdBQUcsdUJBQWdCLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDckQsSUFBSSxhQUFhLEVBQUU7UUFDakIsU0FBUyxJQUFJLFlBQVksYUFBYSxDQUFDLElBQUksR0FBRyxDQUFDO0tBQ2hEO0lBRUQsTUFBTSxjQUFjLEdBQUcsd0JBQWlCLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDdkQsSUFBSSxjQUFjLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtRQUM3QixNQUFNLG9CQUFvQixHQUFHLHVCQUF1QixDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ3JFLFNBQVMsSUFBSSxJQUFJLG9CQUFvQixDQUFDLFNBQVMsWUFBWSxvQkFBb0IsR0FBRyxDQUFDO0tBQ3BGO0lBRUQsTUFBTSxnQ0FBZ0IsQ0FBQyxTQUFTLEVBQUUsb0JBQW9CLENBQUMsQ0FBQztJQUN4RCxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDO0FBRUQsS0FBSyxVQUFVLFNBQVMsQ0FBQyxTQUFpQixFQUFFLFlBQTBCO0lBQ3BFLE1BQU0sZ0NBQWdCLENBQUMsY0FBYyxTQUFTLEVBQUUsRUFBRSxZQUFZLENBQUMsQ0FBQztBQUNsRSxDQUFDO0FBRUQsS0FBSyxVQUFVLFdBQVcsQ0FDeEIsU0FBaUIsRUFDakIsZUFBdUIsRUFDdkIsZUFBdUIsRUFDdkIsWUFBc0IsRUFDdEIsb0JBQTBDLEVBQzFDLHFCQUEyQztJQUUzQyxNQUFNLG9CQUFvQixHQUFhLEVBQUUsQ0FBQztJQUUxQyxNQUFNLGVBQWUsR0FBRyxxQkFBcUIsQ0FBQztJQUM5QyxJQUFJLG9CQUFvQixDQUFDLFdBQVcsS0FBSyxlQUFlLENBQUMsV0FBVyxJQUFJLG9CQUFvQixDQUFDLFlBQVksS0FBSyxlQUFlLENBQUMsWUFBWSxFQUFFO1FBQzFJLE9BQU8sV0FBVyxDQUFDLGVBQWUsRUFBRSxlQUFlLEVBQUUsWUFBWSxFQUFFLG9CQUFvQixDQUFDLENBQUM7S0FDMUY7SUFFRCxNQUFNLGtCQUFrQixHQUFHLHFCQUFxQixDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7SUFDbEUsSUFBSSxlQUFlLEtBQUssa0JBQWtCLEVBQUU7UUFDMUMsT0FBTyxXQUFXLENBQUMsZUFBZSxFQUFFLGVBQWUsRUFBRSxZQUFZLEVBQUUsb0JBQW9CLENBQUMsQ0FBQztLQUMxRjtJQUVELE1BQU0sZUFBZSxHQUFHLHFCQUFxQixDQUFDLFlBQVksQ0FBQztJQUMzRCxNQUFNLGVBQWUsR0FBRyxlQUFlLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FDMUQsWUFBWSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEtBQUssTUFBTSxDQUFDLElBQUksQ0FBQyxDQUM3RCxDQUFDLENBQUM7SUFDSCxJQUFJLGVBQWUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1FBQzlCLG9CQUFvQixDQUFDLElBQUksQ0FBQyxHQUFHLGVBQWUsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxlQUFlLFNBQVMsZ0JBQWdCLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7S0FDcEg7SUFFRCxNQUFNLGVBQWUsR0FBRyxZQUFZLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFO1FBQ25ELE9BQU8sQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxTQUFTLENBQUMsSUFBSSxJQUFJLE1BQU0sQ0FBQyxRQUFRLEtBQUssU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ3RILENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLE9BQU8sTUFBTSxDQUFDLElBQUksSUFBSSxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztJQUMxRCxJQUFJLGVBQWUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1FBQzlCLG9CQUFvQixDQUFDLElBQUksQ0FBQyxHQUFHLGVBQWUsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxlQUFlLFNBQVMsSUFBSSxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUM7S0FDdkc7SUFFRCxNQUFNLFlBQVksR0FBRyxxQkFBcUIsQ0FBQyxTQUFTLENBQUM7SUFDckQsSUFBSSxDQUFDLENBQUMsWUFBWSxJQUFJLG9CQUFvQixDQUFDLFNBQVMsQ0FBQztRQUNuRCxDQUFDLFlBQVksSUFBSSxDQUFDLG9CQUFvQixDQUFDLFNBQVMsQ0FBQyxFQUFFO1FBQ25ELE9BQU8sV0FBVyxDQUFDLGVBQWUsRUFBRSxlQUFlLEVBQUUsWUFBWSxFQUFFLG9CQUFvQixDQUFDLENBQUM7S0FDMUY7U0FBTSxJQUFJLFlBQVksS0FBSyxvQkFBb0IsQ0FBQyxTQUFTLEVBQUU7UUFDMUQsb0JBQW9CLENBQUMsSUFBSSxDQUFDLGVBQWUsU0FBUyxvQkFBb0Isb0JBQW9CLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQztLQUN6RztJQUVELE1BQU0sVUFBVSxHQUFHLHVCQUFnQixDQUFDLGVBQWUsQ0FBQyxFQUFFLElBQUksQ0FBQztJQUMzRCxNQUFNLFVBQVUsR0FBRyx1QkFBZ0IsQ0FBQyxZQUFZLENBQUMsRUFBRSxJQUFJLENBQUM7SUFDeEQsSUFBSSxDQUFDLENBQUMsVUFBVSxJQUFJLFVBQVUsQ0FBRSxJQUFJLENBQUMsVUFBVSxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQUU7UUFDL0QsT0FBTyxXQUFXLENBQUMsZUFBZSxFQUFFLGVBQWUsRUFBRSxZQUFZLEVBQUUsb0JBQW9CLENBQUMsQ0FBQztLQUMxRjtTQUFNLElBQUksVUFBVSxLQUFLLFVBQVUsRUFBRTtRQUNwQyxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsZUFBZSxTQUFTLGtCQUFrQixVQUFVLEVBQUUsQ0FBQyxDQUFDO0tBQ25GO0lBRUQsTUFBTSxpQkFBaUIsR0FBRyx3QkFBaUIsQ0FBQyxlQUFlLENBQUMsQ0FBQztJQUM3RCxNQUFNLGlCQUFpQixHQUFHLHdCQUFpQixDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQzFELE1BQU0sWUFBWSxHQUFHLHFCQUFxQixDQUFDLFNBQVMsQ0FBQztJQUNyRCxNQUFNLFlBQVksR0FBRyxvQkFBb0IsQ0FBQyxTQUFTLENBQUM7SUFDcEQsSUFBSSxDQUFDLFlBQVksS0FBSyxZQUFZLElBQUksQ0FBQyxzQkFBZSxDQUFDLGlCQUFpQixFQUFFLGlCQUFpQixDQUFDLENBQUM7V0FDeEYsQ0FBQyxZQUFZLEtBQUssWUFBWSxDQUFDLEVBQUU7UUFDcEMsUUFBUSxZQUFZLEVBQUU7WUFDcEIsS0FBSyxzQkFBYyxDQUFDLFdBQVc7Z0JBQzdCLHNEQUFzRDtnQkFDdEQsb0VBQW9FO2dCQUNwRSxPQUFPLFdBQVcsQ0FBQyxlQUFlLEVBQUUsZUFBZSxFQUFFLFlBQVksRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO1lBRTNGLEtBQUssc0JBQWMsQ0FBQyxRQUFRLENBQUMsQ0FBQztnQkFDNUIsTUFBTSxvQkFBb0IsR0FBRyx1QkFBdUIsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO2dCQUN4RSxvQkFBb0IsQ0FBQyxJQUFJLENBQUMsZUFBZSxTQUFTLFVBQVUsWUFBWSxZQUFZLG9CQUFvQixHQUFHLENBQUMsQ0FBQztnQkFDN0csTUFBTTthQUNQO1lBRUQsS0FBSyxzQkFBYyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUN4QixvQkFBb0IsQ0FBQyxJQUFJLENBQUMsZUFBZSxTQUFTLGtCQUFrQixZQUFZLEVBQUUsQ0FBQyxDQUFDO2dCQUNwRixNQUFNO2FBQ1A7U0FDRjtLQUNGO0lBRUQsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLG9CQUFvQixDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLGdDQUFnQixDQUFDLFNBQVMsRUFBRSxvQkFBb0IsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUU1RyxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDO0FBRUQsU0FBUyx1QkFBdUIsQ0FBQyxjQUF3QjtJQUN2RCxPQUFPLGNBQWMsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7QUFDMUQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tdW5yZXNvbHZlZCAqL1xuaW1wb3J0ICogYXMgQVdTTGFtYmRhIGZyb20gJ2F3cy1sYW1iZGEnO1xuaW1wb3J0IHsgQ29sdW1uIH0gZnJvbSAnLi4vLi4vdGFibGUnO1xuaW1wb3J0IHsgZXhlY3V0ZVN0YXRlbWVudCB9IGZyb20gJy4vcmVkc2hpZnQtZGF0YSc7XG5pbXBvcnQgeyBDbHVzdGVyUHJvcHMsIFRhYmxlQW5kQ2x1c3RlclByb3BzLCBUYWJsZVNvcnRTdHlsZSB9IGZyb20gJy4vdHlwZXMnO1xuaW1wb3J0IHsgYXJlQ29sdW1uc0VxdWFsLCBnZXREaXN0S2V5Q29sdW1uLCBnZXRTb3J0S2V5Q29sdW1ucyB9IGZyb20gJy4vdXRpbCc7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBoYW5kbGVyKHByb3BzOiBUYWJsZUFuZENsdXN0ZXJQcm9wcywgZXZlbnQ6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQpIHtcbiAgY29uc3QgdGFibGVOYW1lUHJlZml4ID0gcHJvcHMudGFibGVOYW1lLnByZWZpeDtcbiAgY29uc3QgdGFibGVOYW1lU3VmZml4ID0gcHJvcHMudGFibGVOYW1lLmdlbmVyYXRlU3VmZml4ID09PSAndHJ1ZScgPyBgJHtldmVudC5SZXF1ZXN0SWQuc3Vic3RyaW5nKDAsIDgpfWAgOiAnJztcbiAgY29uc3QgdGFibGVDb2x1bW5zID0gcHJvcHMudGFibGVDb2x1bW5zO1xuICBjb25zdCB0YWJsZUFuZENsdXN0ZXJQcm9wcyA9IHByb3BzO1xuXG4gIGlmIChldmVudC5SZXF1ZXN0VHlwZSA9PT0gJ0NyZWF0ZScpIHtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBhd2FpdCBjcmVhdGVUYWJsZSh0YWJsZU5hbWVQcmVmaXgsIHRhYmxlTmFtZVN1ZmZpeCwgdGFibGVDb2x1bW5zLCB0YWJsZUFuZENsdXN0ZXJQcm9wcyk7XG4gICAgcmV0dXJuIHsgUGh5c2ljYWxSZXNvdXJjZUlkOiB0YWJsZU5hbWUgfTtcbiAgfSBlbHNlIGlmIChldmVudC5SZXF1ZXN0VHlwZSA9PT0gJ0RlbGV0ZScpIHtcbiAgICBhd2FpdCBkcm9wVGFibGUoZXZlbnQuUGh5c2ljYWxSZXNvdXJjZUlkLCB0YWJsZUFuZENsdXN0ZXJQcm9wcyk7XG4gICAgcmV0dXJuO1xuICB9IGVsc2UgaWYgKGV2ZW50LlJlcXVlc3RUeXBlID09PSAnVXBkYXRlJykge1xuICAgIGNvbnN0IHRhYmxlTmFtZSA9IGF3YWl0IHVwZGF0ZVRhYmxlKFxuICAgICAgZXZlbnQuUGh5c2ljYWxSZXNvdXJjZUlkLFxuICAgICAgdGFibGVOYW1lUHJlZml4LFxuICAgICAgdGFibGVOYW1lU3VmZml4LFxuICAgICAgdGFibGVDb2x1bW5zLFxuICAgICAgdGFibGVBbmRDbHVzdGVyUHJvcHMsXG4gICAgICBldmVudC5PbGRSZXNvdXJjZVByb3BlcnRpZXMgYXMgVGFibGVBbmRDbHVzdGVyUHJvcHMsXG4gICAgKTtcbiAgICByZXR1cm4geyBQaHlzaWNhbFJlc291cmNlSWQ6IHRhYmxlTmFtZSB9O1xuICB9IGVsc2Uge1xuICAgIC8qIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBkb3Qtbm90YXRpb24gKi9cbiAgICB0aHJvdyBuZXcgRXJyb3IoYFVucmVjb2duaXplZCBldmVudCB0eXBlOiAke2V2ZW50WydSZXF1ZXN0VHlwZSddfWApO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNyZWF0ZVRhYmxlKFxuICB0YWJsZU5hbWVQcmVmaXg6IHN0cmluZyxcbiAgdGFibGVOYW1lU3VmZml4OiBzdHJpbmcsXG4gIHRhYmxlQ29sdW1uczogQ29sdW1uW10sXG4gIHRhYmxlQW5kQ2x1c3RlclByb3BzOiBUYWJsZUFuZENsdXN0ZXJQcm9wcyxcbik6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IHRhYmxlTmFtZSA9IHRhYmxlTmFtZVByZWZpeCArIHRhYmxlTmFtZVN1ZmZpeDtcbiAgY29uc3QgdGFibGVDb2x1bW5zU3RyaW5nID0gdGFibGVDb2x1bW5zLm1hcChjb2x1bW4gPT4gYCR7Y29sdW1uLm5hbWV9ICR7Y29sdW1uLmRhdGFUeXBlfWApLmpvaW4oKTtcblxuICBsZXQgc3RhdGVtZW50ID0gYENSRUFURSBUQUJMRSAke3RhYmxlTmFtZX0gKCR7dGFibGVDb2x1bW5zU3RyaW5nfSlgO1xuXG4gIGlmICh0YWJsZUFuZENsdXN0ZXJQcm9wcy5kaXN0U3R5bGUpIHtcbiAgICBzdGF0ZW1lbnQgKz0gYCBESVNUU1RZTEUgJHt0YWJsZUFuZENsdXN0ZXJQcm9wcy5kaXN0U3R5bGV9YDtcbiAgfVxuXG4gIGNvbnN0IGRpc3RLZXlDb2x1bW4gPSBnZXREaXN0S2V5Q29sdW1uKHRhYmxlQ29sdW1ucyk7XG4gIGlmIChkaXN0S2V5Q29sdW1uKSB7XG4gICAgc3RhdGVtZW50ICs9IGAgRElTVEtFWSgke2Rpc3RLZXlDb2x1bW4ubmFtZX0pYDtcbiAgfVxuXG4gIGNvbnN0IHNvcnRLZXlDb2x1bW5zID0gZ2V0U29ydEtleUNvbHVtbnModGFibGVDb2x1bW5zKTtcbiAgaWYgKHNvcnRLZXlDb2x1bW5zLmxlbmd0aCA+IDApIHtcbiAgICBjb25zdCBzb3J0S2V5Q29sdW1uc1N0cmluZyA9IGdldFNvcnRLZXlDb2x1bW5zU3RyaW5nKHNvcnRLZXlDb2x1bW5zKTtcbiAgICBzdGF0ZW1lbnQgKz0gYCAke3RhYmxlQW5kQ2x1c3RlclByb3BzLnNvcnRTdHlsZX0gU09SVEtFWSgke3NvcnRLZXlDb2x1bW5zU3RyaW5nfSlgO1xuICB9XG5cbiAgYXdhaXQgZXhlY3V0ZVN0YXRlbWVudChzdGF0ZW1lbnQsIHRhYmxlQW5kQ2x1c3RlclByb3BzKTtcbiAgcmV0dXJuIHRhYmxlTmFtZTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZHJvcFRhYmxlKHRhYmxlTmFtZTogc3RyaW5nLCBjbHVzdGVyUHJvcHM6IENsdXN0ZXJQcm9wcykge1xuICBhd2FpdCBleGVjdXRlU3RhdGVtZW50KGBEUk9QIFRBQkxFICR7dGFibGVOYW1lfWAsIGNsdXN0ZXJQcm9wcyk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHVwZGF0ZVRhYmxlKFxuICB0YWJsZU5hbWU6IHN0cmluZyxcbiAgdGFibGVOYW1lUHJlZml4OiBzdHJpbmcsXG4gIHRhYmxlTmFtZVN1ZmZpeDogc3RyaW5nLFxuICB0YWJsZUNvbHVtbnM6IENvbHVtbltdLFxuICB0YWJsZUFuZENsdXN0ZXJQcm9wczogVGFibGVBbmRDbHVzdGVyUHJvcHMsXG4gIG9sZFJlc291cmNlUHJvcGVydGllczogVGFibGVBbmRDbHVzdGVyUHJvcHMsXG4pOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCBhbHRlcmF0aW9uU3RhdGVtZW50czogc3RyaW5nW10gPSBbXTtcblxuICBjb25zdCBvbGRDbHVzdGVyUHJvcHMgPSBvbGRSZXNvdXJjZVByb3BlcnRpZXM7XG4gIGlmICh0YWJsZUFuZENsdXN0ZXJQcm9wcy5jbHVzdGVyTmFtZSAhPT0gb2xkQ2x1c3RlclByb3BzLmNsdXN0ZXJOYW1lIHx8IHRhYmxlQW5kQ2x1c3RlclByb3BzLmRhdGFiYXNlTmFtZSAhPT0gb2xkQ2x1c3RlclByb3BzLmRhdGFiYXNlTmFtZSkge1xuICAgIHJldHVybiBjcmVhdGVUYWJsZSh0YWJsZU5hbWVQcmVmaXgsIHRhYmxlTmFtZVN1ZmZpeCwgdGFibGVDb2x1bW5zLCB0YWJsZUFuZENsdXN0ZXJQcm9wcyk7XG4gIH1cblxuICBjb25zdCBvbGRUYWJsZU5hbWVQcmVmaXggPSBvbGRSZXNvdXJjZVByb3BlcnRpZXMudGFibGVOYW1lLnByZWZpeDtcbiAgaWYgKHRhYmxlTmFtZVByZWZpeCAhPT0gb2xkVGFibGVOYW1lUHJlZml4KSB7XG4gICAgcmV0dXJuIGNyZWF0ZVRhYmxlKHRhYmxlTmFtZVByZWZpeCwgdGFibGVOYW1lU3VmZml4LCB0YWJsZUNvbHVtbnMsIHRhYmxlQW5kQ2x1c3RlclByb3BzKTtcbiAgfVxuXG4gIGNvbnN0IG9sZFRhYmxlQ29sdW1ucyA9IG9sZFJlc291cmNlUHJvcGVydGllcy50YWJsZUNvbHVtbnM7XG4gIGNvbnN0IGNvbHVtbkRlbGV0aW9ucyA9IG9sZFRhYmxlQ29sdW1ucy5maWx0ZXIob2xkQ29sdW1uID0+IChcbiAgICB0YWJsZUNvbHVtbnMuZXZlcnkoY29sdW1uID0+IG9sZENvbHVtbi5uYW1lICE9PSBjb2x1bW4ubmFtZSlcbiAgKSk7XG4gIGlmIChjb2x1bW5EZWxldGlvbnMubGVuZ3RoID4gMCkge1xuICAgIGFsdGVyYXRpb25TdGF0ZW1lbnRzLnB1c2goLi4uY29sdW1uRGVsZXRpb25zLm1hcChjb2x1bW4gPT4gYEFMVEVSIFRBQkxFICR7dGFibGVOYW1lfSBEUk9QIENPTFVNTiAke2NvbHVtbi5uYW1lfWApKTtcbiAgfVxuXG4gIGNvbnN0IGNvbHVtbkFkZGl0aW9ucyA9IHRhYmxlQ29sdW1ucy5maWx0ZXIoY29sdW1uID0+IHtcbiAgICByZXR1cm4gIW9sZFRhYmxlQ29sdW1ucy5zb21lKG9sZENvbHVtbiA9PiBjb2x1bW4ubmFtZSA9PT0gb2xkQ29sdW1uLm5hbWUgJiYgY29sdW1uLmRhdGFUeXBlID09PSBvbGRDb2x1bW4uZGF0YVR5cGUpO1xuICB9KS5tYXAoY29sdW1uID0+IGBBREQgJHtjb2x1bW4ubmFtZX0gJHtjb2x1bW4uZGF0YVR5cGV9YCk7XG4gIGlmIChjb2x1bW5BZGRpdGlvbnMubGVuZ3RoID4gMCkge1xuICAgIGFsdGVyYXRpb25TdGF0ZW1lbnRzLnB1c2goLi4uY29sdW1uQWRkaXRpb25zLm1hcChhZGRpdGlvbiA9PiBgQUxURVIgVEFCTEUgJHt0YWJsZU5hbWV9ICR7YWRkaXRpb259YCkpO1xuICB9XG5cbiAgY29uc3Qgb2xkRGlzdFN0eWxlID0gb2xkUmVzb3VyY2VQcm9wZXJ0aWVzLmRpc3RTdHlsZTtcbiAgaWYgKCghb2xkRGlzdFN0eWxlICYmIHRhYmxlQW5kQ2x1c3RlclByb3BzLmRpc3RTdHlsZSkgfHxcbiAgICAob2xkRGlzdFN0eWxlICYmICF0YWJsZUFuZENsdXN0ZXJQcm9wcy5kaXN0U3R5bGUpKSB7XG4gICAgcmV0dXJuIGNyZWF0ZVRhYmxlKHRhYmxlTmFtZVByZWZpeCwgdGFibGVOYW1lU3VmZml4LCB0YWJsZUNvbHVtbnMsIHRhYmxlQW5kQ2x1c3RlclByb3BzKTtcbiAgfSBlbHNlIGlmIChvbGREaXN0U3R5bGUgIT09IHRhYmxlQW5kQ2x1c3RlclByb3BzLmRpc3RTdHlsZSkge1xuICAgIGFsdGVyYXRpb25TdGF0ZW1lbnRzLnB1c2goYEFMVEVSIFRBQkxFICR7dGFibGVOYW1lfSBBTFRFUiBESVNUU1RZTEUgJHt0YWJsZUFuZENsdXN0ZXJQcm9wcy5kaXN0U3R5bGV9YCk7XG4gIH1cblxuICBjb25zdCBvbGREaXN0S2V5ID0gZ2V0RGlzdEtleUNvbHVtbihvbGRUYWJsZUNvbHVtbnMpPy5uYW1lO1xuICBjb25zdCBuZXdEaXN0S2V5ID0gZ2V0RGlzdEtleUNvbHVtbih0YWJsZUNvbHVtbnMpPy5uYW1lO1xuICBpZiAoKCFvbGREaXN0S2V5ICYmIG5ld0Rpc3RLZXkgKSB8fCAob2xkRGlzdEtleSAmJiAhbmV3RGlzdEtleSkpIHtcbiAgICByZXR1cm4gY3JlYXRlVGFibGUodGFibGVOYW1lUHJlZml4LCB0YWJsZU5hbWVTdWZmaXgsIHRhYmxlQ29sdW1ucywgdGFibGVBbmRDbHVzdGVyUHJvcHMpO1xuICB9IGVsc2UgaWYgKG9sZERpc3RLZXkgIT09IG5ld0Rpc3RLZXkpIHtcbiAgICBhbHRlcmF0aW9uU3RhdGVtZW50cy5wdXNoKGBBTFRFUiBUQUJMRSAke3RhYmxlTmFtZX0gQUxURVIgRElTVEtFWSAke25ld0Rpc3RLZXl9YCk7XG4gIH1cblxuICBjb25zdCBvbGRTb3J0S2V5Q29sdW1ucyA9IGdldFNvcnRLZXlDb2x1bW5zKG9sZFRhYmxlQ29sdW1ucyk7XG4gIGNvbnN0IG5ld1NvcnRLZXlDb2x1bW5zID0gZ2V0U29ydEtleUNvbHVtbnModGFibGVDb2x1bW5zKTtcbiAgY29uc3Qgb2xkU29ydFN0eWxlID0gb2xkUmVzb3VyY2VQcm9wZXJ0aWVzLnNvcnRTdHlsZTtcbiAgY29uc3QgbmV3U29ydFN0eWxlID0gdGFibGVBbmRDbHVzdGVyUHJvcHMuc29ydFN0eWxlO1xuICBpZiAoKG9sZFNvcnRTdHlsZSA9PT0gbmV3U29ydFN0eWxlICYmICFhcmVDb2x1bW5zRXF1YWwob2xkU29ydEtleUNvbHVtbnMsIG5ld1NvcnRLZXlDb2x1bW5zKSlcbiAgICB8fCAob2xkU29ydFN0eWxlICE9PSBuZXdTb3J0U3R5bGUpKSB7XG4gICAgc3dpdGNoIChuZXdTb3J0U3R5bGUpIHtcbiAgICAgIGNhc2UgVGFibGVTb3J0U3R5bGUuSU5URVJMRUFWRUQ6XG4gICAgICAgIC8vIElOVEVSTEVBVkVEIHNvcnQga2V5IGFkZGl0aW9uIHJlcXVpcmVzIHJlcGxhY2VtZW50LlxuICAgICAgICAvLyBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vcmVkc2hpZnQvbGF0ZXN0L2RnL3JfQUxURVJfVEFCTEUuaHRtbFxuICAgICAgICByZXR1cm4gY3JlYXRlVGFibGUodGFibGVOYW1lUHJlZml4LCB0YWJsZU5hbWVTdWZmaXgsIHRhYmxlQ29sdW1ucywgdGFibGVBbmRDbHVzdGVyUHJvcHMpO1xuXG4gICAgICBjYXNlIFRhYmxlU29ydFN0eWxlLkNPTVBPVU5EOiB7XG4gICAgICAgIGNvbnN0IHNvcnRLZXlDb2x1bW5zU3RyaW5nID0gZ2V0U29ydEtleUNvbHVtbnNTdHJpbmcobmV3U29ydEtleUNvbHVtbnMpO1xuICAgICAgICBhbHRlcmF0aW9uU3RhdGVtZW50cy5wdXNoKGBBTFRFUiBUQUJMRSAke3RhYmxlTmFtZX0gQUxURVIgJHtuZXdTb3J0U3R5bGV9IFNPUlRLRVkoJHtzb3J0S2V5Q29sdW1uc1N0cmluZ30pYCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICBjYXNlIFRhYmxlU29ydFN0eWxlLkFVVE86IHtcbiAgICAgICAgYWx0ZXJhdGlvblN0YXRlbWVudHMucHVzaChgQUxURVIgVEFCTEUgJHt0YWJsZU5hbWV9IEFMVEVSIFNPUlRLRVkgJHtuZXdTb3J0U3R5bGV9YCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGF3YWl0IFByb21pc2UuYWxsKGFsdGVyYXRpb25TdGF0ZW1lbnRzLm1hcChzdGF0ZW1lbnQgPT4gZXhlY3V0ZVN0YXRlbWVudChzdGF0ZW1lbnQsIHRhYmxlQW5kQ2x1c3RlclByb3BzKSkpO1xuXG4gIHJldHVybiB0YWJsZU5hbWU7XG59XG5cbmZ1bmN0aW9uIGdldFNvcnRLZXlDb2x1bW5zU3RyaW5nKHNvcnRLZXlDb2x1bW5zOiBDb2x1bW5bXSkge1xuICByZXR1cm4gc29ydEtleUNvbHVtbnMubWFwKGNvbHVtbiA9PiBjb2x1bW4ubmFtZSkuam9pbigpO1xufVxuIl19 \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/types.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/types.js similarity index 100% rename from packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/types.js rename to packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/types.js diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/user.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/user.js similarity index 100% rename from packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/user.js rename to packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/user.js diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/util.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/util.js similarity index 100% rename from packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/util.js rename to packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415/util.js diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/cfn-response.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/cfn-response.js new file mode 100644 index 000000000000..1966567b2164 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/cfn-response.js @@ -0,0 +1,87 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Retry = exports.safeHandler = exports.includeStackTraces = exports.submitResponse = exports.MISSING_PHYSICAL_ID_MARKER = exports.CREATE_FAILED_PHYSICAL_ID_MARKER = void 0; +/* eslint-disable max-len */ +/* eslint-disable no-console */ +const url = require("url"); +const outbound_1 = require("./outbound"); +const util_1 = require("./util"); +exports.CREATE_FAILED_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::CREATE_FAILED'; +exports.MISSING_PHYSICAL_ID_MARKER = 'AWSCDK::CustomResourceProviderFramework::MISSING_PHYSICAL_ID'; +async function submitResponse(status, event, options = {}) { + const json = { + Status: status, + Reason: options.reason || status, + StackId: event.StackId, + RequestId: event.RequestId, + PhysicalResourceId: event.PhysicalResourceId || exports.MISSING_PHYSICAL_ID_MARKER, + LogicalResourceId: event.LogicalResourceId, + NoEcho: options.noEcho, + Data: event.Data, + }; + util_1.log('submit response to cloudformation', json); + const responseBody = JSON.stringify(json); + const parsedUrl = url.parse(event.ResponseURL); + const retryOptions = { + attempts: 5, + sleep: 1000, + }; + await util_1.withRetries(retryOptions, outbound_1.httpRequest)({ + hostname: parsedUrl.hostname, + path: parsedUrl.path, + method: 'PUT', + headers: { + 'content-type': '', + 'content-length': responseBody.length, + }, + }, responseBody); +} +exports.submitResponse = submitResponse; +exports.includeStackTraces = true; // for unit tests +function safeHandler(block) { + return async (event) => { + // ignore DELETE event when the physical resource ID is the marker that + // indicates that this DELETE is a subsequent DELETE to a failed CREATE + // operation. + if (event.RequestType === 'Delete' && event.PhysicalResourceId === exports.CREATE_FAILED_PHYSICAL_ID_MARKER) { + util_1.log('ignoring DELETE event caused by a failed CREATE event'); + await submitResponse('SUCCESS', event); + return; + } + try { + await block(event); + } + catch (e) { + // tell waiter state machine to retry + if (e instanceof Retry) { + util_1.log('retry requested by handler'); + throw e; + } + if (!event.PhysicalResourceId) { + // special case: if CREATE fails, which usually implies, we usually don't + // have a physical resource id. in this case, the subsequent DELETE + // operation does not have any meaning, and will likely fail as well. to + // address this, we use a marker so the provider framework can simply + // ignore the subsequent DELETE. + if (event.RequestType === 'Create') { + util_1.log('CREATE failed, responding with a marker physical resource id so that the subsequent DELETE will be ignored'); + event.PhysicalResourceId = exports.CREATE_FAILED_PHYSICAL_ID_MARKER; + } + else { + // otherwise, if PhysicalResourceId is not specified, something is + // terribly wrong because all other events should have an ID. + util_1.log(`ERROR: Malformed event. "PhysicalResourceId" is required: ${JSON.stringify({ ...event, ResponseURL: '...' })}`); + } + } + // this is an actual error, fail the activity altogether and exist. + await submitResponse('FAILED', event, { + reason: exports.includeStackTraces ? e.stack : e.message, + }); + } + }; +} +exports.safeHandler = safeHandler; +class Retry extends Error { +} +exports.Retry = Retry; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2ZuLXJlc3BvbnNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiY2ZuLXJlc3BvbnNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLDRCQUE0QjtBQUM1QiwrQkFBK0I7QUFDL0IsMkJBQTJCO0FBQzNCLHlDQUF5QztBQUN6QyxpQ0FBMEM7QUFFN0IsUUFBQSxnQ0FBZ0MsR0FBRyx3REFBd0QsQ0FBQztBQUM1RixRQUFBLDBCQUEwQixHQUFHLDhEQUE4RCxDQUFDO0FBZ0JsRyxLQUFLLFVBQVUsY0FBYyxDQUFDLE1BQTRCLEVBQUUsS0FBaUMsRUFBRSxVQUF5QyxFQUFHO0lBQ2hKLE1BQU0sSUFBSSxHQUFtRDtRQUMzRCxNQUFNLEVBQUUsTUFBTTtRQUNkLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTSxJQUFJLE1BQU07UUFDaEMsT0FBTyxFQUFFLEtBQUssQ0FBQyxPQUFPO1FBQ3RCLFNBQVMsRUFBRSxLQUFLLENBQUMsU0FBUztRQUMxQixrQkFBa0IsRUFBRSxLQUFLLENBQUMsa0JBQWtCLElBQUksa0NBQTBCO1FBQzFFLGlCQUFpQixFQUFFLEtBQUssQ0FBQyxpQkFBaUI7UUFDMUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNO1FBQ3RCLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSTtLQUNqQixDQUFDO0lBRUYsVUFBRyxDQUFDLG1DQUFtQyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBRS9DLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7SUFFMUMsTUFBTSxTQUFTLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUM7SUFFL0MsTUFBTSxZQUFZLEdBQUc7UUFDbkIsUUFBUSxFQUFFLENBQUM7UUFDWCxLQUFLLEVBQUUsSUFBSTtLQUNaLENBQUM7SUFDRixNQUFNLGtCQUFXLENBQUMsWUFBWSxFQUFFLHNCQUFXLENBQUMsQ0FBQztRQUMzQyxRQUFRLEVBQUUsU0FBUyxDQUFDLFFBQVE7UUFDNUIsSUFBSSxFQUFFLFNBQVMsQ0FBQyxJQUFJO1FBQ3BCLE1BQU0sRUFBRSxLQUFLO1FBQ2IsT0FBTyxFQUFFO1lBQ1AsY0FBYyxFQUFFLEVBQUU7WUFDbEIsZ0JBQWdCLEVBQUUsWUFBWSxDQUFDLE1BQU07U0FDdEM7S0FDRixFQUFFLFlBQVksQ0FBQyxDQUFDO0FBQ25CLENBQUM7QUEvQkQsd0NBK0JDO0FBRVUsUUFBQSxrQkFBa0IsR0FBRyxJQUFJLENBQUMsQ0FBQyxpQkFBaUI7QUFFdkQsU0FBZ0IsV0FBVyxDQUFDLEtBQW9DO0lBQzlELE9BQU8sS0FBSyxFQUFFLEtBQVUsRUFBRSxFQUFFO1FBRTFCLHVFQUF1RTtRQUN2RSx1RUFBdUU7UUFDdkUsYUFBYTtRQUNiLElBQUksS0FBSyxDQUFDLFdBQVcsS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLGtCQUFrQixLQUFLLHdDQUFnQyxFQUFFO1lBQ25HLFVBQUcsQ0FBQyx1REFBdUQsQ0FBQyxDQUFDO1lBQzdELE1BQU0sY0FBYyxDQUFDLFNBQVMsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUN2QyxPQUFPO1NBQ1I7UUFFRCxJQUFJO1lBQ0YsTUFBTSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7U0FDcEI7UUFBQyxPQUFPLENBQUMsRUFBRTtZQUNWLHFDQUFxQztZQUNyQyxJQUFJLENBQUMsWUFBWSxLQUFLLEVBQUU7Z0JBQ3RCLFVBQUcsQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO2dCQUNsQyxNQUFNLENBQUMsQ0FBQzthQUNUO1lBRUQsSUFBSSxDQUFDLEtBQUssQ0FBQyxrQkFBa0IsRUFBRTtnQkFDN0IseUVBQXlFO2dCQUN6RSxtRUFBbUU7Z0JBQ25FLHdFQUF3RTtnQkFDeEUscUVBQXFFO2dCQUNyRSxnQ0FBZ0M7Z0JBQ2hDLElBQUksS0FBSyxDQUFDLFdBQVcsS0FBSyxRQUFRLEVBQUU7b0JBQ2xDLFVBQUcsQ0FBQyw0R0FBNEcsQ0FBQyxDQUFDO29CQUNsSCxLQUFLLENBQUMsa0JBQWtCLEdBQUcsd0NBQWdDLENBQUM7aUJBQzdEO3FCQUFNO29CQUNMLGtFQUFrRTtvQkFDbEUsNkRBQTZEO29CQUM3RCxVQUFHLENBQUMsNkRBQTZELElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxHQUFHLEtBQUssRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7aUJBQ3RIO2FBQ0Y7WUFFRCxtRUFBbUU7WUFDbkUsTUFBTSxjQUFjLENBQUMsUUFBUSxFQUFFLEtBQUssRUFBRTtnQkFDcEMsTUFBTSxFQUFFLDBCQUFrQixDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTzthQUNqRCxDQUFDLENBQUM7U0FDSjtJQUNILENBQUMsQ0FBQztBQUNKLENBQUM7QUEzQ0Qsa0NBMkNDO0FBRUQsTUFBYSxLQUFNLFNBQVEsS0FBSztDQUFJO0FBQXBDLHNCQUFvQyIsInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIG1heC1sZW4gKi9cbi8qIGVzbGludC1kaXNhYmxlIG5vLWNvbnNvbGUgKi9cbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xuaW1wb3J0IHsgaHR0cFJlcXVlc3QgfSBmcm9tICcuL291dGJvdW5kJztcbmltcG9ydCB7IGxvZywgd2l0aFJldHJpZXMgfSBmcm9tICcuL3V0aWwnO1xuXG5leHBvcnQgY29uc3QgQ1JFQVRFX0ZBSUxFRF9QSFlTSUNBTF9JRF9NQVJLRVIgPSAnQVdTQ0RLOjpDdXN0b21SZXNvdXJjZVByb3ZpZGVyRnJhbWV3b3JrOjpDUkVBVEVfRkFJTEVEJztcbmV4cG9ydCBjb25zdCBNSVNTSU5HX1BIWVNJQ0FMX0lEX01BUktFUiA9ICdBV1NDREs6OkN1c3RvbVJlc291cmNlUHJvdmlkZXJGcmFtZXdvcms6Ok1JU1NJTkdfUEhZU0lDQUxfSUQnO1xuXG5leHBvcnQgaW50ZXJmYWNlIENsb3VkRm9ybWF0aW9uUmVzcG9uc2VPcHRpb25zIHtcbiAgcmVhZG9ubHkgcmVhc29uPzogc3RyaW5nO1xuICByZWFkb25seSBub0VjaG8/OiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENsb3VkRm9ybWF0aW9uRXZlbnRDb250ZXh0IHtcbiAgU3RhY2tJZDogc3RyaW5nO1xuICBSZXF1ZXN0SWQ6IHN0cmluZztcbiAgUGh5c2ljYWxSZXNvdXJjZUlkPzogc3RyaW5nO1xuICBMb2dpY2FsUmVzb3VyY2VJZDogc3RyaW5nO1xuICBSZXNwb25zZVVSTDogc3RyaW5nO1xuICBEYXRhPzogYW55XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdWJtaXRSZXNwb25zZShzdGF0dXM6ICdTVUNDRVNTJyB8ICdGQUlMRUQnLCBldmVudDogQ2xvdWRGb3JtYXRpb25FdmVudENvbnRleHQsIG9wdGlvbnM6IENsb3VkRm9ybWF0aW9uUmVzcG9uc2VPcHRpb25zID0geyB9KSB7XG4gIGNvbnN0IGpzb246IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlUmVzcG9uc2UgPSB7XG4gICAgU3RhdHVzOiBzdGF0dXMsXG4gICAgUmVhc29uOiBvcHRpb25zLnJlYXNvbiB8fCBzdGF0dXMsXG4gICAgU3RhY2tJZDogZXZlbnQuU3RhY2tJZCxcbiAgICBSZXF1ZXN0SWQ6IGV2ZW50LlJlcXVlc3RJZCxcbiAgICBQaHlzaWNhbFJlc291cmNlSWQ6IGV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCB8fCBNSVNTSU5HX1BIWVNJQ0FMX0lEX01BUktFUixcbiAgICBMb2dpY2FsUmVzb3VyY2VJZDogZXZlbnQuTG9naWNhbFJlc291cmNlSWQsXG4gICAgTm9FY2hvOiBvcHRpb25zLm5vRWNobyxcbiAgICBEYXRhOiBldmVudC5EYXRhLFxuICB9O1xuXG4gIGxvZygnc3VibWl0IHJlc3BvbnNlIHRvIGNsb3VkZm9ybWF0aW9uJywganNvbik7XG5cbiAgY29uc3QgcmVzcG9uc2VCb2R5ID0gSlNPTi5zdHJpbmdpZnkoanNvbik7XG5cbiAgY29uc3QgcGFyc2VkVXJsID0gdXJsLnBhcnNlKGV2ZW50LlJlc3BvbnNlVVJMKTtcblxuICBjb25zdCByZXRyeU9wdGlvbnMgPSB7XG4gICAgYXR0ZW1wdHM6IDUsXG4gICAgc2xlZXA6IDEwMDAsXG4gIH07XG4gIGF3YWl0IHdpdGhSZXRyaWVzKHJldHJ5T3B0aW9ucywgaHR0cFJlcXVlc3QpKHtcbiAgICBob3N0bmFtZTogcGFyc2VkVXJsLmhvc3RuYW1lLFxuICAgIHBhdGg6IHBhcnNlZFVybC5wYXRoLFxuICAgIG1ldGhvZDogJ1BVVCcsXG4gICAgaGVhZGVyczoge1xuICAgICAgJ2NvbnRlbnQtdHlwZSc6ICcnLFxuICAgICAgJ2NvbnRlbnQtbGVuZ3RoJzogcmVzcG9uc2VCb2R5Lmxlbmd0aCxcbiAgICB9LFxuICB9LCByZXNwb25zZUJvZHkpO1xufVxuXG5leHBvcnQgbGV0IGluY2x1ZGVTdGFja1RyYWNlcyA9IHRydWU7IC8vIGZvciB1bml0IHRlc3RzXG5cbmV4cG9ydCBmdW5jdGlvbiBzYWZlSGFuZGxlcihibG9jazogKGV2ZW50OiBhbnkpID0+IFByb21pc2U8dm9pZD4pIHtcbiAgcmV0dXJuIGFzeW5jIChldmVudDogYW55KSA9PiB7XG5cbiAgICAvLyBpZ25vcmUgREVMRVRFIGV2ZW50IHdoZW4gdGhlIHBoeXNpY2FsIHJlc291cmNlIElEIGlzIHRoZSBtYXJrZXIgdGhhdFxuICAgIC8vIGluZGljYXRlcyB0aGF0IHRoaXMgREVMRVRFIGlzIGEgc3Vic2VxdWVudCBERUxFVEUgdG8gYSBmYWlsZWQgQ1JFQVRFXG4gICAgLy8gb3BlcmF0aW9uLlxuICAgIGlmIChldmVudC5SZXF1ZXN0VHlwZSA9PT0gJ0RlbGV0ZScgJiYgZXZlbnQuUGh5c2ljYWxSZXNvdXJjZUlkID09PSBDUkVBVEVfRkFJTEVEX1BIWVNJQ0FMX0lEX01BUktFUikge1xuICAgICAgbG9nKCdpZ25vcmluZyBERUxFVEUgZXZlbnQgY2F1c2VkIGJ5IGEgZmFpbGVkIENSRUFURSBldmVudCcpO1xuICAgICAgYXdhaXQgc3VibWl0UmVzcG9uc2UoJ1NVQ0NFU1MnLCBldmVudCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGJsb2NrKGV2ZW50KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAvLyB0ZWxsIHdhaXRlciBzdGF0ZSBtYWNoaW5lIHRvIHJldHJ5XG4gICAgICBpZiAoZSBpbnN0YW5jZW9mIFJldHJ5KSB7XG4gICAgICAgIGxvZygncmV0cnkgcmVxdWVzdGVkIGJ5IGhhbmRsZXInKTtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFldmVudC5QaHlzaWNhbFJlc291cmNlSWQpIHtcbiAgICAgICAgLy8gc3BlY2lhbCBjYXNlOiBpZiBDUkVBVEUgZmFpbHMsIHdoaWNoIHVzdWFsbHkgaW1wbGllcywgd2UgdXN1YWxseSBkb24ndFxuICAgICAgICAvLyBoYXZlIGEgcGh5c2ljYWwgcmVzb3VyY2UgaWQuIGluIHRoaXMgY2FzZSwgdGhlIHN1YnNlcXVlbnQgREVMRVRFXG4gICAgICAgIC8vIG9wZXJhdGlvbiBkb2VzIG5vdCBoYXZlIGFueSBtZWFuaW5nLCBhbmQgd2lsbCBsaWtlbHkgZmFpbCBhcyB3ZWxsLiB0b1xuICAgICAgICAvLyBhZGRyZXNzIHRoaXMsIHdlIHVzZSBhIG1hcmtlciBzbyB0aGUgcHJvdmlkZXIgZnJhbWV3b3JrIGNhbiBzaW1wbHlcbiAgICAgICAgLy8gaWdub3JlIHRoZSBzdWJzZXF1ZW50IERFTEVURS5cbiAgICAgICAgaWYgKGV2ZW50LlJlcXVlc3RUeXBlID09PSAnQ3JlYXRlJykge1xuICAgICAgICAgIGxvZygnQ1JFQVRFIGZhaWxlZCwgcmVzcG9uZGluZyB3aXRoIGEgbWFya2VyIHBoeXNpY2FsIHJlc291cmNlIGlkIHNvIHRoYXQgdGhlIHN1YnNlcXVlbnQgREVMRVRFIHdpbGwgYmUgaWdub3JlZCcpO1xuICAgICAgICAgIGV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCA9IENSRUFURV9GQUlMRURfUEhZU0lDQUxfSURfTUFSS0VSO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIG90aGVyd2lzZSwgaWYgUGh5c2ljYWxSZXNvdXJjZUlkIGlzIG5vdCBzcGVjaWZpZWQsIHNvbWV0aGluZyBpc1xuICAgICAgICAgIC8vIHRlcnJpYmx5IHdyb25nIGJlY2F1c2UgYWxsIG90aGVyIGV2ZW50cyBzaG91bGQgaGF2ZSBhbiBJRC5cbiAgICAgICAgICBsb2coYEVSUk9SOiBNYWxmb3JtZWQgZXZlbnQuIFwiUGh5c2ljYWxSZXNvdXJjZUlkXCIgaXMgcmVxdWlyZWQ6ICR7SlNPTi5zdHJpbmdpZnkoeyAuLi5ldmVudCwgUmVzcG9uc2VVUkw6ICcuLi4nIH0pfWApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIHRoaXMgaXMgYW4gYWN0dWFsIGVycm9yLCBmYWlsIHRoZSBhY3Rpdml0eSBhbHRvZ2V0aGVyIGFuZCBleGlzdC5cbiAgICAgIGF3YWl0IHN1Ym1pdFJlc3BvbnNlKCdGQUlMRUQnLCBldmVudCwge1xuICAgICAgICByZWFzb246IGluY2x1ZGVTdGFja1RyYWNlcyA/IGUuc3RhY2sgOiBlLm1lc3NhZ2UsXG4gICAgICB9KTtcbiAgICB9XG4gIH07XG59XG5cbmV4cG9ydCBjbGFzcyBSZXRyeSBleHRlbmRzIEVycm9yIHsgfVxuIl19 \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/consts.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/consts.js similarity index 100% rename from packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/consts.js rename to packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/consts.js diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/framework.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/framework.js similarity index 100% rename from packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671/framework.js rename to packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/framework.js diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/outbound.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/outbound.js new file mode 100644 index 000000000000..cc0667d42f0e --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/outbound.js @@ -0,0 +1,69 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.httpRequest = exports.invokeFunction = exports.startExecution = void 0; +/* istanbul ignore file */ +const https = require("https"); +// eslint-disable-next-line import/no-extraneous-dependencies +const AWS = require("aws-sdk"); +const FRAMEWORK_HANDLER_TIMEOUT = 900000; // 15 minutes +// In order to honor the overall maximum timeout set for the target process, +// the default 2 minutes from AWS SDK has to be overriden: +// https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Config.html#httpOptions-property +const awsSdkConfig = { + httpOptions: { timeout: FRAMEWORK_HANDLER_TIMEOUT }, +}; +async function defaultHttpRequest(options, responseBody) { + return new Promise((resolve, reject) => { + try { + const request = https.request(options, resolve); + request.on('error', reject); + request.write(responseBody); + request.end(); + } + catch (e) { + reject(e); + } + }); +} +let sfn; +let lambda; +async function defaultStartExecution(req) { + if (!sfn) { + sfn = new AWS.StepFunctions(awsSdkConfig); + } + return sfn.startExecution(req).promise(); +} +async function defaultInvokeFunction(req) { + if (!lambda) { + lambda = new AWS.Lambda(awsSdkConfig); + } + try { + /** + * Try an initial invoke. + * + * When you try to invoke a function that is inactive, the invocation fails and Lambda sets + * the function to pending state until the function resources are recreated. + * If Lambda fails to recreate the resources, the function is set to the inactive state. + * + * We're using invoke first because `waitFor` doesn't trigger an inactive function to do anything, + * it just runs `getFunction` and checks the state. + */ + return await lambda.invoke(req).promise(); + } + catch (error) { + /** + * The status of the Lambda function is checked every second for up to 300 seconds. + * Exits the loop on 'Active' state and throws an error on 'Inactive' or 'Failed'. + * + * And now we wait. + */ + await lambda.waitFor('functionActiveV2', { + FunctionName: req.FunctionName, + }).promise(); + return await lambda.invoke(req).promise(); + } +} +exports.startExecution = defaultStartExecution; +exports.invokeFunction = defaultInvokeFunction; +exports.httpRequest = defaultHttpRequest; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3V0Ym91bmQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJvdXRib3VuZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwwQkFBMEI7QUFDMUIsK0JBQStCO0FBQy9CLDZEQUE2RDtBQUM3RCwrQkFBK0I7QUFJL0IsTUFBTSx5QkFBeUIsR0FBRyxNQUFNLENBQUMsQ0FBQyxhQUFhO0FBRXZELDRFQUE0RTtBQUM1RSwwREFBMEQ7QUFDMUQsMkZBQTJGO0FBQzNGLE1BQU0sWUFBWSxHQUF5QjtJQUN6QyxXQUFXLEVBQUUsRUFBRSxPQUFPLEVBQUUseUJBQXlCLEVBQUU7Q0FDcEQsQ0FBQztBQUVGLEtBQUssVUFBVSxrQkFBa0IsQ0FBQyxPQUE2QixFQUFFLFlBQW9CO0lBQ25GLE9BQU8sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7UUFDckMsSUFBSTtZQUNGLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1lBQ2hELE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQzVCLE9BQU8sQ0FBQyxLQUFLLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDNUIsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDO1NBQ2Y7UUFBQyxPQUFPLENBQUMsRUFBRTtZQUNWLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztTQUNYO0lBQ0gsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsSUFBSSxHQUFzQixDQUFDO0FBQzNCLElBQUksTUFBa0IsQ0FBQztBQUV2QixLQUFLLFVBQVUscUJBQXFCLENBQUMsR0FBMEM7SUFDN0UsSUFBSSxDQUFDLEdBQUcsRUFBRTtRQUNSLEdBQUcsR0FBRyxJQUFJLEdBQUcsQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDLENBQUM7S0FDM0M7SUFFRCxPQUFPLEdBQUcsQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7QUFDM0MsQ0FBQztBQUVELEtBQUssVUFBVSxxQkFBcUIsQ0FBQyxHQUFpQztJQUNwRSxJQUFJLENBQUMsTUFBTSxFQUFFO1FBQ1gsTUFBTSxHQUFHLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztLQUN2QztJQUVELElBQUk7UUFDRjs7Ozs7Ozs7O1dBU0c7UUFDSCxPQUFPLE1BQU0sTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztLQUMzQztJQUFDLE9BQU8sS0FBSyxFQUFFO1FBRWQ7Ozs7O1dBS0c7UUFDSCxNQUFNLE1BQU0sQ0FBQyxPQUFPLENBQUMsa0JBQWtCLEVBQUU7WUFDdkMsWUFBWSxFQUFFLEdBQUcsQ0FBQyxZQUFZO1NBQy9CLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztRQUNiLE9BQU8sTUFBTSxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO0tBQzNDO0FBQ0gsQ0FBQztBQUVVLFFBQUEsY0FBYyxHQUFHLHFCQUFxQixDQUFDO0FBQ3ZDLFFBQUEsY0FBYyxHQUFHLHFCQUFxQixDQUFDO0FBQ3ZDLFFBQUEsV0FBVyxHQUFHLGtCQUFrQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogaXN0YW5idWwgaWdub3JlIGZpbGUgKi9cbmltcG9ydCAqIGFzIGh0dHBzIGZyb20gJ2h0dHBzJztcbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXNcbmltcG9ydCAqIGFzIEFXUyBmcm9tICdhd3Mtc2RrJztcbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXNcbmltcG9ydCB0eXBlIHsgQ29uZmlndXJhdGlvbk9wdGlvbnMgfSBmcm9tICdhd3Mtc2RrL2xpYi9jb25maWctYmFzZSc7XG5cbmNvbnN0IEZSQU1FV09SS19IQU5ETEVSX1RJTUVPVVQgPSA5MDAwMDA7IC8vIDE1IG1pbnV0ZXNcblxuLy8gSW4gb3JkZXIgdG8gaG9ub3IgdGhlIG92ZXJhbGwgbWF4aW11bSB0aW1lb3V0IHNldCBmb3IgdGhlIHRhcmdldCBwcm9jZXNzLFxuLy8gdGhlIGRlZmF1bHQgMiBtaW51dGVzIGZyb20gQVdTIFNESyBoYXMgdG8gYmUgb3ZlcnJpZGVuOlxuLy8gaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FXU0phdmFTY3JpcHRTREsvbGF0ZXN0L0FXUy9Db25maWcuaHRtbCNodHRwT3B0aW9ucy1wcm9wZXJ0eVxuY29uc3QgYXdzU2RrQ29uZmlnOiBDb25maWd1cmF0aW9uT3B0aW9ucyA9IHtcbiAgaHR0cE9wdGlvbnM6IHsgdGltZW91dDogRlJBTUVXT1JLX0hBTkRMRVJfVElNRU9VVCB9LFxufTtcblxuYXN5bmMgZnVuY3Rpb24gZGVmYXVsdEh0dHBSZXF1ZXN0KG9wdGlvbnM6IGh0dHBzLlJlcXVlc3RPcHRpb25zLCByZXNwb25zZUJvZHk6IHN0cmluZykge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXF1ZXN0ID0gaHR0cHMucmVxdWVzdChvcHRpb25zLCByZXNvbHZlKTtcbiAgICAgIHJlcXVlc3Qub24oJ2Vycm9yJywgcmVqZWN0KTtcbiAgICAgIHJlcXVlc3Qud3JpdGUocmVzcG9uc2VCb2R5KTtcbiAgICAgIHJlcXVlc3QuZW5kKCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgcmVqZWN0KGUpO1xuICAgIH1cbiAgfSk7XG59XG5cbmxldCBzZm46IEFXUy5TdGVwRnVuY3Rpb25zO1xubGV0IGxhbWJkYTogQVdTLkxhbWJkYTtcblxuYXN5bmMgZnVuY3Rpb24gZGVmYXVsdFN0YXJ0RXhlY3V0aW9uKHJlcTogQVdTLlN0ZXBGdW5jdGlvbnMuU3RhcnRFeGVjdXRpb25JbnB1dCk6IFByb21pc2U8QVdTLlN0ZXBGdW5jdGlvbnMuU3RhcnRFeGVjdXRpb25PdXRwdXQ+IHtcbiAgaWYgKCFzZm4pIHtcbiAgICBzZm4gPSBuZXcgQVdTLlN0ZXBGdW5jdGlvbnMoYXdzU2RrQ29uZmlnKTtcbiAgfVxuXG4gIHJldHVybiBzZm4uc3RhcnRFeGVjdXRpb24ocmVxKS5wcm9taXNlKCk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGRlZmF1bHRJbnZva2VGdW5jdGlvbihyZXE6IEFXUy5MYW1iZGEuSW52b2NhdGlvblJlcXVlc3QpOiBQcm9taXNlPEFXUy5MYW1iZGEuSW52b2NhdGlvblJlc3BvbnNlPiB7XG4gIGlmICghbGFtYmRhKSB7XG4gICAgbGFtYmRhID0gbmV3IEFXUy5MYW1iZGEoYXdzU2RrQ29uZmlnKTtcbiAgfVxuXG4gIHRyeSB7XG4gICAgLyoqXG4gICAgICogVHJ5IGFuIGluaXRpYWwgaW52b2tlLlxuICAgICAqXG4gICAgICogV2hlbiB5b3UgdHJ5IHRvIGludm9rZSBhIGZ1bmN0aW9uIHRoYXQgaXMgaW5hY3RpdmUsIHRoZSBpbnZvY2F0aW9uIGZhaWxzIGFuZCBMYW1iZGEgc2V0c1xuICAgICAqIHRoZSBmdW5jdGlvbiB0byBwZW5kaW5nIHN0YXRlIHVudGlsIHRoZSBmdW5jdGlvbiByZXNvdXJjZXMgYXJlIHJlY3JlYXRlZC5cbiAgICAgKiBJZiBMYW1iZGEgZmFpbHMgdG8gcmVjcmVhdGUgdGhlIHJlc291cmNlcywgdGhlIGZ1bmN0aW9uIGlzIHNldCB0byB0aGUgaW5hY3RpdmUgc3RhdGUuXG4gICAgICpcbiAgICAgKiBXZSdyZSB1c2luZyBpbnZva2UgZmlyc3QgYmVjYXVzZSBgd2FpdEZvcmAgZG9lc24ndCB0cmlnZ2VyIGFuIGluYWN0aXZlIGZ1bmN0aW9uIHRvIGRvIGFueXRoaW5nLFxuICAgICAqIGl0IGp1c3QgcnVucyBgZ2V0RnVuY3Rpb25gIGFuZCBjaGVja3MgdGhlIHN0YXRlLlxuICAgICAqL1xuICAgIHJldHVybiBhd2FpdCBsYW1iZGEuaW52b2tlKHJlcSkucHJvbWlzZSgpO1xuICB9IGNhdGNoIChlcnJvcikge1xuXG4gICAgLyoqXG4gICAgICogVGhlIHN0YXR1cyBvZiB0aGUgTGFtYmRhIGZ1bmN0aW9uIGlzIGNoZWNrZWQgZXZlcnkgc2Vjb25kIGZvciB1cCB0byAzMDAgc2Vjb25kcy5cbiAgICAgKiBFeGl0cyB0aGUgbG9vcCBvbiAnQWN0aXZlJyBzdGF0ZSBhbmQgdGhyb3dzIGFuIGVycm9yIG9uICdJbmFjdGl2ZScgb3IgJ0ZhaWxlZCcuXG4gICAgICpcbiAgICAgKiBBbmQgbm93IHdlIHdhaXQuXG4gICAgICovXG4gICAgYXdhaXQgbGFtYmRhLndhaXRGb3IoJ2Z1bmN0aW9uQWN0aXZlVjInLCB7XG4gICAgICBGdW5jdGlvbk5hbWU6IHJlcS5GdW5jdGlvbk5hbWUsXG4gICAgfSkucHJvbWlzZSgpO1xuICAgIHJldHVybiBhd2FpdCBsYW1iZGEuaW52b2tlKHJlcSkucHJvbWlzZSgpO1xuICB9XG59XG5cbmV4cG9ydCBsZXQgc3RhcnRFeGVjdXRpb24gPSBkZWZhdWx0U3RhcnRFeGVjdXRpb247XG5leHBvcnQgbGV0IGludm9rZUZ1bmN0aW9uID0gZGVmYXVsdEludm9rZUZ1bmN0aW9uO1xuZXhwb3J0IGxldCBodHRwUmVxdWVzdCA9IGRlZmF1bHRIdHRwUmVxdWVzdDtcbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/util.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/util.js new file mode 100644 index 000000000000..f09276d40ac9 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585/util.js @@ -0,0 +1,39 @@ +"use strict"; +/* eslint-disable no-console */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.withRetries = exports.log = exports.getEnv = void 0; +function getEnv(name) { + const value = process.env[name]; + if (!value) { + throw new Error(`The environment variable "${name}" is not defined`); + } + return value; +} +exports.getEnv = getEnv; +function log(title, ...args) { + console.log('[provider-framework]', title, ...args.map(x => typeof (x) === 'object' ? JSON.stringify(x, undefined, 2) : x)); +} +exports.log = log; +function withRetries(options, fn) { + return async (...xs) => { + let attempts = options.attempts; + let ms = options.sleep; + while (true) { + try { + return await fn(...xs); + } + catch (e) { + if (attempts-- <= 0) { + throw e; + } + await sleep(Math.floor(Math.random() * ms)); + ms *= 2; + } + } + }; +} +exports.withRetries = withRetries; +async function sleep(ms) { + return new Promise((ok) => setTimeout(ok, ms)); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInV0aWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLCtCQUErQjs7O0FBRS9CLFNBQWdCLE1BQU0sQ0FBQyxJQUFZO0lBQ2pDLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDaEMsSUFBSSxDQUFDLEtBQUssRUFBRTtRQUNWLE1BQU0sSUFBSSxLQUFLLENBQUMsNkJBQTZCLElBQUksa0JBQWtCLENBQUMsQ0FBQztLQUN0RTtJQUNELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQU5ELHdCQU1DO0FBRUQsU0FBZ0IsR0FBRyxDQUFDLEtBQVUsRUFBRSxHQUFHLElBQVc7SUFDNUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxzQkFBc0IsRUFBRSxLQUFLLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsT0FBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQzdILENBQUM7QUFGRCxrQkFFQztBQVNELFNBQWdCLFdBQVcsQ0FBMEIsT0FBcUIsRUFBRSxFQUE0QjtJQUN0RyxPQUFPLEtBQUssRUFBRSxHQUFHLEVBQUssRUFBRSxFQUFFO1FBQ3hCLElBQUksUUFBUSxHQUFHLE9BQU8sQ0FBQyxRQUFRLENBQUM7UUFDaEMsSUFBSSxFQUFFLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQztRQUN2QixPQUFPLElBQUksRUFBRTtZQUNYLElBQUk7Z0JBQ0YsT0FBTyxNQUFNLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO2FBQ3hCO1lBQUMsT0FBTyxDQUFDLEVBQUU7Z0JBQ1YsSUFBSSxRQUFRLEVBQUUsSUFBSSxDQUFDLEVBQUU7b0JBQ25CLE1BQU0sQ0FBQyxDQUFDO2lCQUNUO2dCQUNELE1BQU0sS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUM7Z0JBQzVDLEVBQUUsSUFBSSxDQUFDLENBQUM7YUFDVDtTQUNGO0lBQ0gsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQWhCRCxrQ0FnQkM7QUFFRCxLQUFLLFVBQVUsS0FBSyxDQUFDLEVBQVU7SUFDN0IsT0FBTyxJQUFJLE9BQU8sQ0FBQyxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsVUFBVSxDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO0FBQ2pELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBuby1jb25zb2xlICovXG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRFbnYobmFtZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgdmFsdWUgPSBwcm9jZXNzLmVudltuYW1lXTtcbiAgaWYgKCF2YWx1ZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgVGhlIGVudmlyb25tZW50IHZhcmlhYmxlIFwiJHtuYW1lfVwiIGlzIG5vdCBkZWZpbmVkYCk7XG4gIH1cbiAgcmV0dXJuIHZhbHVlO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbG9nKHRpdGxlOiBhbnksIC4uLmFyZ3M6IGFueVtdKSB7XG4gIGNvbnNvbGUubG9nKCdbcHJvdmlkZXItZnJhbWV3b3JrXScsIHRpdGxlLCAuLi5hcmdzLm1hcCh4ID0+IHR5cGVvZih4KSA9PT0gJ29iamVjdCcgPyBKU09OLnN0cmluZ2lmeSh4LCB1bmRlZmluZWQsIDIpIDogeCkpO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJldHJ5T3B0aW9ucyB7XG4gIC8qKiBIb3cgbWFueSByZXRyaWVzICh3aWxsIGF0IGxlYXN0IHRyeSBvbmNlKSAqL1xuICByZWFkb25seSBhdHRlbXB0czogbnVtYmVyO1xuICAvKiogU2xlZXAgYmFzZSwgaW4gbXMgKi9cbiAgcmVhZG9ubHkgc2xlZXA6IG51bWJlcjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHdpdGhSZXRyaWVzPEEgZXh0ZW5kcyBBcnJheTxhbnk+LCBCPihvcHRpb25zOiBSZXRyeU9wdGlvbnMsIGZuOiAoLi4ueHM6IEEpID0+IFByb21pc2U8Qj4pOiAoLi4ueHM6IEEpID0+IFByb21pc2U8Qj4ge1xuICByZXR1cm4gYXN5bmMgKC4uLnhzOiBBKSA9PiB7XG4gICAgbGV0IGF0dGVtcHRzID0gb3B0aW9ucy5hdHRlbXB0cztcbiAgICBsZXQgbXMgPSBvcHRpb25zLnNsZWVwO1xuICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4gYXdhaXQgZm4oLi4ueHMpO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBpZiAoYXR0ZW1wdHMtLSA8PSAwKSB7XG4gICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCBzbGVlcChNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBtcykpO1xuICAgICAgICBtcyAqPSAyO1xuICAgICAgfVxuICAgIH1cbiAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gc2xlZXAobXM6IG51bWJlcik6IFByb21pc2U8dm9pZD4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKG9rKSA9PiBzZXRUaW1lb3V0KG9rLCBtcykpO1xufSJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/table.js b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/table.js deleted file mode 100644 index f85a0f3c2936..000000000000 --- a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3/table.js +++ /dev/null @@ -1,116 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.handler = void 0; -const redshift_data_1 = require("./redshift-data"); -const types_1 = require("./types"); -const util_1 = require("./util"); -async function handler(props, event) { - const tableNamePrefix = props.tableName.prefix; - const tableNameSuffix = props.tableName.generateSuffix === 'true' ? `${event.RequestId.substring(0, 8)}` : ''; - const tableColumns = props.tableColumns; - const tableAndClusterProps = props; - if (event.RequestType === 'Create') { - const tableName = await createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps); - return { PhysicalResourceId: tableName }; - } - else if (event.RequestType === 'Delete') { - await dropTable(event.PhysicalResourceId, tableAndClusterProps); - return; - } - else if (event.RequestType === 'Update') { - const tableName = await updateTable(event.PhysicalResourceId, tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps, event.OldResourceProperties); - return { PhysicalResourceId: tableName }; - } - else { - /* eslint-disable-next-line dot-notation */ - throw new Error(`Unrecognized event type: ${event['RequestType']}`); - } -} -exports.handler = handler; -async function createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps) { - const tableName = tableNamePrefix + tableNameSuffix; - const tableColumnsString = tableColumns.map(column => `${column.name} ${column.dataType}`).join(); - let statement = `CREATE TABLE ${tableName} (${tableColumnsString})`; - if (tableAndClusterProps.distStyle) { - statement += ` DISTSTYLE ${tableAndClusterProps.distStyle}`; - } - const distKeyColumn = util_1.getDistKeyColumn(tableColumns); - if (distKeyColumn) { - statement += ` DISTKEY(${distKeyColumn.name})`; - } - const sortKeyColumns = util_1.getSortKeyColumns(tableColumns); - if (sortKeyColumns.length > 0) { - const sortKeyColumnsString = getSortKeyColumnsString(sortKeyColumns); - statement += ` ${tableAndClusterProps.sortStyle} SORTKEY(${sortKeyColumnsString})`; - } - await redshift_data_1.executeStatement(statement, tableAndClusterProps); - return tableName; -} -async function dropTable(tableName, clusterProps) { - await redshift_data_1.executeStatement(`DROP TABLE ${tableName}`, clusterProps); -} -async function updateTable(tableName, tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps, oldResourceProperties) { - const alterationStatements = []; - const oldClusterProps = oldResourceProperties; - if (tableAndClusterProps.clusterName !== oldClusterProps.clusterName || tableAndClusterProps.databaseName !== oldClusterProps.databaseName) { - return createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps); - } - const oldTableNamePrefix = oldResourceProperties.tableName.prefix; - if (tableNamePrefix !== oldTableNamePrefix) { - return createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps); - } - const oldTableColumns = oldResourceProperties.tableColumns; - if (!oldTableColumns.every(oldColumn => tableColumns.some(column => column.name === oldColumn.name && column.dataType === oldColumn.dataType))) { - return createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps); - } - const columnAdditions = tableColumns.filter(column => { - return !oldTableColumns.some(oldColumn => column.name === oldColumn.name && column.dataType === oldColumn.dataType); - }).map(column => `ADD ${column.name} ${column.dataType}`); - if (columnAdditions.length > 0) { - alterationStatements.push(...columnAdditions.map(addition => `ALTER TABLE ${tableName} ${addition}`)); - } - const oldDistStyle = oldResourceProperties.distStyle; - if ((!oldDistStyle && tableAndClusterProps.distStyle) || - (oldDistStyle && !tableAndClusterProps.distStyle)) { - return createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps); - } - else if (oldDistStyle !== tableAndClusterProps.distStyle) { - alterationStatements.push(`ALTER TABLE ${tableName} ALTER DISTSTYLE ${tableAndClusterProps.distStyle}`); - } - const oldDistKey = util_1.getDistKeyColumn(oldTableColumns)?.name; - const newDistKey = util_1.getDistKeyColumn(tableColumns)?.name; - if ((!oldDistKey && newDistKey) || (oldDistKey && !newDistKey)) { - return createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps); - } - else if (oldDistKey !== newDistKey) { - alterationStatements.push(`ALTER TABLE ${tableName} ALTER DISTKEY ${newDistKey}`); - } - const oldSortKeyColumns = util_1.getSortKeyColumns(oldTableColumns); - const newSortKeyColumns = util_1.getSortKeyColumns(tableColumns); - const oldSortStyle = oldResourceProperties.sortStyle; - const newSortStyle = tableAndClusterProps.sortStyle; - if ((oldSortStyle === newSortStyle && !util_1.areColumnsEqual(oldSortKeyColumns, newSortKeyColumns)) - || (oldSortStyle !== newSortStyle)) { - switch (newSortStyle) { - case types_1.TableSortStyle.INTERLEAVED: - // INTERLEAVED sort key addition requires replacement. - // https://docs.aws.amazon.com/redshift/latest/dg/r_ALTER_TABLE.html - return createTable(tableNamePrefix, tableNameSuffix, tableColumns, tableAndClusterProps); - case types_1.TableSortStyle.COMPOUND: { - const sortKeyColumnsString = getSortKeyColumnsString(newSortKeyColumns); - alterationStatements.push(`ALTER TABLE ${tableName} ALTER ${newSortStyle} SORTKEY(${sortKeyColumnsString})`); - break; - } - case types_1.TableSortStyle.AUTO: { - alterationStatements.push(`ALTER TABLE ${tableName} ALTER SORTKEY ${newSortStyle}`); - break; - } - } - } - await Promise.all(alterationStatements.map(statement => redshift_data_1.executeStatement(statement, tableAndClusterProps))); - return tableName; -} -function getSortKeyColumnsString(sortKeyColumns) { - return sortKeyColumns.map(column => column.name).join(); -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ0YWJsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFHQSxtREFBbUQ7QUFDbkQsbUNBQTZFO0FBQzdFLGlDQUE4RTtBQUV2RSxLQUFLLFVBQVUsT0FBTyxDQUFDLEtBQTJCLEVBQUUsS0FBa0Q7SUFDM0csTUFBTSxlQUFlLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7SUFDL0MsTUFBTSxlQUFlLEdBQUcsS0FBSyxDQUFDLFNBQVMsQ0FBQyxjQUFjLEtBQUssTUFBTSxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7SUFDOUcsTUFBTSxZQUFZLEdBQUcsS0FBSyxDQUFDLFlBQVksQ0FBQztJQUN4QyxNQUFNLG9CQUFvQixHQUFHLEtBQUssQ0FBQztJQUVuQyxJQUFJLEtBQUssQ0FBQyxXQUFXLEtBQUssUUFBUSxFQUFFO1FBQ2xDLE1BQU0sU0FBUyxHQUFHLE1BQU0sV0FBVyxDQUFDLGVBQWUsRUFBRSxlQUFlLEVBQUUsWUFBWSxFQUFFLG9CQUFvQixDQUFDLENBQUM7UUFDMUcsT0FBTyxFQUFFLGtCQUFrQixFQUFFLFNBQVMsRUFBRSxDQUFDO0tBQzFDO1NBQU0sSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFBRTtRQUN6QyxNQUFNLFNBQVMsQ0FBQyxLQUFLLENBQUMsa0JBQWtCLEVBQUUsb0JBQW9CLENBQUMsQ0FBQztRQUNoRSxPQUFPO0tBQ1I7U0FBTSxJQUFJLEtBQUssQ0FBQyxXQUFXLEtBQUssUUFBUSxFQUFFO1FBQ3pDLE1BQU0sU0FBUyxHQUFHLE1BQU0sV0FBVyxDQUNqQyxLQUFLLENBQUMsa0JBQWtCLEVBQ3hCLGVBQWUsRUFDZixlQUFlLEVBQ2YsWUFBWSxFQUNaLG9CQUFvQixFQUNwQixLQUFLLENBQUMscUJBQTZDLENBQ3BELENBQUM7UUFDRixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsU0FBUyxFQUFFLENBQUM7S0FDMUM7U0FBTTtRQUNMLDJDQUEyQztRQUMzQyxNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixLQUFLLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0tBQ3JFO0FBQ0gsQ0FBQztBQTFCRCwwQkEwQkM7QUFFRCxLQUFLLFVBQVUsV0FBVyxDQUN4QixlQUF1QixFQUN2QixlQUF1QixFQUN2QixZQUFzQixFQUN0QixvQkFBMEM7SUFFMUMsTUFBTSxTQUFTLEdBQUcsZUFBZSxHQUFHLGVBQWUsQ0FBQztJQUNwRCxNQUFNLGtCQUFrQixHQUFHLFlBQVksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxJQUFJLElBQUksTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7SUFFbEcsSUFBSSxTQUFTLEdBQUcsZ0JBQWdCLFNBQVMsS0FBSyxrQkFBa0IsR0FBRyxDQUFDO0lBRXBFLElBQUksb0JBQW9CLENBQUMsU0FBUyxFQUFFO1FBQ2xDLFNBQVMsSUFBSSxjQUFjLG9CQUFvQixDQUFDLFNBQVMsRUFBRSxDQUFDO0tBQzdEO0lBRUQsTUFBTSxhQUFhLEdBQUcsdUJBQWdCLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDckQsSUFBSSxhQUFhLEVBQUU7UUFDakIsU0FBUyxJQUFJLFlBQVksYUFBYSxDQUFDLElBQUksR0FBRyxDQUFDO0tBQ2hEO0lBRUQsTUFBTSxjQUFjLEdBQUcsd0JBQWlCLENBQUMsWUFBWSxDQUFDLENBQUM7SUFDdkQsSUFBSSxjQUFjLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtRQUM3QixNQUFNLG9CQUFvQixHQUFHLHVCQUF1QixDQUFDLGNBQWMsQ0FBQyxDQUFDO1FBQ3JFLFNBQVMsSUFBSSxJQUFJLG9CQUFvQixDQUFDLFNBQVMsWUFBWSxvQkFBb0IsR0FBRyxDQUFDO0tBQ3BGO0lBRUQsTUFBTSxnQ0FBZ0IsQ0FBQyxTQUFTLEVBQUUsb0JBQW9CLENBQUMsQ0FBQztJQUN4RCxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDO0FBRUQsS0FBSyxVQUFVLFNBQVMsQ0FBQyxTQUFpQixFQUFFLFlBQTBCO0lBQ3BFLE1BQU0sZ0NBQWdCLENBQUMsY0FBYyxTQUFTLEVBQUUsRUFBRSxZQUFZLENBQUMsQ0FBQztBQUNsRSxDQUFDO0FBRUQsS0FBSyxVQUFVLFdBQVcsQ0FDeEIsU0FBaUIsRUFDakIsZUFBdUIsRUFDdkIsZUFBdUIsRUFDdkIsWUFBc0IsRUFDdEIsb0JBQTBDLEVBQzFDLHFCQUEyQztJQUUzQyxNQUFNLG9CQUFvQixHQUFhLEVBQUUsQ0FBQztJQUUxQyxNQUFNLGVBQWUsR0FBRyxxQkFBcUIsQ0FBQztJQUM5QyxJQUFJLG9CQUFvQixDQUFDLFdBQVcsS0FBSyxlQUFlLENBQUMsV0FBVyxJQUFJLG9CQUFvQixDQUFDLFlBQVksS0FBSyxlQUFlLENBQUMsWUFBWSxFQUFFO1FBQzFJLE9BQU8sV0FBVyxDQUFDLGVBQWUsRUFBRSxlQUFlLEVBQUUsWUFBWSxFQUFFLG9CQUFvQixDQUFDLENBQUM7S0FDMUY7SUFFRCxNQUFNLGtCQUFrQixHQUFHLHFCQUFxQixDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUM7SUFDbEUsSUFBSSxlQUFlLEtBQUssa0JBQWtCLEVBQUU7UUFDMUMsT0FBTyxXQUFXLENBQUMsZUFBZSxFQUFFLGVBQWUsRUFBRSxZQUFZLEVBQUUsb0JBQW9CLENBQUMsQ0FBQztLQUMxRjtJQUVELE1BQU0sZUFBZSxHQUFHLHFCQUFxQixDQUFDLFlBQVksQ0FBQztJQUMzRCxJQUFJLENBQUMsZUFBZSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxLQUFLLFNBQVMsQ0FBQyxJQUFJLElBQUksTUFBTSxDQUFDLFFBQVEsS0FBSyxTQUFTLENBQUMsUUFBUSxDQUFDLENBQUMsRUFBRTtRQUM5SSxPQUFPLFdBQVcsQ0FBQyxlQUFlLEVBQUUsZUFBZSxFQUFFLFlBQVksRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO0tBQzFGO0lBRUQsTUFBTSxlQUFlLEdBQUcsWUFBWSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRTtRQUNuRCxPQUFPLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssU0FBUyxDQUFDLElBQUksSUFBSSxNQUFNLENBQUMsUUFBUSxLQUFLLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN0SCxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxPQUFPLE1BQU0sQ0FBQyxJQUFJLElBQUksTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7SUFDMUQsSUFBSSxlQUFlLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtRQUM5QixvQkFBb0IsQ0FBQyxJQUFJLENBQUMsR0FBRyxlQUFlLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsZUFBZSxTQUFTLElBQUksUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDO0tBQ3ZHO0lBRUQsTUFBTSxZQUFZLEdBQUcscUJBQXFCLENBQUMsU0FBUyxDQUFDO0lBQ3JELElBQUksQ0FBQyxDQUFDLFlBQVksSUFBSSxvQkFBb0IsQ0FBQyxTQUFTLENBQUM7UUFDbkQsQ0FBQyxZQUFZLElBQUksQ0FBQyxvQkFBb0IsQ0FBQyxTQUFTLENBQUMsRUFBRTtRQUNuRCxPQUFPLFdBQVcsQ0FBQyxlQUFlLEVBQUUsZUFBZSxFQUFFLFlBQVksRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO0tBQzFGO1NBQU0sSUFBSSxZQUFZLEtBQUssb0JBQW9CLENBQUMsU0FBUyxFQUFFO1FBQzFELG9CQUFvQixDQUFDLElBQUksQ0FBQyxlQUFlLFNBQVMsb0JBQW9CLG9CQUFvQixDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUM7S0FDekc7SUFFRCxNQUFNLFVBQVUsR0FBRyx1QkFBZ0IsQ0FBQyxlQUFlLENBQUMsRUFBRSxJQUFJLENBQUM7SUFDM0QsTUFBTSxVQUFVLEdBQUcsdUJBQWdCLENBQUMsWUFBWSxDQUFDLEVBQUUsSUFBSSxDQUFDO0lBQ3hELElBQUksQ0FBQyxDQUFDLFVBQVUsSUFBSSxVQUFVLENBQUUsSUFBSSxDQUFDLFVBQVUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxFQUFFO1FBQy9ELE9BQU8sV0FBVyxDQUFDLGVBQWUsRUFBRSxlQUFlLEVBQUUsWUFBWSxFQUFFLG9CQUFvQixDQUFDLENBQUM7S0FDMUY7U0FBTSxJQUFJLFVBQVUsS0FBSyxVQUFVLEVBQUU7UUFDcEMsb0JBQW9CLENBQUMsSUFBSSxDQUFDLGVBQWUsU0FBUyxrQkFBa0IsVUFBVSxFQUFFLENBQUMsQ0FBQztLQUNuRjtJQUVELE1BQU0saUJBQWlCLEdBQUcsd0JBQWlCLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDN0QsTUFBTSxpQkFBaUIsR0FBRyx3QkFBaUIsQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUMxRCxNQUFNLFlBQVksR0FBRyxxQkFBcUIsQ0FBQyxTQUFTLENBQUM7SUFDckQsTUFBTSxZQUFZLEdBQUcsb0JBQW9CLENBQUMsU0FBUyxDQUFDO0lBQ3BELElBQUksQ0FBQyxZQUFZLEtBQUssWUFBWSxJQUFJLENBQUMsc0JBQWUsQ0FBQyxpQkFBaUIsRUFBRSxpQkFBaUIsQ0FBQyxDQUFDO1dBQ3hGLENBQUMsWUFBWSxLQUFLLFlBQVksQ0FBQyxFQUFFO1FBQ3BDLFFBQVEsWUFBWSxFQUFFO1lBQ3BCLEtBQUssc0JBQWMsQ0FBQyxXQUFXO2dCQUM3QixzREFBc0Q7Z0JBQ3RELG9FQUFvRTtnQkFDcEUsT0FBTyxXQUFXLENBQUMsZUFBZSxFQUFFLGVBQWUsRUFBRSxZQUFZLEVBQUUsb0JBQW9CLENBQUMsQ0FBQztZQUUzRixLQUFLLHNCQUFjLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQzVCLE1BQU0sb0JBQW9CLEdBQUcsdUJBQXVCLENBQUMsaUJBQWlCLENBQUMsQ0FBQztnQkFDeEUsb0JBQW9CLENBQUMsSUFBSSxDQUFDLGVBQWUsU0FBUyxVQUFVLFlBQVksWUFBWSxvQkFBb0IsR0FBRyxDQUFDLENBQUM7Z0JBQzdHLE1BQU07YUFDUDtZQUVELEtBQUssc0JBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDeEIsb0JBQW9CLENBQUMsSUFBSSxDQUFDLGVBQWUsU0FBUyxrQkFBa0IsWUFBWSxFQUFFLENBQUMsQ0FBQztnQkFDcEYsTUFBTTthQUNQO1NBQ0Y7S0FDRjtJQUVELE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxnQ0FBZ0IsQ0FBQyxTQUFTLEVBQUUsb0JBQW9CLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFNUcsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQUVELFNBQVMsdUJBQXVCLENBQUMsY0FBd0I7SUFDdkQsT0FBTyxjQUFjLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO0FBQzFELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLXVucmVzb2x2ZWQgKi9cbmltcG9ydCAqIGFzIEFXU0xhbWJkYSBmcm9tICdhd3MtbGFtYmRhJztcbmltcG9ydCB7IENvbHVtbiB9IGZyb20gJy4uLy4uL3RhYmxlJztcbmltcG9ydCB7IGV4ZWN1dGVTdGF0ZW1lbnQgfSBmcm9tICcuL3JlZHNoaWZ0LWRhdGEnO1xuaW1wb3J0IHsgQ2x1c3RlclByb3BzLCBUYWJsZUFuZENsdXN0ZXJQcm9wcywgVGFibGVTb3J0U3R5bGUgfSBmcm9tICcuL3R5cGVzJztcbmltcG9ydCB7IGFyZUNvbHVtbnNFcXVhbCwgZ2V0RGlzdEtleUNvbHVtbiwgZ2V0U29ydEtleUNvbHVtbnMgfSBmcm9tICcuL3V0aWwnO1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaGFuZGxlcihwcm9wczogVGFibGVBbmRDbHVzdGVyUHJvcHMsIGV2ZW50OiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50KSB7XG4gIGNvbnN0IHRhYmxlTmFtZVByZWZpeCA9IHByb3BzLnRhYmxlTmFtZS5wcmVmaXg7XG4gIGNvbnN0IHRhYmxlTmFtZVN1ZmZpeCA9IHByb3BzLnRhYmxlTmFtZS5nZW5lcmF0ZVN1ZmZpeCA9PT0gJ3RydWUnID8gYCR7ZXZlbnQuUmVxdWVzdElkLnN1YnN0cmluZygwLCA4KX1gIDogJyc7XG4gIGNvbnN0IHRhYmxlQ29sdW1ucyA9IHByb3BzLnRhYmxlQ29sdW1ucztcbiAgY29uc3QgdGFibGVBbmRDbHVzdGVyUHJvcHMgPSBwcm9wcztcblxuICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdDcmVhdGUnKSB7XG4gICAgY29uc3QgdGFibGVOYW1lID0gYXdhaXQgY3JlYXRlVGFibGUodGFibGVOYW1lUHJlZml4LCB0YWJsZU5hbWVTdWZmaXgsIHRhYmxlQ29sdW1ucywgdGFibGVBbmRDbHVzdGVyUHJvcHMpO1xuICAgIHJldHVybiB7IFBoeXNpY2FsUmVzb3VyY2VJZDogdGFibGVOYW1lIH07XG4gIH0gZWxzZSBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnKSB7XG4gICAgYXdhaXQgZHJvcFRhYmxlKGV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCwgdGFibGVBbmRDbHVzdGVyUHJvcHMpO1xuICAgIHJldHVybjtcbiAgfSBlbHNlIGlmIChldmVudC5SZXF1ZXN0VHlwZSA9PT0gJ1VwZGF0ZScpIHtcbiAgICBjb25zdCB0YWJsZU5hbWUgPSBhd2FpdCB1cGRhdGVUYWJsZShcbiAgICAgIGV2ZW50LlBoeXNpY2FsUmVzb3VyY2VJZCxcbiAgICAgIHRhYmxlTmFtZVByZWZpeCxcbiAgICAgIHRhYmxlTmFtZVN1ZmZpeCxcbiAgICAgIHRhYmxlQ29sdW1ucyxcbiAgICAgIHRhYmxlQW5kQ2x1c3RlclByb3BzLFxuICAgICAgZXZlbnQuT2xkUmVzb3VyY2VQcm9wZXJ0aWVzIGFzIFRhYmxlQW5kQ2x1c3RlclByb3BzLFxuICAgICk7XG4gICAgcmV0dXJuIHsgUGh5c2ljYWxSZXNvdXJjZUlkOiB0YWJsZU5hbWUgfTtcbiAgfSBlbHNlIHtcbiAgICAvKiBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgZG90LW5vdGF0aW9uICovXG4gICAgdGhyb3cgbmV3IEVycm9yKGBVbnJlY29nbml6ZWQgZXZlbnQgdHlwZTogJHtldmVudFsnUmVxdWVzdFR5cGUnXX1gKTtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBjcmVhdGVUYWJsZShcbiAgdGFibGVOYW1lUHJlZml4OiBzdHJpbmcsXG4gIHRhYmxlTmFtZVN1ZmZpeDogc3RyaW5nLFxuICB0YWJsZUNvbHVtbnM6IENvbHVtbltdLFxuICB0YWJsZUFuZENsdXN0ZXJQcm9wczogVGFibGVBbmRDbHVzdGVyUHJvcHMsXG4pOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCB0YWJsZU5hbWUgPSB0YWJsZU5hbWVQcmVmaXggKyB0YWJsZU5hbWVTdWZmaXg7XG4gIGNvbnN0IHRhYmxlQ29sdW1uc1N0cmluZyA9IHRhYmxlQ29sdW1ucy5tYXAoY29sdW1uID0+IGAke2NvbHVtbi5uYW1lfSAke2NvbHVtbi5kYXRhVHlwZX1gKS5qb2luKCk7XG5cbiAgbGV0IHN0YXRlbWVudCA9IGBDUkVBVEUgVEFCTEUgJHt0YWJsZU5hbWV9ICgke3RhYmxlQ29sdW1uc1N0cmluZ30pYDtcblxuICBpZiAodGFibGVBbmRDbHVzdGVyUHJvcHMuZGlzdFN0eWxlKSB7XG4gICAgc3RhdGVtZW50ICs9IGAgRElTVFNUWUxFICR7dGFibGVBbmRDbHVzdGVyUHJvcHMuZGlzdFN0eWxlfWA7XG4gIH1cblxuICBjb25zdCBkaXN0S2V5Q29sdW1uID0gZ2V0RGlzdEtleUNvbHVtbih0YWJsZUNvbHVtbnMpO1xuICBpZiAoZGlzdEtleUNvbHVtbikge1xuICAgIHN0YXRlbWVudCArPSBgIERJU1RLRVkoJHtkaXN0S2V5Q29sdW1uLm5hbWV9KWA7XG4gIH1cblxuICBjb25zdCBzb3J0S2V5Q29sdW1ucyA9IGdldFNvcnRLZXlDb2x1bW5zKHRhYmxlQ29sdW1ucyk7XG4gIGlmIChzb3J0S2V5Q29sdW1ucy5sZW5ndGggPiAwKSB7XG4gICAgY29uc3Qgc29ydEtleUNvbHVtbnNTdHJpbmcgPSBnZXRTb3J0S2V5Q29sdW1uc1N0cmluZyhzb3J0S2V5Q29sdW1ucyk7XG4gICAgc3RhdGVtZW50ICs9IGAgJHt0YWJsZUFuZENsdXN0ZXJQcm9wcy5zb3J0U3R5bGV9IFNPUlRLRVkoJHtzb3J0S2V5Q29sdW1uc1N0cmluZ30pYDtcbiAgfVxuXG4gIGF3YWl0IGV4ZWN1dGVTdGF0ZW1lbnQoc3RhdGVtZW50LCB0YWJsZUFuZENsdXN0ZXJQcm9wcyk7XG4gIHJldHVybiB0YWJsZU5hbWU7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGRyb3BUYWJsZSh0YWJsZU5hbWU6IHN0cmluZywgY2x1c3RlclByb3BzOiBDbHVzdGVyUHJvcHMpIHtcbiAgYXdhaXQgZXhlY3V0ZVN0YXRlbWVudChgRFJPUCBUQUJMRSAke3RhYmxlTmFtZX1gLCBjbHVzdGVyUHJvcHMpO1xufVxuXG5hc3luYyBmdW5jdGlvbiB1cGRhdGVUYWJsZShcbiAgdGFibGVOYW1lOiBzdHJpbmcsXG4gIHRhYmxlTmFtZVByZWZpeDogc3RyaW5nLFxuICB0YWJsZU5hbWVTdWZmaXg6IHN0cmluZyxcbiAgdGFibGVDb2x1bW5zOiBDb2x1bW5bXSxcbiAgdGFibGVBbmRDbHVzdGVyUHJvcHM6IFRhYmxlQW5kQ2x1c3RlclByb3BzLFxuICBvbGRSZXNvdXJjZVByb3BlcnRpZXM6IFRhYmxlQW5kQ2x1c3RlclByb3BzLFxuKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgY29uc3QgYWx0ZXJhdGlvblN0YXRlbWVudHM6IHN0cmluZ1tdID0gW107XG5cbiAgY29uc3Qgb2xkQ2x1c3RlclByb3BzID0gb2xkUmVzb3VyY2VQcm9wZXJ0aWVzO1xuICBpZiAodGFibGVBbmRDbHVzdGVyUHJvcHMuY2x1c3Rlck5hbWUgIT09IG9sZENsdXN0ZXJQcm9wcy5jbHVzdGVyTmFtZSB8fCB0YWJsZUFuZENsdXN0ZXJQcm9wcy5kYXRhYmFzZU5hbWUgIT09IG9sZENsdXN0ZXJQcm9wcy5kYXRhYmFzZU5hbWUpIHtcbiAgICByZXR1cm4gY3JlYXRlVGFibGUodGFibGVOYW1lUHJlZml4LCB0YWJsZU5hbWVTdWZmaXgsIHRhYmxlQ29sdW1ucywgdGFibGVBbmRDbHVzdGVyUHJvcHMpO1xuICB9XG5cbiAgY29uc3Qgb2xkVGFibGVOYW1lUHJlZml4ID0gb2xkUmVzb3VyY2VQcm9wZXJ0aWVzLnRhYmxlTmFtZS5wcmVmaXg7XG4gIGlmICh0YWJsZU5hbWVQcmVmaXggIT09IG9sZFRhYmxlTmFtZVByZWZpeCkge1xuICAgIHJldHVybiBjcmVhdGVUYWJsZSh0YWJsZU5hbWVQcmVmaXgsIHRhYmxlTmFtZVN1ZmZpeCwgdGFibGVDb2x1bW5zLCB0YWJsZUFuZENsdXN0ZXJQcm9wcyk7XG4gIH1cblxuICBjb25zdCBvbGRUYWJsZUNvbHVtbnMgPSBvbGRSZXNvdXJjZVByb3BlcnRpZXMudGFibGVDb2x1bW5zO1xuICBpZiAoIW9sZFRhYmxlQ29sdW1ucy5ldmVyeShvbGRDb2x1bW4gPT4gdGFibGVDb2x1bW5zLnNvbWUoY29sdW1uID0+IGNvbHVtbi5uYW1lID09PSBvbGRDb2x1bW4ubmFtZSAmJiBjb2x1bW4uZGF0YVR5cGUgPT09IG9sZENvbHVtbi5kYXRhVHlwZSkpKSB7XG4gICAgcmV0dXJuIGNyZWF0ZVRhYmxlKHRhYmxlTmFtZVByZWZpeCwgdGFibGVOYW1lU3VmZml4LCB0YWJsZUNvbHVtbnMsIHRhYmxlQW5kQ2x1c3RlclByb3BzKTtcbiAgfVxuXG4gIGNvbnN0IGNvbHVtbkFkZGl0aW9ucyA9IHRhYmxlQ29sdW1ucy5maWx0ZXIoY29sdW1uID0+IHtcbiAgICByZXR1cm4gIW9sZFRhYmxlQ29sdW1ucy5zb21lKG9sZENvbHVtbiA9PiBjb2x1bW4ubmFtZSA9PT0gb2xkQ29sdW1uLm5hbWUgJiYgY29sdW1uLmRhdGFUeXBlID09PSBvbGRDb2x1bW4uZGF0YVR5cGUpO1xuICB9KS5tYXAoY29sdW1uID0+IGBBREQgJHtjb2x1bW4ubmFtZX0gJHtjb2x1bW4uZGF0YVR5cGV9YCk7XG4gIGlmIChjb2x1bW5BZGRpdGlvbnMubGVuZ3RoID4gMCkge1xuICAgIGFsdGVyYXRpb25TdGF0ZW1lbnRzLnB1c2goLi4uY29sdW1uQWRkaXRpb25zLm1hcChhZGRpdGlvbiA9PiBgQUxURVIgVEFCTEUgJHt0YWJsZU5hbWV9ICR7YWRkaXRpb259YCkpO1xuICB9XG5cbiAgY29uc3Qgb2xkRGlzdFN0eWxlID0gb2xkUmVzb3VyY2VQcm9wZXJ0aWVzLmRpc3RTdHlsZTtcbiAgaWYgKCghb2xkRGlzdFN0eWxlICYmIHRhYmxlQW5kQ2x1c3RlclByb3BzLmRpc3RTdHlsZSkgfHxcbiAgICAob2xkRGlzdFN0eWxlICYmICF0YWJsZUFuZENsdXN0ZXJQcm9wcy5kaXN0U3R5bGUpKSB7XG4gICAgcmV0dXJuIGNyZWF0ZVRhYmxlKHRhYmxlTmFtZVByZWZpeCwgdGFibGVOYW1lU3VmZml4LCB0YWJsZUNvbHVtbnMsIHRhYmxlQW5kQ2x1c3RlclByb3BzKTtcbiAgfSBlbHNlIGlmIChvbGREaXN0U3R5bGUgIT09IHRhYmxlQW5kQ2x1c3RlclByb3BzLmRpc3RTdHlsZSkge1xuICAgIGFsdGVyYXRpb25TdGF0ZW1lbnRzLnB1c2goYEFMVEVSIFRBQkxFICR7dGFibGVOYW1lfSBBTFRFUiBESVNUU1RZTEUgJHt0YWJsZUFuZENsdXN0ZXJQcm9wcy5kaXN0U3R5bGV9YCk7XG4gIH1cblxuICBjb25zdCBvbGREaXN0S2V5ID0gZ2V0RGlzdEtleUNvbHVtbihvbGRUYWJsZUNvbHVtbnMpPy5uYW1lO1xuICBjb25zdCBuZXdEaXN0S2V5ID0gZ2V0RGlzdEtleUNvbHVtbih0YWJsZUNvbHVtbnMpPy5uYW1lO1xuICBpZiAoKCFvbGREaXN0S2V5ICYmIG5ld0Rpc3RLZXkgKSB8fCAob2xkRGlzdEtleSAmJiAhbmV3RGlzdEtleSkpIHtcbiAgICByZXR1cm4gY3JlYXRlVGFibGUodGFibGVOYW1lUHJlZml4LCB0YWJsZU5hbWVTdWZmaXgsIHRhYmxlQ29sdW1ucywgdGFibGVBbmRDbHVzdGVyUHJvcHMpO1xuICB9IGVsc2UgaWYgKG9sZERpc3RLZXkgIT09IG5ld0Rpc3RLZXkpIHtcbiAgICBhbHRlcmF0aW9uU3RhdGVtZW50cy5wdXNoKGBBTFRFUiBUQUJMRSAke3RhYmxlTmFtZX0gQUxURVIgRElTVEtFWSAke25ld0Rpc3RLZXl9YCk7XG4gIH1cblxuICBjb25zdCBvbGRTb3J0S2V5Q29sdW1ucyA9IGdldFNvcnRLZXlDb2x1bW5zKG9sZFRhYmxlQ29sdW1ucyk7XG4gIGNvbnN0IG5ld1NvcnRLZXlDb2x1bW5zID0gZ2V0U29ydEtleUNvbHVtbnModGFibGVDb2x1bW5zKTtcbiAgY29uc3Qgb2xkU29ydFN0eWxlID0gb2xkUmVzb3VyY2VQcm9wZXJ0aWVzLnNvcnRTdHlsZTtcbiAgY29uc3QgbmV3U29ydFN0eWxlID0gdGFibGVBbmRDbHVzdGVyUHJvcHMuc29ydFN0eWxlO1xuICBpZiAoKG9sZFNvcnRTdHlsZSA9PT0gbmV3U29ydFN0eWxlICYmICFhcmVDb2x1bW5zRXF1YWwob2xkU29ydEtleUNvbHVtbnMsIG5ld1NvcnRLZXlDb2x1bW5zKSlcbiAgICB8fCAob2xkU29ydFN0eWxlICE9PSBuZXdTb3J0U3R5bGUpKSB7XG4gICAgc3dpdGNoIChuZXdTb3J0U3R5bGUpIHtcbiAgICAgIGNhc2UgVGFibGVTb3J0U3R5bGUuSU5URVJMRUFWRUQ6XG4gICAgICAgIC8vIElOVEVSTEVBVkVEIHNvcnQga2V5IGFkZGl0aW9uIHJlcXVpcmVzIHJlcGxhY2VtZW50LlxuICAgICAgICAvLyBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vcmVkc2hpZnQvbGF0ZXN0L2RnL3JfQUxURVJfVEFCTEUuaHRtbFxuICAgICAgICByZXR1cm4gY3JlYXRlVGFibGUodGFibGVOYW1lUHJlZml4LCB0YWJsZU5hbWVTdWZmaXgsIHRhYmxlQ29sdW1ucywgdGFibGVBbmRDbHVzdGVyUHJvcHMpO1xuXG4gICAgICBjYXNlIFRhYmxlU29ydFN0eWxlLkNPTVBPVU5EOiB7XG4gICAgICAgIGNvbnN0IHNvcnRLZXlDb2x1bW5zU3RyaW5nID0gZ2V0U29ydEtleUNvbHVtbnNTdHJpbmcobmV3U29ydEtleUNvbHVtbnMpO1xuICAgICAgICBhbHRlcmF0aW9uU3RhdGVtZW50cy5wdXNoKGBBTFRFUiBUQUJMRSAke3RhYmxlTmFtZX0gQUxURVIgJHtuZXdTb3J0U3R5bGV9IFNPUlRLRVkoJHtzb3J0S2V5Q29sdW1uc1N0cmluZ30pYCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICBjYXNlIFRhYmxlU29ydFN0eWxlLkFVVE86IHtcbiAgICAgICAgYWx0ZXJhdGlvblN0YXRlbWVudHMucHVzaChgQUxURVIgVEFCTEUgJHt0YWJsZU5hbWV9IEFMVEVSIFNPUlRLRVkgJHtuZXdTb3J0U3R5bGV9YCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGF3YWl0IFByb21pc2UuYWxsKGFsdGVyYXRpb25TdGF0ZW1lbnRzLm1hcChzdGF0ZW1lbnQgPT4gZXhlY3V0ZVN0YXRlbWVudChzdGF0ZW1lbnQsIHRhYmxlQW5kQ2x1c3RlclByb3BzKSkpO1xuXG4gIHJldHVybiB0YWJsZU5hbWU7XG59XG5cbmZ1bmN0aW9uIGdldFNvcnRLZXlDb2x1bW5zU3RyaW5nKHNvcnRLZXlDb2x1bW5zOiBDb2x1bW5bXSkge1xuICByZXR1cm4gc29ydEtleUNvbHVtbnMubWFwKGNvbHVtbiA9PiBjb2x1bW4ubmFtZSkuam9pbigpO1xufVxuIl19 \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/aws-cdk-redshift-cluster-database.assets.json b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/aws-cdk-redshift-cluster-database.assets.json index f92a39bfbbce..1acb843ce81a 100644 --- a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/aws-cdk-redshift-cluster-database.assets.json +++ b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/aws-cdk-redshift-cluster-database.assets.json @@ -1,33 +1,33 @@ { - "version": "21.0.0", + "version": "22.0.0", "files": { - "fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3": { + "8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415": { "source": { - "path": "asset.fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3", + "path": "asset.8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415", "packaging": "zip" }, "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3.zip", + "objectKey": "8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415.zip", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } }, - "3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671": { + "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585": { "source": { - "path": "asset.3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671", + "path": "asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585", "packaging": "zip" }, "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671.zip", + "objectKey": "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585.zip", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } }, - "784177efbde5b0ae9662ffc9f5f85895be269347870d0564efaa1281f8a1c38e": { + "fadca82b7c081a8b6de68f952878e92ba5610dce63ccbead865e1b854073bff0": { "source": { "path": "aws-cdk-redshift-cluster-database.template.json", "packaging": "file" @@ -35,7 +35,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "784177efbde5b0ae9662ffc9f5f85895be269347870d0564efaa1281f8a1c38e.json", + "objectKey": "fadca82b7c081a8b6de68f952878e92ba5610dce63ccbead865e1b854073bff0.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/aws-cdk-redshift-cluster-database.template.json b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/aws-cdk-redshift-cluster-database.template.json index 2d14182a7f2a..7d7265311c8a 100644 --- a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/aws-cdk-redshift-cluster-database.template.json +++ b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/aws-cdk-redshift-cluster-database.template.json @@ -1,5 +1,40 @@ { "Resources": { + "customkmskey377C6F9A": { + "Type": "AWS::KMS::Key", + "Properties": { + "KeyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, "Vpc8378EB38": { "Type": "AWS::EC2::VPC", "Properties": { @@ -437,41 +472,6 @@ "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, - "customkmskey377C6F9A": { - "Type": "AWS::KMS::Key", - "Properties": { - "KeyPolicy": { - "Statement": [ - { - "Action": "kms:*", - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::", - { - "Ref": "AWS::AccountId" - }, - ":root" - ] - ] - } - }, - "Resource": "*" - } - ], - "Version": "2012-10-17" - } - }, - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete" - }, "ClusterSubnetsDCFA5CB7": { "Type": "AWS::Redshift::ClusterSubnetGroup", "Properties": { @@ -715,7 +715,7 @@ "S3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "S3Key": "3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671.zip" + "S3Key": "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585.zip" }, "Role": { "Fn::GetAtt": [ @@ -854,7 +854,7 @@ "S3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "S3Key": "3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671.zip" + "S3Key": "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585.zip" }, "Role": { "Fn::GetAtt": [ @@ -1004,7 +1004,7 @@ "S3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "S3Key": "fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3.zip" + "S3Key": "8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415.zip" }, "Role": { "Fn::GetAtt": [ @@ -1107,7 +1107,7 @@ "S3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "S3Key": "3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671.zip" + "S3Key": "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585.zip" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/cdk.out b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/cdk.out index 8ecc185e9dbe..145739f53958 100644 --- a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/cdk.out +++ b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"21.0.0"} \ No newline at end of file +{"version":"22.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/integ.json b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/integ.json index 092005713819..f624a18a308e 100644 --- a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/integ.json +++ b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/integ.json @@ -1,14 +1,12 @@ { - "version": "21.0.0", + "version": "22.0.0", "testCases": { - "integ.database": { + "redshift-cluster-database-integ/DefaultTest": { "stacks": [ "aws-cdk-redshift-cluster-database" ], - "diffAssets": false, - "stackUpdateWorkflow": true + "assertionStack": "redshift-cluster-database-integ/DefaultTest/DeployAssert", + "assertionStackName": "redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48" } - }, - "synthContext": {}, - "enableLookups": false + } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/manifest.json b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/manifest.json index fe9068d22e8a..38184219376b 100644 --- a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/manifest.json +++ b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/manifest.json @@ -1,12 +1,6 @@ { - "version": "21.0.0", + "version": "22.0.0", "artifacts": { - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - }, "aws-cdk-redshift-cluster-database.assets": { "type": "cdk:asset-manifest", "properties": { @@ -23,7 +17,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/784177efbde5b0ae9662ffc9f5f85895be269347870d0564efaa1281f8a1c38e.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/fadca82b7c081a8b6de68f952878e92ba5610dce63ccbead865e1b854073bff0.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -39,6 +33,12 @@ "aws-cdk-redshift-cluster-database.assets" ], "metadata": { + "/aws-cdk-redshift-cluster-database/custom-kms-key/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "customkmskey377C6F9A" + } + ], "/aws-cdk-redshift-cluster-database/Vpc/Resource": [ { "type": "aws:cdk:logicalId", @@ -177,12 +177,6 @@ "data": "VpcVPCGWBF912B6E" } ], - "/aws-cdk-redshift-cluster-database/custom-kms-key/Resource": [ - { - "type": "aws:cdk:logicalId", - "data": "customkmskey377C6F9A" - } - ], "/aws-cdk-redshift-cluster-database/Cluster/Subnets/Default": [ { "type": "aws:cdk:logicalId", @@ -216,10 +210,7 @@ "/aws-cdk-redshift-cluster-database/Cluster/ParameterGroup/Resource": [ { "type": "aws:cdk:logicalId", - "data": "ClusterParameterGroup879806FD", - "trace": [ - "!!DESTRUCTIVE_CHANGES: WILL_REPLACE" - ] + "data": "ClusterParameterGroup879806FD" } ], "/aws-cdk-redshift-cluster-database/User/Secret/Resource": [ @@ -338,6 +329,59 @@ ] }, "displayName": "aws-cdk-redshift-cluster-database" + }, + "redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48.assets" + ], + "metadata": { + "/redshift-cluster-database-integ/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/redshift-cluster-database-integ/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "redshift-cluster-database-integ/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48.assets.json b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48.assets.json new file mode 100644 index 000000000000..0584a656f04d --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48.assets.json @@ -0,0 +1,19 @@ +{ + "version": "22.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48.template.json b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48.template.json new file mode 100644 index 000000000000..ad9d0fb73d1d --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/redshiftclusterdatabaseintegDefaultTestDeployAssert4339FB48.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/tree.json b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/tree.json index 1f4c6c4140f6..a8cbab7a274d 100644 --- a/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/tree.json +++ b/packages/@aws-cdk/aws-redshift/test/integ.database.js.snapshot/tree.json @@ -4,18 +4,61 @@ "id": "App", "path": "", "children": { - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.92" - } - }, "aws-cdk-redshift-cluster-database": { "id": "aws-cdk-redshift-cluster-database", "path": "aws-cdk-redshift-cluster-database", "children": { + "custom-kms-key": { + "id": "custom-kms-key", + "path": "aws-cdk-redshift-cluster-database/custom-kms-key", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-database/custom-kms-key/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::KMS::Key", + "aws:cdk:cloudformation:props": { + "keyPolicy": { + "Statement": [ + { + "Action": "kms:*", + "Effect": "Allow", + "Principal": { + "AWS": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::", + { + "Ref": "AWS::AccountId" + }, + ":root" + ] + ] + } + }, + "Resource": "*" + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-kms.CfnKey", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-kms.Key", + "version": "0.0.0" + } + }, "Vpc": { "id": "Vpc", "path": "aws-cdk-redshift-cluster-database/Vpc", @@ -659,57 +702,6 @@ "version": "0.0.0" } }, - "custom-kms-key": { - "id": "custom-kms-key", - "path": "aws-cdk-redshift-cluster-database/custom-kms-key", - "children": { - "Resource": { - "id": "Resource", - "path": "aws-cdk-redshift-cluster-database/custom-kms-key/Resource", - "attributes": { - "aws:cdk:cloudformation:type": "AWS::KMS::Key", - "aws:cdk:cloudformation:props": { - "keyPolicy": { - "Statement": [ - { - "Action": "kms:*", - "Effect": "Allow", - "Principal": { - "AWS": { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":iam::", - { - "Ref": "AWS::AccountId" - }, - ":root" - ] - ] - } - }, - "Resource": "*" - } - ], - "Version": "2012-10-17" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-kms.CfnKey", - "version": "0.0.0" - } - } - }, - "constructInfo": { - "fqn": "@aws-cdk/aws-kms.Key", - "version": "0.0.0" - } - }, "Cluster": { "id": "Cluster", "path": "aws-cdk-redshift-cluster-database/Cluster", @@ -1025,6 +1017,14 @@ "id": "ServiceRole", "path": "aws-cdk-redshift-cluster-database/User/Resource/Provider/framework-onEvent/ServiceRole", "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "aws-cdk-redshift-cluster-database/User/Resource/Provider/framework-onEvent/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, "Resource": { "id": "Resource", "path": "aws-cdk-redshift-cluster-database/User/Resource/Provider/framework-onEvent/ServiceRole/Resource", @@ -1166,7 +1166,7 @@ "s3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "s3Key": "3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671.zip" + "s3Key": "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585.zip" }, "role": { "Fn::GetAtt": [ @@ -1228,7 +1228,7 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.92" + "version": "10.1.182" } }, "TablePrivileges": { @@ -1259,6 +1259,14 @@ "id": "ServiceRole", "path": "aws-cdk-redshift-cluster-database/User/TablePrivileges/Resource/Provider/framework-onEvent/ServiceRole", "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "aws-cdk-redshift-cluster-database/User/TablePrivileges/Resource/Provider/framework-onEvent/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, "Resource": { "id": "Resource", "path": "aws-cdk-redshift-cluster-database/User/TablePrivileges/Resource/Provider/framework-onEvent/ServiceRole/Resource", @@ -1400,7 +1408,7 @@ "s3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "s3Key": "3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671.zip" + "s3Key": "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585.zip" }, "role": { "Fn::GetAtt": [ @@ -1462,13 +1470,13 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.92" + "version": "10.1.182" } } }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.92" + "version": "10.1.182" } } }, @@ -1485,6 +1493,14 @@ "id": "ServiceRole", "path": "aws-cdk-redshift-cluster-database/Query Redshift Database3de5bea727da479686625efb56431b5f/ServiceRole", "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "aws-cdk-redshift-cluster-database/Query Redshift Database3de5bea727da479686625efb56431b5f/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, "Resource": { "id": "Resource", "path": "aws-cdk-redshift-cluster-database/Query Redshift Database3de5bea727da479686625efb56431b5f/ServiceRole/Resource", @@ -1623,7 +1639,7 @@ "s3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "s3Key": "fb53353ae3322d38cf92fc2d8a73910a88c06a725900f0815aeaab985e6a19e3.zip" + "s3Key": "8359857aa9b7c3fbc8bba9a505282ba848915383c4549f21b9f93f9f35b56415.zip" }, "role": { "Fn::GetAtt": [ @@ -1675,6 +1691,14 @@ "id": "ServiceRole", "path": "aws-cdk-redshift-cluster-database/Table/Resource/Provider/framework-onEvent/ServiceRole", "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "aws-cdk-redshift-cluster-database/Table/Resource/Provider/framework-onEvent/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, "Resource": { "id": "Resource", "path": "aws-cdk-redshift-cluster-database/Table/Resource/Provider/framework-onEvent/ServiceRole/Resource", @@ -1816,7 +1840,7 @@ "s3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "s3Key": "3b263c2ad043fd069ef446753788c36e595c82b51a70478e58258c8ef7471671.zip" + "s3Key": "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585.zip" }, "role": { "Fn::GetAtt": [ @@ -1878,7 +1902,7 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.92" + "version": "10.1.182" } } }, @@ -1886,12 +1910,90 @@ "fqn": "@aws-cdk/aws-redshift.Table", "version": "0.0.0" } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-cdk-redshift-cluster-database/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-cdk-redshift-cluster-database/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } } }, "constructInfo": { "fqn": "@aws-cdk/core.Stack", "version": "0.0.0" } + }, + "redshift-cluster-database-integ": { + "id": "redshift-cluster-database-integ", + "path": "redshift-cluster-database-integ", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "redshift-cluster-database-integ/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "redshift-cluster-database-integ/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.182" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "redshift-cluster-database-integ/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "redshift-cluster-database-integ/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "redshift-cluster-database-integ/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.182" + } } }, "constructInfo": { diff --git a/packages/@aws-cdk/aws-redshift/test/integ.database.ts b/packages/@aws-cdk/aws-redshift/test/integ.database.ts index 45a67f26f499..5938e67652c9 100644 --- a/packages/@aws-cdk/aws-redshift/test/integ.database.ts +++ b/packages/@aws-cdk/aws-redshift/test/integ.database.ts @@ -2,6 +2,7 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; import * as cdk from '@aws-cdk/core'; +import * as integ from '@aws-cdk/integ-tests'; import * as constructs from 'constructs'; import * as redshift from '../lib'; @@ -16,6 +17,7 @@ cdk.Aspects.of(stack).add({ }, }); +const key = new kms.Key(stack, 'custom-kms-key'); const vpc = new ec2.Vpc(stack, 'Vpc'); const databaseName = 'my_db'; const cluster = new redshift.Cluster(stack, 'Cluster', { @@ -28,7 +30,7 @@ const cluster = new redshift.Cluster(stack, 'Cluster', { }, defaultDatabaseName: databaseName, publiclyAccessible: true, - encryptionKey: new kms.Key(stack, 'custom-kms-key'), + encryptionKey: key, }); cluster.addToParameterGroup('enable_user_activity_logging', 'true'); @@ -49,4 +51,9 @@ const table = new redshift.Table(stack, 'Table', { sortStyle: redshift.TableSortStyle.INTERLEAVED, }); table.grant(user, redshift.TableAction.INSERT, redshift.TableAction.DELETE); + +new integ.IntegTest(app, 'redshift-cluster-database-integ', { + testCases: [stack], +}); + app.synth(); From 429367965c722e00a122a395325f9c5c423ad9e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Doma=C5=84ski?= Date: Tue, 27 Dec 2022 18:44:29 +0100 Subject: [PATCH 2/8] docs(aws-apigatewayv2-alpha): update domain name documentation (#23462) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ---- I am requesting an update to `apigwv2.DomainName`, which accepts `domainName` as a prop. Current documentation has an error, it currently says: ``` const domainName = 'example.com'; const dn = new apigwv2.DomainName(this, 'DN', { domainName, certificate: acm.Certificate.fromCertificateArn(this, 'cert', certArn), }); ``` When you run the above ā˜ļø it errors out. It should read: ``` const dn = new apigwv2.DomainName(this, 'DN', { domainName: domainName, certificate: acm.Certificate.fromCertificateArn(this, 'cert', certArn), }); ``` ### All Submissions: * [X] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-apigatewayv2/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-apigatewayv2/README.md b/packages/@aws-cdk/aws-apigatewayv2/README.md index 040ee20d0bf6..88b42b4d7c10 100644 --- a/packages/@aws-cdk/aws-apigatewayv2/README.md +++ b/packages/@aws-cdk/aws-apigatewayv2/README.md @@ -184,7 +184,7 @@ const certArn = 'arn:aws:acm:us-east-1:111111111111:certificate'; const domainName = 'example.com'; const dn = new apigwv2.DomainName(this, 'DN', { - domainName, + domainName: domainName, certificate: acm.Certificate.fromCertificateArn(this, 'cert', certArn), }); From a1370a062168a8bf9ef15298c6515fbce0c83496 Mon Sep 17 00:00:00 2001 From: AWS CDK Team Date: Tue, 27 Dec 2022 17:50:03 +0000 Subject: [PATCH 3/8] chore(release): 2.57.0 --- CHANGELOG.v2.alpha.md | 7 +++++++ CHANGELOG.v2.md | 15 +++++++++++++++ version.v2.json | 4 ++-- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.v2.alpha.md b/CHANGELOG.v2.alpha.md index 5c0234bdf43a..dc71586c9599 100644 --- a/CHANGELOG.v2.alpha.md +++ b/CHANGELOG.v2.alpha.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.57.0-alpha.0](https://github.com/aws/aws-cdk/compare/v2.56.1-alpha.0...v2.57.0-alpha.0) (2022-12-27) + + +### Bug Fixes + +* **aws-redshift:** Columns are not dropped on removal from array ([#23011](https://github.com/aws/aws-cdk/issues/23011)) ([2981313](https://github.com/aws/aws-cdk/commit/298131312b513c0e73865e6fff74c189ee99e328)), closes [#22208](https://github.com/aws/aws-cdk/issues/22208) + ## [2.56.1-alpha.0](https://github.com/aws/aws-cdk/compare/v2.56.0-alpha.0...v2.56.1-alpha.0) (2022-12-23) ## [2.56.0-alpha.0](https://github.com/aws/aws-cdk/compare/v2.55.1-alpha.0...v2.56.0-alpha.0) (2022-12-21) diff --git a/CHANGELOG.v2.md b/CHANGELOG.v2.md index 627dbdbf8472..2443b6984fd0 100644 --- a/CHANGELOG.v2.md +++ b/CHANGELOG.v2.md @@ -2,6 +2,21 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [2.57.0](https://github.com/aws/aws-cdk/compare/v2.56.1...v2.57.0) (2022-12-27) + + +### Features + +* **cfnspec:** cloudformation spec v103.0.0 ([#23452](https://github.com/aws/aws-cdk/issues/23452)) ([e49e57d](https://github.com/aws/aws-cdk/commit/e49e57d3106f62c5d64c428cba73b4107d664cba)) +* **lambda:** add support for auto-instrumentation with ADOT Lambda layer ([#23027](https://github.com/aws/aws-cdk/issues/23027)) ([fc70535](https://github.com/aws/aws-cdk/commit/fc70535fe699e72332d5ddb4543308e76a89594a)) + + +### Bug Fixes + +* **cfnspec:** v101.0.0 introduced specific types on several types that previously were typed as json ([#23448](https://github.com/aws/aws-cdk/issues/23448)) ([4fbc182](https://github.com/aws/aws-cdk/commit/4fbc1827b8978262da0b5b77b1ee9bc0ecfdcc3e)) +* **codedeploy:** referenced Applications are not environment-aware ([#23405](https://github.com/aws/aws-cdk/issues/23405)) ([96242d7](https://github.com/aws/aws-cdk/commit/96242d73c0ae853524a567aece86f8a8a514495c)) +* **s3:** buckets with SSE-KMS silently fail to receive logs ([#23385](https://github.com/aws/aws-cdk/issues/23385)) ([1b7a384](https://github.com/aws/aws-cdk/commit/1b7a384c330d168d64c0cd82118e5b5473d08a67)) + ## [2.56.1](https://github.com/aws/aws-cdk/compare/v2.56.0...v2.56.1) (2022-12-23) diff --git a/version.v2.json b/version.v2.json index 1484929ef453..9357fea915cf 100644 --- a/version.v2.json +++ b/version.v2.json @@ -1,4 +1,4 @@ { - "version": "2.56.1", - "alphaVersion": "2.56.1-alpha.0" + "version": "2.57.0", + "alphaVersion": "2.57.0-alpha.0" } \ No newline at end of file From 267638674474c4cac9be5ca0d7f8b9a538ba2e39 Mon Sep 17 00:00:00 2001 From: Rico Hermans Date: Wed, 28 Dec 2022 12:42:45 +0100 Subject: [PATCH 4/8] feat(assertions): improve printing of match failures (#23453) Debugging match failures with the `assertions` library used to be a bit frustrating. The library used to guess the single closest matching resource and print it fully, with a list of match failures underneath. This has two problems: - Matching the failures up to the data structure requires a lot of scanning back and forth between different screen lines. - The library could incorrectly guess at the closest match, giving you useless information. This change is a first (and by no means the last) stab at improving the situation: - Mismatch errors are printed in-line with the data structure, making it very clear what they are referencing (removing the need for scanning). - Fields in complex data structures that aren't involved in the mismatch at all are collapsed. For example, a complex subobject that matches be printed as `{ ... }` so it doesn't take up too much vertical space. - Because we now have a lot of vertical space left, we can print the N closest matches, lowering the chance that we guess wrong and leave you without information to correct the test. The last point can probably be improved more in the future, by coming up with a more accurate metric for "closest match" than "failure count", but this will do for now. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/assertions/lib/match.ts | 131 ++++++--- packages/@aws-cdk/assertions/lib/matcher.ts | 262 +++++++++++++++++- .../assertions/lib/private/conditions.ts | 11 +- .../assertions/lib/private/mappings.ts | 12 +- .../assertions/lib/private/messages.ts | 15 +- .../assertions/lib/private/outputs.ts | 11 +- .../assertions/lib/private/parameters.ts | 11 +- .../assertions/lib/private/resources.ts | 11 +- .../assertions/lib/private/section.ts | 42 ++- .../assertions/lib/private/sorting.ts | 27 ++ .../assertions/lib/private/sparse-matrix.ts | 20 ++ .../test/__snapshots__/render.test.js.snap | 124 +++++++++ .../assertions/test/annotations.test.ts | 8 +- .../@aws-cdk/assertions/test/capture.test.ts | 30 ++ .../@aws-cdk/assertions/test/match.test.ts | 72 ++--- .../assertions/test/private/section.test.ts | 6 +- .../@aws-cdk/assertions/test/render.test.ts | 157 +++++++++++ .../@aws-cdk/assertions/test/template.test.ts | 119 +++----- .../aws-ecs-patterns/test/ec2/l3s-v2.test.ts | 6 +- .../providers/lambda-handler/assertion.ts | 5 +- .../lambda-handler/assertion.test.ts | 14 +- 21 files changed, 845 insertions(+), 249 deletions(-) create mode 100644 packages/@aws-cdk/assertions/lib/private/sorting.ts create mode 100644 packages/@aws-cdk/assertions/lib/private/sparse-matrix.ts create mode 100644 packages/@aws-cdk/assertions/test/__snapshots__/render.test.js.snap create mode 100644 packages/@aws-cdk/assertions/test/render.test.ts diff --git a/packages/@aws-cdk/assertions/lib/match.ts b/packages/@aws-cdk/assertions/lib/match.ts index 9e53898ef37d..c7ea80ad91db 100644 --- a/packages/@aws-cdk/assertions/lib/match.ts +++ b/packages/@aws-cdk/assertions/lib/match.ts @@ -1,5 +1,7 @@ import { Matcher, MatchResult } from './matcher'; import { AbsentMatch } from './private/matchers/absent'; +import { sortKeyComparator } from './private/sorting'; +import { SparseMatrix } from './private/sparse-matrix'; import { getType } from './private/type'; /** @@ -196,18 +198,53 @@ class ArrayMatch extends Matcher { message: `Expected type array but received ${getType(actual)}`, }); } - if (!this.subsequence && this.pattern.length !== actual.length) { - return new MatchResult(actual).recordFailure({ + + return this.subsequence ? this.testSubsequence(actual) : this.testFullArray(actual); + } + + private testFullArray(actual: Array): MatchResult { + const result = new MatchResult(actual); + + let i = 0; + for (; i < this.pattern.length && i < actual.length; i++) { + const patternElement = this.pattern[i]; + const matcher = Matcher.isMatcher(patternElement) + ? patternElement + : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); + + const innerResult = matcher.test(actual[i]); + result.compose(`${i}`, innerResult); + } + + if (i < this.pattern.length) { + result.recordFailure({ matcher: this, - path: [], - message: `Expected array of length ${this.pattern.length} but received ${actual.length}`, + message: `Not enough elements in array (expecting ${this.pattern.length}, got ${actual.length})`, + path: [`${i}`], }); } + if (i < actual.length) { + result.recordFailure({ + matcher: this, + message: `Too many elements in array (expecting ${this.pattern.length}, got ${actual.length})`, + path: [`${i}`], + }); + } + + return result; + } + + private testSubsequence(actual: Array): MatchResult { + const result = new MatchResult(actual); + + // For subsequences, there is a lot of testing and backtracking that happens + // here, keep track of it all so we can report in a sensible amount of + // detail on what we did if the match happens to fail. let patternIdx = 0; let actualIdx = 0; + const matches = new SparseMatrix(); - const result = new MatchResult(actual); while (patternIdx < this.pattern.length && actualIdx < actual.length) { const patternElement = this.pattern[patternIdx]; @@ -216,30 +253,59 @@ class ArrayMatch extends Matcher { : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); const matcherName = matcher.name; - if (this.subsequence && (matcherName == 'absent' || matcherName == 'anyValue')) { + if (matcherName == 'absent' || matcherName == 'anyValue') { // array subsequence matcher is not compatible with anyValue() or absent() matcher. They don't make sense to be used together. throw new Error(`The Matcher ${matcherName}() cannot be nested within arrayWith()`); } const innerResult = matcher.test(actual[actualIdx]); + matches.set(patternIdx, actualIdx, innerResult); - if (!this.subsequence || !innerResult.hasFailed()) { - result.compose(`[${actualIdx}]`, innerResult); + actualIdx++; + if (innerResult.isSuccess) { + result.compose(`${actualIdx}`, innerResult); // Record any captures patternIdx++; - actualIdx++; - } else { - actualIdx++; } } - for (; patternIdx < this.pattern.length; patternIdx++) { - const pattern = this.pattern[patternIdx]; - const element = (Matcher.isMatcher(pattern) || typeof pattern === 'object') ? ' ' : ` [${pattern}] `; - result.recordFailure({ - matcher: this, - path: [], - message: `Missing element${element}at pattern index ${patternIdx}`, - }); + // If we haven't matched all patterns: + // - Report on each one that did match on where it matched (perhaps it was wrong) + // - Report the closest match for the failing one + if (patternIdx < this.pattern.length) { + // Succeeded Pattern Index + for (let spi = 0; spi < patternIdx; spi++) { + const foundMatch = matches.row(spi).find(([, r]) => r.isSuccess); + if (!foundMatch) { continue; } // Should never fail but let's be defensive + + const [index] = foundMatch; + + result.compose(`${index}`, new MatchResult(actual[index]).recordFailure({ + matcher: this, + message: `arrayWith pattern ${spi} matched here`, + path: [], + cost: 0, // This is an informational message so it would be unfair to assign it cost + })); + } + + const failedMatches = matches.row(patternIdx); + failedMatches.sort(sortKeyComparator(([i, r]) => [r.failCost, i])); + if (failedMatches.length > 0) { + const [index, innerResult] = failedMatches[0]; + result.recordFailure({ + matcher: this, + message: `Could not match arrayWith pattern ${patternIdx}. This is the closest match`, + path: [`${index}`], + cost: 0, // Informational message + }); + result.compose(`${index}`, innerResult); + } else { + // The previous matcher matched at the end of the pattern and we didn't even get to try anything + result.recordFailure({ + matcher: this, + message: `Could not match arrayWith pattern ${patternIdx}. No more elements to try`, + path: [`${actual.length}`], + }); + } } return result; @@ -288,8 +354,8 @@ class ObjectMatch extends Matcher { if (!(a in this.pattern)) { result.recordFailure({ matcher: this, - path: [`/${a}`], - message: 'Unexpected key', + path: [a], + message: `Unexpected key ${a}`, }); } } @@ -299,8 +365,8 @@ class ObjectMatch extends Matcher { if (!(patternKey in actual) && !(patternVal instanceof AbsentMatch)) { result.recordFailure({ matcher: this, - path: [`/${patternKey}`], - message: `Missing key '${patternKey}' among {${Object.keys(actual).join(',')}}`, + path: [patternKey], + message: `Missing key '${patternKey}'`, }); continue; } @@ -308,7 +374,7 @@ class ObjectMatch extends Matcher { patternVal : new LiteralMatch(this.name, patternVal, { partialObjects: this.partial }); const inner = matcher.test(actual[patternKey]); - result.compose(`/${patternKey}`, inner); + result.compose(patternKey, inner); } return result; @@ -324,26 +390,23 @@ class SerializedJson extends Matcher { }; public test(actual: any): MatchResult { - const result = new MatchResult(actual); if (getType(actual) !== 'string') { - result.recordFailure({ + return new MatchResult(actual).recordFailure({ matcher: this, path: [], message: `Expected JSON as a string but found ${getType(actual)}`, }); - return result; } let parsed; try { parsed = JSON.parse(actual); } catch (err) { if (err instanceof SyntaxError) { - result.recordFailure({ + return new MatchResult(actual).recordFailure({ matcher: this, path: [], message: `Invalid JSON string: ${actual}`, }); - return result; } else { throw err; } @@ -351,8 +414,14 @@ class SerializedJson extends Matcher { const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); const innerResult = matcher.test(parsed); - result.compose(`(${this.name})`, innerResult); - return result; + if (innerResult.hasFailed()) { + innerResult.recordFailure({ + matcher: this, + path: [], + message: 'Encoded JSON value does not match', + }); + } + return innerResult; } } diff --git a/packages/@aws-cdk/assertions/lib/matcher.ts b/packages/@aws-cdk/assertions/lib/matcher.ts index da345fcbd193..7bfa886e5a54 100644 --- a/packages/@aws-cdk/assertions/lib/matcher.ts +++ b/packages/@aws-cdk/assertions/lib/matcher.ts @@ -48,6 +48,13 @@ export interface MatchFailure { * Failure message */ readonly message: string; + + /** + * The cost of this particular mismatch + * + * @default 1 + */ + readonly cost?: number; } /** @@ -72,9 +79,13 @@ export class MatchResult { * The target for which this result was generated. */ public readonly target: any; - private readonly failures: MatchFailure[] = []; + private readonly failuresHere = new Map(); private readonly captures: Map = new Map(); private finalized: boolean = false; + private readonly innerMatchFailures = new Map(); + private _hasFailed = false; + private _failCount = 0; + private _cost = 0; constructor(target: any) { this.target = target; @@ -92,18 +103,38 @@ export class MatchResult { * Record a new failure into this result at a specific path. */ public recordFailure(failure: MatchFailure): this { - this.failures.push(failure); + const failKey = failure.path.join('.'); + let list = this.failuresHere.get(failKey); + if (!list) { + list = []; + this.failuresHere.set(failKey, list); + } + + this._failCount += 1; + this._cost += failure.cost ?? 1; + list.push(failure); + this._hasFailed = true; return this; } + /** Whether the match is a success */ + public get isSuccess(): boolean { + return !this._hasFailed; + } + /** Does the result contain any failures. If not, the result is a success */ public hasFailed(): boolean { - return this.failures.length !== 0; + return this._hasFailed; } /** The number of failures */ public get failCount(): number { - return this.failures.length; + return this._failCount; + } + + /** The cost of the failures so far */ + public get failCost(): number { + return this._cost; } /** @@ -111,10 +142,15 @@ export class MatchResult { * @param id the id of the parent tree. */ public compose(id: string, inner: MatchResult): this { - const innerF = inner.failures; - this.failures.push(...innerF.map(f => { - return { path: [id, ...f.path], message: f.message, matcher: f.matcher }; - })); + // Record inner failure + if (inner.hasFailed()) { + this._hasFailed = true; + this._failCount += inner.failCount; + this._cost += inner._cost; + this.innerMatchFailures.set(id, inner); + } + + // Copy captures so we all finalize them together inner.captures.forEach((vals, capture) => { vals.forEach(value => this.recordCapture({ capture, value })); }); @@ -138,13 +174,203 @@ export class MatchResult { } /** - * Get the list of failures as human readable strings + * Render the failed match in a presentable way + * + * Prefer using `renderMismatch` over this method. It is left for backwards + * compatibility for test suites that expect it, but `renderMismatch()` will + * produce better output. */ public toHumanStrings(): string[] { - return this.failures.map(r => { - const loc = r.path.length === 0 ? '' : ` at ${r.path.join('')}`; + const failures = new Array(); + debugger; + recurse(this, []); + + return failures.map(r => { + const loc = r.path.length === 0 ? '' : ` at /${r.path.join('/')}`; return '' + r.message + loc + ` (using ${r.matcher.name} matcher)`; }); + + function recurse(x: MatchResult, prefix: string[]): void { + for (const fail of Array.from(x.failuresHere.values()).flat()) { + failures.push({ + matcher: fail.matcher, + message: fail.message, + path: [...prefix, ...fail.path], + }); + } + for (const [key, inner] of x.innerMatchFailures.entries()) { + recurse(inner, [...prefix, key]); + } + } + } + + /** + * Do a deep render of the match result, showing the structure mismatches in context + */ + public renderMismatch(): string { + if (!this.hasFailed()) { + return ''; + } + + const parts = new Array(); + const indents = new Array(); + emitFailures(this, ''); + recurse(this); + return moveMarkersToFront(parts.join('').trimEnd()); + + // Implementation starts here. + // Yes this is a lot of code in one place. That's a bit unfortunate, but this is + // the simplest way to access private state of the MatchResult, that we definitely + // do NOT want to make part of the public API. + + function emit(x: string): void { + if (x === undefined) { + debugger; + } + parts.push(x.replace(/\n/g, `\n${indents.join('')}`)); + } + + function emitFailures(r: MatchResult, path: string, scrapSet?: Set): void { + for (const fail of r.failuresHere.get(path) ?? []) { + emit(`!! ${fail.message}\n`); + } + scrapSet?.delete(path); + } + + function recurse(r: MatchResult): void { + // Failures that have been reported against this MatchResult that we didn't print yet + const remainingFailures = new Set(Array.from(r.failuresHere.keys()).filter(x => x !== '')); + + ////////////////////////////////////////////////////////////////////// + if (Array.isArray(r.target)) { + indents.push(' '); + emit('[\n'); + for (const [first, i] of enumFirst(range(r.target.length))) { + if (!first) { emit(',\n'); } + + emitFailures(r, `${i}`, remainingFailures); + const innerMatcher = r.innerMatchFailures.get(`${i}`); + if (innerMatcher) { + // Report the top-level failures on the line before the content + emitFailures(innerMatcher, ''); + recurseComparingValues(innerMatcher, r.target[i]); + } else { + emit(renderAbridged(r.target[i])); + } + } + + emitRemaining(); + indents.pop(); + emit('\n]'); + + return; + } + + ////////////////////////////////////////////////////////////////////// + if (r.target && typeof r.target === 'object') { + indents.push(' '); + emit('{\n'); + const keys = Array.from(new Set([ + ...Object.keys(r.target), + ...Array.from(remainingFailures), + ])).sort(); + + for (const [first, key] of enumFirst(keys)) { + if (!first) { emit(',\n'); } + + emitFailures(r, key, remainingFailures); + const innerMatcher = r.innerMatchFailures.get(key); + if (innerMatcher) { + // Report the top-level failures on the line before the content + emitFailures(innerMatcher, ''); + emit(`${jsonify(key)}: `); + recurseComparingValues(innerMatcher, r.target[key]); + } else { + emit(`${jsonify(key)}: `); + emit(renderAbridged(r.target[key])); + } + } + + emitRemaining(); + indents.pop(); + emit('\n}'); + + return; + } + + ////////////////////////////////////////////////////////////////////// + emitRemaining(); + emit(jsonify(r.target)); + + function emitRemaining(): void { + if (remainingFailures.size > 0) { + emit('\n'); + } + for (const key of remainingFailures) { + emitFailures(r, key); + } + } + } + + /** + * Recurse to the inner matcher, but with a twist: + * + * If the match result target value is not the same as the given value, + * then the matcher is matching a transformation of the given value. + * + * In that case, render both. + * + * FIXME: All of this rendering should have been at the discretion of + * the matcher, it shouldn't all live here. + */ + function recurseComparingValues(inner: MatchResult, actualValue: any): void { + if (inner.target === actualValue) { + return recurse(inner); + } + emit(renderAbridged(actualValue)); + emit(' <*> '); + recurse(inner); + } + + /** + * Render an abridged version of a value + */ + function renderAbridged(x: any): string { + if (Array.isArray(x)) { + switch (x.length) { + case 0: return '[]'; + case 1: return `[ ${renderAbridged(x[0])} ]`; + case 2: + // Render if all values are scalars + if (x.every(e => ['number', 'boolean', 'string'].includes(typeof e))) { + return `[ ${x.map(renderAbridged).join(', ')} ]`; + } + return '[ ... ]'; + default: return '[ ... ]'; + } + } + if (x && typeof x === 'object') { + const keys = Object.keys(x); + switch (keys.length) { + case 0: return '{}'; + case 1: return `{ ${JSON.stringify(keys[0])}: ${renderAbridged(x[keys[0]])} }`; + default: return '{ ... }'; + } + } + return jsonify(x); + } + + function jsonify(x: any): string { + return JSON.stringify(x) ?? 'undefined'; + } + + /** + * Move markers to the front of each line + */ + function moveMarkersToFront(x: string): string { + const re = /^(\s+)!!/gm; + return x.replace(re, (_, spaces: string) => `!!${spaces.substring(0, spaces.length - 2) }`); + } } /** @@ -159,3 +385,17 @@ export class MatchResult { this.captures.set(options.capture, values); } } + +function* range(n: number): Iterable { + for (let i = 0; i < n; i++) { + yield i; + } +} + +function* enumFirst(xs: Iterable): Iterable<[boolean, A]> { + let first = true; + for (const x of xs) { + yield [first, x]; + first = false; + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/lib/private/conditions.ts b/packages/@aws-cdk/assertions/lib/private/conditions.ts index 6ed10379dea9..aed523e05d7e 100644 --- a/packages/@aws-cdk/assertions/lib/private/conditions.ts +++ b/packages/@aws-cdk/assertions/lib/private/conditions.ts @@ -1,4 +1,4 @@ -import { filterLogicalId, formatFailure, matchSection } from './section'; +import { filterLogicalId, matchSection, formatSectionMatchFailure } from './section'; import { Template } from './template'; export function findConditions(template: Template, logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } { @@ -19,12 +19,5 @@ export function hasCondition(template: Template, logicalId: string, props: any): return; } - if (result.closestResult === undefined) { - return 'No conditions found in the template'; - } - - return [ - `Template has ${result.analyzedCount} conditions, but none match as expected.`, - formatFailure(result.closestResult), - ].join('\n'); + return formatSectionMatchFailure(`conditions with logicalId ${logicalId}`, result); } diff --git a/packages/@aws-cdk/assertions/lib/private/mappings.ts b/packages/@aws-cdk/assertions/lib/private/mappings.ts index e8788fb2ef11..352c83f1c82d 100644 --- a/packages/@aws-cdk/assertions/lib/private/mappings.ts +++ b/packages/@aws-cdk/assertions/lib/private/mappings.ts @@ -1,4 +1,4 @@ -import { filterLogicalId, formatFailure, matchSection } from './section'; +import { filterLogicalId, matchSection, formatSectionMatchFailure } from './section'; import { Template } from './template'; export function findMappings(template: Template, logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } { @@ -15,17 +15,9 @@ export function findMappings(template: Template, logicalId: string, props: any = export function hasMapping(template: Template, logicalId: string, props: any): string | void { const section: { [key: string]: {} } = template.Mappings ?? {}; const result = matchSection(filterLogicalId(section, logicalId), props); - if (result.match) { return; } - if (result.closestResult === undefined) { - return 'No mappings found in the template'; - } - - return [ - `Template has ${result.analyzedCount} mappings, but none match as expected.`, - formatFailure(result.closestResult), - ].join('\n'); + return formatSectionMatchFailure(`mappings with logicalId ${logicalId}`, result); } \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/lib/private/messages.ts b/packages/@aws-cdk/assertions/lib/private/messages.ts index f152ebcefb0e..140eb3fd9520 100644 --- a/packages/@aws-cdk/assertions/lib/private/messages.ts +++ b/packages/@aws-cdk/assertions/lib/private/messages.ts @@ -1,6 +1,6 @@ import { SynthesisMessage } from '@aws-cdk/cx-api'; import { Messages } from './message'; -import { formatAllMatches, formatFailure, matchSection } from './section'; +import { formatAllMatches, matchSection, formatSectionMatchFailure } from './section'; export function findMessage(messages: Messages, constructPath: string, props: any = {}): { [key: string]: { [key: string]: any } } { const section: { [key: string]: SynthesisMessage } = messages; @@ -16,20 +16,15 @@ export function findMessage(messages: Messages, constructPath: string, props: an export function hasMessage(messages: Messages, constructPath: string, props: any): string | void { const section: { [key: string]: SynthesisMessage } = messages; const result = matchSection(filterPath(section, constructPath), props); - if (result.match) { return; } - if (result.closestResult === undefined) { - return 'No messages found in the stack'; + for (const mr of Object.values(result.closestResults)) { + redactTraces(mr.target); } - handleTrace(result.closestResult.target); - return [ - `Stack has ${result.analyzedCount} messages, but none match as expected.`, - formatFailure(result.closestResult), - ].join('\n'); + return formatSectionMatchFailure(`messages at path ${constructPath}`, result, 'Stack'); } export function hasNoMessage(messages: Messages, constructPath: string, props: any): string | void { @@ -48,7 +43,7 @@ export function hasNoMessage(messages: Messages, constructPath: string, props: a // We redact the stack trace by default because it is unnecessarily long and unintelligible. // If there is a use case for rendering the trace, we can add it later. -function handleTrace(match: any, redact: boolean = true): void { +function redactTraces(match: any, redact: boolean = true): void { if (redact && match.entry?.trace !== undefined) { match.entry.trace = 'redacted'; }; diff --git a/packages/@aws-cdk/assertions/lib/private/outputs.ts b/packages/@aws-cdk/assertions/lib/private/outputs.ts index a24d44881d30..6df28a9988ed 100644 --- a/packages/@aws-cdk/assertions/lib/private/outputs.ts +++ b/packages/@aws-cdk/assertions/lib/private/outputs.ts @@ -1,4 +1,4 @@ -import { filterLogicalId, formatFailure, matchSection } from './section'; +import { filterLogicalId, matchSection, formatSectionMatchFailure } from './section'; import { Template } from './template'; export function findOutputs(template: Template, logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } { @@ -19,12 +19,5 @@ export function hasOutput(template: Template, logicalId: string, props: any): st return; } - if (result.closestResult === undefined) { - return `No outputs named ${logicalId} found in the template (found: ${Object.keys(section).join(', ')})`; - } - - return [ - `Template has ${result.analyzedCount} outputs named ${logicalId}, but none match as expected.`, - formatFailure(result.closestResult), - ].join('\n'); + return formatSectionMatchFailure(`outputs named ${logicalId}`, result); } diff --git a/packages/@aws-cdk/assertions/lib/private/parameters.ts b/packages/@aws-cdk/assertions/lib/private/parameters.ts index 0e73160ea5a7..a12457325d67 100644 --- a/packages/@aws-cdk/assertions/lib/private/parameters.ts +++ b/packages/@aws-cdk/assertions/lib/private/parameters.ts @@ -1,4 +1,4 @@ -import { filterLogicalId, formatFailure, matchSection } from './section'; +import { filterLogicalId, matchSection, formatSectionMatchFailure } from './section'; import { Template } from './template'; export function findParameters(template: Template, logicalId: string, props: any = {}): { [key: string]: { [key: string]: any } } { @@ -19,12 +19,5 @@ export function hasParameter(template: Template, logicalId: string, props: any): return; } - if (result.closestResult === undefined) { - return 'No parameters found in the template'; - } - - return [ - `Template has ${result.analyzedCount} parameters, but none match as expected.`, - formatFailure(result.closestResult), - ].join('\n'); + return formatSectionMatchFailure(`parameters with logicalId '${logicalId}'`, result); } diff --git a/packages/@aws-cdk/assertions/lib/private/resources.ts b/packages/@aws-cdk/assertions/lib/private/resources.ts index 155156df5b9a..badded669e46 100644 --- a/packages/@aws-cdk/assertions/lib/private/resources.ts +++ b/packages/@aws-cdk/assertions/lib/private/resources.ts @@ -1,6 +1,6 @@ import { Match, Matcher } from '..'; import { AbsentMatch } from './matchers/absent'; -import { formatAllMismatches, formatFailure, matchSection } from './section'; +import { formatAllMismatches, matchSection, formatSectionMatchFailure } from './section'; import { Resource, Template } from './template'; export function findResources(template: Template, type: string, props: any = {}): { [key: string]: { [key: string]: any } } { @@ -57,14 +57,7 @@ export function hasResource(template: Template, type: string, props: any): strin return; } - if (result.closestResult === undefined) { - return `No resource with type ${type} found`; - } - - return [ - `Template has ${result.analyzedCount} resources with type ${type}, but none match as expected.`, - formatFailure(result.closestResult), - ].join('\n'); + return formatSectionMatchFailure(`resources with type ${type}`, result); } export function hasResourceProperties(template: Template, type: string, props: any): string | void { diff --git a/packages/@aws-cdk/assertions/lib/private/section.ts b/packages/@aws-cdk/assertions/lib/private/section.ts index 3d81f2f1ce68..5076fe75d848 100644 --- a/packages/@aws-cdk/assertions/lib/private/section.ts +++ b/packages/@aws-cdk/assertions/lib/private/section.ts @@ -1,18 +1,18 @@ import { Match } from '../match'; import { Matcher, MatchResult } from '../matcher'; +import { sortKeyComparator } from './sorting'; export type MatchSuccess = { match: true, matches: { [key: string]: any }, analyzed: { [key: string]: any }, analyzedCount: number }; -export type MatchFailure = { match: false, closestResult?: MatchResult, analyzed: { [key: string]: any }, analyzedCount: number }; +export type MatchFailure = { match: false, closestResults: Record, analyzed: { [key: string]: any }, analyzedCount: number }; export function matchSection(section: any, props: any): MatchSuccess | MatchFailure { const matcher = Matcher.isMatcher(props) ? props : Match.objectLike(props); - let closestResult: MatchResult | undefined = undefined; - let matching: { [key: string]: any } = {}; - let analyzed: { [key: string]: any } = {}; + const matching: { [key: string]: any } = {}; + const analyzed: { [key: string]: any } = {}; + const failures = new Array<[string, MatchResult]>(); eachEntryInSection( section, - (logicalId, entry) => { analyzed[logicalId] = entry; const result = matcher.test(entry); @@ -20,16 +20,18 @@ export function matchSection(section: any, props: any): MatchSuccess | MatchFail if (!result.hasFailed()) { matching[logicalId] = entry; } else { - if (closestResult === undefined || closestResult.failCount > result.failCount) { - closestResult = result; - } + failures.push([logicalId, result]); } }, ); if (Object.keys(matching).length > 0) { return { match: true, matches: matching, analyzedCount: Object.keys(analyzed).length, analyzed: analyzed }; } else { - return { match: false, closestResult, analyzedCount: Object.keys(analyzed).length, analyzed: analyzed }; + // Sort by cost, use logicalId as a tie breaker. Take the 3 closest + // matches (helps debugging in case we get the top pick wrong). + failures.sort(sortKeyComparator(([logicalId, result]) => [result.failCost, logicalId])); + const closestResults = Object.fromEntries(failures.slice(0, 3)); + return { match: false, closestResults, analyzedCount: Object.keys(analyzed).length, analyzed: analyzed }; } } @@ -56,12 +58,24 @@ export function formatAllMismatches(analyzed: { [key: string]: any }, matches: { ].join('\n'); } -export function formatFailure(closestResult: MatchResult): string { +export function formatSectionMatchFailure(qualifier: string, result: MatchFailure, what='Template'): string { + return [ + `${what} has ${result.analyzedCount} ${qualifier}`, + result.analyzedCount > 0 ? ', but none match as expected' : '', + '.\n', + formatFailure(result.closestResults), + ].join(''); +} + +export function formatFailure(closestResults: Record): string { + const keys = Object.keys(closestResults); + if (keys.length === 0) { + return 'No matches found'; + } + return [ - 'The closest result is:', - leftPad(JSON.stringify(closestResult.target, undefined, 2)), - 'with the following mismatches:', - ...closestResult.toHumanStrings().map(s => `\t${s}`), + `The ${keys.length} closest matches:`, + ...keys.map(key => `${key} :: ${closestResults[key].renderMismatch()}`), ].join('\n'); } diff --git a/packages/@aws-cdk/assertions/lib/private/sorting.ts b/packages/@aws-cdk/assertions/lib/private/sorting.ts new file mode 100644 index 000000000000..dd345f6431b3 --- /dev/null +++ b/packages/@aws-cdk/assertions/lib/private/sorting.ts @@ -0,0 +1,27 @@ +/** + * Make a sorting comparator that will sort by a given sort key + */ +export function sortKeyComparator(keyFn: (x: A) => Array) { + return (a: A, b: A): number => { + const ak = keyFn(a); + const bk = keyFn(b); + + for (let i = 0; i < ak.length && i < bk.length; i++) { + const av = ak[i]; + const bv = bk[i]; + + let diff = 0; + if (typeof av === 'number' && typeof bv === 'number') { + diff = av - bv; + } else if (typeof av === 'string' && typeof bv === 'string') { + diff = av.localeCompare(bv); + } + + if (diff !== 0) { + return diff; + } + } + + return (bk.length - ak.length); + }; +} \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/lib/private/sparse-matrix.ts b/packages/@aws-cdk/assertions/lib/private/sparse-matrix.ts new file mode 100644 index 000000000000..bef1e4fa0ea9 --- /dev/null +++ b/packages/@aws-cdk/assertions/lib/private/sparse-matrix.ts @@ -0,0 +1,20 @@ +export class SparseMatrix { + private readonly matrix = new Map>(); + + public get(row: number, col: number): A | undefined { + return this.matrix.get(row)?.get(col); + } + + public row(row: number): Array<[number, A]> { + return Array.from(this.matrix.get(row)?.entries() ?? []); + } + + public set(row: number, col: number, value: A): void { + let r = this.matrix.get(row); + if (!r) { + r = new Map(); + this.matrix.set(row, r); + } + r.set(col, value); + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/test/__snapshots__/render.test.js.snap b/packages/@aws-cdk/assertions/test/__snapshots__/render.test.js.snap new file mode 100644 index 000000000000..ff920992eb40 --- /dev/null +++ b/packages/@aws-cdk/assertions/test/__snapshots__/render.test.js.snap @@ -0,0 +1,124 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Abridged rendering of uninteresting keys (hiding Other) 1`] = ` +" +{ + \\"Other\\": { ... }, +!! Expected Balue but received Value + \\"Value\\": \\"Value\\" +}" +`; + +exports[`Abridged rendering of uninteresting keys (showing Other) 1`] = ` +" +{ + \\"Other\\": { \\"OneKey\\": \\"Visible\\" }, +!! Expected Balue but received Value + \\"Value\\": \\"Value\\" +}" +`; + +exports[`ArrayWith matcher 1`] = ` +"Most entries should be collapsed but at least one should for a deep comparison +{ + \\"List\\": [ +!! Could not match arrayWith pattern 0. This is the closest match + { + \\"MakeItBig\\": true, +!! Expected 5 but received 1 + \\"Value\\": \\"1\\" + }, + { ... }, + { ... }, + { ... } + ] +}" +`; + +exports[`ArrayWith out-of-order match 1`] = ` +" +[ + 5, +!! arrayWith pattern 0 matched here + 3 +!! Could not match arrayWith pattern 1. No more elements to try + +]" +`; + +exports[`ArrayWith partial match 1`] = ` +"Most entries should be collapsed but at least one should for a deep comparison, and should show a place for previous matches +{ + \\"List\\": [ + { ... }, +!! arrayWith pattern 0 matched here + { + \\"MakeItBig\\": true, + \\"Value\\": \\"2\\" + }, +!! Could not match arrayWith pattern 1. This is the closest match + { + \\"MakeItBig\\": true, +!! Expected 5 but received 3 + \\"Value\\": \\"3\\" + }, + { ... } + ] +}" +`; + +exports[`Deep Match.objectLike with mismatched string value 1`] = ` +" +{ + \\"Deep\\": { + \\"Other\\": \\"Other\\", +!! Expected Value but received Balue + \\"Value\\": \\"Balue\\" + } +}" +`; + +exports[`Encodedjson matcher 1`] = ` +" +{ +!! Encoded JSON value does not match + \\"Json\\": \\"{\\\\\\"Value\\\\\\":\\\\\\"Value\\\\\\"}\\" <*> { +!! Expected Balue but received Value + \\"Value\\": \\"Value\\" + } +}" +`; + +exports[`Match.objectEquals with missing key 1`] = ` +" +{ +!! Missing key 'Value' + \\"Value\\": undefined +}" +`; + +exports[`Match.objectEquals with unexpected key 1`] = ` +" +{ +!! Unexpected key Other + \\"Other\\": \\"Other\\", + \\"Value\\": \\"Value\\" +}" +`; + +exports[`Match.objectLike looking for absent key 1`] = ` +" +{ +!! Received Value, but key should be absent + \\"Value\\": \\"Value\\" +}" +`; + +exports[`Match.objectLike with mismatched string value 1`] = ` +" +{ + \\"Other\\": \\"Other\\", +!! Expected Value but received Balue + \\"Value\\": \\"Balue\\" +}" +`; diff --git a/packages/@aws-cdk/assertions/test/annotations.test.ts b/packages/@aws-cdk/assertions/test/annotations.test.ts index ebc1ca081d86..2732f7db7c77 100644 --- a/packages/@aws-cdk/assertions/test/annotations.test.ts +++ b/packages/@aws-cdk/assertions/test/annotations.test.ts @@ -46,7 +46,7 @@ describe('Messages', () => { test('no match', () => { expect(() => annotations.hasError('/Default/Fred', Match.anyValue())) - .toThrowError(/Stack has 1 messages, but none match as expected./); + .toThrowError(/Stack has 1 messages.*but none match as expected./); }); }); @@ -79,7 +79,7 @@ describe('Messages', () => { }); test('no match', () => { - expect(() => annotations.hasWarning('/Default/Foo', Match.anyValue())).toThrowError(/Stack has 1 messages, but none match as expected./); + expect(() => annotations.hasWarning('/Default/Foo', Match.anyValue())).toThrowError(/Stack has 1 messages.*but none match as expected./); }); }); @@ -112,7 +112,7 @@ describe('Messages', () => { }); test('no match', () => { - expect(() => annotations.hasInfo('/Default/Qux', 'this info is incorrect')).toThrowError(/Stack has 1 messages, but none match as expected./); + expect(() => annotations.hasInfo('/Default/Qux', 'this info is incorrect')).toThrowError(/Stack has 1 messages.*but none match as expected./); }); }); @@ -147,7 +147,7 @@ describe('Messages', () => { test('not', () => { expect(() => annotations.hasError('/Default/Foo', Match.not('this is an error'))) - .toThrowError(/Found unexpected match: "this is an error" at \/entry\/data/); + .toThrowError(/Found unexpected match: "this is an error"/); }); test('stringLikeRegEx', () => { diff --git a/packages/@aws-cdk/assertions/test/capture.test.ts b/packages/@aws-cdk/assertions/test/capture.test.ts index 27f8f91d1c3d..e26920b9cbb9 100644 --- a/packages/@aws-cdk/assertions/test/capture.test.ts +++ b/packages/@aws-cdk/assertions/test/capture.test.ts @@ -120,4 +120,34 @@ describe('Capture', () => { expect(() => capture.asObject()).toThrow(/No value captured/); }); + + test('capture in arraywith and objectlike', () => { + const capture = new Capture(); + const matcher = Match.objectLike({ + People: Match.arrayWith([{ + Name: 'Alice', + Attributes: [ + Match.objectLike({ + Name: 'HairColor', + Value: capture, + }), + ], + }]), + }); + + const result = matcher.test({ + People: [ + { + Name: 'Alice', + Attributes: [ + { Name: 'HairColor', Value: 'Black' }, + ], + }, + ], + }); + + expect(result.isSuccess).toEqual(true); + result.finished(); + expect(capture.asString()).toEqual('Black'); + }); }); diff --git a/packages/@aws-cdk/assertions/test/match.test.ts b/packages/@aws-cdk/assertions/test/match.test.ts index b0e6bd8a5eb7..02d832574dbd 100644 --- a/packages/@aws-cdk/assertions/test/match.test.ts +++ b/packages/@aws-cdk/assertions/test/match.test.ts @@ -24,22 +24,22 @@ describe('Matchers', () => { test('arrays', () => { matcher = Match.exact([4]); expectPass(matcher, [4]); - expectFailure(matcher, [4, 5], [/Expected array of length 1 but received 2/]); + expectFailure(matcher, [4, 5], [/Too many elements in array/]); expectFailure(matcher, 'foo', [/Expected type array but received string/]); matcher = Match.exact(['foo', 3]); expectPass(matcher, ['foo', 3]); - expectFailure(matcher, ['bar', 3], [/Expected foo but received bar at \[0\]/]); - expectFailure(matcher, ['foo', 5], [/Expected 3 but received 5 at \[1\]/]); + expectFailure(matcher, ['bar', 3], [/Expected foo but received bar at \/0/]); + expectFailure(matcher, ['foo', 5], [/Expected 3 but received 5 at \/1/]); matcher = Match.exact([{ foo: 'bar', baz: 'qux' }, { waldo: 'fred', wobble: 'flob' }]); expectPass(matcher, [{ foo: 'bar', baz: 'qux' }, { waldo: 'fred', wobble: 'flob' }]); - expectFailure(matcher, [{ foo: 'bar', baz: 'qux' }], [/Expected array of length 2 but received 1/]); + expectFailure(matcher, [{ foo: 'bar', baz: 'qux' }], [/Not enough elements in array/]); expectFailure(matcher, [{ foo: 'bar', baz: 'qux' }, { waldo: 'flob', wobble: 'fred' }], [ - 'Expected fred but received flob at [1]/waldo', - 'Expected flob but received fred at [1]/wobble', + 'Expected fred but received flob at /1/waldo', + 'Expected flob but received fred at /1/wobble', ]); - expectFailure(matcher, [{ foo: 'bar', baz: 'qux' }, { waldo: 'fred' }], [/Missing key.*at \[1\]\/wobble/]); + expectFailure(matcher, [{ foo: 'bar', baz: 'qux' }, { waldo: 'fred' }], [/Missing key.*at \/1\/wobble/]); }); test('objects', () => { @@ -48,13 +48,13 @@ describe('Matchers', () => { expectFailure(matcher, 5, [/Expected type object but received number/]); expectFailure(matcher, ['3', 5], [/Expected type object but received array/]); expectFailure(matcher, { baz: 'qux' }, [ - 'Unexpected key at /baz', + 'Unexpected key baz at /baz', /Missing key.*at \/foo/, ]); matcher = Match.exact({ foo: 'bar', baz: 5 }); expectFailure(matcher, { foo: 'bar', baz: '5' }, [/Expected type number but received string at \/baz/]); - expectFailure(matcher, { foo: 'bar', baz: 5, qux: 7 }, [/Unexpected key at \/qux/]); + expectFailure(matcher, { foo: 'bar', baz: 5, qux: 7 }, [/Unexpected key qux at \/qux/]); matcher = Match.exact({ foo: [2, 3], bar: 'baz' }); expectPass(matcher, { foo: [2, 3], bar: 'baz' }); @@ -67,8 +67,8 @@ describe('Matchers', () => { 'Expected type string but received array at /bar', ]); expectFailure(matcher, { foo: [3, 5], bar: 'baz' }, [ - 'Expected 2 but received 3 at /foo[0]', - 'Expected 3 but received 5 at /foo[1]', + 'Expected 2 but received 3 at /foo/0', + 'Expected 3 but received 5 at /foo/1', ]); }); @@ -93,18 +93,18 @@ describe('Matchers', () => { expectPass(matcher, [3]); expectPass(matcher, [3, 5]); expectPass(matcher, [1, 3, 5]); - expectFailure(matcher, [5], [/Missing element \[3\] at pattern index 0/]); + expectFailure(matcher, [5], [/Could not match arrayWith pattern 0/]); matcher = Match.arrayWith([5, false]); expectPass(matcher, [5, false, 'foo']); expectPass(matcher, [5, 'foo', false]); - expectFailure(matcher, [5, 'foo'], [/Missing element \[false\] at pattern index 1/]); + expectFailure(matcher, [5, 'foo'], [/Could not match arrayWith pattern 1/]); matcher = Match.arrayWith([{ foo: 'bar' }]); expectPass(matcher, [{ fred: 'waldo' }, { foo: 'bar' }, { baz: 'qux' }]); expectPass(matcher, [{ foo: 'bar' }]); - expectFailure(matcher, [{ foo: 'baz' }], [/Missing element at pattern index 0/]); - expectFailure(matcher, [{ baz: 'qux' }], [/Missing element at pattern index 0/]); + expectFailure(matcher, [{ foo: 'baz' }], [/Could not match arrayWith pattern 0/]); + expectFailure(matcher, [{ baz: 'qux' }], [/Could not match arrayWith pattern 0/]); }); test('not array', () => { @@ -115,14 +115,14 @@ describe('Matchers', () => { test('out of order', () => { matcher = Match.arrayWith([3, 5]); - expectFailure(matcher, [5, 3], [/Missing element \[5\] at pattern index 1/]); + expectFailure(matcher, [5, 3], [/Could not match arrayWith pattern 1/]); }); test('nested with ObjectLike', () => { matcher = Match.arrayWith([Match.objectLike({ foo: 'bar' })]); expectPass(matcher, [{ baz: 'qux' }, { foo: 'bar' }]); expectPass(matcher, [{ baz: 'qux' }, { foo: 'bar', fred: 'waldo' }]); - expectFailure(matcher, [{ foo: 'baz', fred: 'waldo' }], [/Missing element at pattern index 0/]); + expectFailure(matcher, [{ foo: 'baz', fred: 'waldo' }], [/Could not match arrayWith pattern 0/]); }); test('incompatible with absent', () => { @@ -142,8 +142,8 @@ describe('Matchers', () => { test('exact match', () => { matcher = Match.arrayEquals([5, false]); expectPass(matcher, [5, false]); - expectFailure(matcher, [5, 'foo', false], [/Expected array of length 2 but received 3/]); - expectFailure(matcher, [5, 'foo'], [/Expected type boolean but received string at \[1\]/]); + expectFailure(matcher, [5, 'foo', false], [/Too many elements in array/]); + expectFailure(matcher, [5, 'foo'], [/Expected type boolean but received string at \/1/]); }); }); @@ -181,7 +181,7 @@ describe('Matchers', () => { foo: Match.arrayWith(['bar']), }); expectPass(matcher, { foo: ['bar', 'baz'], fred: 'waldo' }); - expectFailure(matcher, { foo: ['baz'], fred: 'waldo' }, [/Missing element \[bar\] at pattern index 0 at \/foo/]); + expectFailure(matcher, { foo: ['baz'], fred: 'waldo' }, [/Could not match arrayWith pattern 0/]); }); test('Partiality is maintained throughout arrays', () => { @@ -214,7 +214,7 @@ describe('Matchers', () => { test('exact match', () => { matcher = Match.objectEquals({ foo: 'bar' }); expectPass(matcher, { foo: 'bar' }); - expectFailure(matcher, { foo: 'bar', baz: 'qux' }, [/Unexpected key at \/baz/]); + expectFailure(matcher, { foo: 'bar', baz: 'qux' }, [/Unexpected key baz at \/baz/]); }); }); @@ -329,7 +329,7 @@ describe('Matchers', () => { expectPass(matcher, ['foo', 'baz', 'bar']); expectPass(matcher, ['foo', 3, 'bar']); - expectFailure(matcher, ['foo', null, 'bar'], ['Expected a value but found none at [1]']); + expectFailure(matcher, ['foo', null, 'bar'], ['Expected a value but found none at /1']); }); test('nested in object', () => { @@ -354,11 +354,12 @@ describe('Matchers', () => { matcher = Match.serializedJson({ Foo: 'Bar' }); expectPass(matcher, '{ "Foo": "Bar" }'); - expectFailure(matcher, '{ "Foo": "Baz" }', ['Expected Bar but received Baz at (serializedJson)/Foo']); - expectFailure(matcher, '{ "Foo": 4 }', ['Expected type string but received number at (serializedJson)/Foo']); + expectFailure(matcher, '{ "Foo": "Baz" }', [/Encoded JSON value does not match/, 'Expected Bar but received Baz at /Foo']); + expectFailure(matcher, '{ "Foo": 4 }', [/Encoded JSON value does not match/, 'Expected type string but received number at /Foo']); expectFailure(matcher, '{ "Bar": "Baz" }', [ - 'Unexpected key at (serializedJson)/Bar', - /Missing key.*at \(serializedJson\)\/Foo/, + /Encoded JSON value does not match/, + 'Unexpected key Bar at /Bar', + /Missing key.*at \/Foo/, ]); }); @@ -371,8 +372,8 @@ describe('Matchers', () => { expectPass(matcher, '{ "Foo": ["Bar", "Baz"] }'); expectPass(matcher, '{ "Foo": ["Bar", "Baz"], "Fred": "Waldo" }'); - expectFailure(matcher, '{ "Foo": ["Baz"] }', ['Missing element [Bar] at pattern index 0 at (serializedJson)/Foo']); - expectFailure(matcher, '{ "Bar": ["Baz"] }', [/Missing key.*at \(serializedJson\)\/Foo/]); + expectFailure(matcher, '{ "Foo": ["Baz"] }', ['Could not match arrayWith pattern 0']); + expectFailure(matcher, '{ "Bar": ["Baz"] }', [/Missing key.*at \/Foo/]); }); test('invalid json string', () => { @@ -430,13 +431,12 @@ function expectFailure(matcher: Matcher, target: any, expected: (string | RegExp const result = matcher.test(target); expect(result.failCount).toBeGreaterThan(0); const actual = result.toHumanStrings(); - if (expected.length > 0 && actual.length !== expected.length) { - // only do this if the lengths are different, so as to display a nice failure message. - // otherwise need to use `toMatch()` to support RegExp - expect(actual).toEqual(expected); - } - for (let i = 0; i < expected.length; i++) { - const e = expected[i]; - expect(actual[i]).toMatch(e); + + const notFound = expected.filter(needle => !actual.some(haystack => { + return typeof needle === 'string' ? haystack.includes(needle) : haystack.match(needle); + })); + + if (notFound.length > 0) { + throw new Error(`Patterns: ${notFound}\nMissing from error:\n${actual.join('\n')}`); } } \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/test/private/section.test.ts b/packages/@aws-cdk/assertions/test/private/section.test.ts index 28cdece823df..3480f944746e 100644 --- a/packages/@aws-cdk/assertions/test/private/section.test.ts +++ b/packages/@aws-cdk/assertions/test/private/section.test.ts @@ -38,8 +38,10 @@ describe('section', () => { expect(result.match).toEqual(false); const success = result as MatchFailure; expect(success.analyzedCount).toEqual(2); - expect(success.closestResult).toBeDefined(); - expect(success.closestResult?.target).toEqual({ foo: 'qux' }); + + const ckeys = Object.keys(success.closestResults); + expect(ckeys).not.toEqual([]); + expect(success.closestResults[ckeys[0]].target).toEqual({ foo: 'qux' }); }); }); }); \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/test/render.test.ts b/packages/@aws-cdk/assertions/test/render.test.ts new file mode 100644 index 000000000000..cd93aaf2a7d1 --- /dev/null +++ b/packages/@aws-cdk/assertions/test/render.test.ts @@ -0,0 +1,157 @@ +/** + * Snapshot tests to assert that the rendering styles of the deep mismatch rendering make sense + */ + +import { Matcher, Match } from '../lib'; + +interface Case { + readonly name: string; + readonly note?: string; + readonly matcher: Matcher; + readonly target: any; +} + +const CASES: Case[] = [ + ////////////////////////////////////////////////////////////////////// + { + name: 'Match.objectLike with mismatched string value', + target: { + Value: 'Balue', + Other: 'Other', + }, + matcher: Match.objectLike({ + Value: 'Value', + }), + }, + ////////////////////////////////////////////////////////////////////// + { + name: 'Deep Match.objectLike with mismatched string value', + target: { + Deep: { + Value: 'Balue', + Other: 'Other', + }, + }, + matcher: Match.objectLike({ + Deep: { + Value: 'Value', + }, + }), + }, + ////////////////////////////////////////////////////////////////////// + { + name: 'Match.objectEquals with unexpected key', + target: { + Value: 'Value', + Other: 'Other', + }, + matcher: Match.objectEquals({ + Value: 'Value', + }), + }, + ////////////////////////////////////////////////////////////////////// + { + name: 'Match.objectEquals with missing key', + target: { + }, + matcher: Match.objectEquals({ + Value: 'Value', + }), + }, + ////////////////////////////////////////////////////////////////////// + { + name: 'Match.objectLike looking for absent key', + target: { + Value: 'Value', + }, + matcher: Match.objectEquals({ + Value: Match.absent(), + }), + }, + ////////////////////////////////////////////////////////////////////// + { + name: 'Abridged rendering of uninteresting keys (showing Other)', + target: { + Other: { OneKey: 'Visible' }, + Value: 'Value', + }, + matcher: Match.objectLike({ + Value: 'Balue', + }), + }, + ////////////////////////////////////////////////////////////////////// + { + name: 'Abridged rendering of uninteresting keys (hiding Other)', + target: { + Other: { OneKey: 'Visible', TooMany: 'Keys' }, + Value: 'Value', + }, + matcher: Match.objectLike({ + Value: 'Balue', + }), + }, + ////////////////////////////////////////////////////////////////////// + { + name: 'Encodedjson matcher', + target: { + Json: JSON.stringify({ + Value: 'Value', + }), + }, + matcher: Match.objectLike({ + Json: Match.serializedJson({ + Value: 'Balue', + }), + }), + }, + ////////////////////////////////////////////////////////////////////// + { + name: 'ArrayWith matcher', + note: 'Most entries should be collapsed but at least one should for a deep comparison', + target: { + List: [ + { Value: '1', MakeItBig: true }, + { Value: '2', MakeItBig: true }, + { Value: '3', MakeItBig: true }, + { Value: '4', MakeItBig: true }, + ], + }, + matcher: Match.objectLike({ + List: Match.arrayWith([ + Match.objectLike({ Value: '5' }), + ]), + }), + }, + ////////////////////////////////////////////////////////////////////// + { + name: 'ArrayWith partial match', + note: 'Most entries should be collapsed but at least one should for a deep comparison, and should show a place for previous matches', + target: { + List: [ + { Value: '1', MakeItBig: true }, + { Value: '2', MakeItBig: true }, + { Value: '3', MakeItBig: true }, + { Value: '4', MakeItBig: true }, + ], + }, + matcher: Match.objectLike({ + List: Match.arrayWith([ + Match.objectLike({ Value: '2' }), + Match.objectLike({ Value: '5' }), + ]), + }), + }, + ////////////////////////////////////////////////////////////////////// + { + name: 'ArrayWith out-of-order match', + target: [5, 3], + matcher: Match.arrayWith([3, 5]), + }, +]; + +CASES.forEach(c => { + test(c.name, () => { + const result = c.matcher.test(c.target); + expect(`${c.note ?? ''}\n${result.renderMismatch()}`).toMatchSnapshot(); + }); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/assertions/test/template.test.ts b/packages/@aws-cdk/assertions/test/template.test.ts index 7eb60db07a63..da23ade89b83 100644 --- a/packages/@aws-cdk/assertions/test/template.test.ts +++ b/packages/@aws-cdk/assertions/test/template.test.ts @@ -248,7 +248,7 @@ describe('Template', () => { Properties: { baz: 'waldo' }, }, }, - })).toThrowError(/Expected waldo but received qux at \/Resources\/Foo\/Properties\/baz/); + })).toThrowError(/Expected waldo but received qux/); }); }); @@ -267,11 +267,11 @@ describe('Template', () => { expect(() => inspect.hasResource('Foo::Bar', { Properties: { baz: 'waldo' }, - })).toThrow(/Expected waldo but received qux at \/Properties\/baz/); + })).toThrow(/Expected waldo but received qux/); expect(() => inspect.hasResource('Foo::Bar', { Properties: { baz: 'qux', fred: 'waldo' }, - })).toThrow(/Missing key.*at \/Properties\/fred/); + })).toThrow(/Missing key/); }); test('arrayWith', () => { @@ -288,10 +288,10 @@ describe('Template', () => { expect(() => inspect.hasResource('Foo::Bar', { Properties: { baz: Match.arrayWith(['waldo']) }, - })).toThrow(/Missing element \[waldo\] at pattern index 0 at \/Properties\/baz/); + })).toThrow(/Could not match arrayWith pattern 0/); }); - test('arrayWith - multiple resources', done => { + test('arrayWith - multiple resources', async () => { const stack = new Stack(); new CfnResource(stack, 'Foo1', { type: 'Foo::Bar', @@ -304,13 +304,11 @@ describe('Template', () => { const inspect = Template.fromStack(stack); - expectToThrow(() => { + await expectToThrow(() => { inspect.hasResource('Foo::Bar', { Properties: Match.arrayWith(['flob']), }); - }, [/The closest result/, /flob/, /qux/], done); - - done(); + }, [/closest matches/, /flob/, /qux/]); }); test('objectLike', () => { @@ -330,10 +328,10 @@ describe('Template', () => { expect(() => inspect.hasResource('Foo::Bar', { Properties: Match.objectLike({ baz: 'waldo' }), - })).toThrow(/Expected waldo but received qux at \/Properties\/baz/); + })).toThrow(/Expected waldo but received qux/); }); - test('objectLike - multiple resources', done => { + test('objectLike - multiple resources', () => { const stack = new Stack(); new CfnResource(stack, 'Foo1', { type: 'Foo::Bar', @@ -350,9 +348,7 @@ describe('Template', () => { inspect.hasResource('Foo::Bar', { Properties: Match.objectLike({ foo: { flob: 'foo' } }), }); - }, [/The closest result/, /"flob": "qux"/], done); - - done(); + }, [/closest match/, /"flob": "qux"/]); }); test('absent', () => { @@ -368,7 +364,7 @@ describe('Template', () => { }); expect(() => inspect.hasResource('Foo::Bar', { Properties: Match.objectLike({ baz: Match.absent() }), - })).toThrow(/key should be absent at \/Properties\/baz/); + })).toThrow(/key should be absent/); }); test('incorrect types', () => { @@ -381,7 +377,7 @@ describe('Template', () => { const inspect = Template.fromStack(stack); expect(() => inspect.hasResource('Foo::Baz', { Properties: Match.objectLike({ baz: 'qux' }), - })).toThrow(/No resource/); + })).toThrow(/0 resources with type Foo::Baz/); }); test('capture', () => { @@ -424,10 +420,10 @@ describe('Template', () => { inspect.hasResourceProperties('Foo::Bar', { baz: 'qux' }); expect(() => inspect.hasResourceProperties('Foo::Bar', { baz: 'waldo' })) - .toThrow(/Expected waldo but received qux at \/Properties\/baz/); + .toThrow(/Expected waldo but received qux/); expect(() => inspect.hasResourceProperties('Foo::Bar', { baz: 'qux', fred: 'waldo' })) - .toThrow(/Missing key.*at \/Properties\/fred/); + .toThrow(/Missing key/); }); test('absent - with properties', () => { @@ -445,7 +441,7 @@ describe('Template', () => { expect(() => inspect.hasResourceProperties('Foo::Bar', { baz: Match.absent(), - })).toThrow(/key should be absent at \/Properties\/baz/); + })).toThrow(/key should be absent/); }); test('absent - no properties', () => { @@ -457,7 +453,7 @@ describe('Template', () => { const inspect = Template.fromStack(stack); expect(() => inspect.hasResourceProperties('Foo::Bar', { bar: Match.absent(), baz: 'qux' })) - .toThrow(/Missing key.*at \/Properties\/baz/); + .toThrow(/Missing key/); inspect.hasResourceProperties('Foo::Bar', Match.absent()); }); @@ -570,7 +566,7 @@ describe('Template', () => { expect(inspect.allResources('Foo::Bar', { Properties: partialProps })); }); - test('no resources match', (done) => { + test('no resources match', () => { const stack = new Stack(); new CfnResource(stack, 'Foo', { type: 'Foo::Bar', @@ -590,12 +586,10 @@ describe('Template', () => { /Foo/, /Foo2/, ], - done, ); - done(); }); - test('some resources match', (done) => { + test('some resources match', () => { const stack = new Stack(); new CfnResource(stack, 'Foo', { type: 'Foo::Bar', @@ -614,9 +608,7 @@ describe('Template', () => { 'The following resources do not match the given definition:', /Foo2/, ], - done, ); - done(); }); test('using a "not" matcher ', () => { @@ -652,7 +644,7 @@ describe('Template', () => { expect(inspect.allResourcesProperties('Foo::Bar', partialProps)); }); - test('no resources match', (done) => { + test('no resources match', () => { const stack = new Stack(); new CfnResource(stack, 'Foo', { type: 'Foo::Bar', @@ -676,12 +668,10 @@ describe('Template', () => { /Foo/, /Foo2/, ], - done, ); - done(); }); - test('some resources match', (done) => { + test('some resources match', () => { const stack = new Stack(); new CfnResource(stack, 'Foo', { type: 'Foo::Bar', @@ -700,9 +690,7 @@ describe('Template', () => { 'The following resources do not match the given definition:', /Foo2/, ], - done, ); - done(); }); test('using a "not" matcher ', () => { @@ -735,7 +723,7 @@ describe('Template', () => { expect(() => inspect.hasOutput('Foo', { Value: 'Bar' })).not.toThrow(); }); - test('not matching', (done) => { + test('not matching', () => { const stack = new Stack(); new CfnOutput(stack, 'Foo', { value: 'Bar', @@ -755,12 +743,10 @@ describe('Template', () => { /1 outputs named Foo/, /Expected ExportBaz but received ExportBar/, ], - done, ); - done(); }); - test('value not matching with outputName', (done) => { + test('value not matching with outputName', () => { const stack = new Stack(); new CfnOutput(stack, 'Foo', { value: 'Bar', @@ -778,13 +764,11 @@ describe('Template', () => { /1 outputs named Fred/, /Expected Bar but received Baz/, ], - done, ); - done(); }); }); - test('outputName not matching', (done) => { + test('outputName not matching', () => { const stack = new Stack(); new CfnOutput(stack, 'Foo', { value: 'Bar', @@ -798,11 +782,9 @@ describe('Template', () => { Export: { Name: 'ExportBar' }, }), [ - /No outputs named Fred found in the template./, + /Template has 0 outputs named Fred./, ], - done, ); - done(); }); describe('findOutputs', () => { @@ -891,7 +873,7 @@ describe('Template', () => { expect(() => inspect.hasMapping('*', { Foo: { Bar: 'Lightning' } })).not.toThrow(); }); - test('not matching', (done) => { + test('not matching', () => { const stack = new Stack(); new CfnMapping(stack, 'Foo', { mapping: { @@ -914,9 +896,7 @@ describe('Template', () => { /2 mappings/, /Expected Qux but received Fred/, ], - done, ); - done(); }); test('matching specific outputName', () => { @@ -937,7 +917,7 @@ describe('Template', () => { expect(() => inspect.hasMapping('Foo', { Baz: { Bar: 'Qux' } })).not.toThrow(); }); - test('not matching specific outputName', (done) => { + test('not matching specific outputName', () => { const stack = new Stack(); new CfnMapping(stack, 'Foo', { mapping: { @@ -960,9 +940,7 @@ describe('Template', () => { /1 mappings/, /Expected Fred but received Baz/, ], - done, ); - done(); }); }); @@ -1054,7 +1032,7 @@ describe('Template', () => { expect(() => inspect.findParameters('p3', { Type: 'String' })).not.toThrow(); }); - test('not matching', (done) => { + test('not matching', () => { const stack = new Stack(); new CfnParameter(stack, 'p1', { type: 'String', @@ -1073,9 +1051,7 @@ describe('Template', () => { /3 parameters/, /Expected CommaDelimitedList but received String/, ], - done, ); - done(); }); test('matching specific parameter name', () => { @@ -1093,7 +1069,7 @@ describe('Template', () => { expect(() => inspect.findParameters('p1', { Type: 'String' })).not.toThrow(); }); - test('not matching specific parameter name', (done) => { + test('not matching specific parameter name', () => { const stack = new Stack(); new CfnParameter(stack, 'p1', { type: 'String', @@ -1111,9 +1087,7 @@ describe('Template', () => { /1 parameter/, /Expected CommaDelimitedList but received Number/, ], - done, ); - done(); }); }); @@ -1211,7 +1185,7 @@ describe('Template', () => { expect(() => inspect.hasCondition('*', { 'Fn::Equals': ['Bar', 'Baz'] })).not.toThrow(); }); - test('not matching', (done) => { + test('not matching', () => { const stack = new Stack(); new CfnCondition(stack, 'Foo', { expression: Fn.conditionEquals('Bar', 'Baz'), @@ -1230,9 +1204,7 @@ describe('Template', () => { /2 conditions/, /Missing key/, ], - done, ); - done(); }); test('matching specific outputName', () => { @@ -1245,7 +1217,7 @@ describe('Template', () => { expect(() => inspect.hasCondition('Foo', { 'Fn::Equals': ['Bar', 'Baz'] })).not.toThrow(); }); - test('not matching specific outputName', (done) => { + test('not matching specific outputName', () => { const stack = new Stack(); new CfnCondition(stack, 'Foo', { expression: Fn.conditionEquals('Baz', 'Bar'), @@ -1260,9 +1232,7 @@ describe('Template', () => { /1 conditions/, /Expected Baz but received Bar/, ], - done, ); - done(); }); }); @@ -1385,34 +1355,23 @@ describe('Template', () => { }); }); -function expectToThrow(fn: () => void, msgs: (RegExp | string)[], done: jest.DoneCallback): void { +function expectToThrow(fn: () => void, msgs: (RegExp | string)[]): void { try { fn(); - done.fail('Function expected to throw, did not throw'); + throw new Error('Function expected to throw, did not throw'); } catch (error) { const message = (error as Error).message; - const splits = message.split('\n'); - let splitIdx = 0; - let msgsIdx = 0; - while (splitIdx < splits.length && msgsIdx < msgs.length) { - const msg = msgs[msgsIdx]; - const split = splits[splitIdx]; - let match = false; + const unmatching = msgs.filter(msg => { if (msg instanceof RegExp) { - match = msg.test(split); + return !msg.test(message); } else { - match = (msg === split); - } - - if (match) { - msgsIdx++; + return !message.includes(msg); } - splitIdx++; - } + }); - if (msgsIdx < msgs.length) { - done.fail([ - `Error thrown did not contain expected messages: ${msgs.slice(msgsIdx, msgs.length)}`, + if (unmatching.length > 0) { + throw new Error([ + `Error thrown did not contain expected messages: ${unmatching}`, `Received error: ${message}`, ].join('\n')); } diff --git a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts index 48c18736117c..02df03f67434 100644 --- a/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts +++ b/packages/@aws-cdk/aws-ecs-patterns/test/ec2/l3s-v2.test.ts @@ -1054,9 +1054,9 @@ describe('When Network Load Balancer', () => { }); // THEN - expect(() => Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { - EnableExecuteCommand: true, - })).toThrow('Expected true but received false at /Properties/EnableExecuteCommand (using objectLike matcher)'); + Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', { + EnableExecuteCommand: false, + }); }); test('test ECS NLB construct with all settings', () => { diff --git a/packages/@aws-cdk/integ-tests/lib/assertions/providers/lambda-handler/assertion.ts b/packages/@aws-cdk/integ-tests/lib/assertions/providers/lambda-handler/assertion.ts index 964b60f7a10d..3d5f3207b022 100644 --- a/packages/@aws-cdk/integ-tests/lib/assertions/providers/lambda-handler/assertion.ts +++ b/packages/@aws-cdk/integ-tests/lib/assertions/providers/lambda-handler/assertion.ts @@ -19,10 +19,7 @@ export class AssertionHandler extends CustomResourceHandler { } catch (e) { failed = e; } - expect(failed.message).toMatch(/String 'this is the actual results' did not match pattern 'abcd' (using stringLikeRegexp matcher)*/); + expect(failed.message).toMatch(/String 'this is the actual results' did not match pattern 'abcd'/); }); describe('stringLike', () => { test('pass', async () => { @@ -67,7 +67,7 @@ describe('AssertionHandler', () => { // THEN expect(JSON.parse(response.assertion)).toEqual({ status: 'fail', - message: expect.stringMatching(/String 'this is the actual results' did not match pattern 'abcd' (using stringLikeRegexp matcher)*/), + message: expect.stringMatching(/String 'this is the actual results' did not match pattern 'abcd'/), }); }); }); @@ -123,7 +123,7 @@ describe('AssertionHandler', () => { // THEN expect(JSON.parse(response.assertion)).toEqual({ status: 'fail', - message: expect.stringMatching(/Missing element at pattern index 0 (using arrayWith matcher)*/), + message: expect.stringMatching(/Could not match arrayWith pattern 0/), }); }); }); @@ -182,8 +182,7 @@ describe('AssertionHandler', () => { // THEN expect(JSON.parse(response.assertion)).toEqual({ status: 'fail', - message: 'Expected bar but received foo at /stringParam (using objectLike matcher)\n' + - '{\n \"stringParam\": \"foo\",\n \"numberParam\": 3,\n \"booleanParam\": true\n}', + message: expect.stringMatching(/Expected bar but received foo/), }); }); }); @@ -232,8 +231,7 @@ describe('AssertionHandler', () => { // THEN expect(JSON.parse(response.assertion)).toEqual({ status: 'fail', - message: 'Expected bar but received foo at /Payload(serializedJson)/stringParam (using serializedJson matcher)\n' + - '{\n \"Payload\": \"{\\\"stringParam\\\":\\\"foo\\\"}\"\n}', + message: expect.stringMatching(/Expected bar but received foo/), }); }); }); @@ -295,7 +293,7 @@ describe('AssertionHandler', () => { // THEN expect(JSON.parse(response.assertion)).toEqual({ status: 'fail', - message: 'Expected bar but received foo at /stringParam (using exact matcher)\n{\n \"stringParam\": \"foo\"\n}', + message: expect.stringMatching(/Expected bar but received foo/), }); }); }); From 46dbfa2f2bb8ee274148ca144717a9b2feb775cf Mon Sep 17 00:00:00 2001 From: kazuho cryer-shinozuka Date: Thu, 29 Dec 2022 01:02:59 +0900 Subject: [PATCH 5/8] docs(aws-lambda-nodejs): corrected description of default values for mainfields arguments (#23480) Corrected description of default values for mainfields arguments. closes #23211 ---- ### All Submissions: * [x] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Construct Runtime Dependencies: * [ ] This PR adds new construct runtime dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-construct-runtime-dependencies) ### New Features * [ ] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [ ] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)? *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts index 0d79db703287..bb3c0c855974 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts @@ -289,7 +289,7 @@ export interface BundlingOptions extends DockerRunOptions { * How to determine the entry point for modules. * Try ['module', 'main'] to default to ES module versions. * - * @default ['main', 'module'] + * @default [] */ readonly mainFields?: string[]; From b195465b622cee24376bcc8b0acfe19e80918f39 Mon Sep 17 00:00:00 2001 From: Liz Snyder <31932630+lizsnyder@users.noreply.github.com> Date: Wed, 28 Dec 2022 10:15:29 -0800 Subject: [PATCH 6/8] docs(elasticsearch): remove elasticsearch service references (#23476) ---- Elastic has requested that we remove all "Amazon Elasticsearch Service" references from our docs for legal reasons. ### All Submissions: * [X] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-elasticsearch/README.md | 10 +++++----- tools/@aws-cdk/pkglint/lib/rules.ts | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/@aws-cdk/aws-elasticsearch/README.md b/packages/@aws-cdk/aws-elasticsearch/README.md index 6d979176d8ff..b88e2cb1b880 100644 --- a/packages/@aws-cdk/aws-elasticsearch/README.md +++ b/packages/@aws-cdk/aws-elasticsearch/README.md @@ -1,4 +1,4 @@ -# Amazon Elasticsearch Service Construct Library +# Amazon OpenSearch Service (legacy Elasticsearch) Construct Library --- @@ -60,7 +60,7 @@ logging the domain logs and slow search logs. ## A note about SLR -Some cluster configurations (e.g VPC access) require the existence of the [`AWSServiceRoleForAmazonElasticsearchService`](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/slr-es.html) Service-Linked Role. +Some cluster configurations (e.g VPC access) require the existence of the [`AWSServiceRoleForAmazonElasticsearchService`](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/slr.html) service-linked role. When performing such operations via the AWS Console, this SLR is created automatically when needed. However, this is not the behavior when using CloudFormation. If an SLR is needed, but doesn't exist, you will encounter a failure message similar to: @@ -135,7 +135,7 @@ rest. Elasticsearch domains can be placed inside a VPC, providing a secure communication between Amazon ES and other services within the VPC without the need for an internet gateway, NAT device, or VPN connection. -> Visit [VPC Support for Amazon Elasticsearch Service Domains](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-vpc.html) for more details. +> See [Launching your Amazon OpenSearch Service domains within a VPC](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/vpc.html) for more details. ```ts const vpc = new ec2.Vpc(this, 'Vpc'); @@ -281,7 +281,7 @@ domain.addAccessPolicies( ## Audit logs -Audit logs can be enabled for a domain, but only when fine grained access control is enabled. +Audit logs can be enabled for a domain, but only when fine-grained access control is enabled. ```ts const domain = new es.Domain(this, 'Domain', { @@ -337,7 +337,7 @@ Additionally, an automatic CNAME-Record is created if a hosted zone is provided ## Advanced options -[Advanced options](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/es-createupdatedomains.html#es-createdomain-configure-advanced-options) can used to configure additional options. +[Advanced cluster settings](https://docs.aws.amazon.com/opensearch-service/latest/developerguide/createupdatedomains.html#createdomain-configure-advanced-options) can used to configure additional options. ```ts new es.Domain(this, 'Domain', { diff --git a/tools/@aws-cdk/pkglint/lib/rules.ts b/tools/@aws-cdk/pkglint/lib/rules.ts index 5a921a7d27db..9f257954fcab 100644 --- a/tools/@aws-cdk/pkglint/lib/rules.ts +++ b/tools/@aws-cdk/pkglint/lib/rules.ts @@ -276,7 +276,8 @@ export class ReadmeFile extends ValidationRule { if (!scopes) { return; } - if (pkg.packageName === '@aws-cdk/core') { + // elasticsearch is renamed to opensearch service, so its readme does not follow these rules + if (pkg.packageName === '@aws-cdk/core' || pkg.packageName === '@aws-cdk/aws-elasticsearch') { return; } const scope: string = typeof scopes === 'string' ? scopes : scopes[0]; From 7c752db4aa83b242098483fc006c1100d1be11a9 Mon Sep 17 00:00:00 2001 From: Chinedum Echeta <60179183+cecheta@users.noreply.github.com> Date: Wed, 28 Dec 2022 20:21:04 +0000 Subject: [PATCH 7/8] fix(lambda-nodejs): unable to use `nodeModules` with pnpm (#21911) Fixes #21910 By default, pnpm uses symlinks when installing dependencies, and modules only have access to dependencies in their `package.json`. This means when trying to bundle, dependencies of depedencies are not installed. This PR fixes this by using the ` --config.node_linker=hoisted` flag to create a flat `node_modules` structure. [Docs](https://pnpm.io/npmrc#node-linker). The second problem this PR fixes is when using pnpm workspaces. With workspaces, modules are installed within the workspace the command is run in. This means that when installing as part of bundling in a nested directory, no `node_modules` directory is produced at all. By creating a new `pnpm-workspace.yaml` file locally before installing, this essentially creates a new (nested) workspace, and `node_modules` is installed here. An empty file is enough for this to suffice. The PR also removes a `.modules.yaml` file from the `node_modules` after installing. This file contains a datetime of the last install, therefore it would cause the lambda code to change on each deployment if it was included in the bundle. I have tested this fix locally on both Mac and Windows. I have also included an integration test which failed before these changes, however I am not sure if it should be included due to the `node_modules` in the assets. ---- ### All Submissions: * [X] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Unconventional Dependencies: * [ ] This PR adds new unconventional dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-new-unconventional-dependencies) ### New Features * [X] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [X] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)? *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- .../@aws-cdk/aws-lambda-nodejs/lib/Dockerfile | 5 + .../aws-lambda-nodejs/lib/bundling.ts | 29 +- .../aws-lambda-nodejs/lib/function.ts | 6 +- .../aws-lambda-nodejs/lib/package-manager.ts | 4 +- .../@aws-cdk/aws-lambda-nodejs/lib/types.ts | 2 +- .../@aws-cdk/aws-lambda-nodejs/package.json | 1 + .../aws-lambda-nodejs/test/bundling.test.ts | 2 +- .../aws-lambda-nodejs/test/docker.test.ts | 1 + .../integ-handlers/pnpm/dependencies-pnpm.ts | 6 + .../test/integ-handlers/pnpm/pnpm-lock.yaml | 70 ++++ ...efaultTestDeployAssert397EDF83.assets.json | 19 ++ ...aultTestDeployAssert397EDF83.template.json | 36 ++ .../TestStack.assets.json | 45 +++ .../TestStack.template.json | 200 +++++++++++ .../cdk.out | 1 + .../integ.json | 13 + .../manifest.json | 141 ++++++++ .../tree.json | 314 ++++++++++++++++++ .../test/integ.dependencies-pnpm.ts | 35 ++ .../test/package-manager.test.ts | 4 +- 20 files changed, 921 insertions(+), 13 deletions(-) create mode 100644 packages/@aws-cdk/aws-lambda-nodejs/test/integ-handlers/pnpm/dependencies-pnpm.ts create mode 100644 packages/@aws-cdk/aws-lambda-nodejs/test/integ-handlers/pnpm/pnpm-lock.yaml create mode 100644 packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/PnpmTestDefaultTestDeployAssert397EDF83.assets.json create mode 100644 packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/PnpmTestDefaultTestDeployAssert397EDF83.template.json create mode 100644 packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/TestStack.assets.json create mode 100644 packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/TestStack.template.json create mode 100644 packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/cdk.out create mode 100644 packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/integ.json create mode 100644 packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/manifest.json create mode 100644 packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/tree.json create mode 100644 packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.ts diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/Dockerfile b/packages/@aws-cdk/aws-lambda-nodejs/lib/Dockerfile index 54969bb5fde2..f84c7fbfe579 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/Dockerfile +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/Dockerfile @@ -27,6 +27,11 @@ RUN mkdir /tmp/yarn-cache && \ chmod -R 777 /tmp/yarn-cache && \ yarn config set cache-folder /tmp/yarn-cache +# Ensure all users can write to pnpm cache +RUN mkdir /tmp/pnpm-cache && \ + chmod -R 777 /tmp/pnpm-cache && \ + pnpm config --global set store-dir /tmp/pnpm-cache + # Disable npm update notifications RUN npm config --global set update-notifier false diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts index 8809166a6e57..fd0c17a3be46 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts @@ -3,7 +3,7 @@ import * as path from 'path'; import { Architecture, AssetCode, Code, Runtime } from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; import { PackageInstallation } from './package-installation'; -import { PackageManager } from './package-manager'; +import { LockFile, PackageManager } from './package-manager'; import { BundlingOptions, OutputFormat, SourceMapMode } from './types'; import { exec, extractDependencies, findUp, getTsconfigCompilerOptions } from './util'; @@ -229,12 +229,16 @@ export class Bundling implements cdk.BundlingOptions { const lockFilePath = pathJoin(options.inputDir, this.relativeDepsLockFilePath ?? this.packageManager.lockFile); + const isPnpm = this.packageManager.lockFile === LockFile.PNPM; + // Create dummy package.json, copy lock file if any and then install depsCommand = chain([ + isPnpm ? osCommand.write(pathJoin(options.outputDir, 'pnpm-workspace.yaml'), ''): '', // Ensure node_modules directory is installed locally by creating local 'pnpm-workspace.yaml' file osCommand.writeJson(pathJoin(options.outputDir, 'package.json'), { dependencies }), osCommand.copy(lockFilePath, pathJoin(options.outputDir, this.packageManager.lockFile)), osCommand.changeDirectory(options.outputDir), this.packageManager.installCommand.join(' '), + isPnpm ? osCommand.remove(pathJoin(options.outputDir, 'node_modules', '.modules.yaml')) : '', // Remove '.modules.yaml' file which changes on each deployment ]); } @@ -310,13 +314,20 @@ interface BundlingCommandOptions { class OsCommand { constructor(private readonly osPlatform: NodeJS.Platform) {} - public writeJson(filePath: string, data: any): string { - const stringifiedData = JSON.stringify(data); + public write(filePath: string, data: string): string { if (this.osPlatform === 'win32') { - return `echo ^${stringifiedData}^ > "${filePath}"`; + if (!data) { // if `data` is empty, echo a blank line, otherwise the file will contain a `^` character + return `echo. > "${filePath}"`; + } + return `echo ^${data}^ > "${filePath}"`; } - return `echo '${stringifiedData}' > "${filePath}"`; + return `echo '${data}' > "${filePath}"`; + } + + public writeJson(filePath: string, data: any): string { + const stringifiedData = JSON.stringify(data); + return this.write(filePath, stringifiedData); } public copy(src: string, dest: string): string { @@ -330,6 +341,14 @@ class OsCommand { public changeDirectory(dir: string): string { return `cd "${dir}"`; } + + public remove(filePath: string): string { + if (this.osPlatform === 'win32') { + return `del "${filePath}"`; + } + + return `rm "${filePath}"`; + } } /** diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts index ea3b1f9b6f00..202be464b16d 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/function.ts @@ -51,16 +51,16 @@ export interface NodejsFunctionProps extends lambda.FunctionOptions { readonly awsSdkConnectionReuse?: boolean; /** - * The path to the dependencies lock file (`yarn.lock` or `package-lock.json`). + * The path to the dependencies lock file (`yarn.lock`, `pnpm-lock.yaml` or `package-lock.json`). * * This will be used as the source for the volume mounted in the Docker * container. * * Modules specified in `nodeModules` will be installed using the right - * installer (`npm` or `yarn`) along with this lock file. + * installer (`yarn`, `pnpm` or `npm`) along with this lock file. * * @default - the path is found by walking up parent directories searching for - * a `yarn.lock` or `package-lock.json` file + * a `yarn.lock`, `pnpm-lock.yaml` or `package-lock.json` file */ readonly depsLockFilePath?: string; diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/package-manager.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/package-manager.ts index 05ef10999346..5d68f2034784 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/package-manager.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/package-manager.ts @@ -39,7 +39,9 @@ export class PackageManager { case LockFile.PNPM: return new PackageManager({ lockFile: LockFile.PNPM, - installCommand: logLevel && logLevel !== LogLevel.INFO ? ['pnpm', 'install', '--reporter', 'silent'] : ['pnpm', 'install'], + installCommand: logLevel && logLevel !== LogLevel.INFO ? ['pnpm', 'install', '--reporter', 'silent', '--config.node-linker=hoisted', '--config.package-import-method=clone-or-copy'] : ['pnpm', 'install', '--config.node-linker=hoisted', '--config.package-import-method=clone-or-copy'], + // --config.node-linker=hoisted to create flat node_modules without symlinks + // --config.package-import-method=clone-or-copy to avoid hardlinking packages from the store runCommand: ['pnpm', 'exec'], argsSeparator: '--', }); diff --git a/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts b/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts index bb3c0c855974..0ca72b4149b1 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts @@ -247,7 +247,7 @@ export interface BundlingOptions extends DockerRunOptions { * A custom bundling Docker image. * * This image should have esbuild installed globally. If you plan to use `nodeModules` - * it should also have `npm` or `yarn` depending on the lock file you're using. + * it should also have `npm`, `yarn` or `pnpm` depending on the lock file you're using. * * See https://github.com/aws/aws-cdk/blob/main/packages/%40aws-cdk/aws-lambda-nodejs/lib/Dockerfile * for the default image provided by @aws-cdk/aws-lambda-nodejs. diff --git a/packages/@aws-cdk/aws-lambda-nodejs/package.json b/packages/@aws-cdk/aws-lambda-nodejs/package.json index 5f483e81d1cc..cf3cf09fc65f 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/package.json +++ b/packages/@aws-cdk/aws-lambda-nodejs/package.json @@ -78,6 +78,7 @@ "@aws-cdk/integ-runner": "0.0.0", "@aws-cdk/integ-tests": "0.0.0", "@aws-cdk/pkglint": "0.0.0", + "@aws-cdk/triggers": "0.0.0", "@types/jest": "^27.5.2", "delay": "5.0.0", "esbuild": "^0.16.6" diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts index 83029ec60159..9679530a0118 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/bundling.test.ts @@ -408,7 +408,7 @@ test('Detects pnpm-lock.yaml', () => { assetHashType: AssetHashType.OUTPUT, bundling: expect.objectContaining({ command: expect.arrayContaining([ - expect.stringMatching(/pnpm-lock\.yaml.+pnpm install/), + expect.stringMatching(/echo '' > "\/asset-output\/pnpm-workspace.yaml\".+pnpm-lock\.yaml.+pnpm install --config.node-linker=hoisted --config.package-import-method=clone-or-copy && rm "\/asset-output\/node_modules\/.modules.yaml"/), ]), }), }); diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/docker.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/docker.test.ts index d1b85dfcca2b..f347fac6a756 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/docker.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/docker.test.ts @@ -58,6 +58,7 @@ test('cache folders have the right permissions', () => { 'bash', '-c', [ 'stat -c \'%a\' /tmp/npm-cache', 'stat -c \'%a\' /tmp/yarn-cache', + 'stat -c \'%a\' /tmp/pnpm-cache', ].join(' && '), ]); expect(proc.stdout.toString()).toMatch('777\n777'); diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ-handlers/pnpm/dependencies-pnpm.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/integ-handlers/pnpm/dependencies-pnpm.ts new file mode 100644 index 000000000000..81022e2b9e00 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ-handlers/pnpm/dependencies-pnpm.ts @@ -0,0 +1,6 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import axios from 'axios'; + +export async function handler() { + await axios.get('https://www.google.com'); +} diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ-handlers/pnpm/pnpm-lock.yaml b/packages/@aws-cdk/aws-lambda-nodejs/test/integ-handlers/pnpm/pnpm-lock.yaml new file mode 100644 index 000000000000..899ba52e99ec --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ-handlers/pnpm/pnpm-lock.yaml @@ -0,0 +1,70 @@ +lockfileVersion: 5.4 + +specifiers: + axios: ^1.2.1 + +dependencies: + axios: 1.2.1 + +packages: + + /asynckit/0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: false + + /axios/1.2.1: + resolution: {integrity: sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==} + dependencies: + follow-redirects: 1.15.2 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: false + + /combined-stream/1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: false + + /delayed-stream/1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: false + + /follow-redirects/1.15.2: + resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dev: false + + /form-data/4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + + /mime-db/1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types/2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + + /proxy-from-env/1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: false diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/PnpmTestDefaultTestDeployAssert397EDF83.assets.json b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/PnpmTestDefaultTestDeployAssert397EDF83.assets.json new file mode 100644 index 000000000000..f2f1759f8e85 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/PnpmTestDefaultTestDeployAssert397EDF83.assets.json @@ -0,0 +1,19 @@ +{ + "version": "22.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "PnpmTestDefaultTestDeployAssert397EDF83.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/PnpmTestDefaultTestDeployAssert397EDF83.template.json b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/PnpmTestDefaultTestDeployAssert397EDF83.template.json new file mode 100644 index 000000000000..ad9d0fb73d1d --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/PnpmTestDefaultTestDeployAssert397EDF83.template.json @@ -0,0 +1,36 @@ +{ + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/TestStack.assets.json b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/TestStack.assets.json new file mode 100644 index 000000000000..30c2cc5969fc --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/TestStack.assets.json @@ -0,0 +1,45 @@ +{ + "version": "22.0.0", + "files": { + "58d2406e0a74fd42ac31e584a098bb581709c3de7bff389451c2a08db50c4383": { + "source": { + "path": "asset.58d2406e0a74fd42ac31e584a098bb581709c3de7bff389451c2a08db50c4383", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "58d2406e0a74fd42ac31e584a098bb581709c3de7bff389451c2a08db50c4383.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "44fdff138ed916c94d14f276217febea5c4a2e1746518f7f620c37b22a6675b8": { + "source": { + "path": "asset.44fdff138ed916c94d14f276217febea5c4a2e1746518f7f620c37b22a6675b8", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "44fdff138ed916c94d14f276217febea5c4a2e1746518f7f620c37b22a6675b8.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "c51cd09452e746f11796192b2e9025f8c82de145d16aeb2e2c66c2197ecbae26": { + "source": { + "path": "TestStack.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "c51cd09452e746f11796192b2e9025f8c82de145d16aeb2e2c66c2197ecbae26.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/TestStack.template.json b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/TestStack.template.json new file mode 100644 index 000000000000..8b95fc6ae04d --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/TestStack.template.json @@ -0,0 +1,200 @@ +{ + "Resources": { + "FunctionServiceRole675BB04A": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "Function76856677": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "58d2406e0a74fd42ac31e584a098bb581709c3de7bff389451c2a08db50c4383.zip" + }, + "Role": { + "Fn::GetAtt": [ + "FunctionServiceRole675BB04A", + "Arn" + ] + }, + "Environment": { + "Variables": { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1" + } + }, + "Handler": "index.handler", + "Runtime": "nodejs18.x" + }, + "DependsOn": [ + "FunctionServiceRole675BB04A" + ] + }, + "FunctionCurrentVersion4E2B22618dd26ccb3af7b577163fa65856572807": { + "Type": "AWS::Lambda::Version", + "Properties": { + "FunctionName": { + "Ref": "Function76856677" + } + } + }, + "Trigger": { + "Type": "Custom::Trigger", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "AWSCDKTriggerCustomResourceProviderCustomResourceProviderHandler97BECD91", + "Arn" + ] + }, + "HandlerArn": { + "Ref": "FunctionCurrentVersion4E2B22618dd26ccb3af7b577163fa65856572807" + }, + "InvocationType": "RequestResponse", + "Timeout": 120000 + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "AWSCDKTriggerCustomResourceProviderCustomResourceProviderRoleE18FAF0A": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ] + }, + "ManagedPolicyArns": [ + { + "Fn::Sub": "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + } + ], + "Policies": [ + { + "PolicyName": "Inline", + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "lambda:InvokeFunction" + ], + "Resource": [ + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "Function76856677", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + } + ] + } + } + ] + } + }, + "AWSCDKTriggerCustomResourceProviderCustomResourceProviderHandler97BECD91": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "44fdff138ed916c94d14f276217febea5c4a2e1746518f7f620c37b22a6675b8.zip" + }, + "Timeout": 900, + "MemorySize": 128, + "Handler": "__entrypoint__.handler", + "Role": { + "Fn::GetAtt": [ + "AWSCDKTriggerCustomResourceProviderCustomResourceProviderRoleE18FAF0A", + "Arn" + ] + }, + "Runtime": "nodejs14.x" + }, + "DependsOn": [ + "AWSCDKTriggerCustomResourceProviderCustomResourceProviderRoleE18FAF0A" + ] + } + }, + "Parameters": { + "BootstrapVersion": { + "Type": "AWS::SSM::Parameter::Value", + "Default": "/cdk-bootstrap/hnb659fds/version", + "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" + } + }, + "Rules": { + "CheckBootstrapVersion": { + "Assertions": [ + { + "Assert": { + "Fn::Not": [ + { + "Fn::Contains": [ + [ + "1", + "2", + "3", + "4", + "5" + ], + { + "Ref": "BootstrapVersion" + } + ] + } + ] + }, + "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." + } + ] + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/cdk.out b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/cdk.out new file mode 100644 index 000000000000..145739f53958 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"22.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/integ.json b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/integ.json new file mode 100644 index 000000000000..368ae1d1b256 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/integ.json @@ -0,0 +1,13 @@ +{ + "version": "22.0.0", + "testCases": { + "PnpmTest/DefaultTest": { + "stacks": [ + "TestStack" + ], + "stackUpdateWorkflow": false, + "assertionStack": "PnpmTest/DefaultTest/DeployAssert", + "assertionStackName": "PnpmTestDefaultTestDeployAssert397EDF83" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/manifest.json b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/manifest.json new file mode 100644 index 000000000000..d6305be21c36 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/manifest.json @@ -0,0 +1,141 @@ +{ + "version": "22.0.0", + "artifacts": { + "TestStack.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "TestStack.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "TestStack": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "TestStack.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/c51cd09452e746f11796192b2e9025f8c82de145d16aeb2e2c66c2197ecbae26.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "TestStack.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "TestStack.assets" + ], + "metadata": { + "/TestStack/Function/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "FunctionServiceRole675BB04A" + } + ], + "/TestStack/Function/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Function76856677" + } + ], + "/TestStack/Function/CurrentVersion/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "FunctionCurrentVersion4E2B22618dd26ccb3af7b577163fa65856572807" + } + ], + "/TestStack/Trigger/Default/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "Trigger" + } + ], + "/TestStack/AWSCDK.TriggerCustomResourceProviderCustomResourceProvider/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "AWSCDKTriggerCustomResourceProviderCustomResourceProviderRoleE18FAF0A" + } + ], + "/TestStack/AWSCDK.TriggerCustomResourceProviderCustomResourceProvider/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "AWSCDKTriggerCustomResourceProviderCustomResourceProviderHandler97BECD91" + } + ], + "/TestStack/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/TestStack/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "TestStack" + }, + "PnpmTestDefaultTestDeployAssert397EDF83.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "PnpmTestDefaultTestDeployAssert397EDF83.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "PnpmTestDefaultTestDeployAssert397EDF83": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "PnpmTestDefaultTestDeployAssert397EDF83.template.json", + "validateOnSynth": false, + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", + "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "PnpmTestDefaultTestDeployAssert397EDF83.assets" + ], + "lookupRole": { + "arn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-lookup-role-${AWS::AccountId}-${AWS::Region}", + "requiresBootstrapStackVersion": 8, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "dependencies": [ + "PnpmTestDefaultTestDeployAssert397EDF83.assets" + ], + "metadata": { + "/PnpmTest/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/PnpmTest/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "PnpmTest/DefaultTest/DeployAssert" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/tree.json b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/tree.json new file mode 100644 index 000000000000..1fa148c5c734 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.js.snapshot/tree.json @@ -0,0 +1,314 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "TestStack": { + "id": "TestStack", + "path": "TestStack", + "children": { + "Function": { + "id": "Function", + "path": "TestStack/Function", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "TestStack/Function/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "TestStack/Function/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "TestStack/Function/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "assumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "managedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Code": { + "id": "Code", + "path": "TestStack/Function/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "TestStack/Function/Code/Stage", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "TestStack/Function/Code/AssetBucket", + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketBase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3-assets.Asset", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "TestStack/Function/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "s3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "s3Key": "58d2406e0a74fd42ac31e584a098bb581709c3de7bff389451c2a08db50c4383.zip" + }, + "role": { + "Fn::GetAtt": [ + "FunctionServiceRole675BB04A", + "Arn" + ] + }, + "environment": { + "variables": { + "AWS_NODEJS_CONNECTION_REUSE_ENABLED": "1" + } + }, + "handler": "index.handler", + "runtime": "nodejs18.x" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + }, + "CurrentVersion": { + "id": "CurrentVersion", + "path": "TestStack/Function/CurrentVersion", + "children": { + "Resource": { + "id": "Resource", + "path": "TestStack/Function/CurrentVersion/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Version", + "aws:cdk:cloudformation:props": { + "functionName": { + "Ref": "Function76856677" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnVersion", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Version", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda-nodejs.NodejsFunction", + "version": "0.0.0" + } + }, + "Trigger": { + "id": "Trigger", + "path": "TestStack/Trigger", + "children": { + "Default": { + "id": "Default", + "path": "TestStack/Trigger/Default", + "children": { + "Default": { + "id": "Default", + "path": "TestStack/Trigger/Default/Default", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/triggers.Trigger", + "version": "0.0.0" + } + }, + "AWSCDK.TriggerCustomResourceProviderCustomResourceProvider": { + "id": "AWSCDK.TriggerCustomResourceProviderCustomResourceProvider", + "path": "TestStack/AWSCDK.TriggerCustomResourceProviderCustomResourceProvider", + "children": { + "Staging": { + "id": "Staging", + "path": "TestStack/AWSCDK.TriggerCustomResourceProviderCustomResourceProvider/Staging", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "TestStack/AWSCDK.TriggerCustomResourceProviderCustomResourceProvider/Role", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "TestStack/AWSCDK.TriggerCustomResourceProviderCustomResourceProvider/Handler", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResourceProvider", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "TestStack/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "TestStack/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "PnpmTest": { + "id": "PnpmTest", + "path": "PnpmTest", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "PnpmTest/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "PnpmTest/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.189" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "PnpmTest/DefaultTest/DeployAssert", + "children": { + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "PnpmTest/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "PnpmTest/DefaultTest/DeployAssert/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.189" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.ts new file mode 100644 index 000000000000..6c4352ba8f57 --- /dev/null +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/integ.dependencies-pnpm.ts @@ -0,0 +1,35 @@ +import * as path from 'path'; +import { Runtime } from '@aws-cdk/aws-lambda'; +import * as cdk from '@aws-cdk/core'; +import * as integ from '@aws-cdk/integ-tests'; +import * as triggers from '@aws-cdk/triggers'; +import * as lambda from '../lib'; + +const app = new cdk.App(); + +const stack = new cdk.Stack(app, 'TestStack'); + +const handler = new lambda.NodejsFunction(stack, 'Function', { + entry: path.join(__dirname, 'integ-handlers/pnpm/dependencies-pnpm.ts'), + runtime: Runtime.NODEJS_18_X, + bundling: { + minify: true, + // Will be installed, not bundled + // (axios is a package with sub-dependencies, + // will be used to ensure pnpm bundling works as expected) + nodeModules: ['axios'], + forceDockerBundling: true, + }, + depsLockFilePath: path.join(__dirname, 'integ-handlers/pnpm/pnpm-lock.yaml'), +}); + +new triggers.Trigger(stack, 'Trigger', { + handler, +}); + +new integ.IntegTest(app, 'PnpmTest', { + testCases: [stack], + stackUpdateWorkflow: false, // this will tell the runner to not check in assets. +}); + +app.synth(); diff --git a/packages/@aws-cdk/aws-lambda-nodejs/test/package-manager.test.ts b/packages/@aws-cdk/aws-lambda-nodejs/test/package-manager.test.ts index 8bb0682c0d56..6be593f785ef 100644 --- a/packages/@aws-cdk/aws-lambda-nodejs/test/package-manager.test.ts +++ b/packages/@aws-cdk/aws-lambda-nodejs/test/package-manager.test.ts @@ -37,7 +37,7 @@ test('from a pnpm-lock.yaml', () => { const packageManager = PackageManager.fromLockFile('/path/to/pnpm-lock.yaml'); expect(packageManager.lockFile).toEqual(LockFile.PNPM); expect(packageManager.argsSeparator).toEqual('--'); - expect(packageManager.installCommand).toEqual(['pnpm', 'install']); + expect(packageManager.installCommand).toEqual(['pnpm', 'install', '--config.node-linker=hoisted', '--config.package-import-method=clone-or-copy']); expect(packageManager.runCommand).toEqual(['pnpm', 'exec']); expect(packageManager.runBinCommand('my-bin')).toBe('pnpm exec -- my-bin'); @@ -45,7 +45,7 @@ test('from a pnpm-lock.yaml', () => { test('from a pnpm-lock.yaml with LogLevel.ERROR', () => { const packageManager = PackageManager.fromLockFile('/path/to/pnpm-lock.yaml', LogLevel.ERROR); - expect(packageManager.installCommand).toEqual(['pnpm', 'install', '--reporter', 'silent']); + expect(packageManager.installCommand).toEqual(['pnpm', 'install', '--reporter', 'silent', '--config.node-linker=hoisted', '--config.package-import-method=clone-or-copy']); }); test('defaults to NPM', () => { From 6975a7ea06a5680bebd38ad5c26ab5bd566d33b1 Mon Sep 17 00:00:00 2001 From: Kyle Laker Date: Wed, 28 Dec 2022 15:59:34 -0500 Subject: [PATCH 8/8] feat(s3): use Bucket Policy for Server Access Logging grant (under feature flag) (#23386) Using ACLs to grant access to buckets is no longer recommended. In fact, it doesn't work if Object Ownership is set to be enforced for the bucket. According to the service documentation for [enabling server access logging][1], it is now preferred to use a bucket policy to grant permission to deliver logs to a bucket. Changing the default would result in changes to deployed resources, so the new behavior is added behind a feature flag. An alternative here may be to use the Bucket Policy either when the feature flag is enabled or when ownership is set to `BUCKET_OWNER_ENFORCED` since the latter doesn't work with the current implementation anyway. Closes: #22183 [1]: https://docs.aws.amazon.com/AmazonS3/latest/userguide/enable-server-access-logging.html ---- ### All Submissions: * [X] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) ### Adding new Construct Runtime Dependencies: * [ ] This PR adds new construct runtime dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-construct-runtime-dependencies) ### New Features * [X] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)? * [X] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)? *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-s3/README.md | 31 ++++- packages/@aws-cdk/aws-s3/lib/bucket.ts | 36 ++++-- packages/@aws-cdk/aws-s3/test/bucket.test.ts | 65 +++++++++++ .../aws-cdk-s3-access-logs.assets.json | 6 +- .../aws-cdk-s3-access-logs.template.json | 52 ++++++++- .../cdk.out | 2 +- .../integ.json | 2 +- .../manifest.json | 22 ++-- .../tree.json | 109 +++++++++++++++--- packages/@aws-cdk/cx-api/FEATURE_FLAGS.md | 24 +++- packages/@aws-cdk/cx-api/README.md | 19 +++ packages/@aws-cdk/cx-api/lib/features.ts | 18 +++ 12 files changed, 345 insertions(+), 41 deletions(-) diff --git a/packages/@aws-cdk/aws-s3/README.md b/packages/@aws-cdk/aws-s3/README.md index e34dd8067f0e..9a41dc49369d 100644 --- a/packages/@aws-cdk/aws-s3/README.md +++ b/packages/@aws-cdk/aws-s3/README.md @@ -349,7 +349,25 @@ const bucket = new s3.Bucket(this, 'MyBucket', { }); ``` -[S3 Server access logging]: https://docs.aws.amazon.com/AmazonS3/latest/dev/ServerLogs.html +### Allowing access log delivery using a Bucket Policy (recommended) + +When possible, it is recommended to use a bucket policy to grant access instead of +using ACLs. When the `@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy` feature flag +is enabled, this is done by default for server access logs. If S3 Server Access Logs +are the only logs delivered to your bucket (or if all other services logging to the +bucket support using bucket policy instead of ACLs), you can set object ownership +to [bucket owner enforced](#bucket-owner-enforced-recommended), as is recommended. + +```ts +const accessLogsBucket = new s3.Bucket(this, 'AccessLogsBucket', { + objectOwnership: s3.ObjectOwnership.BUCKET_OWNER_ENFORCED, +}); + +const bucket = new s3.Bucket(this, 'MyBucket', { + serverAccessLogsBucket: accessLogsBucket, + serverAccessLogsPrefix: 'logs', +}); +``` ## S3 Inventory @@ -485,7 +503,9 @@ new s3.Bucket(this, 'MyBucket', { ### Bucket owner enforced (recommended) -ACLs are disabled, and the bucket owner automatically owns and has full control over every object in the bucket. ACLs no longer affect permissions to data in the S3 bucket. The bucket uses policies to define access control. +ACLs are disabled, and the bucket owner automatically owns and has full control +over every object in the bucket. ACLs no longer affect permissions to data in the +S3 bucket. The bucket uses policies to define access control. ```ts new s3.Bucket(this, 'MyBucket', { @@ -493,6 +513,13 @@ new s3.Bucket(this, 'MyBucket', { }); ``` +Some services may not not support log delivery to buckets that have object ownership +set to bucket owner enforced, such as +[S3 buckets using ACLs](#allowing-access-log-delivery-using-a-bucket-policy-recommended) +or [CloudFront Distributions][CloudFront S3 Bucket]. + +[CloudFront S3 Bucket]: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/AccessLogs.html#AccessLogsBucketAndFileOwnership + ## Bucket deletion When a bucket is removed from a stack (or the stack is deleted), the S3 diff --git a/packages/@aws-cdk/aws-s3/lib/bucket.ts b/packages/@aws-cdk/aws-s3/lib/bucket.ts index 0a7b7c029e63..36f99fcb2429 100644 --- a/packages/@aws-cdk/aws-s3/lib/bucket.ts +++ b/packages/@aws-cdk/aws-s3/lib/bucket.ts @@ -1832,7 +1832,9 @@ export class Bucket extends BucketBase { } if (props.serverAccessLogsBucket instanceof Bucket) { - props.serverAccessLogsBucket.allowLogDelivery(); + props.serverAccessLogsBucket.allowLogDelivery(this, props.serverAccessLogsPrefix); + } else if (props.serverAccessLogsPrefix) { + this.allowLogDelivery(this, props.serverAccessLogsPrefix); } for (const inventory of props.inventories ?? []) { @@ -2189,17 +2191,35 @@ export class Bucket extends BucketBase { } /** - * Allows the LogDelivery group to write, fails if ACL was set differently. + * Allows Log Delivery to the S3 bucket, using a Bucket Policy if the relevant feature + * flag is enabled, otherwise the canned ACL is used. + * + * If log delivery is to be allowed using the ACL and an ACL has already been set, this fails. * * @see - * https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl - */ - private allowLogDelivery() { - if (this.accessControl && this.accessControl !== BucketAccessControl.LOG_DELIVERY_WRITE) { + * https://docs.aws.amazon.com/AmazonS3/latest/userguide/enable-server-access-logging.html + */ + private allowLogDelivery(from: IBucket, prefix?: string) { + if (FeatureFlags.of(this).isEnabled(cxapi.S3_SERVER_ACCESS_LOGS_USE_BUCKET_POLICY)) { + this.addToResourcePolicy(new iam.PolicyStatement({ + effect: iam.Effect.ALLOW, + principals: [new iam.ServicePrincipal('logging.s3.amazonaws.com')], + actions: ['s3:PutObject'], + resources: [this.arnForObjects(prefix ? `${prefix}*`: '*')], + conditions: { + ArnLike: { + 'aws:SourceArn': from.bucketArn, + }, + StringEquals: { + 'aws:SourceAccount': from.env.account, + }, + }, + })); + } else if (this.accessControl && this.accessControl !== BucketAccessControl.LOG_DELIVERY_WRITE) { throw new Error("Cannot enable log delivery to this bucket because the bucket's ACL has been set and can't be changed"); + } else { + this.accessControl = BucketAccessControl.LOG_DELIVERY_WRITE; } - - this.accessControl = BucketAccessControl.LOG_DELIVERY_WRITE; } private parseInventoryConfiguration(): CfnBucket.InventoryConfigurationProperty[] | undefined { diff --git a/packages/@aws-cdk/aws-s3/test/bucket.test.ts b/packages/@aws-cdk/aws-s3/test/bucket.test.ts index e412ceb2bc6a..1ff083281004 100644 --- a/packages/@aws-cdk/aws-s3/test/bucket.test.ts +++ b/packages/@aws-cdk/aws-s3/test/bucket.test.ts @@ -2205,6 +2205,71 @@ describe('bucket', () => { ).toThrow(/Cannot enable log delivery to this bucket because the bucket's ACL has been set and can't be changed/); }); + test('Bucket Allow Log delivery should use the recommended policy when flag enabled', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext('@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy', true); + + // WHEN + const bucket = new s3.Bucket(stack, 'TestBucket', { serverAccessLogsPrefix: 'test' }); + + // THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::S3::Bucket', { + AccessControl: Match.absent(), + }); + template.hasResourceProperties('AWS::S3::BucketPolicy', { + Bucket: stack.resolve(bucket.bucketName), + PolicyDocument: Match.objectLike({ + Statement: Match.arrayWith([Match.objectLike({ + Effect: 'Allow', + Principal: { Service: 'logging.s3.amazonaws.com' }, + Action: 's3:PutObject', + Resource: stack.resolve(`${bucket.bucketArn}/test*`), + Condition: { + ArnLike: { + 'aws:SourceArn': stack.resolve(bucket.bucketArn), + }, + StringEquals: { + 'aws:SourceAccount': { 'Ref': 'AWS::AccountId' }, + }, + }, + })]), + }), + }); + }); + + test('Log Delivery bucket policy should properly set source bucket ARN/Account', () => { + // GIVEN + const stack = new cdk.Stack(); + stack.node.setContext('@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy', true); + + // WHEN + const targetBucket = new s3.Bucket(stack, 'TargetBucket'); + const sourceBucket = new s3.Bucket(stack, 'SourceBucket', { serverAccessLogsBucket: targetBucket }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::S3::BucketPolicy', { + Bucket: stack.resolve(targetBucket.bucketName), + PolicyDocument: Match.objectLike({ + Statement: Match.arrayWith([Match.objectLike({ + Effect: 'Allow', + Principal: { Service: 'logging.s3.amazonaws.com' }, + Action: 's3:PutObject', + Resource: stack.resolve(`${targetBucket.bucketArn}/*`), + Condition: { + ArnLike: { + 'aws:SourceArn': stack.resolve(sourceBucket.bucketArn), + }, + StringEquals: { + 'aws:SourceAccount': stack.resolve(sourceBucket.env.account), + }, + }, + })]), + }), + }); + }); + test('Defaults for an inventory bucket', () => { // Given const stack = new cdk.Stack(); diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/aws-cdk-s3-access-logs.assets.json b/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/aws-cdk-s3-access-logs.assets.json index aeb33ba4e0d1..1b4fa26e8804 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/aws-cdk-s3-access-logs.assets.json +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/aws-cdk-s3-access-logs.assets.json @@ -1,7 +1,7 @@ { - "version": "20.0.0", + "version": "22.0.0", "files": { - "8091e7796cbf83b5d8109a10ea23dfbe9ac04ad84434da5dd183b89eb89e351b": { + "f58a2b25314952a1a5a6b42c6b9092caf2710430af09ba4f5d807e60f2fd3542": { "source": { "path": "aws-cdk-s3-access-logs.template.json", "packaging": "file" @@ -9,7 +9,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "8091e7796cbf83b5d8109a10ea23dfbe9ac04ad84434da5dd183b89eb89e351b.json", + "objectKey": "f58a2b25314952a1a5a6b42c6b9092caf2710430af09ba4f5d807e60f2fd3542.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/aws-cdk-s3-access-logs.template.json b/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/aws-cdk-s3-access-logs.template.json index f9f202ceb725..532e9c171c42 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/aws-cdk-s3-access-logs.template.json +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/aws-cdk-s3-access-logs.template.json @@ -2,12 +2,58 @@ "Resources": { "MyAccessLogsBucketF7FE6635": { "Type": "AWS::S3::Bucket", - "Properties": { - "AccessControl": "LogDeliveryWrite" - }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, + "MyAccessLogsBucketPolicyEA9AB063": { + "Type": "AWS::S3::BucketPolicy", + "Properties": { + "Bucket": { + "Ref": "MyAccessLogsBucketF7FE6635" + }, + "PolicyDocument": { + "Statement": [ + { + "Action": "s3:PutObject", + "Condition": { + "ArnLike": { + "aws:SourceArn": { + "Fn::GetAtt": [ + "MyBucketF68F3FF0", + "Arn" + ] + } + }, + "StringEquals": { + "aws:SourceAccount": { + "Ref": "AWS::AccountId" + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "logging.s3.amazonaws.com" + }, + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyAccessLogsBucketF7FE6635", + "Arn" + ] + }, + "/example*" + ] + ] + } + } + ], + "Version": "2012-10-17" + } + } + }, "MyBucketF68F3FF0": { "Type": "AWS::S3::Bucket", "Properties": { diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/cdk.out b/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/cdk.out index 588d7b269d34..145739f53958 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/cdk.out +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"20.0.0"} \ No newline at end of file +{"version":"22.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/integ.json b/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/integ.json index b0449f12ced2..eba84b97fa6d 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/integ.json +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "20.0.0", + "version": "22.0.0", "testCases": { "integ.bucket.server-access-logs": { "stacks": [ diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/manifest.json b/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/manifest.json index ff5492fb6b7e..2a1a113d65e6 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/manifest.json +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/manifest.json @@ -1,12 +1,6 @@ { - "version": "20.0.0", + "version": "22.0.0", "artifacts": { - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - }, "aws-cdk-s3-access-logs.assets": { "type": "cdk:asset-manifest", "properties": { @@ -23,7 +17,7 @@ "validateOnSynth": false, "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}", "cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}", - "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/8091e7796cbf83b5d8109a10ea23dfbe9ac04ad84434da5dd183b89eb89e351b.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/f58a2b25314952a1a5a6b42c6b9092caf2710430af09ba4f5d807e60f2fd3542.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -45,6 +39,12 @@ "data": "MyAccessLogsBucketF7FE6635" } ], + "/aws-cdk-s3-access-logs/MyAccessLogsBucket/Policy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "MyAccessLogsBucketPolicyEA9AB063" + } + ], "/aws-cdk-s3-access-logs/MyBucket/Resource": [ { "type": "aws:cdk:logicalId", @@ -65,6 +65,12 @@ ] }, "displayName": "aws-cdk-s3-access-logs" + }, + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } } } } \ No newline at end of file diff --git a/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/tree.json b/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/tree.json index 7ca6e560d2fa..2cdf05900941 100644 --- a/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/tree.json +++ b/packages/@aws-cdk/aws-s3/test/integ.bucket.server-access-logs.js.snapshot/tree.json @@ -4,14 +4,6 @@ "id": "App", "path": "", "children": { - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" - } - }, "aws-cdk-s3-access-logs": { "id": "aws-cdk-s3-access-logs", "path": "aws-cdk-s3-access-logs", @@ -25,14 +17,79 @@ "path": "aws-cdk-s3-access-logs/MyAccessLogsBucket/Resource", "attributes": { "aws:cdk:cloudformation:type": "AWS::S3::Bucket", - "aws:cdk:cloudformation:props": { - "accessControl": "LogDeliveryWrite" - } + "aws:cdk:cloudformation:props": {} }, "constructInfo": { "fqn": "@aws-cdk/aws-s3.CfnBucket", "version": "0.0.0" } + }, + "Policy": { + "id": "Policy", + "path": "aws-cdk-s3-access-logs/MyAccessLogsBucket/Policy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-s3-access-logs/MyAccessLogsBucket/Policy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::S3::BucketPolicy", + "aws:cdk:cloudformation:props": { + "bucket": { + "Ref": "MyAccessLogsBucketF7FE6635" + }, + "policyDocument": { + "Statement": [ + { + "Action": "s3:PutObject", + "Condition": { + "ArnLike": { + "aws:SourceArn": { + "Fn::GetAtt": [ + "MyBucketF68F3FF0", + "Arn" + ] + } + }, + "StringEquals": { + "aws:SourceAccount": { + "Ref": "AWS::AccountId" + } + } + }, + "Effect": "Allow", + "Principal": { + "Service": "logging.s3.amazonaws.com" + }, + "Resource": { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "MyAccessLogsBucketF7FE6635", + "Arn" + ] + }, + "/example*" + ] + ] + } + } + ], + "Version": "2012-10-17" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.CfnBucketPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-s3.BucketPolicy", + "version": "0.0.0" + } } }, "constructInfo": { @@ -68,17 +125,41 @@ "fqn": "@aws-cdk/aws-s3.Bucket", "version": "0.0.0" } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-cdk-s3-access-logs/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-cdk-s3-access-logs/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } } }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "Tree": { + "id": "Tree", + "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.1.85" + "version": "10.1.189" } } }, "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" } } } \ No newline at end of file diff --git a/packages/@aws-cdk/cx-api/FEATURE_FLAGS.md b/packages/@aws-cdk/cx-api/FEATURE_FLAGS.md index 0d060c9a08fc..f85304907020 100644 --- a/packages/@aws-cdk/cx-api/FEATURE_FLAGS.md +++ b/packages/@aws-cdk/cx-api/FEATURE_FLAGS.md @@ -39,6 +39,7 @@ Flags come in three types: | [@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker](#aws-cdkaws-ecsdisableexplicitdeploymentcontrollerforcircuitbreaker) | Avoid setting the "ECS" deployment controller when adding a circuit breaker | 2.51.0 | (fix) | | [@aws-cdk/aws-events:eventsTargetQueueSameAccount](#aws-cdkaws-eventseventstargetqueuesameaccount) | Event Rules may only push to encrypted SQS queues in the same account | 2.51.0 | (fix) | | [@aws-cdk/aws-iam:standardizedServicePrincipals](#aws-cdkaws-iamstandardizedserviceprincipals) | Use standardized (global) service principals everywhere | 2.51.0 | (fix) | +| [@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy](#aws-cdkaws-s3serveraccesslogsusebucketpolicy) | Use S3 Bucket Policy instead of ACLs for Server Access Logging | V2NEXT | (fix) | @@ -68,7 +69,8 @@ The following json shows the current recommended set of flags, as `cdk init` wou "@aws-cdk/core:enablePartitionLiterals": true, "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, "@aws-cdk/aws-iam:standardizedServicePrincipals": true, - "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true } } ``` @@ -695,4 +697,24 @@ This flag disables use of that exceptions database and always uses the global se | 2.51.0 | `false` | `true` | +### @aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy + +*Use S3 Bucket Policy instead of ACLs for Server Access Logging* (fix) + +Enable this feature flag to use S3 Bucket Policy for granting permission fo Server Access Logging +rather than using the canned `LogDeliveryWrite` ACL. ACLs do not work when Object Ownership is +enabled on the bucket. + +This flag uses a Bucket Policy statement to allow Server Access Log delivery, following best +practices for S3. + +@see https://docs.aws.amazon.com/AmazonS3/latest/userguide/enable-server-access-logging.html + + +| Since | Default | Recommended | +| ----- | ----- | ----- | +| (not in v1) | | | +| V2NEXT | `false` | `true` | + + diff --git a/packages/@aws-cdk/cx-api/README.md b/packages/@aws-cdk/cx-api/README.md index 5493d904da83..0d61f27c371b 100644 --- a/packages/@aws-cdk/cx-api/README.md +++ b/packages/@aws-cdk/cx-api/README.md @@ -120,3 +120,22 @@ _cdk.json_ } } ``` + +* `@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy` + +Enable this feature flag to use S3 Bucket Policy for granting permission fo Server Access Logging +rather than using the canned \`LogDeliveryWrite\` ACL. ACLs do not work when Object Ownership is +enabled on the bucket. + +This flag uses a Bucket Policy statement to allow Server Access Log delivery, following best +practices for S3. + +https://docs.aws.amazon.com/AmazonS3/latest/userguide/enable-server-access-logging.html + +```json +{ + "context": { + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true + } +} +``` diff --git a/packages/@aws-cdk/cx-api/lib/features.ts b/packages/@aws-cdk/cx-api/lib/features.ts index 1d29788bd4a9..985873fb9d63 100644 --- a/packages/@aws-cdk/cx-api/lib/features.ts +++ b/packages/@aws-cdk/cx-api/lib/features.ts @@ -74,6 +74,7 @@ export const ENABLE_PARTITION_LITERALS = '@aws-cdk/core:enablePartitionLiterals' export const EVENTS_TARGET_QUEUE_SAME_ACCOUNT = '@aws-cdk/aws-events:eventsTargetQueueSameAccount'; export const IAM_STANDARDIZED_SERVICE_PRINCIPALS = '@aws-cdk/aws-iam:standardizedServicePrincipals'; export const ECS_DISABLE_EXPLICIT_DEPLOYMENT_CONTROLLER_FOR_CIRCUIT_BREAKER = '@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker'; +export const S3_SERVER_ACCESS_LOGS_USE_BUCKET_POLICY = '@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy'; export const FLAGS: Record = { ////////////////////////////////////////////////////////////////////// @@ -558,6 +559,23 @@ export const FLAGS: Record = { introducedIn: { v2: '2.51.0' }, recommendedValue: true, }, + ////////////////////////////////////////////////////////////////////// + [S3_SERVER_ACCESS_LOGS_USE_BUCKET_POLICY]: { + type: FlagType.BugFix, + summary: 'Use S3 Bucket Policy instead of ACLs for Server Access Logging', + detailsMd: ` + Enable this feature flag to use S3 Bucket Policy for granting permission fo Server Access Logging + rather than using the canned \`LogDeliveryWrite\` ACL. ACLs do not work when Object Ownership is + enabled on the bucket. + + This flag uses a Bucket Policy statement to allow Server Access Log delivery, following best + practices for S3. + + @see https://docs.aws.amazon.com/AmazonS3/latest/userguide/enable-server-access-logging.html + `, + introducedIn: { v2: 'V2NEXT' }, + recommendedValue: true, + }, }; const CURRENT_MV = 'v2';