diff --git a/packages/@aws-cdk/aws-neptune-alpha/lib/cluster.ts b/packages/@aws-cdk/aws-neptune-alpha/lib/cluster.ts index 39d5db9cdbb36..8b3cce4ef5aff 100644 --- a/packages/@aws-cdk/aws-neptune-alpha/lib/cluster.ts +++ b/packages/@aws-cdk/aws-neptune-alpha/lib/cluster.ts @@ -633,7 +633,7 @@ export class DatabaseCluster extends DatabaseClusterBase implements IDatabaseClu const retention = props.cloudwatchLogsRetention; if (retention) { props.cloudwatchLogsExports?.forEach(logType => { - new logs.LogRetention(this, `${logType}LogRetention`, { + new logs.LogRetention(this, `${logType.value}LogRetention`, { logGroupName: `/aws/neptune/${this.clusterIdentifier}/${logType.value}`, role: props.cloudwatchLogsRetentionRole, retention, diff --git a/packages/@aws-cdk/aws-neptune-alpha/test/cluster.test.ts b/packages/@aws-cdk/aws-neptune-alpha/test/cluster.test.ts index 5c1d012f470d6..dc9de61ce3768 100644 --- a/packages/@aws-cdk/aws-neptune-alpha/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-neptune-alpha/test/cluster.test.ts @@ -830,6 +830,55 @@ describe('DatabaseCluster', () => { }); }).toThrow(/ServerlessScalingConfiguration minCapacity 10 must be less than serverlessScalingConfiguration maxCapacity 5/); }); + + test('cloudwatchLogsExports log retention is enabled when configured for multiple logs exports', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Cluster', { + vpc, + instanceType: InstanceType.R5_LARGE, + cloudwatchLogsExports: [LogType.AUDIT, new LogType('slowquery')], + cloudwatchLogsRetention: logs.RetentionDays.ONE_MONTH, + }); + + // THEN + Template.fromStack(stack).hasResourceProperties('AWS::Neptune::DBCluster', { + EnableCloudwatchLogsExports: ['audit', 'slowquery'], + }); + Template.fromStack(stack).hasResourceProperties('Custom::LogRetention', { + LogGroupName: { + 'Fn::Join': [ + '', + [ + '/aws/neptune/', + { + Ref: 'ClusterEB0386A7', + }, + '/audit', + ], + ], + }, + RetentionInDays: 30, + }); + Template.fromStack(stack).hasResourceProperties('Custom::LogRetention', { + LogGroupName: { + 'Fn::Join': [ + '', + [ + '/aws/neptune/', + { + Ref: 'ClusterEB0386A7', + }, + '/slowquery', + ], + ], + }, + RetentionInDays: 30, + }); + }); }); function testStack() { diff --git a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/ClusterTestDefaultTestDeployAssert6A1BBA9D.assets.json b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/ClusterTestDefaultTestDeployAssert6A1BBA9D.assets.json index 5ddb3aeafc6f7..1a49d2e15b492 100644 --- a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/ClusterTestDefaultTestDeployAssert6A1BBA9D.assets.json +++ b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/ClusterTestDefaultTestDeployAssert6A1BBA9D.assets.json @@ -1,5 +1,5 @@ { - "version": "34.0.0", + "version": "36.0.0", "files": { "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { "source": { diff --git a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/asset.a8515c042d9c942705087943220417be929ac44f968d8fcef2681681b400c0c0/index.d.ts b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/asset.a8515c042d9c942705087943220417be929ac44f968d8fcef2681681b400c0c0/index.d.ts deleted file mode 100644 index 60193f14b4d6d..0000000000000 --- a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/asset.a8515c042d9c942705087943220417be929ac44f968d8fcef2681681b400c0c0/index.d.ts +++ /dev/null @@ -1,14 +0,0 @@ -interface LogRetentionEvent extends Omit { - ResourceProperties: { - ServiceToken: string; - LogGroupName: string; - LogGroupRegion?: string; - RetentionInDays?: string; - SdkRetry?: { - maxRetries?: string; - }; - RemovalPolicy?: string; - }; -} -export declare function handler(event: LogRetentionEvent, context: AWSLambda.Context): Promise; -export {}; diff --git a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/asset.a8515c042d9c942705087943220417be929ac44f968d8fcef2681681b400c0c0/index.js b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/asset.a8515c042d9c942705087943220417be929ac44f968d8fcef2681681b400c0c0/index.js deleted file mode 100644 index 8d4f5cf13f88d..0000000000000 --- a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/asset.a8515c042d9c942705087943220417be929ac44f968d8fcef2681681b400c0c0/index.js +++ /dev/null @@ -1,192 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.handler = void 0; -/* eslint-disable no-console */ -// eslint-disable-next-line import/no-extraneous-dependencies -const Logs = require("@aws-sdk/client-cloudwatch-logs"); -/** - * Creates a log group and doesn't throw if it exists. - */ -async function createLogGroupSafe(logGroupName, client, withDelay) { - await withDelay(async () => { - try { - const params = { logGroupName }; - const command = new Logs.CreateLogGroupCommand(params); - await client.send(command); - } - catch (error) { - if (error instanceof Logs.ResourceAlreadyExistsException || error.name === 'ResourceAlreadyExistsException') { - // The log group is already created by the lambda execution - return; - } - throw error; - } - }); -} -/** - * Deletes a log group and doesn't throw if it does not exist. - */ -async function deleteLogGroup(logGroupName, client, withDelay) { - await withDelay(async () => { - try { - const params = { logGroupName }; - const command = new Logs.DeleteLogGroupCommand(params); - await client.send(command); - } - catch (error) { - if (error instanceof Logs.ResourceNotFoundException || error.name === 'ResourceNotFoundException') { - // The log group doesn't exist - return; - } - throw error; - } - }); -} -/** - * Puts or deletes a retention policy on a log group. - */ -async function setRetentionPolicy(logGroupName, client, withDelay, retentionInDays) { - await withDelay(async () => { - if (!retentionInDays) { - const params = { logGroupName }; - const deleteCommand = new Logs.DeleteRetentionPolicyCommand(params); - await client.send(deleteCommand); - } - else { - const params = { logGroupName, retentionInDays }; - const putCommand = new Logs.PutRetentionPolicyCommand(params); - await client.send(putCommand); - } - }); -} -async function handler(event, context) { - try { - console.log(JSON.stringify({ ...event, ResponseURL: '...' })); - // The target log group - const logGroupName = event.ResourceProperties.LogGroupName; - // The region of the target log group - const logGroupRegion = event.ResourceProperties.LogGroupRegion; - // Parse to AWS SDK retry options - const maxRetries = parseIntOptional(event.ResourceProperties.SdkRetry?.maxRetries) ?? 5; - const withDelay = makeWithDelay(maxRetries); - const sdkConfig = { - logger: console, - region: logGroupRegion, - maxAttempts: Math.max(5, maxRetries), // Use a minimum for SDK level retries, because it might include retryable failures that withDelay isn't checking for - }; - const client = new Logs.CloudWatchLogsClient(sdkConfig); - if (event.RequestType === 'Create' || event.RequestType === 'Update') { - // Act on the target log group - await createLogGroupSafe(logGroupName, client, withDelay); - await setRetentionPolicy(logGroupName, client, withDelay, parseIntOptional(event.ResourceProperties.RetentionInDays)); - // Configure the Log Group for the Custom Resource function itself - if (event.RequestType === 'Create') { - const clientForCustomResourceFunction = new Logs.CloudWatchLogsClient({ - logger: console, - region: process.env.AWS_REGION, - }); - // Set a retention policy of 1 day on the logs of this very function. - // Due to the async nature of the log group creation, the log group for this function might - // still be not created yet at this point. Therefore we attempt to create it. - // In case it is being created, createLogGroupSafe will handle the conflict. - await createLogGroupSafe(`/aws/lambda/${context.functionName}`, clientForCustomResourceFunction, withDelay); - // If createLogGroupSafe fails, the log group is not created even after multiple attempts. - // In this case we have nothing to set the retention policy on but an exception will skip - // the next line. - await setRetentionPolicy(`/aws/lambda/${context.functionName}`, clientForCustomResourceFunction, withDelay, 1); - } - } - // When the requestType is delete, delete the log group if the removal policy is delete - if (event.RequestType === 'Delete' && event.ResourceProperties.RemovalPolicy === 'destroy') { - await deleteLogGroup(logGroupName, client, withDelay); - // else retain the log group - } - await respond('SUCCESS', 'OK', logGroupName); - } - catch (e) { - console.log(e); - await respond('FAILED', e.message, event.ResourceProperties.LogGroupName); - } - function respond(responseStatus, reason, physicalResourceId) { - const responseBody = JSON.stringify({ - Status: responseStatus, - Reason: reason, - PhysicalResourceId: physicalResourceId, - StackId: event.StackId, - RequestId: event.RequestId, - LogicalResourceId: event.LogicalResourceId, - Data: { - // Add log group name as part of the response so that it's available via Fn::GetAtt - LogGroupName: event.ResourceProperties.LogGroupName, - }, - }); - console.log('Responding', responseBody); - // eslint-disable-next-line @typescript-eslint/no-require-imports - const parsedUrl = require('url').parse(event.ResponseURL); - const requestOptions = { - hostname: parsedUrl.hostname, - path: parsedUrl.path, - method: 'PUT', - headers: { - 'content-type': '', - 'content-length': Buffer.byteLength(responseBody, 'utf8'), - }, - }; - return new Promise((resolve, reject) => { - try { - // eslint-disable-next-line @typescript-eslint/no-require-imports - const request = require('https').request(requestOptions, resolve); - request.on('error', reject); - request.write(responseBody); - request.end(); - } - catch (e) { - reject(e); - } - }); - } -} -exports.handler = handler; -function parseIntOptional(value, base = 10) { - if (value === undefined) { - return undefined; - } - return parseInt(value, base); -} -function makeWithDelay(maxRetries, delayBase = 100, delayCap = 10 * 1000) { - // If we try to update the log group, then due to the async nature of - // Lambda logging there could be a race condition when the same log group is - // already being created by the lambda execution. This can sometime result in - // an error "OperationAbortedException: A conflicting operation is currently - // in progress...Please try again." - // To avoid an error, we do as requested and try again. - return async (block) => { - let attempts = 0; - do { - try { - return await block(); - } - catch (error) { - if (error instanceof Logs.OperationAbortedException - || error.name === 'OperationAbortedException' - || error.name === 'ThrottlingException' // There is no class to check with instanceof, see https://github.com/aws/aws-sdk-js-v3/issues/5140 - ) { - if (attempts < maxRetries) { - attempts++; - await new Promise(resolve => setTimeout(resolve, calculateDelay(attempts, delayBase, delayCap))); - continue; - } - else { - // The log group is still being changed by another execution but we are out of retries - throw new Error('Out of attempts to change log group'); - } - } - throw error; - } - } while (true); // exit happens on retry count check - }; -} -function calculateDelay(attempt, base, cap) { - return Math.round(Math.random() * Math.min(cap, base * 2 ** attempt)); -} -//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSwrQkFBK0I7QUFDL0IsNkRBQTZEO0FBQzdELHdEQUF3RDtBQWV4RDs7R0FFRztBQUNILEtBQUssVUFBVSxrQkFBa0IsQ0FBQyxZQUFvQixFQUFFLE1BQWlDLEVBQUUsU0FBd0Q7SUFDakosTUFBTSxTQUFTLENBQUMsS0FBSyxJQUFJLEVBQUU7UUFDekIsSUFBSTtZQUNGLE1BQU0sTUFBTSxHQUFHLEVBQUUsWUFBWSxFQUFFLENBQUM7WUFDaEMsTUFBTSxPQUFPLEdBQUcsSUFBSSxJQUFJLENBQUMscUJBQXFCLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDdkQsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1NBRTVCO1FBQUMsT0FBTyxLQUFVLEVBQUU7WUFDbkIsSUFBSSxLQUFLLFlBQVksSUFBSSxDQUFDLDhCQUE4QixJQUFJLEtBQUssQ0FBQyxJQUFJLEtBQUssZ0NBQWdDLEVBQUU7Z0JBQzNHLDJEQUEyRDtnQkFDM0QsT0FBTzthQUNSO1lBRUQsTUFBTSxLQUFLLENBQUM7U0FDYjtJQUNILENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVEOztHQUVHO0FBQ0gsS0FBSyxVQUFVLGNBQWMsQ0FBQyxZQUFvQixFQUFFLE1BQWlDLEVBQUUsU0FBd0Q7SUFDN0ksTUFBTSxTQUFTLENBQUMsS0FBSyxJQUFJLEVBQUU7UUFDekIsSUFBSTtZQUNGLE1BQU0sTUFBTSxHQUFHLEVBQUUsWUFBWSxFQUFFLENBQUM7WUFDaEMsTUFBTSxPQUFPLEdBQUcsSUFBSSxJQUFJLENBQUMscUJBQXFCLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDdkQsTUFBTSxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1NBRTVCO1FBQUMsT0FBTyxLQUFVLEVBQUU7WUFDbkIsSUFBSSxLQUFLLFlBQVksSUFBSSxDQUFD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LEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsRUFBRSxJQUFJLEdBQUcsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxDQUFDLENBQUM7QUFDeEUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIG5vLWNvbnNvbGUgKi9cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXNcbmltcG9ydCAqIGFzIExvZ3MgZnJvbSAnQGF3cy1zZGsvY2xpZW50LWNsb3Vkd2F0Y2gtbG9ncyc7XG5cbmludGVyZmFjZSBMb2dSZXRlbnRpb25FdmVudCBleHRlbmRzIE9taXQ8QVdTTGFtYmRhLkNsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VFdmVudCwgJ1Jlc291cmNlUHJvcGVydGllcyc+IHtcbiAgUmVzb3VyY2VQcm9wZXJ0aWVzOiB7XG4gICAgU2VydmljZVRva2VuOiBzdHJpbmc7XG4gICAgTG9nR3JvdXBOYW1lOiBzdHJpbmc7XG4gICAgTG9nR3JvdXBSZWdpb24/OiBzdHJpbmc7XG4gICAgUmV0ZW50aW9uSW5EYXlzPzogc3RyaW5nO1xuICAgIFNka1JldHJ5Pzoge1xuICAgICAgbWF4UmV0cmllcz86IHN0cmluZztcbiAgICB9O1xuICAgIFJlbW92YWxQb2xpY3k/OiBzdHJpbmdcbiAgfTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbG9nIGdyb3VwIGFuZCBkb2Vzbid0IHRocm93IGlmIGl0IGV4aXN0cy5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gY3JlYXRlTG9nR3JvdXBTYWZlKGxvZ0dyb3VwTmFtZTogc3RyaW5nLCBjbGllbnQ6IExvZ3MuQ2xvdWRXYXRjaExvZ3NDbGllbnQsIHdpdGhEZWxheTogKGJsb2NrOiAoKSA9PiBQcm9taXNlPHZvaWQ+KSA9PiBQcm9taXNlPHZvaWQ+KSB7XG4gIGF3YWl0IHdpdGhEZWxheShhc3luYyAoKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHBhcmFtcyA9IHsgbG9nR3JvdXBOYW1lIH07XG4gICAgICBjb25zdCBjb21tYW5kID0gbmV3IExvZ3MuQ3JlYXRlTG9nR3JvdXBDb21tYW5kKHBhcmFtcyk7XG4gICAgICBhd2FpdCBjbGllbnQuc2VuZChjb21tYW5kKTtcblxuICAgIH0gY2F0Y2ggKGVycm9yOiBhbnkpIHtcbiAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIExvZ3MuUmVzb3VyY2VBbHJlYWR5RXhpc3RzRXhjZXB0aW9uIHx8IGVycm9yLm5hbWUgPT09ICdSZXNvdXJjZUFscmVhZHlFeGlzdHNFeGNlcHRpb24nKSB7XG4gICAgICAgIC8vIFRoZSBsb2cgZ3JvdXAgaXMgYWxyZWFkeSBjcmVhdGVkIGJ5IHRoZSBsYW1iZGEgZXhlY3V0aW9uXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuICB9KTtcbn1cblxuLyoqXG4gKiBEZWxldGVzIGEgbG9nIGdyb3VwIGFuZCBkb2Vzbid0IHRocm93IGlmIGl0IGRvZXMgbm90IGV4aXN0LlxuICovXG5hc3luYyBmdW5jdGlvbiBkZWxldGVMb2dHcm91cChsb2dHcm91cE5hbWU6IHN0cmluZywgY2xpZW50OiBMb2dzLkNsb3VkV2F0Y2hMb2dzQ2xpZW50LCB3aXRoRGVsYXk6IChibG9jazogKCkgPT4gUHJvbWlzZTx2b2lkPikgPT4gUHJvbWlzZTx2b2lkPikge1xuICBhd2FpdCB3aXRoRGVsYXkoYXN5bmMgKCkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBwYXJhbXMgPSB7IGxvZ0dyb3VwTmFtZSB9O1xuICAgICAgY29uc3QgY29tbWFuZCA9IG5ldyBMb2dzLkRlbGV0ZUxvZ0dyb3VwQ29tbWFuZChwYXJhbXMpO1xuICAgICAgYXdhaXQgY2xpZW50LnNlbmQoY29tbWFuZCk7XG5cbiAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBMb2dzLlJlc291cmNlTm90Rm91bmRFeGNlcHRpb24gfHwgZXJyb3IubmFtZSA9PT0gJ1Jlc291cmNlTm90Rm91bmRFeGNlcHRpb24nKSB7XG4gICAgICAgIC8vIFRoZSBsb2cgZ3JvdXAgZG9lc24ndCBleGlzdFxuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cbiAgfSk7XG59XG5cbi8qKlxuICogUHV0cyBvciBkZWxldGVzIGEgcmV0ZW50aW9uIHBvbGljeSBvbiBhIGxvZyBncm91cC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gc2V0UmV0ZW50aW9uUG9saWN5KFxuICBsb2dHcm91cE5hbWU6IHN0cmluZyxcbiAgY2xpZW50OiBMb2dzLkNsb3VkV2F0Y2hMb2dzQ2xpZW50LFxuICB3aXRoRGVsYXk6IChibG9jazogKCkgPT4gUHJvbWlzZTx2b2lkPikgPT4gUHJvbWlzZTx2b2lkPixcbiAgcmV0ZW50aW9uSW5EYXlzPzogbnVtYmVyLFxuKSB7XG5cbiAgYXdhaXQgd2l0aERlbGF5KGFzeW5jICgpID0+IHtcbiAgICBpZiAoIXJldGVudGlvbkluRGF5cykge1xuICAgICAgY29uc3QgcGFyYW1zID0geyBsb2dHcm91cE5hbWUgfTtcbiAgICAgIGNvbnN0IGRlbGV0ZUNvbW1hbmQgPSBuZXcgTG9ncy5EZWxldGVSZXRlbnRpb25Qb2xpY3lDb21tYW5kKHBhcmFtcyk7XG4gICAgICBhd2FpdCBjbGllbnQuc2VuZChkZWxldGVDb21tYW5kKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgcGFyYW1zID0geyBsb2dHcm91cE5hbWUsIHJldGVudGlvbkluRGF5cyB9O1xuICAgICAgY29uc3QgcHV0Q29tbWFuZCA9IG5ldyBMb2dzLlB1dFJldGVudGlvblBvbGljeUNvbW1hbmQocGFyYW1zKTtcbiAgICAgIGF3YWl0IGNsaWVudC5zZW5kKHB1dENvbW1hbmQpO1xuICAgIH1cbiAgfSk7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBoYW5kbGVyKGV2ZW50OiBMb2dSZXRlbnRpb25FdmVudCwgY29udGV4dDogQVdTTGFtYmRhLkNvbnRleHQpIHtcbiAgdHJ5IHtcbiAgICBjb25zb2xlLmxvZyhKU09OLnN0cmluZ2lmeSh7IC4uLmV2ZW50LCBSZXNwb25zZVVSTDogJy4uLicgfSkpO1xuXG4gICAgLy8gVGhlIHRhcmdldCBsb2cgZ3JvdXBcbiAgICBjb25zdCBsb2dHcm91cE5hbWUgPSBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuTG9nR3JvdXBOYW1lO1xuXG4gICAgLy8gVGhlIHJlZ2lvbiBvZiB0aGUgdGFyZ2V0IGxvZyBncm91cFxuICAgIGNvbnN0IGxvZ0dyb3VwUmVnaW9uID0gZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzLkxvZ0dyb3VwUmVnaW9uO1xuXG4gICAgLy8gUGFyc2UgdG8gQVdTIFNESyByZXRyeSBvcHRpb25zXG4gICAgY29uc3QgbWF4UmV0cmllcyA9IHBhcnNlSW50T3B0aW9uYWwoZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzLlNka1JldHJ5Py5tYXhSZXRyaWVzKSA/PyA1O1xuICAgIGNvbnN0IHdpdGhEZWxheSA9IG1ha2VXaXRoRGVsYXkobWF4UmV0cmllcyk7XG5cbiAgICBjb25zdCBzZGtDb25maWc6IExvZ3MuQ2xvdWRXYXRjaExvZ3NDbGllbnRDb25maWcgPSB7XG4gICAgICBsb2dnZXI6IGNvbnNvbGUsXG4gICAgICByZWdpb246IGxvZ0dyb3VwUmVnaW9uLFxuICAgICAgbWF4QXR0ZW1wdHM6IE1hdGgubWF4KDUsIG1heFJldHJpZXMpLCAvLyBVc2UgYSBtaW5pbXVtIGZvciBTREsgbGV2ZWwgcmV0cmllcywgYmVjYXVzZSBpdCBtaWdodCBpbmNsdWRlIHJldHJ5YWJsZSBmYWlsdXJlcyB0aGF0IHdpdGhEZWxheSBpc24ndCBjaGVja2luZyBmb3JcbiAgICB9O1xuICAgIGNvbnN0IGNsaWVudCA9IG5ldyBMb2dzLkNsb3VkV2F0Y2hMb2dzQ2xpZW50KHNka0NvbmZpZyk7XG5cbiAgICBpZiAoZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdDcmVhdGUnIHx8IGV2ZW50LlJlcXVlc3RUeXBlID09PSAnVXBkYXRlJykge1xuICAgICAgLy8gQWN0IG9uIHRoZSB0YXJnZXQgbG9nIGdyb3VwXG4gICAgICBhd2FpdCBjcmVhdGVMb2dHcm91cFNhZmUobG9nR3JvdXBOYW1lLCBjbGllbnQsIHdpdGhEZWxheSk7XG4gICAgICBhd2FpdCBzZXRSZXRlbnRpb25Qb2xpY3kobG9nR3JvdXBOYW1lLCBjbGllbnQsIHdpdGhEZWxheSwgcGFyc2VJbnRPcHRpb25hbChldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuUmV0ZW50aW9uSW5EYXlzKSk7XG5cbiAgICAgIC8vIENvbmZpZ3VyZSB0aGUgTG9nIEdyb3VwIGZvciB0aGUgQ3VzdG9tIFJlc291cmNlIGZ1bmN0aW9uIGl0c2VsZlxuICAgICAgaWYgKGV2ZW50LlJlcXVlc3RUeXBlID09PSAnQ3JlYXRlJykge1xuICAgICAgICBjb25zdCBjbGllbnRGb3JDdXN0b21SZXNvdXJjZUZ1bmN0aW9uID0gbmV3IExvZ3MuQ2xvdWRXYXRjaExvZ3NDbGllbnQoe1xuICAgICAgICAgIGxvZ2dlcjogY29uc29sZSxcbiAgICAgICAgICByZWdpb246IHByb2Nlc3MuZW52LkFXU19SRUdJT04sXG4gICAgICAgIH0pO1xuICAgICAgICAvLyBTZXQgYSByZXRlbnRpb24gcG9saWN5IG9mIDEgZGF5IG9uIHRoZSBsb2dzIG9mIHRoaXMgdmVyeSBmdW5jdGlvbi5cbiAgICAgICAgLy8gRHVlIHRvIHRoZSBhc3luYyBuYXR1cmUgb2YgdGhlIGxvZyBncm91cCBjcmVhdGlvbiwgdGhlIGxvZyBncm91cCBmb3IgdGhpcyBmdW5jdGlvbiBtaWdodFxuICAgICAgICAvLyBzdGlsbCBiZSBub3QgY3JlYXRlZCB5ZXQgYXQgdGhpcyBwb2ludC4gVGhlcmVmb3JlIHdlIGF0dGVtcHQgdG8gY3JlYXRlIGl0LlxuICAgICAgICAvLyBJbiBjYXNlIGl0IGlzIGJlaW5nIGNyZWF0ZWQsIGNyZWF0ZUxvZ0dyb3VwU2FmZSB3aWxsIGhhbmRsZSB0aGUgY29uZmxpY3QuXG4gICAgICAgIGF3YWl0IGNyZWF0ZUxvZ0dyb3VwU2FmZShgL2F3cy9sYW1iZGEvJHtjb250ZXh0LmZ1bmN0aW9uTmFtZX1gLCBjbGllbnRGb3JDdXN0b21SZXNvdXJjZUZ1bmN0aW9uLCB3aXRoRGVsYXkpO1xuICAgICAgICAvLyBJZiBjcmVhdGVMb2dHcm91cFNhZmUgZmFpbHMsIHRoZSBsb2cgZ3JvdXAgaXMgbm90IGNyZWF0ZWQgZXZlbiBhZnRlciBtdWx0aXBsZSBhdHRlbXB0cy5cbiAgICAgICAgLy8gSW4gdGhpcyBjYXNlIHdlIGhhdmUgbm90aGluZyB0byBzZXQgdGhlIHJldGVudGlvbiBwb2xpY3kgb24gYnV0IGFuIGV4Y2VwdGlvbiB3aWxsIHNraXBcbiAgICAgICAgLy8gdGhlIG5leHQgbGluZS5cbiAgICAgICAgYXdhaXQgc2V0UmV0ZW50aW9uUG9saWN5KGAvYXdzL2xhbWJkYS8ke2NvbnRleHQuZnVuY3Rpb25OYW1lfWAsIGNsaWVudEZvckN1c3RvbVJlc291cmNlRnVuY3Rpb24sIHdpdGhEZWxheSwgMSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gV2hlbiB0aGUgcmVxdWVzdFR5cGUgaXMgZGVsZXRlLCBkZWxldGUgdGhlIGxvZyBncm91cCBpZiB0aGUgcmVtb3ZhbCBwb2xpY3kgaXMgZGVsZXRlXG4gICAgaWYgKGV2ZW50LlJlcXVlc3RUeXBlID09PSAnRGVsZXRlJyAmJiBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuUmVtb3ZhbFBvbGljeSA9PT0gJ2Rlc3Ryb3knKSB7XG4gICAgICBhd2FpdCBkZWxldGVMb2dHcm91cChsb2dHcm91cE5hbWUsIGNsaWVudCwgd2l0aERlbGF5KTtcbiAgICAgIC8vIGVsc2UgcmV0YWluIHRoZSBsb2cgZ3JvdXBcbiAgICB9XG5cbiAgICBhd2FpdCByZXNwb25kKCdTVUNDRVNTJywgJ09LJywgbG9nR3JvdXBOYW1lKTtcbiAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgY29uc29sZS5sb2coZSk7XG4gICAgYXdhaXQgcmVzcG9uZCgnRkFJTEVEJywgZS5tZXNzYWdlLCBldmVudC5SZXNvdXJjZVByb3BlcnRpZXMuTG9nR3JvdXBOYW1lKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHJlc3BvbmQocmVzcG9uc2VTdGF0dXM6IHN0cmluZywgcmVhc29uOiBzdHJpbmcsIHBoeXNpY2FsUmVzb3VyY2VJZDogc3RyaW5nKSB7XG4gICAgY29uc3QgcmVzcG9uc2VCb2R5ID0gSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgU3RhdHVzOiByZXNwb25zZVN0YXR1cyxcbiAgICAgIFJlYXNvbjogcmVhc29uLFxuICAgICAgUGh5c2ljYWxSZXNvdXJjZUlkOiBwaHlzaWNhbFJlc291cmNlSWQsXG4gICAgICBTdGFja0lkOiBldmVudC5TdGFja0lkLFxuICAgICAgUmVxdWVzdElkOiBldmVudC5SZXF1ZXN0SWQsXG4gICAgICBMb2dpY2FsUmVzb3VyY2VJZDogZXZlbnQuTG9naWNhbFJlc291cmNlSWQsXG4gICAgICBEYXRhOiB7XG4gICAgICAgIC8vIEFkZCBsb2cgZ3JvdXAgbmFtZSBhcyBwYXJ0IG9mIHRoZSByZXNwb25zZSBzbyB0aGF0IGl0J3MgYXZhaWxhYmxlIHZpYSBGbjo6R2V0QXR0XG4gICAgICAgIExvZ0dyb3VwTmFtZTogZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzLkxvZ0dyb3VwTmFtZSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBjb25zb2xlLmxvZygnUmVzcG9uZGluZycsIHJlc3BvbnNlQm9keSk7XG5cbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0c1xuICAgIGNvbnN0IHBhcnNlZFVybCA9IHJlcXVpcmUoJ3VybCcpLnBhcnNlKGV2ZW50LlJlc3BvbnNlVVJMKTtcbiAgICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHtcbiAgICAgIGhvc3RuYW1lOiBwYXJzZWRVcmwuaG9zdG5hbWUsXG4gICAgICBwYXRoOiBwYXJzZWRVcmwucGF0aCxcbiAgICAgIG1ldGhvZDogJ1BVVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdjb250ZW50LXR5cGUnOiAnJyxcbiAgICAgICAgJ2NvbnRlbnQtbGVuZ3RoJzogQnVmZmVyLmJ5dGVMZW5ndGgocmVzcG9uc2VCb2R5LCAndXRmOCcpLFxuICAgICAgfSxcbiAgICB9O1xuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzXG4gICAgICAgIGNvbnN0IHJlcXVlc3QgPSByZXF1aXJlKCdodHRwcycpLnJlcXVlc3QocmVxdWVzdE9wdGlvbnMsIHJlc29sdmUpO1xuICAgICAgICByZXF1ZXN0Lm9uKCdlcnJvcicsIHJlamVjdCk7XG4gICAgICAgIHJlcXVlc3Qud3JpdGUocmVzcG9uc2VCb2R5KTtcbiAgICAgICAgcmVxdWVzdC5lbmQoKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgcmVqZWN0KGUpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG59XG5cbmZ1bmN0aW9uIHBhcnNlSW50T3B0aW9uYWwodmFsdWU/OiBzdHJpbmcsIGJhc2UgPSAxMCk6IG51bWJlciB8IHVuZGVmaW5lZCB7XG4gIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIHJldHVybiBwYXJzZUludCh2YWx1ZSwgYmFzZSk7XG59XG5cbmZ1bmN0aW9uIG1ha2VXaXRoRGVsYXkoXG4gIG1heFJldHJpZXM6IG51bWJlcixcbiAgZGVsYXlCYXNlOiBudW1iZXIgPSAxMDAsXG4gIGRlbGF5Q2FwID0gMTAgKiAxMDAwLCAvLyAxMHNcbik6IChibG9jazogKCkgPT4gUHJvbWlzZTx2b2lkPikgPT4gUHJvbWlzZTx2b2lkPiB7XG4gIC8vIElmIHdlIHRyeSB0byB1cGRhdGUgdGhlIGxvZyBncm91cCwgdGhlbiBkdWUgdG8gdGhlIGFzeW5jIG5hdHVyZSBvZlxuICAvLyBMYW1iZGEgbG9nZ2luZyB0aGVyZSBjb3VsZCBiZSBhIHJhY2UgY29uZGl0aW9uIHdoZW4gdGhlIHNhbWUgbG9nIGdyb3VwIGlzXG4gIC8vIGFscmVhZHkgYmVpbmcgY3JlYXRlZCBieSB0aGUgbGFtYmRhIGV4ZWN1dGlvbi4gVGhpcyBjYW4gc29tZXRpbWUgcmVzdWx0IGluXG4gIC8vIGFuIGVycm9yIFwiT3BlcmF0aW9uQWJvcnRlZEV4Y2VwdGlvbjogQSBjb25mbGljdGluZyBvcGVyYXRpb24gaXMgY3VycmVudGx5XG4gIC8vIGluIHByb2dyZXNzLi4uUGxlYXNlIHRyeSBhZ2Fpbi5cIlxuICAvLyBUbyBhdm9pZCBhbiBlcnJvciwgd2UgZG8gYXMgcmVxdWVzdGVkIGFuZCB0cnkgYWdhaW4uXG5cbiAgcmV0dXJuIGFzeW5jIChibG9jazogKCkgPT4gUHJvbWlzZTx2b2lkPikgPT4ge1xuICAgIGxldCBhdHRlbXB0cyA9IDA7XG4gICAgZG8ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IGJsb2NrKCk7XG4gICAgICB9IGNhdGNoIChlcnJvcjogYW55KSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICBlcnJvciBpbnN0YW5jZW9mIExvZ3MuT3BlcmF0aW9uQWJvcnRlZEV4Y2VwdGlvblxuICAgICAgICAgIHx8IGVycm9yLm5hbWUgPT09ICdPcGVyYXRpb25BYm9ydGVkRXhjZXB0aW9uJ1xuICAgICAgICAgIHx8IGVycm9yLm5hbWUgPT09ICdUaHJvdHRsaW5nRXhjZXB0aW9uJyAvLyBUaGVyZSBpcyBubyBjbGFzcyB0byBjaGVjayB3aXRoIGluc3RhbmNlb2YsIHNlZSBodHRwczovL2dpdGh1Yi5jb20vYXdzL2F3cy1zZGstanMtdjMvaXNzdWVzLzUxNDBcbiAgICAgICAgKSB7XG4gICAgICAgICAgaWYgKGF0dGVtcHRzIDwgbWF4UmV0cmllcyApIHtcbiAgICAgICAgICAgIGF0dGVtcHRzKys7XG4gICAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgY2FsY3VsYXRlRGVsYXkoYXR0ZW1wdHMsIGRlbGF5QmFzZSwgZGVsYXlDYXApKSk7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gVGhlIGxvZyBncm91cCBpcyBzdGlsbCBiZWluZyBjaGFuZ2VkIGJ5IGFub3RoZXIgZXhlY3V0aW9uIGJ1dCB3ZSBhcmUgb3V0IG9mIHJldHJpZXNcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignT3V0IG9mIGF0dGVtcHRzIHRvIGNoYW5nZSBsb2cgZ3JvdXAnKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgfSB3aGlsZSAodHJ1ZSk7IC8vIGV4aXQgaGFwcGVucyBvbiByZXRyeSBjb3VudCBjaGVja1xuICB9O1xufVxuXG5mdW5jdGlvbiBjYWxjdWxhdGVEZWxheShhdHRlbXB0OiBudW1iZXIsIGJhc2U6IG51bWJlciwgY2FwOiBudW1iZXIpOiBudW1iZXIge1xuICByZXR1cm4gTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogTWF0aC5taW4oY2FwLCBiYXNlICogMiAqKiBhdHRlbXB0KSk7XG59XG4iXX0= \ No newline at end of file diff --git a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/asset.a8515c042d9c942705087943220417be929ac44f968d8fcef2681681b400c0c0/index.ts b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/asset.a8515c042d9c942705087943220417be929ac44f968d8fcef2681681b400c0c0/index.ts deleted file mode 100644 index 88843fe3fa016..0000000000000 --- a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/asset.a8515c042d9c942705087943220417be929ac44f968d8fcef2681681b400c0c0/index.ts +++ /dev/null @@ -1,229 +0,0 @@ -/* eslint-disable no-console */ -// eslint-disable-next-line import/no-extraneous-dependencies -import * as Logs from '@aws-sdk/client-cloudwatch-logs'; - -interface LogRetentionEvent extends Omit { - ResourceProperties: { - ServiceToken: string; - LogGroupName: string; - LogGroupRegion?: string; - RetentionInDays?: string; - SdkRetry?: { - maxRetries?: string; - }; - RemovalPolicy?: string - }; -} - -/** - * Creates a log group and doesn't throw if it exists. - */ -async function createLogGroupSafe(logGroupName: string, client: Logs.CloudWatchLogsClient, withDelay: (block: () => Promise) => Promise) { - await withDelay(async () => { - try { - const params = { logGroupName }; - const command = new Logs.CreateLogGroupCommand(params); - await client.send(command); - - } catch (error: any) { - if (error instanceof Logs.ResourceAlreadyExistsException || error.name === 'ResourceAlreadyExistsException') { - // The log group is already created by the lambda execution - return; - } - - throw error; - } - }); -} - -/** - * Deletes a log group and doesn't throw if it does not exist. - */ -async function deleteLogGroup(logGroupName: string, client: Logs.CloudWatchLogsClient, withDelay: (block: () => Promise) => Promise) { - await withDelay(async () => { - try { - const params = { logGroupName }; - const command = new Logs.DeleteLogGroupCommand(params); - await client.send(command); - - } catch (error: any) { - if (error instanceof Logs.ResourceNotFoundException || error.name === 'ResourceNotFoundException') { - // The log group doesn't exist - return; - } - - throw error; - } - }); -} - -/** - * Puts or deletes a retention policy on a log group. - */ -async function setRetentionPolicy( - logGroupName: string, - client: Logs.CloudWatchLogsClient, - withDelay: (block: () => Promise) => Promise, - retentionInDays?: number, -) { - - await withDelay(async () => { - if (!retentionInDays) { - const params = { logGroupName }; - const deleteCommand = new Logs.DeleteRetentionPolicyCommand(params); - await client.send(deleteCommand); - } else { - const params = { logGroupName, retentionInDays }; - const putCommand = new Logs.PutRetentionPolicyCommand(params); - await client.send(putCommand); - } - }); -} - -export async function handler(event: LogRetentionEvent, context: AWSLambda.Context) { - try { - console.log(JSON.stringify({ ...event, ResponseURL: '...' })); - - // The target log group - const logGroupName = event.ResourceProperties.LogGroupName; - - // The region of the target log group - const logGroupRegion = event.ResourceProperties.LogGroupRegion; - - // Parse to AWS SDK retry options - const maxRetries = parseIntOptional(event.ResourceProperties.SdkRetry?.maxRetries) ?? 5; - const withDelay = makeWithDelay(maxRetries); - - const sdkConfig: Logs.CloudWatchLogsClientConfig = { - logger: console, - region: logGroupRegion, - maxAttempts: Math.max(5, maxRetries), // Use a minimum for SDK level retries, because it might include retryable failures that withDelay isn't checking for - }; - const client = new Logs.CloudWatchLogsClient(sdkConfig); - - if (event.RequestType === 'Create' || event.RequestType === 'Update') { - // Act on the target log group - await createLogGroupSafe(logGroupName, client, withDelay); - await setRetentionPolicy(logGroupName, client, withDelay, parseIntOptional(event.ResourceProperties.RetentionInDays)); - - // Configure the Log Group for the Custom Resource function itself - if (event.RequestType === 'Create') { - const clientForCustomResourceFunction = new Logs.CloudWatchLogsClient({ - logger: console, - region: process.env.AWS_REGION, - }); - // Set a retention policy of 1 day on the logs of this very function. - // Due to the async nature of the log group creation, the log group for this function might - // still be not created yet at this point. Therefore we attempt to create it. - // In case it is being created, createLogGroupSafe will handle the conflict. - await createLogGroupSafe(`/aws/lambda/${context.functionName}`, clientForCustomResourceFunction, withDelay); - // If createLogGroupSafe fails, the log group is not created even after multiple attempts. - // In this case we have nothing to set the retention policy on but an exception will skip - // the next line. - await setRetentionPolicy(`/aws/lambda/${context.functionName}`, clientForCustomResourceFunction, withDelay, 1); - } - } - - // When the requestType is delete, delete the log group if the removal policy is delete - if (event.RequestType === 'Delete' && event.ResourceProperties.RemovalPolicy === 'destroy') { - await deleteLogGroup(logGroupName, client, withDelay); - // else retain the log group - } - - await respond('SUCCESS', 'OK', logGroupName); - } catch (e: any) { - console.log(e); - await respond('FAILED', e.message, event.ResourceProperties.LogGroupName); - } - - function respond(responseStatus: string, reason: string, physicalResourceId: string) { - const responseBody = JSON.stringify({ - Status: responseStatus, - Reason: reason, - PhysicalResourceId: physicalResourceId, - StackId: event.StackId, - RequestId: event.RequestId, - LogicalResourceId: event.LogicalResourceId, - Data: { - // Add log group name as part of the response so that it's available via Fn::GetAtt - LogGroupName: event.ResourceProperties.LogGroupName, - }, - }); - - console.log('Responding', responseBody); - - // eslint-disable-next-line @typescript-eslint/no-require-imports - const parsedUrl = require('url').parse(event.ResponseURL); - const requestOptions = { - hostname: parsedUrl.hostname, - path: parsedUrl.path, - method: 'PUT', - headers: { - 'content-type': '', - 'content-length': Buffer.byteLength(responseBody, 'utf8'), - }, - }; - - return new Promise((resolve, reject) => { - try { - // eslint-disable-next-line @typescript-eslint/no-require-imports - const request = require('https').request(requestOptions, resolve); - request.on('error', reject); - request.write(responseBody); - request.end(); - } catch (e) { - reject(e); - } - }); - } -} - -function parseIntOptional(value?: string, base = 10): number | undefined { - if (value === undefined) { - return undefined; - } - - return parseInt(value, base); -} - -function makeWithDelay( - maxRetries: number, - delayBase: number = 100, - delayCap = 10 * 1000, // 10s -): (block: () => Promise) => Promise { - // If we try to update the log group, then due to the async nature of - // Lambda logging there could be a race condition when the same log group is - // already being created by the lambda execution. This can sometime result in - // an error "OperationAbortedException: A conflicting operation is currently - // in progress...Please try again." - // To avoid an error, we do as requested and try again. - - return async (block: () => Promise) => { - let attempts = 0; - do { - try { - return await block(); - } catch (error: any) { - if ( - error instanceof Logs.OperationAbortedException - || error.name === 'OperationAbortedException' - || error.name === 'ThrottlingException' // There is no class to check with instanceof, see https://github.com/aws/aws-sdk-js-v3/issues/5140 - ) { - if (attempts < maxRetries ) { - attempts++; - await new Promise(resolve => setTimeout(resolve, calculateDelay(attempts, delayBase, delayCap))); - continue; - } else { - // The log group is still being changed by another execution but we are out of retries - throw new Error('Out of attempts to change log group'); - } - } - throw error; - } - } while (true); // exit happens on retry count check - }; -} - -function calculateDelay(attempt: number, base: number, cap: number): number { - return Math.round(Math.random() * Math.min(cap, base * 2 ** attempt)); -} diff --git a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/asset.e4afb15788ec44ed9ff3377e1d131ba2768d7b2e2931bc000d1f2005879b3035/index.js b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/asset.e4afb15788ec44ed9ff3377e1d131ba2768d7b2e2931bc000d1f2005879b3035/index.js new file mode 100644 index 0000000000000..ae6165a46ea1e --- /dev/null +++ b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/asset.e4afb15788ec44ed9ff3377e1d131ba2768d7b2e2931bc000d1f2005879b3035/index.js @@ -0,0 +1 @@ +"use strict";var h=Object.create;var d=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var C=Object.getPrototypeOf,P=Object.prototype.hasOwnProperty;var b=(e,o)=>{for(var n in o)d(e,n,{get:o[n],enumerable:!0})},p=(e,o,n,t)=>{if(o&&typeof o=="object"||typeof o=="function")for(let r of f(o))!P.call(e,r)&&r!==n&&d(e,r,{get:()=>o[r],enumerable:!(t=w(o,r))||t.enumerable});return e};var S=(e,o,n)=>(n=e!=null?h(C(e)):{},p(o||!e||!e.__esModule?d(n,"default",{value:e,enumerable:!0}):n,e)),G=e=>p(d({},"__esModule",{value:!0}),e);var q={};b(q,{handler:()=>E});module.exports=G(q);var i=S(require("@aws-sdk/client-cloudwatch-logs"));async function R(e,o,n){await n(async()=>{try{let t={logGroupName:e},r=new i.CreateLogGroupCommand(t);await o.send(r)}catch(t){if(t.name==="ResourceAlreadyExistsException")return;throw t}})}async function x(e,o,n){await n(async()=>{try{let t={logGroupName:e},r=new i.DeleteLogGroupCommand(t);await o.send(r)}catch(t){if(t.name==="ResourceNotFoundException")return;throw t}})}async function y(e,o,n,t){await n(async()=>{if(t){let r={logGroupName:e,retentionInDays:t},s=new i.PutRetentionPolicyCommand(r);await o.send(s)}else{let r={logGroupName:e},s=new i.DeleteRetentionPolicyCommand(r);await o.send(s)}})}async function E(e,o){try{console.log(JSON.stringify({...e,ResponseURL:"..."}));let t=e.ResourceProperties.LogGroupName,r=e.ResourceProperties.LogGroupRegion,s=L(e.ResourceProperties.SdkRetry?.maxRetries)??5,a=I(s),m={logger:console,region:r,maxAttempts:Math.max(5,s)},c=new i.CloudWatchLogsClient(m);if((e.RequestType==="Create"||e.RequestType==="Update")&&(await R(t,c,a),await y(t,c,a,L(e.ResourceProperties.RetentionInDays)),e.RequestType==="Create")){let g=new i.CloudWatchLogsClient({logger:console,region:process.env.AWS_REGION});await R(`/aws/lambda/${o.functionName}`,g,a),await y(`/aws/lambda/${o.functionName}`,g,a,1)}e.RequestType==="Delete"&&e.ResourceProperties.RemovalPolicy==="destroy"&&await x(t,c,a),await n("SUCCESS","OK",t)}catch(t){console.log(t),await n("FAILED",t.message,e.ResourceProperties.LogGroupName)}function n(t,r,s){let a=JSON.stringify({Status:t,Reason:r,PhysicalResourceId:s,StackId:e.StackId,RequestId:e.RequestId,LogicalResourceId:e.LogicalResourceId,Data:{LogGroupName:e.ResourceProperties.LogGroupName}});console.log("Responding",a);let m=require("url").parse(e.ResponseURL),c={hostname:m.hostname,path:m.path,method:"PUT",headers:{"content-type":"","content-length":Buffer.byteLength(a,"utf8")}};return new Promise((g,l)=>{try{let u=require("https").request(c,g);u.on("error",l),u.write(a),u.end()}catch(u){l(u)}})}}function L(e,o=10){if(e!==void 0)return parseInt(e,o)}function I(e,o=100,n=10*1e3){return async t=>{let r=0;do try{return await t()}catch(s){if(s.name==="OperationAbortedException"||s.name==="ThrottlingException")if(rsetTimeout(a,k(r,o,n)));continue}else throw new Error("Out of attempts to change log group");throw s}while(!0)}}function k(e,o,n){return Math.round(Math.random()*Math.min(n,o*2**e))}0&&(module.exports={handler}); diff --git a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/aws-cdk-neptune-integ.assets.json b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/aws-cdk-neptune-integ.assets.json index 28615be1e1498..c919416d31418 100644 --- a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/aws-cdk-neptune-integ.assets.json +++ b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/aws-cdk-neptune-integ.assets.json @@ -1,20 +1,20 @@ { - "version": "34.0.0", + "version": "36.0.0", "files": { - "a8515c042d9c942705087943220417be929ac44f968d8fcef2681681b400c0c0": { + "e4afb15788ec44ed9ff3377e1d131ba2768d7b2e2931bc000d1f2005879b3035": { "source": { - "path": "asset.a8515c042d9c942705087943220417be929ac44f968d8fcef2681681b400c0c0", + "path": "asset.e4afb15788ec44ed9ff3377e1d131ba2768d7b2e2931bc000d1f2005879b3035", "packaging": "zip" }, "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "a8515c042d9c942705087943220417be929ac44f968d8fcef2681681b400c0c0.zip", + "objectKey": "e4afb15788ec44ed9ff3377e1d131ba2768d7b2e2931bc000d1f2005879b3035.zip", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } }, - "31a87fb5aef089dd280a31f79cc97e52f83ad369806b71883a396db15816a8d4": { + "6f53e0ab5a266567481c2d3d250ae20e1c8dd93706e7aaf5f4ebc4942db6ca62": { "source": { "path": "aws-cdk-neptune-integ.template.json", "packaging": "file" @@ -22,7 +22,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "31a87fb5aef089dd280a31f79cc97e52f83ad369806b71883a396db15816a8d4.json", + "objectKey": "6f53e0ab5a266567481c2d3d250ae20e1c8dd93706e7aaf5f4ebc4942db6ca62.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-neptune-alpha/test/integ.cluster.js.snapshot/aws-cdk-neptune-integ.template.json b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/aws-cdk-neptune-integ.template.json index edbf8c2936e38..d2ce907e3161b 100644 --- a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/aws-cdk-neptune-integ.template.json +++ b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/aws-cdk-neptune-integ.template.json @@ -430,7 +430,7 @@ "Type": "AWS::Neptune::DBClusterParameterGroup", "Properties": { "Description": "A nice parameter group", - "Family": "neptune1", + "Family": "neptune1.2", "Parameters": { "neptune_enable_audit_log": "1", "neptune_query_timeout": "100000" @@ -505,6 +505,7 @@ "EnableCloudwatchLogsExports": [ "audit" ], + "EngineVersion": "1.2.1.0", "KmsKeyId": { "Fn::GetAtt": [ "DbSecurity381C2C15", @@ -524,7 +525,7 @@ "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" }, - "DatabaseobjectObjectLogRetentionA247AF0C": { + "DatabaseauditLogRetention8A29F5CC": { "Type": "Custom::LogRetention", "Properties": { "ServiceToken": { @@ -631,7 +632,7 @@ "S3Bucket": { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "S3Key": "a8515c042d9c942705087943220417be929ac44f968d8fcef2681681b400c0c0.zip" + "S3Key": "e4afb15788ec44ed9ff3377e1d131ba2768d7b2e2931bc000d1f2005879b3035.zip" }, "Role": { "Fn::GetAtt": [ diff --git a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/cdk.out b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/cdk.out index 2313ab5436501..1f0068d32659a 100644 --- a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/cdk.out +++ b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"34.0.0"} \ No newline at end of file +{"version":"36.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/integ.json b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/integ.json index e7e257d602124..4d7b253875d40 100644 --- a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/integ.json +++ b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "34.0.0", + "version": "36.0.0", "testCases": { "ClusterTest/DefaultTest": { "stacks": [ diff --git a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/manifest.json b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/manifest.json index 6f3e6c0db8318..b643adda4f179 100644 --- a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/manifest.json +++ b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/manifest.json @@ -1,5 +1,5 @@ { - "version": "34.0.0", + "version": "36.0.0", "artifacts": { "aws-cdk-neptune-integ.assets": { "type": "cdk:asset-manifest", @@ -14,10 +14,11 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "aws-cdk-neptune-integ.template.json", + "terminationProtection": false, "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}/31a87fb5aef089dd280a31f79cc97e52f83ad369806b71883a396db15816a8d4.json", + "stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/6f53e0ab5a266567481c2d3d250ae20e1c8dd93706e7aaf5f4ebc4942db6ca62.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -207,10 +208,10 @@ "data": "DatabaseB269D8BB" } ], - "/aws-cdk-neptune-integ/Database/[object Object]LogRetention/Resource": [ + "/aws-cdk-neptune-integ/Database/auditLogRetention/Resource": [ { "type": "aws:cdk:logicalId", - "data": "DatabaseobjectObjectLogRetentionA247AF0C" + "data": "DatabaseauditLogRetention8A29F5CC" } ], "/aws-cdk-neptune-integ/Database/Instance1": [ @@ -271,6 +272,7 @@ "environment": "aws://unknown-account/unknown-region", "properties": { "templateFile": "ClusterTestDefaultTestDeployAssert6A1BBA9D.template.json", + "terminationProtection": false, "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}", diff --git a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/tree.json b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/tree.json index 6ab4ca12e4bcc..c08d4ad25445c 100644 --- a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/tree.json +++ b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.js.snapshot/tree.json @@ -713,7 +713,7 @@ "aws:cdk:cloudformation:type": "AWS::Neptune::DBClusterParameterGroup", "aws:cdk:cloudformation:props": { "description": "A nice parameter group", - "family": "neptune1", + "family": "neptune1.2", "parameters": { "neptune_enable_audit_log": "1", "neptune_query_timeout": "100000" @@ -850,6 +850,7 @@ "enableCloudwatchLogsExports": [ "audit" ], + "engineVersion": "1.2.1.0", "kmsKeyId": { "Fn::GetAtt": [ "DbSecurity381C2C15", @@ -872,13 +873,13 @@ "version": "0.0.0" } }, - "[object Object]LogRetention": { - "id": "[object Object]LogRetention", - "path": "aws-cdk-neptune-integ/Database/[object Object]LogRetention", + "auditLogRetention": { + "id": "auditLogRetention", + "path": "aws-cdk-neptune-integ/Database/auditLogRetention", "children": { "Resource": { "id": "Resource", - "path": "aws-cdk-neptune-integ/Database/[object Object]LogRetention/Resource", + "path": "aws-cdk-neptune-integ/Database/auditLogRetention/Resource", "constructInfo": { "fqn": "aws-cdk-lib.CfnResource", "version": "0.0.0" @@ -1054,7 +1055,7 @@ }, "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.70" + "version": "10.3.0" } }, "Alarm": { @@ -1130,7 +1131,7 @@ "path": "ClusterTest/DefaultTest/Default", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.70" + "version": "10.3.0" } }, "DeployAssert": { @@ -1176,7 +1177,7 @@ "path": "Tree", "constructInfo": { "fqn": "constructs.Construct", - "version": "10.2.70" + "version": "10.3.0" } } }, diff --git a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.ts b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.ts index c7703edeef279..9eb4e088b00d2 100644 --- a/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.ts +++ b/packages/@aws-cdk/aws-neptune-alpha/test/integ.cluster.ts @@ -4,8 +4,8 @@ import * as kms from 'aws-cdk-lib/aws-kms'; import * as logs from 'aws-cdk-lib/aws-logs'; import * as cdk from 'aws-cdk-lib'; import * as integ from '@aws-cdk/integ-tests-alpha'; -import { DatabaseCluster, InstanceType, LogType } from '../lib'; -import { ClusterParameterGroup } from '../lib/parameter-group'; +import { DatabaseCluster, EngineVersion, InstanceType, LogType } from '../lib'; +import { ClusterParameterGroup, ParameterGroupFamily } from '../lib/parameter-group'; /* * Test creating a cluster without specifying engine version. @@ -27,6 +27,7 @@ const kmsKey = new kms.Key(stack, 'DbSecurity', { const clusterParameterGroup = new ClusterParameterGroup(stack, 'Params', { description: 'A nice parameter group', + family: ParameterGroupFamily.NEPTUNE_1_2, parameters: { neptune_enable_audit_log: '1', neptune_query_timeout: '100000', @@ -37,6 +38,7 @@ const cluster = new DatabaseCluster(stack, 'Database', { vpc, vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, instanceType: InstanceType.R5_LARGE, + engineVersion: EngineVersion.V1_2_1_0, clusterParameterGroup, kmsKey, removalPolicy: cdk.RemovalPolicy.DESTROY,