diff --git a/packages/@aws-cdk/aws-redshift/README.md b/packages/@aws-cdk/aws-redshift/README.md index fcd48b57af0a6..e73ee4c361732 100644 --- a/packages/@aws-cdk/aws-redshift/README.md +++ b/packages/@aws-cdk/aws-redshift/README.md @@ -349,6 +349,25 @@ const cluster = new Cluster(this, 'Cluster', { cluster.addToParameterGroup('enable_user_activity_logging', 'true'); ``` +## Rebooting for Parameter Updates + +In most cases, existing clusters [must be manually rebooted](https://docs.aws.amazon.com/redshift/latest/mgmt/working-with-parameter-groups.html) to apply parameter changes. You can automate parameter related reboots by setting the cluster's `rebootForParameterChanges` property to `true` , or by using `Cluster.enableRebootForParameterChanges()`. + +```ts +declare const vpc: ec2.Vpc; + +const cluster = new Cluster(this, 'Cluster', { + masterUser: { + masterUsername: 'admin', + masterPassword: cdk.SecretValue.unsafePlainText('tooshort'), + }, + vpc, +}); + +cluster.addToParameterGroup('enable_user_activity_logging', 'true'); +cluster.enableRebootForParameterChanges() +``` + ## Elastic IP If you configure your cluster to be publicly accessible, you can optionally select an *elastic IP address* to use for the external IP address. An elastic IP address is a static IP address that is associated with your AWS account. You can use an elastic IP address to connect to your cluster from outside the VPC. An elastic IP address gives you the ability to change your underlying configuration without affecting the IP address that clients use to connect to your cluster. This approach can be helpful for situations such as recovery after a failure. diff --git a/packages/@aws-cdk/aws-redshift/lib/cluster-parameter-change-reboot-handler/index.ts b/packages/@aws-cdk/aws-redshift/lib/cluster-parameter-change-reboot-handler/index.ts new file mode 100644 index 0000000000000..ab7432375fc55 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/lib/cluster-parameter-change-reboot-handler/index.ts @@ -0,0 +1,53 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import { Redshift } from 'aws-sdk'; + +const redshift = new Redshift(); + +export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent): Promise { + if (event.RequestType !== 'Delete') { + return rebootClusterIfRequired(event.ResourceProperties?.ClusterId, event.ResourceProperties?.ParameterGroupName); + } else { + return; + } +} + +async function rebootClusterIfRequired(clusterId: string, parameterGroupName: string): Promise { + return executeActionForStatus(await getApplyStatus()); + + // https://docs.aws.amazon.com/redshift/latest/APIReference/API_ClusterParameterStatus.html + async function executeActionForStatus(status: string, retryDurationMs?: number): Promise { + await sleep(retryDurationMs ?? 0); + if (['pending-reboot', 'apply-deferred', 'apply-error'].includes(status)) { + try { + await redshift.rebootCluster({ ClusterIdentifier: clusterId }).promise(); + } catch (err) { + if ((err as any).code === 'InvalidClusterState') { + return await executeActionForStatus(status, 30000); + } else { + throw err; + } + } + return; + } else if (['applying', 'retry'].includes(status)) { + return executeActionForStatus(await getApplyStatus(), 30000); + } + return; + } + + async function getApplyStatus(): Promise { + const clusterDetails = await redshift.describeClusters({ ClusterIdentifier: clusterId }).promise(); + if (clusterDetails.Clusters?.[0].ClusterParameterGroups === undefined) { + throw new Error(`Unable to find any Parameter Groups associated with ClusterId "${clusterId}".`); + } + for (const group of clusterDetails.Clusters?.[0].ClusterParameterGroups) { + if (group.ParameterGroupName === parameterGroupName) { + return group.ParameterApplyStatus ?? 'retry'; + } + } + throw new Error(`Unable to find Parameter Group named "${parameterGroupName}" associated with ClusterId "${clusterId}".`); + } +} + +function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/lib/cluster.ts b/packages/@aws-cdk/aws-redshift/lib/cluster.ts index 50e3e5e1265a7..3e415604d035a 100644 --- a/packages/@aws-cdk/aws-redshift/lib/cluster.ts +++ b/packages/@aws-cdk/aws-redshift/lib/cluster.ts @@ -1,17 +1,18 @@ +import * as path from 'path'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as iam from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; +import * as lambda from '@aws-cdk/aws-lambda'; import * as s3 from '@aws-cdk/aws-s3'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; -import { Duration, IResource, Lazy, RemovalPolicy, Resource, SecretValue, Token } from '@aws-cdk/core'; -import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId } from '@aws-cdk/custom-resources'; +import { ArnFormat, CustomResource, Duration, IResource, Lazy, RemovalPolicy, Resource, SecretValue, Stack, Token } from '@aws-cdk/core'; +import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId, Provider } from '@aws-cdk/custom-resources'; import { Construct } from 'constructs'; import { DatabaseSecret } from './database-secret'; import { Endpoint } from './endpoint'; import { ClusterParameterGroup, IClusterParameterGroup } from './parameter-group'; import { CfnCluster } from './redshift.generated'; import { ClusterSubnetGroup, IClusterSubnetGroup } from './subnet-group'; - /** * Possible Node Types to use in the cluster * used for defining `ClusterProps.nodeType`. @@ -364,6 +365,12 @@ export interface ClusterProps { */ readonly elasticIp?: string + /** + * If this flag is set, the cluster will be rebooted when changes to the cluster's parameter group that require a restart to apply. + * @default false + */ + readonly rebootForParameterChanges?: boolean + /** * If this flag is set, Amazon Redshift forces all COPY and UNLOAD traffic between your cluster and your data repositories through your virtual private cloud (VPC). * @@ -592,7 +599,9 @@ export class Cluster extends ClusterBase { const defaultPort = ec2.Port.tcp(this.clusterEndpoint.port); this.connections = new ec2.Connections({ securityGroups, defaultPort }); - + if (props.rebootForParameterChanges) { + this.enableRebootForParameterChanges(); + } // Add default role if specified and also available in the roles list if (props.defaultRole) { if (props.roles?.some(x => x === props.defaultRole)) { @@ -689,6 +698,71 @@ export class Cluster extends ClusterBase { } } + /** + * Enables automatic cluster rebooting when changes to the cluster's parameter group require a restart to apply. + */ + public enableRebootForParameterChanges(): void { + if (this.node.tryFindChild('RedshiftClusterRebooterCustomResource')) { + return; + } + const rebootFunction = new lambda.SingletonFunction(this, 'RedshiftClusterRebooterFunction', { + uuid: '511e207f-13df-4b8b-b632-c32b30b65ac2', + runtime: lambda.Runtime.NODEJS_16_X, + code: lambda.Code.fromAsset(path.join(__dirname, 'cluster-parameter-change-reboot-handler')), + handler: 'index.handler', + timeout: Duration.seconds(900), + }); + rebootFunction.addToRolePolicy(new iam.PolicyStatement({ + actions: ['redshift:DescribeClusters'], + resources: ['*'], + })); + rebootFunction.addToRolePolicy(new iam.PolicyStatement({ + actions: ['redshift:RebootCluster'], + resources: [ + Stack.of(this).formatArn({ + service: 'redshift', + resource: 'cluster', + resourceName: this.clusterName, + arnFormat: ArnFormat.COLON_RESOURCE_NAME, + }), + ], + })); + const provider = new Provider(this, 'ResourceProvider', { + onEventHandler: rebootFunction, + }); + const customResource = new CustomResource(this, 'RedshiftClusterRebooterCustomResource', { + resourceType: 'Custom::RedshiftClusterRebooter', + serviceToken: provider.serviceToken, + properties: { + ClusterId: this.clusterName, + ParameterGroupName: Lazy.string({ + produce: () => { + if (!this.parameterGroup) { + throw new Error('Cannot enable reboot for parameter changes when there is no associated ClusterParameterGroup.'); + } + return this.parameterGroup.clusterParameterGroupName; + }, + }), + ParametersString: Lazy.string({ + produce: () => { + if (!(this.parameterGroup instanceof ClusterParameterGroup)) { + throw new Error('Cannot enable reboot for parameter changes when using an imported parameter group.'); + } + return JSON.stringify(this.parameterGroup.parameters); + }, + }), + }, + }); + Lazy.any({ + produce: () => { + if (!this.parameterGroup) { + throw new Error('Cannot enable reboot for parameter changes when there is no associated ClusterParameterGroup.'); + } + customResource.node.addDependency(this, this.parameterGroup); + }, + }); + } + /** * Adds default IAM role to cluster. The default IAM role must be already associated to the cluster to be added as the default role. * diff --git a/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e/index.d.ts b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e/index.d.ts new file mode 100644 index 0000000000000..3554dc94d4617 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e/index.d.ts @@ -0,0 +1 @@ +export declare function handler(event: AWSLambda.CloudFormationCustomResourceEvent): Promise; diff --git a/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e/index.js b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e/index.js new file mode 100644 index 0000000000000..1113eac7f709c --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e/index.js @@ -0,0 +1,56 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.handler = void 0; +// eslint-disable-next-line import/no-extraneous-dependencies +const aws_sdk_1 = require("aws-sdk"); +const redshift = new aws_sdk_1.Redshift(); +async function handler(event) { + if (event.RequestType !== 'Delete') { + return rebootClusterIfRequired(event.ResourceProperties?.ClusterId, event.ResourceProperties?.ParameterGroupName); + } + else { + return; + } +} +exports.handler = handler; +async function rebootClusterIfRequired(clusterId, parameterGroupName) { + return executeActionForStatus(await getApplyStatus()); + // https://docs.aws.amazon.com/redshift/latest/APIReference/API_ClusterParameterStatus.html + async function executeActionForStatus(status, retryDurationMs) { + await sleep(retryDurationMs ?? 0); + if (['pending-reboot', 'apply-deferred', 'apply-error', 'unknown-error'].includes(status)) { + try { + await redshift.rebootCluster({ ClusterIdentifier: clusterId }).promise(); + } + catch (err) { + if (err.code === 'InvalidClusterState') { + return await executeActionForStatus(status, 30000); + } + else { + throw err; + } + } + return; + } + else if (['applying', 'retry'].includes(status)) { + return executeActionForStatus(await getApplyStatus(), 30000); + } + return; + } + async function getApplyStatus() { + const clusterDetails = await redshift.describeClusters({ ClusterIdentifier: clusterId }).promise(); + if (clusterDetails.Clusters?.[0].ClusterParameterGroups === undefined) { + throw new Error(`Unable to find any Parameter Groups associated with ClusterId "${clusterId}".`); + } + for (const group of clusterDetails.Clusters?.[0].ClusterParameterGroups) { + if (group.ParameterGroupName === parameterGroupName) { + return group.ParameterApplyStatus ?? 'retry'; + } + } + throw new Error(`Unable to find Parameter Group named "${parameterGroupName}" associated with ClusterId "${clusterId}".`); + } +} +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJpbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSw2REFBNkQ7QUFDN0QscUNBQW1DO0FBRW5DLE1BQU0sUUFBUSxHQUFHLElBQUksa0JBQVEsRUFBRSxDQUFDO0FBRXpCLEtBQUssVUFBVSxPQUFPLENBQUMsS0FBa0Q7SUFDOUUsSUFBSSxLQUFLLENBQUMsV0FBVyxLQUFLLFFBQVEsRUFBRTtRQUNsQyxPQUFPLHVCQUF1QixDQUFDLEtBQUssQ0FBQyxrQkFBa0IsRUFBRSxTQUFTLEVBQUUsS0FBSyxDQUFDLGtCQUFrQixFQUFFLGtCQUFrQixDQUFDLENBQUM7S0FDbkg7U0FBTTtRQUNMLE9BQU87S0FDUjtBQUNILENBQUM7QUFORCwwQkFNQztBQUVELEtBQUssVUFBVSx1QkFBdUIsQ0FBQyxTQUFpQixFQUFFLGtCQUEwQjtJQUNsRixPQUFPLHNCQUFzQixDQUFDLE1BQU0sY0FBYyxFQUFFLENBQUMsQ0FBQztJQUV0RCwyRkFBMkY7SUFDM0YsS0FBSyxVQUFVLHNCQUFzQixDQUFDLE1BQWMsRUFBRSxlQUF3QjtRQUM1RSxNQUFNLEtBQUssQ0FBQyxlQUFlLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDbEMsSUFBSSxDQUFDLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLGFBQWEsRUFBRSxlQUFlLENBQUMsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEVBQUU7WUFDekYsSUFBSTtnQkFDRixNQUFNLFFBQVEsQ0FBQyxhQUFhLENBQUMsRUFBRSxpQkFBaUIsRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDO2FBQzFFO1lBQUMsT0FBTyxHQUFHLEVBQUU7Z0JBQ1osSUFBVSxHQUFJLENBQUMsSUFBSSxLQUFLLHFCQUFxQixFQUFFO29CQUM3QyxPQUFPLE1BQU0sc0JBQXNCLENBQUMsTUFBTSxFQUFFLEtBQUssQ0FBQyxDQUFDO2lCQUNwRDtxQkFBTTtvQkFDTCxNQUFNLEdBQUcsQ0FBQztpQkFDWDthQUNGO1lBQ0QsT0FBTztTQUNSO2FBQU0sSUFBSSxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLEVBQUU7WUFDakQsT0FBTyxzQkFBc0IsQ0FBQyxNQUFNLGNBQWMsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO1NBQzlEO1FBQ0QsT0FBTztJQUNULENBQUM7SUFFRCxLQUFLLFVBQVUsY0FBYztRQUMzQixNQUFNLGNBQWMsR0FBRyxNQUFNLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLGlCQUFpQixFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDbkcsSUFBSSxjQUFjLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsc0JBQXNCLEtBQUssU0FBUyxFQUFFO1lBQ3JFLE1BQU0sSUFBSSxLQUFLLENBQUMsa0VBQWtFLFNBQVMsSUFBSSxDQUFDLENBQUM7U0FDbEc7UUFDRCxLQUFLLE1BQU0sS0FBSyxJQUFJLGNBQWMsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxzQkFBc0IsRUFBRTtZQUN2RSxJQUFJLEtBQUssQ0FBQyxrQkFBa0IsS0FBSyxrQkFBa0IsRUFBRTtnQkFDbkQsT0FBTyxLQUFLLENBQUMsb0JBQW9CLElBQUksT0FBTyxDQUFDO2FBQzlDO1NBQ0Y7UUFDRCxNQUFNLElBQUksS0FBSyxDQUFDLHlDQUF5QyxrQkFBa0IsZ0NBQWdDLFNBQVMsSUFBSSxDQUFDLENBQUM7SUFDNUgsQ0FBQztBQUNILENBQUM7QUFFRCxTQUFTLEtBQUssQ0FBQyxFQUFVO0lBQ3ZCLE9BQU8sSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUM7QUFDekQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXNcbmltcG9ydCB7IFJlZHNoaWZ0IH0gZnJvbSAnYXdzLXNkayc7XG5cbmNvbnN0IHJlZHNoaWZ0ID0gbmV3IFJlZHNoaWZ0KCk7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBoYW5kbGVyKGV2ZW50OiBBV1NMYW1iZGEuQ2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUV2ZW50KTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmIChldmVudC5SZXF1ZXN0VHlwZSAhPT0gJ0RlbGV0ZScpIHtcbiAgICByZXR1cm4gcmVib290Q2x1c3RlcklmUmVxdWlyZWQoZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzPy5DbHVzdGVySWQsIGV2ZW50LlJlc291cmNlUHJvcGVydGllcz8uUGFyYW1ldGVyR3JvdXBOYW1lKTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm47XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVib290Q2x1c3RlcklmUmVxdWlyZWQoY2x1c3RlcklkOiBzdHJpbmcsIHBhcmFtZXRlckdyb3VwTmFtZTogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIHJldHVybiBleGVjdXRlQWN0aW9uRm9yU3RhdHVzKGF3YWl0IGdldEFwcGx5U3RhdHVzKCkpO1xuXG4gIC8vIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9yZWRzaGlmdC9sYXRlc3QvQVBJUmVmZXJlbmNlL0FQSV9DbHVzdGVyUGFyYW1ldGVyU3RhdHVzLmh0bWxcbiAgYXN5bmMgZnVuY3Rpb24gZXhlY3V0ZUFjdGlvbkZvclN0YXR1cyhzdGF0dXM6IHN0cmluZywgcmV0cnlEdXJhdGlvbk1zPzogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgYXdhaXQgc2xlZXAocmV0cnlEdXJhdGlvbk1zID8/IDApO1xuICAgIGlmIChbJ3BlbmRpbmctcmVib290JywgJ2FwcGx5LWRlZmVycmVkJywgJ2FwcGx5LWVycm9yJywgJ3Vua25vd24tZXJyb3InXS5pbmNsdWRlcyhzdGF0dXMpKSB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCByZWRzaGlmdC5yZWJvb3RDbHVzdGVyKHsgQ2x1c3RlcklkZW50aWZpZXI6IGNsdXN0ZXJJZCB9KS5wcm9taXNlKCk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgaWYgKCg8YW55PmVycikuY29kZSA9PT0gJ0ludmFsaWRDbHVzdGVyU3RhdGUnKSB7XG4gICAgICAgICAgcmV0dXJuIGF3YWl0IGV4ZWN1dGVBY3Rpb25Gb3JTdGF0dXMoc3RhdHVzLCAzMDAwMCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm47XG4gICAgfSBlbHNlIGlmIChbJ2FwcGx5aW5nJywgJ3JldHJ5J10uaW5jbHVkZXMoc3RhdHVzKSkge1xuICAgICAgcmV0dXJuIGV4ZWN1dGVBY3Rpb25Gb3JTdGF0dXMoYXdhaXQgZ2V0QXBwbHlTdGF0dXMoKSwgMzAwMDApO1xuICAgIH1cbiAgICByZXR1cm47XG4gIH1cblxuICBhc3luYyBmdW5jdGlvbiBnZXRBcHBseVN0YXR1cygpOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIGNvbnN0IGNsdXN0ZXJEZXRhaWxzID0gYXdhaXQgcmVkc2hpZnQuZGVzY3JpYmVDbHVzdGVycyh7IENsdXN0ZXJJZGVudGlmaWVyOiBjbHVzdGVySWQgfSkucHJvbWlzZSgpO1xuICAgIGlmIChjbHVzdGVyRGV0YWlscy5DbHVzdGVycz8uWzBdLkNsdXN0ZXJQYXJhbWV0ZXJHcm91cHMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gZmluZCBhbnkgUGFyYW1ldGVyIEdyb3VwcyBhc3NvY2lhdGVkIHdpdGggQ2x1c3RlcklkIFwiJHtjbHVzdGVySWR9XCIuYCk7XG4gICAgfVxuICAgIGZvciAoY29uc3QgZ3JvdXAgb2YgY2x1c3RlckRldGFpbHMuQ2x1c3RlcnM/LlswXS5DbHVzdGVyUGFyYW1ldGVyR3JvdXBzKSB7XG4gICAgICBpZiAoZ3JvdXAuUGFyYW1ldGVyR3JvdXBOYW1lID09PSBwYXJhbWV0ZXJHcm91cE5hbWUpIHtcbiAgICAgICAgcmV0dXJuIGdyb3VwLlBhcmFtZXRlckFwcGx5U3RhdHVzID8/ICdyZXRyeSc7XG4gICAgICB9XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihgVW5hYmxlIHRvIGZpbmQgUGFyYW1ldGVyIEdyb3VwIG5hbWVkIFwiJHtwYXJhbWV0ZXJHcm91cE5hbWV9XCIgYXNzb2NpYXRlZCB3aXRoIENsdXN0ZXJJZCBcIiR7Y2x1c3RlcklkfVwiLmApO1xuICB9XG59XG5cbmZ1bmN0aW9uIHNsZWVwKG1zOiBudW1iZXIpIHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKHJlc29sdmUgPT4gc2V0VGltZW91dChyZXNvbHZlLCBtcykpO1xufSJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e/index.ts b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e/index.ts new file mode 100644 index 0000000000000..f69314783b600 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e/index.ts @@ -0,0 +1,53 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import { Redshift } from 'aws-sdk'; + +const redshift = new Redshift(); + +export async function handler(event: AWSLambda.CloudFormationCustomResourceEvent): Promise { + if (event.RequestType !== 'Delete') { + return rebootClusterIfRequired(event.ResourceProperties?.ClusterId, event.ResourceProperties?.ParameterGroupName); + } else { + return; + } +} + +async function rebootClusterIfRequired(clusterId: string, parameterGroupName: string): Promise { + return executeActionForStatus(await getApplyStatus()); + + // https://docs.aws.amazon.com/redshift/latest/APIReference/API_ClusterParameterStatus.html + async function executeActionForStatus(status: string, retryDurationMs?: number): Promise { + await sleep(retryDurationMs ?? 0); + if (['pending-reboot', 'apply-deferred', 'apply-error', 'unknown-error'].includes(status)) { + try { + await redshift.rebootCluster({ ClusterIdentifier: clusterId }).promise(); + } catch (err) { + if ((err).code === 'InvalidClusterState') { + return await executeActionForStatus(status, 30000); + } else { + throw err; + } + } + return; + } else if (['applying', 'retry'].includes(status)) { + return executeActionForStatus(await getApplyStatus(), 30000); + } + return; + } + + async function getApplyStatus(): Promise { + const clusterDetails = await redshift.describeClusters({ ClusterIdentifier: clusterId }).promise(); + if (clusterDetails.Clusters?.[0].ClusterParameterGroups === undefined) { + throw new Error(`Unable to find any Parameter Groups associated with ClusterId "${clusterId}".`); + } + for (const group of clusterDetails.Clusters?.[0].ClusterParameterGroups) { + if (group.ParameterGroupName === parameterGroupName) { + return group.ParameterApplyStatus ?? 'retry'; + } + } + throw new Error(`Unable to find Parameter Group named "${parameterGroupName}" associated with ClusterId "${clusterId}".`); + } +} + +function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037/cfn-response.js b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037/cfn-response.js new file mode 100644 index 0000000000000..1966567b21646 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037/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/cluster-reboot.integ.snapshot/asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037/consts.js b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037/consts.js new file mode 100644 index 0000000000000..31faa077ae313 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037/consts.js @@ -0,0 +1,10 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.FRAMEWORK_ON_TIMEOUT_HANDLER_NAME = exports.FRAMEWORK_IS_COMPLETE_HANDLER_NAME = exports.FRAMEWORK_ON_EVENT_HANDLER_NAME = exports.WAITER_STATE_MACHINE_ARN_ENV = exports.USER_IS_COMPLETE_FUNCTION_ARN_ENV = exports.USER_ON_EVENT_FUNCTION_ARN_ENV = void 0; +exports.USER_ON_EVENT_FUNCTION_ARN_ENV = 'USER_ON_EVENT_FUNCTION_ARN'; +exports.USER_IS_COMPLETE_FUNCTION_ARN_ENV = 'USER_IS_COMPLETE_FUNCTION_ARN'; +exports.WAITER_STATE_MACHINE_ARN_ENV = 'WAITER_STATE_MACHINE_ARN'; +exports.FRAMEWORK_ON_EVENT_HANDLER_NAME = 'onEvent'; +exports.FRAMEWORK_IS_COMPLETE_HANDLER_NAME = 'isComplete'; +exports.FRAMEWORK_ON_TIMEOUT_HANDLER_NAME = 'onTimeout'; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiY29uc3RzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFhLFFBQUEsOEJBQThCLEdBQUcsNEJBQTRCLENBQUM7QUFDOUQsUUFBQSxpQ0FBaUMsR0FBRywrQkFBK0IsQ0FBQztBQUNwRSxRQUFBLDRCQUE0QixHQUFHLDBCQUEwQixDQUFDO0FBRTFELFFBQUEsK0JBQStCLEdBQUcsU0FBUyxDQUFDO0FBQzVDLFFBQUEsa0NBQWtDLEdBQUcsWUFBWSxDQUFDO0FBQ2xELFFBQUEsaUNBQWlDLEdBQUcsV0FBVyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGNvbnN0IFVTRVJfT05fRVZFTlRfRlVOQ1RJT05fQVJOX0VOViA9ICdVU0VSX09OX0VWRU5UX0ZVTkNUSU9OX0FSTic7XG5leHBvcnQgY29uc3QgVVNFUl9JU19DT01QTEVURV9GVU5DVElPTl9BUk5fRU5WID0gJ1VTRVJfSVNfQ09NUExFVEVfRlVOQ1RJT05fQVJOJztcbmV4cG9ydCBjb25zdCBXQUlURVJfU1RBVEVfTUFDSElORV9BUk5fRU5WID0gJ1dBSVRFUl9TVEFURV9NQUNISU5FX0FSTic7XG5cbmV4cG9ydCBjb25zdCBGUkFNRVdPUktfT05fRVZFTlRfSEFORExFUl9OQU1FID0gJ29uRXZlbnQnO1xuZXhwb3J0IGNvbnN0IEZSQU1FV09SS19JU19DT01QTEVURV9IQU5ETEVSX05BTUUgPSAnaXNDb21wbGV0ZSc7XG5leHBvcnQgY29uc3QgRlJBTUVXT1JLX09OX1RJTUVPVVRfSEFORExFUl9OQU1FID0gJ29uVGltZW91dCc7XG4iXX0= \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037/framework.js b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037/framework.js new file mode 100644 index 0000000000000..3f8a03e88aae0 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037/framework.js @@ -0,0 +1,168 @@ +"use strict"; +const cfnResponse = require("./cfn-response"); +const consts = require("./consts"); +const outbound_1 = require("./outbound"); +const util_1 = require("./util"); +/** + * The main runtime entrypoint of the async custom resource lambda function. + * + * Any lifecycle event changes to the custom resources will invoke this handler, which will, in turn, + * interact with the user-defined `onEvent` and `isComplete` handlers. + * + * This function will always succeed. If an error occurs + * + * @param cfnRequest The cloudformation custom resource event. + */ +async function onEvent(cfnRequest) { + const sanitizedRequest = { ...cfnRequest, ResponseURL: '...' }; + util_1.log('onEventHandler', sanitizedRequest); + cfnRequest.ResourceProperties = cfnRequest.ResourceProperties || {}; + const onEventResult = await invokeUserFunction(consts.USER_ON_EVENT_FUNCTION_ARN_ENV, sanitizedRequest, cfnRequest.ResponseURL); + util_1.log('onEvent returned:', onEventResult); + // merge the request and the result from onEvent to form the complete resource event + // this also performs validation. + const resourceEvent = createResponseEvent(cfnRequest, onEventResult); + util_1.log('event:', onEventResult); + // determine if this is an async provider based on whether we have an isComplete handler defined. + // if it is not defined, then we are basically ready to return a positive response. + if (!process.env[consts.USER_IS_COMPLETE_FUNCTION_ARN_ENV]) { + return cfnResponse.submitResponse('SUCCESS', resourceEvent, { noEcho: resourceEvent.NoEcho }); + } + // ok, we are not complete, so kick off the waiter workflow + const waiter = { + stateMachineArn: util_1.getEnv(consts.WAITER_STATE_MACHINE_ARN_ENV), + name: resourceEvent.RequestId, + input: JSON.stringify(resourceEvent), + }; + util_1.log('starting waiter', waiter); + // kick off waiter state machine + await outbound_1.startExecution(waiter); +} +// invoked a few times until `complete` is true or until it times out. +async function isComplete(event) { + const sanitizedRequest = { ...event, ResponseURL: '...' }; + util_1.log('isComplete', sanitizedRequest); + const isCompleteResult = await invokeUserFunction(consts.USER_IS_COMPLETE_FUNCTION_ARN_ENV, sanitizedRequest, event.ResponseURL); + util_1.log('user isComplete returned:', isCompleteResult); + // if we are not complete, return false, and don't send a response back. + if (!isCompleteResult.IsComplete) { + if (isCompleteResult.Data && Object.keys(isCompleteResult.Data).length > 0) { + throw new Error('"Data" is not allowed if "IsComplete" is "False"'); + } + // This must be the full event, it will be deserialized in `onTimeout` to send the response to CloudFormation + throw new cfnResponse.Retry(JSON.stringify(event)); + } + const response = { + ...event, + ...isCompleteResult, + Data: { + ...event.Data, + ...isCompleteResult.Data, + }, + }; + await cfnResponse.submitResponse('SUCCESS', response, { noEcho: event.NoEcho }); +} +// invoked when completion retries are exhaused. +async function onTimeout(timeoutEvent) { + util_1.log('timeoutHandler', timeoutEvent); + const isCompleteRequest = JSON.parse(JSON.parse(timeoutEvent.Cause).errorMessage); + await cfnResponse.submitResponse('FAILED', isCompleteRequest, { + reason: 'Operation timed out', + }); +} +async function invokeUserFunction(functionArnEnv, sanitizedPayload, responseUrl) { + const functionArn = util_1.getEnv(functionArnEnv); + util_1.log(`executing user function ${functionArn} with payload`, sanitizedPayload); + // transient errors such as timeouts, throttling errors (429), and other + // errors that aren't caused by a bad request (500 series) are retried + // automatically by the JavaScript SDK. + const resp = await outbound_1.invokeFunction({ + FunctionName: functionArn, + // Cannot strip 'ResponseURL' here as this would be a breaking change even though the downstream CR doesn't need it + Payload: JSON.stringify({ ...sanitizedPayload, ResponseURL: responseUrl }), + }); + util_1.log('user function response:', resp, typeof (resp)); + const jsonPayload = parseJsonPayload(resp.Payload); + if (resp.FunctionError) { + util_1.log('user function threw an error:', resp.FunctionError); + const errorMessage = jsonPayload.errorMessage || 'error'; + // parse function name from arn + // arn:${Partition}:lambda:${Region}:${Account}:function:${FunctionName} + const arn = functionArn.split(':'); + const functionName = arn[arn.length - 1]; + // append a reference to the log group. + const message = [ + errorMessage, + '', + `Logs: /aws/lambda/${functionName}`, + '', + ].join('\n'); + const e = new Error(message); + // the output that goes to CFN is what's in `stack`, not the error message. + // if we have a remote trace, construct a nice message with log group information + if (jsonPayload.trace) { + // skip first trace line because it's the message + e.stack = [message, ...jsonPayload.trace.slice(1)].join('\n'); + } + throw e; + } + return jsonPayload; +} +function parseJsonPayload(payload) { + if (!payload) { + return {}; + } + const text = payload.toString(); + try { + return JSON.parse(text); + } + catch (e) { + throw new Error(`return values from user-handlers must be JSON objects. got: "${text}"`); + } +} +function createResponseEvent(cfnRequest, onEventResult) { + // + // validate that onEventResult always includes a PhysicalResourceId + onEventResult = onEventResult || {}; + // if physical ID is not returned, we have some defaults for you based + // on the request type. + const physicalResourceId = onEventResult.PhysicalResourceId || defaultPhysicalResourceId(cfnRequest); + // if we are in DELETE and physical ID was changed, it's an error. + if (cfnRequest.RequestType === 'Delete' && physicalResourceId !== cfnRequest.PhysicalResourceId) { + throw new Error(`DELETE: cannot change the physical resource ID from "${cfnRequest.PhysicalResourceId}" to "${onEventResult.PhysicalResourceId}" during deletion`); + } + // if we are in UPDATE and physical ID was changed, it's a replacement (just log) + if (cfnRequest.RequestType === 'Update' && physicalResourceId !== cfnRequest.PhysicalResourceId) { + util_1.log(`UPDATE: changing physical resource ID from "${cfnRequest.PhysicalResourceId}" to "${onEventResult.PhysicalResourceId}"`); + } + // merge request event and result event (result prevails). + return { + ...cfnRequest, + ...onEventResult, + PhysicalResourceId: physicalResourceId, + }; +} +/** + * Calculates the default physical resource ID based in case user handler did + * not return a PhysicalResourceId. + * + * For "CREATE", it uses the RequestId. + * For "UPDATE" and "DELETE" and returns the current PhysicalResourceId (the one provided in `event`). + */ +function defaultPhysicalResourceId(req) { + switch (req.RequestType) { + case 'Create': + return req.RequestId; + case 'Update': + case 'Delete': + return req.PhysicalResourceId; + default: + throw new Error(`Invalid "RequestType" in request "${JSON.stringify(req)}"`); + } +} +module.exports = { + [consts.FRAMEWORK_ON_EVENT_HANDLER_NAME]: cfnResponse.safeHandler(onEvent), + [consts.FRAMEWORK_IS_COMPLETE_HANDLER_NAME]: cfnResponse.safeHandler(isComplete), + [consts.FRAMEWORK_ON_TIMEOUT_HANDLER_NAME]: onTimeout, +}; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnJhbWV3b3JrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZnJhbWV3b3JrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFHQSw4Q0FBOEM7QUFDOUMsbUNBQW1DO0FBQ25DLHlDQUE0RDtBQUM1RCxpQ0FBcUM7QUFTckM7Ozs7Ozs7OztHQVNHO0FBQ0gsS0FBSyxVQUFVLE9BQU8sQ0FBQyxVQUF1RDtJQUM1RSxNQUFNLGdCQUFnQixHQUFHLEVBQUUsR0FBRyxVQUFVLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBVyxDQUFDO0lBQ3hFLFVBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDO0lBRXhDLFVBQVUsQ0FBQyxrQkFBa0IsR0FBRyxVQUFVLENBQUMsa0JBQWtCLElBQUksRUFBRyxDQUFDO0lBRXJFLE1BQU0sYUFBYSxHQUFHLE1BQU0sa0JBQWtCLENBQUMsTUFBTSxDQUFDLDhCQUE4QixFQUFFLGdCQUFnQixFQUFFLFVBQVUsQ0FBQyxXQUFXLENBQW9CLENBQUM7SUFDbkosVUFBRyxDQUFDLG1CQUFtQixFQUFFLGFBQWEsQ0FBQyxDQUFDO0lBRXhDLG9GQUFvRjtJQUNwRixpQ0FBaUM7SUFDakMsTUFBTSxhQUFhLEdBQUcsbUJBQW1CLENBQUMsVUFBVSxFQUFFLGFBQWEsQ0FBQyxDQUFDO0lBQ3JFLFVBQUcsQ0FBQyxRQUFRLEVBQUUsYUFBYSxDQUFDLENBQUM7SUFFN0IsaUdBQWlHO0lBQ2pHLG1GQUFtRjtJQUNuRixJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsaUNBQWlDLENBQUMsRUFBRTtRQUMxRCxPQUFPLFdBQVcsQ0FBQyxjQUFjLENBQUMsU0FBUyxFQUFFLGFBQWEsRUFBRSxFQUFFLE1BQU0sRUFBRSxhQUFhLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztLQUMvRjtJQUVELDJEQUEyRDtJQUMzRCxNQUFNLE1BQU0sR0FBRztRQUNiLGVBQWUsRUFBRSxhQUFNLENBQUMsTUFBTSxDQUFDLDRCQUE0QixDQUFDO1FBQzVELElBQUksRUFBRSxhQUFhLENBQUMsU0FBUztRQUM3QixLQUFLLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxhQUFhLENBQUM7S0FDckMsQ0FBQztJQUVGLFVBQUcsQ0FBQyxpQkFBaUIsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUUvQixnQ0FBZ0M7SUFDaEMsTUFBTSx5QkFBYyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0FBQy9CLENBQUM7QUFFRCxzRUFBc0U7QUFDdEUsS0FBSyxVQUFVLFVBQVUsQ0FBQyxLQUFrRDtJQUMxRSxNQUFNLGdCQUFnQixHQUFHLEVBQUUsR0FBRyxLQUFLLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBVyxDQUFDO0lBQ25FLFVBQUcsQ0FBQyxZQUFZLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztJQUVwQyxNQUFNLGdCQUFnQixHQUFHLE1BQU0sa0JBQWtCLENBQUMsTUFBTSxDQUFDLGlDQUFpQyxFQUFFLGdCQUFnQixFQUFFLEtBQUssQ0FBQyxXQUFXLENBQXVCLENBQUM7SUFDdkosVUFBRyxDQUFDLDJCQUEyQixFQUFFLGdCQUFnQixDQUFDLENBQUM7SUFFbkQsd0VBQXdFO0lBQ3hFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxVQUFVLEVBQUU7UUFDaEMsSUFBSSxnQkFBZ0IsQ0FBQyxJQUFJLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1lBQzFFLE1BQU0sSUFBSSxLQUFLLENBQUMsa0RBQWtELENBQUMsQ0FBQztTQUNyRTtRQUVELDZHQUE2RztRQUM3RyxNQUFNLElBQUksV0FBVyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7S0FDcEQ7SUFFRCxNQUFNLFFBQVEsR0FBRztRQUNmLEdBQUcsS0FBSztRQUNSLEdBQUcsZ0JBQWdCO1FBQ25CLElBQUksRUFBRTtZQUNKLEdBQUcsS0FBSyxDQUFDLElBQUk7WUFDYixHQUFHLGdCQUFnQixDQUFDLElBQUk7U0FDekI7S0FDRixDQUFDO0lBRUYsTUFBTSxXQUFXLENBQUMsY0FBYyxDQUFDLFNBQVMsRUFBRSxRQUFRLEVBQUUsRUFBRSxNQUFNLEVBQUUsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7QUFDbEYsQ0FBQztBQUVELGdEQUFnRDtBQUNoRCxLQUFLLFVBQVUsU0FBUyxDQUFDLFlBQWlCO0lBQ3hDLFVBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxZQUFZLENBQUMsQ0FBQztJQUVwQyxNQUFNLGlCQUFpQixHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUMsWUFBWSxDQUFnRCxDQUFDO0lBQ2pJLE1BQU0sV0FBVyxDQUFDLGNBQWMsQ0FBQyxRQUFRLEVBQUUsaUJBQWlCLEVBQUU7UUFDNUQsTUFBTSxFQUFFLHFCQUFxQjtLQUM5QixDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsS0FBSyxVQUFVLGtCQUFrQixDQUFtQyxjQUFzQixFQUFFLGdCQUFtQixFQUFFLFdBQW1CO0lBQ2xJLE1BQU0sV0FBVyxHQUFHLGFBQU0sQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUMzQyxVQUFHLENBQUMsMkJBQTJCLFdBQVcsZUFBZSxFQUFFLGdCQUFnQixDQUFDLENBQUM7SUFFN0Usd0VBQXdFO0lBQ3hFLHNFQUFzRTtJQUN0RSx1Q0FBdUM7SUFDdkMsTUFBTSxJQUFJLEdBQUcsTUFBTSx5QkFBYyxDQUFDO1FBQ2hDLFlBQVksRUFBRSxXQUFXO1FBRXpCLG1IQUFtSDtRQUNuSCxPQUFPLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEdBQUcsZ0JBQWdCLEVBQUUsV0FBVyxFQUFFLFdBQVcsRUFBRSxDQUFDO0tBQzNFLENBQUMsQ0FBQztJQUVILFVBQUcsQ0FBQyx5QkFBeUIsRUFBRSxJQUFJLEVBQUUsT0FBTSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFFbkQsTUFBTSxXQUFXLEdBQUcsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ25ELElBQUksSUFBSSxDQUFDLGFBQWEsRUFBRTtRQUN0QixVQUFHLENBQUMsK0JBQStCLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBRXpELE1BQU0sWUFBWSxHQUFHLFdBQVcsQ0FBQyxZQUFZLElBQUksT0FBTyxDQUFDO1FBRXpELCtCQUErQjtRQUMvQix3RUFBd0U7UUFDeEUsTUFBTSxHQUFHLEdBQUcsV0FBVyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUNuQyxNQUFNLFlBQVksR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztRQUV6Qyx1Q0FBdUM7UUFDdkMsTUFBTSxPQUFPLEdBQUc7WUFDZCxZQUFZO1lBQ1osRUFBRTtZQUNGLHFCQUFxQixZQUFZLEVBQUU7WUFDbkMsRUFBRTtTQUNILENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRWIsTUFBTSxDQUFDLEdBQUcsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFN0IsMkVBQTJFO1FBQzNFLGlGQUFpRjtRQUNqRixJQUFJLFdBQVcsQ0FBQyxLQUFLLEVBQUU7WUFDckIsaURBQWlEO1lBQ2pELENBQUMsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxPQUFPLEVBQUUsR0FBRyxXQUFXLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztTQUMvRDtRQUVELE1BQU0sQ0FBQyxDQUFDO0tBQ1Q7SUFFRCxPQUFPLFdBQVcsQ0FBQztBQUNyQixDQUFDO0FBRUQsU0FBUyxnQkFBZ0IsQ0FBQyxPQUFZO0lBQ3BDLElBQUksQ0FBQyxPQUFPLEVBQUU7UUFBRSxPQUFPLEVBQUcsQ0FBQztLQUFFO0lBQzdCLE1BQU0sSUFBSSxHQUFHLE9BQU8sQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUNoQyxJQUFJO1FBQ0YsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO0tBQ3pCO0lBQUMsT0FBTyxDQUFDLEVBQUU7UUFDVixNQUFNLElBQUksS0FBSyxDQUFDLGdFQUFnRSxJQUFJLEdBQUcsQ0FBQyxDQUFDO0tBQzFGO0FBQ0gsQ0FBQztBQUVELFNBQVMsbUJBQW1CLENBQUMsVUFBdUQsRUFBRSxhQUE4QjtJQUNsSCxFQUFFO0lBQ0YsbUVBQW1FO0lBRW5FLGFBQWEsR0FBRyxhQUFhLElBQUksRUFBRyxDQUFDO0lBRXJDLHNFQUFzRTtJQUN0RSx1QkFBdUI7SUFDdkIsTUFBTSxrQkFBa0IsR0FBRyxhQUFhLENBQUMsa0JBQWtCLElBQUkseUJBQXlCLENBQUMsVUFBVSxDQUFDLENBQUM7SUFFckcsa0VBQWtFO0lBQ2xFLElBQUksVUFBVSxDQUFDLFdBQVcsS0FBSyxRQUFRLElBQUksa0JBQWtCLEtBQUssVUFBVSxDQUFDLGtCQUFrQixFQUFFO1FBQy9GLE1BQU0sSUFBSSxLQUFLLENBQUMsd0RBQXdELFVBQVUsQ0FBQyxrQkFBa0IsU0FBUyxhQUFhLENBQUMsa0JBQWtCLG1CQUFtQixDQUFDLENBQUM7S0FDcEs7SUFFRCxpRkFBaUY7SUFDakYsSUFBSSxVQUFVLENBQUMsV0FBVyxLQUFLLFFBQVEsSUFBSSxrQkFBa0IsS0FBSyxVQUFVLENBQUMsa0JBQWtCLEVBQUU7UUFDL0YsVUFBRyxDQUFDLCtDQUErQyxVQUFVLENBQUMsa0JBQWtCLFNBQVMsYUFBYSxDQUFDLGtCQUFrQixHQUFHLENBQUMsQ0FBQztLQUMvSDtJQUVELDBEQUEwRDtJQUMxRCxPQUFPO1FBQ0wsR0FBRyxVQUFVO1FBQ2IsR0FBRyxhQUFhO1FBQ2hCLGtCQUFrQixFQUFFLGtCQUFrQjtLQUN2QyxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILFNBQVMseUJBQXlCLENBQUMsR0FBZ0Q7SUFDakYsUUFBUSxHQUFHLENBQUMsV0FBVyxFQUFFO1FBQ3ZCLEtBQUssUUFBUTtZQUNYLE9BQU8sR0FBRyxDQUFDLFNBQVMsQ0FBQztRQUV2QixLQUFLLFFBQVEsQ0FBQztRQUNkLEtBQUssUUFBUTtZQUNYLE9BQU8sR0FBRyxDQUFDLGtCQUFrQixDQUFDO1FBRWhDO1lBQ0UsTUFBTSxJQUFJLEtBQUssQ0FBQyxxQ0FBcUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7S0FDaEY7QUFDSCxDQUFDO0FBcE1ELGlCQUFTO0lBQ1AsQ0FBQyxNQUFNLENBQUMsK0JBQStCLENBQUMsRUFBRSxXQUFXLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQztJQUMxRSxDQUFDLE1BQU0sQ0FBQyxrQ0FBa0MsQ0FBQyxFQUFFLFdBQVcsQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDO0lBQ2hGLENBQUMsTUFBTSxDQUFDLGlDQUFpQyxDQUFDLEVBQUUsU0FBUztDQUN0RCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgbWF4LWxlbiAqL1xuLyogZXNsaW50LWRpc2FibGUgbm8tY29uc29sZSAqL1xuaW1wb3J0IHsgSXNDb21wbGV0ZVJlc3BvbnNlLCBPbkV2ZW50UmVzcG9uc2UgfSBmcm9tICcuLi90eXBlcyc7XG5pbXBvcnQgKiBhcyBjZm5SZXNwb25zZSBmcm9tICcuL2Nmbi1yZXNwb25zZSc7XG5pbXBvcnQgKiBhcyBjb25zdHMgZnJvbSAnLi9jb25zdHMnO1xuaW1wb3J0IHsgaW52b2tlRnVuY3Rpb24sIHN0YXJ0RXhlY3V0aW9uIH0gZnJvbSAnLi9vdXRib3VuZCc7XG5pbXBvcnQgeyBnZXRFbnYsIGxvZyB9IGZyb20gJy4vdXRpbCc7XG5cbi8vIHVzZSBjb25zdHMgZm9yIGhhbmRsZXIgbmFtZXMgdG8gY29tcGlsZXItZW5mb3JjZSB0aGUgY291cGxpbmcgd2l0aCBjb25zdHJ1Y3Rpb24gY29kZS5cbmV4cG9ydCA9IHtcbiAgW2NvbnN0cy5GUkFNRVdPUktfT05fRVZFTlRfSEFORExFUl9OQU1FXTogY2ZuUmVzcG9uc2Uuc2FmZUhhbmRsZXIob25FdmVudCksXG4gIFtjb25zdHMuRlJBTUVXT1JLX0lTX0NPTVBMRVRFX0hBTkRMRVJfTkFNRV06IGNmblJlc3BvbnNlLnNhZmVIYW5kbGVyKGlzQ29tcGxldGUpLFxuICBbY29uc3RzLkZSQU1FV09SS19PTl9USU1FT1VUX0hBTkRMRVJfTkFNRV06IG9uVGltZW91dCxcbn07XG5cbi8qKlxuICogVGhlIG1haW4gcnVudGltZSBlbnRyeXBvaW50IG9mIHRoZSBhc3luYyBjdXN0b20gcmVzb3VyY2UgbGFtYmRhIGZ1bmN0aW9uLlxuICpcbiAqIEFueSBsaWZlY3ljbGUgZXZlbnQgY2hhbmdlcyB0byB0aGUgY3VzdG9tIHJlc291cmNlcyB3aWxsIGludm9rZSB0aGlzIGhhbmRsZXIsIHdoaWNoIHdpbGwsIGluIHR1cm4sXG4gKiBpbnRlcmFjdCB3aXRoIHRoZSB1c2VyLWRlZmluZWQgYG9uRXZlbnRgIGFuZCBgaXNDb21wbGV0ZWAgaGFuZGxlcnMuXG4gKlxuICogVGhpcyBmdW5jdGlvbiB3aWxsIGFsd2F5cyBzdWNjZWVkLiBJZiBhbiBlcnJvciBvY2N1cnNcbiAqXG4gKiBAcGFyYW0gY2ZuUmVxdWVzdCBUaGUgY2xvdWRmb3JtYXRpb24gY3VzdG9tIHJlc291cmNlIGV2ZW50LlxuICovXG5hc3luYyBmdW5jdGlvbiBvbkV2ZW50KGNmblJlcXVlc3Q6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQpIHtcbiAgY29uc3Qgc2FuaXRpemVkUmVxdWVzdCA9IHsgLi4uY2ZuUmVxdWVzdCwgUmVzcG9uc2VVUkw6ICcuLi4nIH0gYXMgY29uc3Q7XG4gIGxvZygnb25FdmVudEhhbmRsZXInLCBzYW5pdGl6ZWRSZXF1ZXN0KTtcblxuICBjZm5SZXF1ZXN0LlJlc291cmNlUHJvcGVydGllcyA9IGNmblJlcXVlc3QuUmVzb3VyY2VQcm9wZXJ0aWVzIHx8IHsgfTtcblxuICBjb25zdCBvbkV2ZW50UmVzdWx0ID0gYXdhaXQgaW52b2tlVXNlckZ1bmN0aW9uKGNvbnN0cy5VU0VSX09OX0VWRU5UX0ZVTkNUSU9OX0FSTl9FTlYsIHNhbml0aXplZFJlcXVlc3QsIGNmblJlcXVlc3QuUmVzcG9uc2VVUkwpIGFzIE9uRXZlbnRSZXNwb25zZTtcbiAgbG9nKCdvbkV2ZW50IHJldHVybmVkOicsIG9uRXZlbnRSZXN1bHQpO1xuXG4gIC8vIG1lcmdlIHRoZSByZXF1ZXN0IGFuZCB0aGUgcmVzdWx0IGZyb20gb25FdmVudCB0byBmb3JtIHRoZSBjb21wbGV0ZSByZXNvdXJjZSBldmVudFxuICAvLyB0aGlzIGFsc28gcGVyZm9ybXMgdmFsaWRhdGlvbi5cbiAgY29uc3QgcmVzb3VyY2VFdmVudCA9IGNyZWF0ZVJlc3BvbnNlRXZlbnQoY2ZuUmVxdWVzdCwgb25FdmVudFJlc3VsdCk7XG4gIGxvZygnZXZlbnQ6Jywgb25FdmVudFJlc3VsdCk7XG5cbiAgLy8gZGV0ZXJtaW5lIGlmIHRoaXMgaXMgYW4gYXN5bmMgcHJvdmlkZXIgYmFzZWQgb24gd2hldGhlciB3ZSBoYXZlIGFuIGlzQ29tcGxldGUgaGFuZGxlciBkZWZpbmVkLlxuICAvLyBpZiBpdCBpcyBub3QgZGVmaW5lZCwgdGhlbiB3ZSBhcmUgYmFzaWNhbGx5IHJlYWR5IHRvIHJldHVybiBhIHBvc2l0aXZlIHJlc3BvbnNlLlxuICBpZiAoIXByb2Nlc3MuZW52W2NvbnN0cy5VU0VSX0lTX0NPTVBMRVRFX0ZVTkNUSU9OX0FSTl9FTlZdKSB7XG4gICAgcmV0dXJuIGNmblJlc3BvbnNlLnN1Ym1pdFJlc3BvbnNlKCdTVUNDRVNTJywgcmVzb3VyY2VFdmVudCwgeyBub0VjaG86IHJlc291cmNlRXZlbnQuTm9FY2hvIH0pO1xuICB9XG5cbiAgLy8gb2ssIHdlIGFyZSBub3QgY29tcGxldGUsIHNvIGtpY2sgb2ZmIHRoZSB3YWl0ZXIgd29ya2Zsb3dcbiAgY29uc3Qgd2FpdGVyID0ge1xuICAgIHN0YXRlTWFjaGluZUFybjogZ2V0RW52KGNvbnN0cy5XQUlURVJfU1RBVEVfTUFDSElORV9BUk5fRU5WKSxcbiAgICBuYW1lOiByZXNvdXJjZUV2ZW50LlJlcXVlc3RJZCxcbiAgICBpbnB1dDogSlNPTi5zdHJpbmdpZnkocmVzb3VyY2VFdmVudCksXG4gIH07XG5cbiAgbG9nKCdzdGFydGluZyB3YWl0ZXInLCB3YWl0ZXIpO1xuXG4gIC8vIGtpY2sgb2ZmIHdhaXRlciBzdGF0ZSBtYWNoaW5lXG4gIGF3YWl0IHN0YXJ0RXhlY3V0aW9uKHdhaXRlcik7XG59XG5cbi8vIGludm9rZWQgYSBmZXcgdGltZXMgdW50aWwgYGNvbXBsZXRlYCBpcyB0cnVlIG9yIHVudGlsIGl0IHRpbWVzIG91dC5cbmFzeW5jIGZ1bmN0aW9uIGlzQ29tcGxldGUoZXZlbnQ6IEFXU0NES0FzeW5jQ3VzdG9tUmVzb3VyY2UuSXNDb21wbGV0ZVJlcXVlc3QpIHtcbiAgY29uc3Qgc2FuaXRpemVkUmVxdWVzdCA9IHsgLi4uZXZlbnQsIFJlc3BvbnNlVVJMOiAnLi4uJyB9IGFzIGNvbnN0O1xuICBsb2coJ2lzQ29tcGxldGUnLCBzYW5pdGl6ZWRSZXF1ZXN0KTtcblxuICBjb25zdCBpc0NvbXBsZXRlUmVzdWx0ID0gYXdhaXQgaW52b2tlVXNlckZ1bmN0aW9uKGNvbnN0cy5VU0VSX0lTX0NPTVBMRVRFX0ZVTkNUSU9OX0FSTl9FTlYsIHNhbml0aXplZFJlcXVlc3QsIGV2ZW50LlJlc3BvbnNlVVJMKSBhcyBJc0NvbXBsZXRlUmVzcG9uc2U7XG4gIGxvZygndXNlciBpc0NvbXBsZXRlIHJldHVybmVkOicsIGlzQ29tcGxldGVSZXN1bHQpO1xuXG4gIC8vIGlmIHdlIGFyZSBub3QgY29tcGxldGUsIHJldHVybiBmYWxzZSwgYW5kIGRvbid0IHNlbmQgYSByZXNwb25zZSBiYWNrLlxuICBpZiAoIWlzQ29tcGxldGVSZXN1bHQuSXNDb21wbGV0ZSkge1xuICAgIGlmIChpc0NvbXBsZXRlUmVzdWx0LkRhdGEgJiYgT2JqZWN0LmtleXMoaXNDb21wbGV0ZVJlc3VsdC5EYXRhKS5sZW5ndGggPiAwKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ1wiRGF0YVwiIGlzIG5vdCBhbGxvd2VkIGlmIFwiSXNDb21wbGV0ZVwiIGlzIFwiRmFsc2VcIicpO1xuICAgIH1cblxuICAgIC8vIFRoaXMgbXVzdCBiZSB0aGUgZnVsbCBldmVudCwgaXQgd2lsbCBiZSBkZXNlcmlhbGl6ZWQgaW4gYG9uVGltZW91dGAgdG8gc2VuZCB0aGUgcmVzcG9uc2UgdG8gQ2xvdWRGb3JtYXRpb25cbiAgICB0aHJvdyBuZXcgY2ZuUmVzcG9uc2UuUmV0cnkoSlNPTi5zdHJpbmdpZnkoZXZlbnQpKTtcbiAgfVxuXG4gIGNvbnN0IHJlc3BvbnNlID0ge1xuICAgIC4uLmV2ZW50LFxuICAgIC4uLmlzQ29tcGxldGVSZXN1bHQsXG4gICAgRGF0YToge1xuICAgICAgLi4uZXZlbnQuRGF0YSxcbiAgICAgIC4uLmlzQ29tcGxldGVSZXN1bHQuRGF0YSxcbiAgICB9LFxuICB9O1xuXG4gIGF3YWl0IGNmblJlc3BvbnNlLnN1Ym1pdFJlc3BvbnNlKCdTVUNDRVNTJywgcmVzcG9uc2UsIHsgbm9FY2hvOiBldmVudC5Ob0VjaG8gfSk7XG59XG5cbi8vIGludm9rZWQgd2hlbiBjb21wbGV0aW9uIHJldHJpZXMgYXJlIGV4aGF1c2VkLlxuYXN5bmMgZnVuY3Rpb24gb25UaW1lb3V0KHRpbWVvdXRFdmVudDogYW55KSB7XG4gIGxvZygndGltZW91dEhhbmRsZXInLCB0aW1lb3V0RXZlbnQpO1xuXG4gIGNvbnN0IGlzQ29tcGxldGVSZXF1ZXN0ID0gSlNPTi5wYXJzZShKU09OLnBhcnNlKHRpbWVvdXRFdmVudC5DYXVzZSkuZXJyb3JNZXNzYWdlKSBhcyBBV1NDREtBc3luY0N1c3RvbVJlc291cmNlLklzQ29tcGxldGVSZXF1ZXN0O1xuICBhd2FpdCBjZm5SZXNwb25zZS5zdWJtaXRSZXNwb25zZSgnRkFJTEVEJywgaXNDb21wbGV0ZVJlcXVlc3QsIHtcbiAgICByZWFzb246ICdPcGVyYXRpb24gdGltZWQgb3V0JyxcbiAgfSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGludm9rZVVzZXJGdW5jdGlvbjxBIGV4dGVuZHMgeyBSZXNwb25zZVVSTDogJy4uLicgfT4oZnVuY3Rpb25Bcm5FbnY6IHN0cmluZywgc2FuaXRpemVkUGF5bG9hZDogQSwgcmVzcG9uc2VVcmw6IHN0cmluZykge1xuICBjb25zdCBmdW5jdGlvbkFybiA9IGdldEVudihmdW5jdGlvbkFybkVudik7XG4gIGxvZyhgZXhlY3V0aW5nIHVzZXIgZnVuY3Rpb24gJHtmdW5jdGlvbkFybn0gd2l0aCBwYXlsb2FkYCwgc2FuaXRpemVkUGF5bG9hZCk7XG5cbiAgLy8gdHJhbnNpZW50IGVycm9ycyBzdWNoIGFzIHRpbWVvdXRzLCB0aHJvdHRsaW5nIGVycm9ycyAoNDI5KSwgYW5kIG90aGVyXG4gIC8vIGVycm9ycyB0aGF0IGFyZW4ndCBjYXVzZWQgYnkgYSBiYWQgcmVxdWVzdCAoNTAwIHNlcmllcykgYXJlIHJldHJpZWRcbiAgLy8gYXV0b21hdGljYWxseSBieSB0aGUgSmF2YVNjcmlwdCBTREsuXG4gIGNvbnN0IHJlc3AgPSBhd2FpdCBpbnZva2VGdW5jdGlvbih7XG4gICAgRnVuY3Rpb25OYW1lOiBmdW5jdGlvbkFybixcblxuICAgIC8vIENhbm5vdCBzdHJpcCAnUmVzcG9uc2VVUkwnIGhlcmUgYXMgdGhpcyB3b3VsZCBiZSBhIGJyZWFraW5nIGNoYW5nZSBldmVuIHRob3VnaCB0aGUgZG93bnN0cmVhbSBDUiBkb2Vzbid0IG5lZWQgaXRcbiAgICBQYXlsb2FkOiBKU09OLnN0cmluZ2lmeSh7IC4uLnNhbml0aXplZFBheWxvYWQsIFJlc3BvbnNlVVJMOiByZXNwb25zZVVybCB9KSxcbiAgfSk7XG5cbiAgbG9nKCd1c2VyIGZ1bmN0aW9uIHJlc3BvbnNlOicsIHJlc3AsIHR5cGVvZihyZXNwKSk7XG5cbiAgY29uc3QganNvblBheWxvYWQgPSBwYXJzZUpzb25QYXlsb2FkKHJlc3AuUGF5bG9hZCk7XG4gIGlmIChyZXNwLkZ1bmN0aW9uRXJyb3IpIHtcbiAgICBsb2coJ3VzZXIgZnVuY3Rpb24gdGhyZXcgYW4gZXJyb3I6JywgcmVzcC5GdW5jdGlvbkVycm9yKTtcblxuICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IGpzb25QYXlsb2FkLmVycm9yTWVzc2FnZSB8fCAnZXJyb3InO1xuXG4gICAgLy8gcGFyc2UgZnVuY3Rpb24gbmFtZSBmcm9tIGFyblxuICAgIC8vIGFybjoke1BhcnRpdGlvbn06bGFtYmRhOiR7UmVnaW9ufToke0FjY291bnR9OmZ1bmN0aW9uOiR7RnVuY3Rpb25OYW1lfVxuICAgIGNvbnN0IGFybiA9IGZ1bmN0aW9uQXJuLnNwbGl0KCc6Jyk7XG4gICAgY29uc3QgZnVuY3Rpb25OYW1lID0gYXJuW2Fybi5sZW5ndGggLSAxXTtcblxuICAgIC8vIGFwcGVuZCBhIHJlZmVyZW5jZSB0byB0aGUgbG9nIGdyb3VwLlxuICAgIGNvbnN0IG1lc3NhZ2UgPSBbXG4gICAgICBlcnJvck1lc3NhZ2UsXG4gICAgICAnJyxcbiAgICAgIGBMb2dzOiAvYXdzL2xhbWJkYS8ke2Z1bmN0aW9uTmFtZX1gLCAvLyBjbG91ZHdhdGNoIGxvZyBncm91cFxuICAgICAgJycsXG4gICAgXS5qb2luKCdcXG4nKTtcblxuICAgIGNvbnN0IGUgPSBuZXcgRXJyb3IobWVzc2FnZSk7XG5cbiAgICAvLyB0aGUgb3V0cHV0IHRoYXQgZ29lcyB0byBDRk4gaXMgd2hhdCdzIGluIGBzdGFja2AsIG5vdCB0aGUgZXJyb3IgbWVzc2FnZS5cbiAgICAvLyBpZiB3ZSBoYXZlIGEgcmVtb3RlIHRyYWNlLCBjb25zdHJ1Y3QgYSBuaWNlIG1lc3NhZ2Ugd2l0aCBsb2cgZ3JvdXAgaW5mb3JtYXRpb25cbiAgICBpZiAoanNvblBheWxvYWQudHJhY2UpIHtcbiAgICAgIC8vIHNraXAgZmlyc3QgdHJhY2UgbGluZSBiZWNhdXNlIGl0J3MgdGhlIG1lc3NhZ2VcbiAgICAgIGUuc3RhY2sgPSBbbWVzc2FnZSwgLi4uanNvblBheWxvYWQudHJhY2Uuc2xpY2UoMSldLmpvaW4oJ1xcbicpO1xuICAgIH1cblxuICAgIHRocm93IGU7XG4gIH1cblxuICByZXR1cm4ganNvblBheWxvYWQ7XG59XG5cbmZ1bmN0aW9uIHBhcnNlSnNvblBheWxvYWQocGF5bG9hZDogYW55KTogYW55IHtcbiAgaWYgKCFwYXlsb2FkKSB7IHJldHVybiB7IH07IH1cbiAgY29uc3QgdGV4dCA9IHBheWxvYWQudG9TdHJpbmcoKTtcbiAgdHJ5IHtcbiAgICByZXR1cm4gSlNPTi5wYXJzZSh0ZXh0KTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgcmV0dXJuIHZhbHVlcyBmcm9tIHVzZXItaGFuZGxlcnMgbXVzdCBiZSBKU09OIG9iamVjdHMuIGdvdDogXCIke3RleHR9XCJgKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBjcmVhdGVSZXNwb25zZUV2ZW50KGNmblJlcXVlc3Q6IEFXU0xhbWJkYS5DbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlRXZlbnQsIG9uRXZlbnRSZXN1bHQ6IE9uRXZlbnRSZXNwb25zZSk6IEFXU0NES0FzeW5jQ3VzdG9tUmVzb3VyY2UuSXNDb21wbGV0ZVJlcXVlc3Qge1xuICAvL1xuICAvLyB2YWxpZGF0ZSB0aGF0IG9uRXZlbnRSZXN1bHQgYWx3YXlzIGluY2x1ZGVzIGEgUGh5c2ljYWxSZXNvdXJjZUlkXG5cbiAgb25FdmVudFJlc3VsdCA9IG9uRXZlbnRSZXN1bHQgfHwgeyB9O1xuXG4gIC8vIGlmIHBoeXNpY2FsIElEIGlzIG5vdCByZXR1cm5lZCwgd2UgaGF2ZSBzb21lIGRlZmF1bHRzIGZvciB5b3UgYmFzZWRcbiAgLy8gb24gdGhlIHJlcXVlc3QgdHlwZS5cbiAgY29uc3QgcGh5c2ljYWxSZXNvdXJjZUlkID0gb25FdmVudFJlc3VsdC5QaHlzaWNhbFJlc291cmNlSWQgfHwgZGVmYXVsdFBoeXNpY2FsUmVzb3VyY2VJZChjZm5SZXF1ZXN0KTtcblxuICAvLyBpZiB3ZSBhcmUgaW4gREVMRVRFIGFuZCBwaHlzaWNhbCBJRCB3YXMgY2hhbmdlZCwgaXQncyBhbiBlcnJvci5cbiAgaWYgKGNmblJlcXVlc3QuUmVxdWVzdFR5cGUgPT09ICdEZWxldGUnICYmIHBoeXNpY2FsUmVzb3VyY2VJZCAhPT0gY2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYERFTEVURTogY2Fubm90IGNoYW5nZSB0aGUgcGh5c2ljYWwgcmVzb3VyY2UgSUQgZnJvbSBcIiR7Y2ZuUmVxdWVzdC5QaHlzaWNhbFJlc291cmNlSWR9XCIgdG8gXCIke29uRXZlbnRSZXN1bHQuUGh5c2ljYWxSZXNvdXJjZUlkfVwiIGR1cmluZyBkZWxldGlvbmApO1xuICB9XG5cbiAgLy8gaWYgd2UgYXJlIGluIFVQREFURSBhbmQgcGh5c2ljYWwgSUQgd2FzIGNoYW5nZWQsIGl0J3MgYSByZXBsYWNlbWVudCAoanVzdCBsb2cpXG4gIGlmIChjZm5SZXF1ZXN0LlJlcXVlc3RUeXBlID09PSAnVXBkYXRlJyAmJiBwaHlzaWNhbFJlc291cmNlSWQgIT09IGNmblJlcXVlc3QuUGh5c2ljYWxSZXNvdXJjZUlkKSB7XG4gICAgbG9nKGBVUERBVEU6IGNoYW5naW5nIHBoeXNpY2FsIHJlc291cmNlIElEIGZyb20gXCIke2NmblJlcXVlc3QuUGh5c2ljYWxSZXNvdXJjZUlkfVwiIHRvIFwiJHtvbkV2ZW50UmVzdWx0LlBoeXNpY2FsUmVzb3VyY2VJZH1cImApO1xuICB9XG5cbiAgLy8gbWVyZ2UgcmVxdWVzdCBldmVudCBhbmQgcmVzdWx0IGV2ZW50IChyZXN1bHQgcHJldmFpbHMpLlxuICByZXR1cm4ge1xuICAgIC4uLmNmblJlcXVlc3QsXG4gICAgLi4ub25FdmVudFJlc3VsdCxcbiAgICBQaHlzaWNhbFJlc291cmNlSWQ6IHBoeXNpY2FsUmVzb3VyY2VJZCxcbiAgfTtcbn1cblxuLyoqXG4gKiBDYWxjdWxhdGVzIHRoZSBkZWZhdWx0IHBoeXNpY2FsIHJlc291cmNlIElEIGJhc2VkIGluIGNhc2UgdXNlciBoYW5kbGVyIGRpZFxuICogbm90IHJldHVybiBhIFBoeXNpY2FsUmVzb3VyY2VJZC5cbiAqXG4gKiBGb3IgXCJDUkVBVEVcIiwgaXQgdXNlcyB0aGUgUmVxdWVzdElkLlxuICogRm9yIFwiVVBEQVRFXCIgYW5kIFwiREVMRVRFXCIgYW5kIHJldHVybnMgdGhlIGN1cnJlbnQgUGh5c2ljYWxSZXNvdXJjZUlkICh0aGUgb25lIHByb3ZpZGVkIGluIGBldmVudGApLlxuICovXG5mdW5jdGlvbiBkZWZhdWx0UGh5c2ljYWxSZXNvdXJjZUlkKHJlcTogQVdTTGFtYmRhLkNsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VFdmVudCk6IHN0cmluZyB7XG4gIHN3aXRjaCAocmVxLlJlcXVlc3RUeXBlKSB7XG4gICAgY2FzZSAnQ3JlYXRlJzpcbiAgICAgIHJldHVybiByZXEuUmVxdWVzdElkO1xuXG4gICAgY2FzZSAnVXBkYXRlJzpcbiAgICBjYXNlICdEZWxldGUnOlxuICAgICAgcmV0dXJuIHJlcS5QaHlzaWNhbFJlc291cmNlSWQ7XG5cbiAgICBkZWZhdWx0OlxuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIFwiUmVxdWVzdFR5cGVcIiBpbiByZXF1ZXN0IFwiJHtKU09OLnN0cmluZ2lmeShyZXEpfVwiYCk7XG4gIH1cbn1cbiJdfQ== \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037/outbound.js b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037/outbound.js new file mode 100644 index 0000000000000..70203dcc42f3f --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037/outbound.js @@ -0,0 +1,45 @@ +"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/cluster-reboot.integ.snapshot/asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037/util.js b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037/util.js new file mode 100644 index 0000000000000..f09276d40ac91 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037/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/cluster-reboot.integ.snapshot/aws-cdk-redshift-cluster-create.assets.json b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/aws-cdk-redshift-cluster-create.assets.json new file mode 100644 index 0000000000000..32f731309e1e8 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/aws-cdk-redshift-cluster-create.assets.json @@ -0,0 +1,45 @@ +{ + "version": "21.0.0", + "files": { + "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e": { + "source": { + "path": "asset.1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037": { + "source": { + "path": "asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "0615d9633720df23ed3ec04f24f592c61f3b60ed92abd110e96e5ed52be73605": { + "source": { + "path": "aws-cdk-redshift-cluster-create.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "0615d9633720df23ed3ec04f24f592c61f3b60ed92abd110e96e5ed52be73605.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/cluster-reboot.integ.snapshot/aws-cdk-redshift-cluster-create.template.json b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/aws-cdk-redshift-cluster-create.template.json new file mode 100644 index 0000000000000..2dbd05dfbd459 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/aws-cdk-redshift-cluster-create.template.json @@ -0,0 +1,553 @@ +{ + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-create/Vpc" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet1Subnet77A7FDC6": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.0.0/17", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "foobar" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet1RouteTableAF4E5874": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet1RouteTableAssociation502CBE55": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcfoobarSubnet1RouteTableAF4E5874" + }, + "SubnetId": { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet2Subnet85B013AD": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.128.0/17", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "foobar" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet2RouteTable5127598D": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet2RouteTableAssociation5013D70B": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcfoobarSubnet2RouteTable5127598D" + }, + "SubnetId": { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ParameterGroup5E32DECB": { + "Type": "AWS::Redshift::ClusterParameterGroup", + "Properties": { + "Description": "Cluster parameter group for family redshift-1.0", + "ParameterGroupFamily": "redshift-1.0", + "Parameters": [ + { + "ParameterName": "enable_user_activity_logging", + "ParameterValue": "true" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSubnetsDCFA5CB7": { + "Type": "AWS::Redshift::ClusterSubnetGroup", + "Properties": { + "Description": "Subnets for Cluster Redshift cluster", + "SubnetIds": [ + { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + }, + { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSecurityGroup0921994B": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Redshift security group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSecret6368BD0F": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "GenerateSecretString": { + "ExcludeCharacters": "\"@/\\ '", + "GenerateStringKey": "password", + "PasswordLength": 30, + "SecretStringTemplate": "{\"username\":\"admin\"}" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSecretAttachment769E6258": { + "Type": "AWS::SecretsManager::SecretTargetAttachment", + "Properties": { + "SecretId": { + "Ref": "ClusterSecret6368BD0F" + }, + "TargetId": { + "Ref": "ClusterEB0386A7" + }, + "TargetType": "AWS::Redshift::Cluster" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterEB0386A7": { + "Type": "AWS::Redshift::Cluster", + "Properties": { + "ClusterType": "multi-node", + "DBName": "default_db", + "MasterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:username::}}" + ] + ] + }, + "MasterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:password::}}" + ] + ] + }, + "NodeType": "dc2.large", + "AllowVersionUpgrade": true, + "AutomatedSnapshotRetentionPeriod": 1, + "ClusterParameterGroupName": { + "Ref": "ParameterGroup5E32DECB" + }, + "ClusterSubnetGroupName": { + "Ref": "ClusterSubnetsDCFA5CB7" + }, + "Encrypted": true, + "NumberOfNodes": 2, + "PubliclyAccessible": false, + "VpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "ClusterSecurityGroup0921994B", + "GroupId" + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE": { + "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" + ] + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86", + "Roles": [ + { + "Ref": "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterResourceProviderframeworkonEvent15BB3722": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE", + "Arn" + ] + }, + "Description": "AWS CDK resource provider framework - onEvent (aws-cdk-redshift-cluster-create/Cluster/ResourceProvider)", + "Environment": { + "Variables": { + "USER_ON_EVENT_FUNCTION_ARN": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + } + } + }, + "Handler": "framework.onEvent", + "Runtime": "nodejs14.x", + "Timeout": 900 + }, + "DependsOn": [ + "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86", + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterRedshiftClusterRebooterCustomResource773361E1": { + "Type": "Custom::RedshiftClusterRebooter", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "ClusterResourceProviderframeworkonEvent15BB3722", + "Arn" + ] + }, + "ClusterId": { + "Ref": "ClusterEB0386A7" + }, + "ParameterGroupName": { + "Ref": "ParameterGroup5E32DECB" + }, + "ParametersString": "{\"enable_user_activity_logging\":\"true\"}" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525": { + "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" + ] + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "redshift:DescribeClusters", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "redshift:RebootCluster", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":redshift:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":cluster:", + { + "Ref": "ClusterEB0386A7" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF", + "Roles": [ + { + "Ref": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e.zip" + }, + "Role": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs16.x", + "Timeout": 900 + }, + "DependsOn": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF", + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "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/cluster-reboot.integ.snapshot/aws-cdk-redshift-cluster-update.assets.json b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/aws-cdk-redshift-cluster-update.assets.json new file mode 100644 index 0000000000000..cb546e95f709b --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/aws-cdk-redshift-cluster-update.assets.json @@ -0,0 +1,45 @@ +{ + "version": "21.0.0", + "files": { + "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e": { + "source": { + "path": "asset.1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037": { + "source": { + "path": "asset.7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "d2c10b460302950fe5b01e119da8d706f03cced8872d296f6721d3f607defc94": { + "source": { + "path": "aws-cdk-redshift-cluster-update.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "d2c10b460302950fe5b01e119da8d706f03cced8872d296f6721d3f607defc94.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/cluster-reboot.integ.snapshot/aws-cdk-redshift-cluster-update.template.json b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/aws-cdk-redshift-cluster-update.template.json new file mode 100644 index 0000000000000..1e653b14c0a28 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/aws-cdk-redshift-cluster-update.template.json @@ -0,0 +1,557 @@ +{ + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-update/Vpc" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet1Subnet77A7FDC6": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.0.0/17", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "foobar" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet1RouteTableAF4E5874": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet1RouteTableAssociation502CBE55": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcfoobarSubnet1RouteTableAF4E5874" + }, + "SubnetId": { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet2Subnet85B013AD": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.128.0/17", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "foobar" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet2RouteTable5127598D": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet2RouteTableAssociation5013D70B": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcfoobarSubnet2RouteTable5127598D" + }, + "SubnetId": { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ParameterGroup5E32DECB": { + "Type": "AWS::Redshift::ClusterParameterGroup", + "Properties": { + "Description": "Cluster parameter group for family redshift-1.0", + "ParameterGroupFamily": "redshift-1.0", + "Parameters": [ + { + "ParameterName": "enable_user_activity_logging", + "ParameterValue": "false" + }, + { + "ParameterName": "use_fips_ssl", + "ParameterValue": "true" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSubnetsDCFA5CB7": { + "Type": "AWS::Redshift::ClusterSubnetGroup", + "Properties": { + "Description": "Subnets for Cluster Redshift cluster", + "SubnetIds": [ + { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + }, + { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSecurityGroup0921994B": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Redshift security group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSecret6368BD0F": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "GenerateSecretString": { + "ExcludeCharacters": "\"@/\\ '", + "GenerateStringKey": "password", + "PasswordLength": 30, + "SecretStringTemplate": "{\"username\":\"admin\"}" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSecretAttachment769E6258": { + "Type": "AWS::SecretsManager::SecretTargetAttachment", + "Properties": { + "SecretId": { + "Ref": "ClusterSecret6368BD0F" + }, + "TargetId": { + "Ref": "ClusterEB0386A7" + }, + "TargetType": "AWS::Redshift::Cluster" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterEB0386A7": { + "Type": "AWS::Redshift::Cluster", + "Properties": { + "ClusterType": "multi-node", + "DBName": "default_db", + "MasterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:username::}}" + ] + ] + }, + "MasterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:password::}}" + ] + ] + }, + "NodeType": "dc2.large", + "AllowVersionUpgrade": true, + "AutomatedSnapshotRetentionPeriod": 1, + "ClusterParameterGroupName": { + "Ref": "ParameterGroup5E32DECB" + }, + "ClusterSubnetGroupName": { + "Ref": "ClusterSubnetsDCFA5CB7" + }, + "Encrypted": true, + "NumberOfNodes": 2, + "PubliclyAccessible": false, + "VpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "ClusterSecurityGroup0921994B", + "GroupId" + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE": { + "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" + ] + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86", + "Roles": [ + { + "Ref": "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterResourceProviderframeworkonEvent15BB3722": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE", + "Arn" + ] + }, + "Description": "AWS CDK resource provider framework - onEvent (aws-cdk-redshift-cluster-update/Cluster/ResourceProvider)", + "Environment": { + "Variables": { + "USER_ON_EVENT_FUNCTION_ARN": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + } + } + }, + "Handler": "framework.onEvent", + "Runtime": "nodejs14.x", + "Timeout": 900 + }, + "DependsOn": [ + "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86", + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterRedshiftClusterRebooterCustomResource773361E1": { + "Type": "Custom::RedshiftClusterRebooter", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "ClusterResourceProviderframeworkonEvent15BB3722", + "Arn" + ] + }, + "ClusterId": { + "Ref": "ClusterEB0386A7" + }, + "ParameterGroupName": { + "Ref": "ParameterGroup5E32DECB" + }, + "ParametersString": "{\"enable_user_activity_logging\":\"false\",\"use_fips_ssl\":\"true\"}" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525": { + "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" + ] + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "redshift:DescribeClusters", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "redshift:RebootCluster", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":redshift:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":cluster:", + { + "Ref": "ClusterEB0386A7" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF", + "Roles": [ + { + "Ref": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e.zip" + }, + "Role": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs16.x", + "Timeout": 900 + }, + "DependsOn": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF", + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "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/cluster-reboot.integ.snapshot/awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.assets.json b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.assets.json new file mode 100644 index 0000000000000..84fbb303ccb99 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.assets.json @@ -0,0 +1,19 @@ +{ + "version": "21.0.0", + "files": { + "21fbb51d7b23f6a6c262b46a9caee79d744a3ac019fd45422d988b96d44b2a22": { + "source": { + "path": "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.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/cluster-reboot.integ.snapshot/awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.template.json b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.template.json new file mode 100644 index 0000000000000..ad9d0fb73d1dd --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.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/cluster-reboot.integ.snapshot/cdk.out b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/cdk.out new file mode 100644 index 0000000000000..8ecc185e9dbee --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"21.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/integ.json b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/integ.json new file mode 100644 index 0000000000000..8323a65d93e55 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/integ.json @@ -0,0 +1,14 @@ +{ + "version": "21.0.0", + "testCases": { + "aws-cdk-redshift-reboot-test/DefaultTest": { + "stacks": [ + "aws-cdk-redshift-cluster-create", + "aws-cdk-redshift-cluster-update" + ], + "stackUpdateWorkflow": true, + "assertionStack": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert", + "assertionStackName": "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/manifest.json b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/manifest.json new file mode 100644 index 0000000000000..b5212572f6de6 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/manifest.json @@ -0,0 +1,395 @@ +{ + "version": "21.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "aws-cdk-redshift-cluster-create.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-redshift-cluster-create.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-redshift-cluster-create": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-redshift-cluster-create.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}/0615d9633720df23ed3ec04f24f592c61f3b60ed92abd110e96e5ed52be73605.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-redshift-cluster-create.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" + }, + "stackName": "aws-cdk-redshift-cluster-reboot-integ" + }, + "dependencies": [ + "aws-cdk-redshift-cluster-create.assets" + ], + "metadata": { + "/aws-cdk-redshift-cluster-create/Vpc/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Vpc8378EB38" + } + ], + "/aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet1Subnet77A7FDC6" + } + ], + "/aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet1RouteTableAF4E5874" + } + ], + "/aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet1RouteTableAssociation502CBE55" + } + ], + "/aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet2Subnet85B013AD" + } + ], + "/aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet2RouteTable5127598D" + } + ], + "/aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet2RouteTableAssociation5013D70B" + } + ], + "/aws-cdk-redshift-cluster-create/ParameterGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ParameterGroup5E32DECB" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/Subnets/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSubnetsDCFA5CB7" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/SecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSecurityGroup0921994B" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/Secret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSecret6368BD0F" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/Secret/Attachment/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSecretAttachment769E6258" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterEB0386A7" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterResourceProviderframeworkonEvent15BB3722" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/RedshiftClusterRebooterCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterRedshiftClusterRebooterCustomResource773361E1" + } + ], + "/aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + } + ], + "/aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF" + } + ], + "/aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5" + } + ], + "/aws-cdk-redshift-cluster-create/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-redshift-cluster-create/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-redshift-cluster-create" + }, + "aws-cdk-redshift-cluster-update.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-redshift-cluster-update.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-redshift-cluster-update": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-redshift-cluster-update.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}/d2c10b460302950fe5b01e119da8d706f03cced8872d296f6721d3f607defc94.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-redshift-cluster-update.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" + }, + "stackName": "aws-cdk-redshift-cluster-reboot-integ" + }, + "dependencies": [ + "aws-cdk-redshift-cluster-create", + "aws-cdk-redshift-cluster-update.assets" + ], + "metadata": { + "/aws-cdk-redshift-cluster-update/Vpc/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Vpc8378EB38" + } + ], + "/aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet1Subnet77A7FDC6" + } + ], + "/aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet1RouteTableAF4E5874" + } + ], + "/aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet1RouteTableAssociation502CBE55" + } + ], + "/aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet2Subnet85B013AD" + } + ], + "/aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet2RouteTable5127598D" + } + ], + "/aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet2RouteTableAssociation5013D70B" + } + ], + "/aws-cdk-redshift-cluster-update/ParameterGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ParameterGroup5E32DECB" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/Subnets/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSubnetsDCFA5CB7" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/SecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSecurityGroup0921994B" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/Secret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSecret6368BD0F" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/Secret/Attachment/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSecretAttachment769E6258" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterEB0386A7" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterResourceProviderframeworkonEvent15BB3722" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/RedshiftClusterRebooterCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterRedshiftClusterRebooterCustomResource773361E1" + } + ], + "/aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + } + ], + "/aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF" + } + ], + "/aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5" + } + ], + "/aws-cdk-redshift-cluster-update/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-redshift-cluster-update/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-redshift-cluster-update" + }, + "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.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": [ + "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.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": [ + "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.assets" + ], + "metadata": { + "/aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/tree.json b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/tree.json new file mode 100644 index 0000000000000..09d0274a71891 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/cluster-reboot.integ.snapshot/tree.json @@ -0,0 +1,1791 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.129" + } + }, + "aws-cdk-redshift-cluster-create": { + "id": "aws-cdk-redshift-cluster-create", + "path": "aws-cdk-redshift-cluster-create", + "children": { + "Vpc": { + "id": "Vpc", + "path": "aws-cdk-redshift-cluster-create/Vpc", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/Vpc/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPC", + "aws:cdk:cloudformation:props": { + "cidrBlock": "10.0.0.0/16", + "enableDnsHostnames": true, + "enableDnsSupport": true, + "instanceTenancy": "default", + "tags": [ + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-create/Vpc" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnVPC", + "version": "0.0.0" + } + }, + "foobarSubnet1": { + "id": "foobarSubnet1", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.0.0/17", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "foobar" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Isolated" + }, + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1/Acl", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VpcfoobarSubnet1RouteTableAF4E5874" + }, + "subnetId": { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", + "version": "0.0.0" + } + }, + "foobarSubnet2": { + "id": "foobarSubnet2", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.128.0/17", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "foobar" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Isolated" + }, + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2/Acl", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VpcfoobarSubnet2RouteTable5127598D" + }, + "subnetId": { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.Vpc", + "version": "0.0.0" + } + }, + "ParameterGroup": { + "id": "ParameterGroup", + "path": "aws-cdk-redshift-cluster-create/ParameterGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/ParameterGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Redshift::ClusterParameterGroup", + "aws:cdk:cloudformation:props": { + "description": "Cluster parameter group for family redshift-1.0", + "parameterGroupFamily": "redshift-1.0", + "parameters": [ + { + "parameterName": "enable_user_activity_logging", + "parameterValue": "true" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.CfnClusterParameterGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.ClusterParameterGroup", + "version": "0.0.0" + } + }, + "Cluster": { + "id": "Cluster", + "path": "aws-cdk-redshift-cluster-create/Cluster", + "children": { + "Subnets": { + "id": "Subnets", + "path": "aws-cdk-redshift-cluster-create/Cluster/Subnets", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-redshift-cluster-create/Cluster/Subnets/Default", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Redshift::ClusterSubnetGroup", + "aws:cdk:cloudformation:props": { + "description": "Subnets for Cluster Redshift cluster", + "subnetIds": [ + { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + }, + { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.CfnClusterSubnetGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.ClusterSubnetGroup", + "version": "0.0.0" + } + }, + "SecurityGroup": { + "id": "SecurityGroup", + "path": "aws-cdk-redshift-cluster-create/Cluster/SecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/Cluster/SecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "Redshift security group", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.SecurityGroup", + "version": "0.0.0" + } + }, + "Secret": { + "id": "Secret", + "path": "aws-cdk-redshift-cluster-create/Cluster/Secret", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/Cluster/Secret/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::Secret", + "aws:cdk:cloudformation:props": { + "generateSecretString": { + "passwordLength": 30, + "secretStringTemplate": "{\"username\":\"admin\"}", + "generateStringKey": "password", + "excludeCharacters": "\"@/\\ '" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-secretsmanager.CfnSecret", + "version": "0.0.0" + } + }, + "Attachment": { + "id": "Attachment", + "path": "aws-cdk-redshift-cluster-create/Cluster/Secret/Attachment", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/Cluster/Secret/Attachment/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::SecretTargetAttachment", + "aws:cdk:cloudformation:props": { + "secretId": { + "Ref": "ClusterSecret6368BD0F" + }, + "targetId": { + "Ref": "ClusterEB0386A7" + }, + "targetType": "AWS::Redshift::Cluster" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-secretsmanager.CfnSecretTargetAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-secretsmanager.SecretTargetAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.DatabaseSecret", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/Cluster/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Redshift::Cluster", + "aws:cdk:cloudformation:props": { + "clusterType": "multi-node", + "dbName": "default_db", + "masterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:username::}}" + ] + ] + }, + "masterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:password::}}" + ] + ] + }, + "nodeType": "dc2.large", + "allowVersionUpgrade": true, + "automatedSnapshotRetentionPeriod": 1, + "clusterParameterGroupName": { + "Ref": "ParameterGroup5E32DECB" + }, + "clusterSubnetGroupName": { + "Ref": "ClusterSubnetsDCFA5CB7" + }, + "encrypted": true, + "numberOfNodes": 2, + "publiclyAccessible": false, + "vpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "ClusterSecurityGroup0921994B", + "GroupId" + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.CfnCluster", + "version": "0.0.0" + } + }, + "RedshiftClusterRebooterFunction": { + "id": "RedshiftClusterRebooterFunction", + "path": "aws-cdk-redshift-cluster-create/Cluster/RedshiftClusterRebooterFunction", + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.SingletonFunction", + "version": "0.0.0" + } + }, + "ResourceProvider": { + "id": "ResourceProvider", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider", + "children": { + "framework-onEvent": { + "id": "framework-onEvent", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/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" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/ServiceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/ServiceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86", + "roles": [ + { + "Ref": "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Code": { + "id": "Code", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/Code/Stage", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/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": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/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": "7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037.zip" + }, + "role": { + "Fn::GetAtt": [ + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE", + "Arn" + ] + }, + "description": "AWS CDK resource provider framework - onEvent (aws-cdk-redshift-cluster-create/Cluster/ResourceProvider)", + "environment": { + "variables": { + "USER_ON_EVENT_FUNCTION_ARN": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + } + } + }, + "handler": "framework.onEvent", + "runtime": "nodejs14.x", + "timeout": 900 + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/custom-resources.Provider", + "version": "0.0.0" + } + }, + "RedshiftClusterRebooterCustomResource": { + "id": "RedshiftClusterRebooterCustomResource", + "path": "aws-cdk-redshift-cluster-create/Cluster/RedshiftClusterRebooterCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-redshift-cluster-create/Cluster/RedshiftClusterRebooterCustomResource/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/aws-redshift.Cluster", + "version": "0.0.0" + } + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2": { + "id": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/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" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "redshift:DescribeClusters", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "redshift:RebootCluster", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":redshift:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":cluster:", + { + "Ref": "ClusterEB0386A7" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF", + "roles": [ + { + "Ref": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Code": { + "id": "Code", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/Code/Stage", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/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": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/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": "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e.zip" + }, + "role": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs16.x", + "timeout": 900 + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "aws-cdk-redshift-cluster-update": { + "id": "aws-cdk-redshift-cluster-update", + "path": "aws-cdk-redshift-cluster-update", + "children": { + "Vpc": { + "id": "Vpc", + "path": "aws-cdk-redshift-cluster-update/Vpc", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/Vpc/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPC", + "aws:cdk:cloudformation:props": { + "cidrBlock": "10.0.0.0/16", + "enableDnsHostnames": true, + "enableDnsSupport": true, + "instanceTenancy": "default", + "tags": [ + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-update/Vpc" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnVPC", + "version": "0.0.0" + } + }, + "foobarSubnet1": { + "id": "foobarSubnet1", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.0.0/17", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "foobar" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Isolated" + }, + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1/Acl", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VpcfoobarSubnet1RouteTableAF4E5874" + }, + "subnetId": { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", + "version": "0.0.0" + } + }, + "foobarSubnet2": { + "id": "foobarSubnet2", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.128.0/17", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "foobar" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Isolated" + }, + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2/Acl", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VpcfoobarSubnet2RouteTable5127598D" + }, + "subnetId": { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.Vpc", + "version": "0.0.0" + } + }, + "ParameterGroup": { + "id": "ParameterGroup", + "path": "aws-cdk-redshift-cluster-update/ParameterGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/ParameterGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Redshift::ClusterParameterGroup", + "aws:cdk:cloudformation:props": { + "description": "Cluster parameter group for family redshift-1.0", + "parameterGroupFamily": "redshift-1.0", + "parameters": [ + { + "parameterName": "enable_user_activity_logging", + "parameterValue": "false" + }, + { + "parameterName": "use_fips_ssl", + "parameterValue": "true" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.CfnClusterParameterGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.ClusterParameterGroup", + "version": "0.0.0" + } + }, + "Cluster": { + "id": "Cluster", + "path": "aws-cdk-redshift-cluster-update/Cluster", + "children": { + "Subnets": { + "id": "Subnets", + "path": "aws-cdk-redshift-cluster-update/Cluster/Subnets", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-redshift-cluster-update/Cluster/Subnets/Default", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Redshift::ClusterSubnetGroup", + "aws:cdk:cloudformation:props": { + "description": "Subnets for Cluster Redshift cluster", + "subnetIds": [ + { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + }, + { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.CfnClusterSubnetGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.ClusterSubnetGroup", + "version": "0.0.0" + } + }, + "SecurityGroup": { + "id": "SecurityGroup", + "path": "aws-cdk-redshift-cluster-update/Cluster/SecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/Cluster/SecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "Redshift security group", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.SecurityGroup", + "version": "0.0.0" + } + }, + "Secret": { + "id": "Secret", + "path": "aws-cdk-redshift-cluster-update/Cluster/Secret", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/Cluster/Secret/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::Secret", + "aws:cdk:cloudformation:props": { + "generateSecretString": { + "passwordLength": 30, + "secretStringTemplate": "{\"username\":\"admin\"}", + "generateStringKey": "password", + "excludeCharacters": "\"@/\\ '" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-secretsmanager.CfnSecret", + "version": "0.0.0" + } + }, + "Attachment": { + "id": "Attachment", + "path": "aws-cdk-redshift-cluster-update/Cluster/Secret/Attachment", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/Cluster/Secret/Attachment/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::SecretTargetAttachment", + "aws:cdk:cloudformation:props": { + "secretId": { + "Ref": "ClusterSecret6368BD0F" + }, + "targetId": { + "Ref": "ClusterEB0386A7" + }, + "targetType": "AWS::Redshift::Cluster" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-secretsmanager.CfnSecretTargetAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-secretsmanager.SecretTargetAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.DatabaseSecret", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/Cluster/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Redshift::Cluster", + "aws:cdk:cloudformation:props": { + "clusterType": "multi-node", + "dbName": "default_db", + "masterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:username::}}" + ] + ] + }, + "masterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:password::}}" + ] + ] + }, + "nodeType": "dc2.large", + "allowVersionUpgrade": true, + "automatedSnapshotRetentionPeriod": 1, + "clusterParameterGroupName": { + "Ref": "ParameterGroup5E32DECB" + }, + "clusterSubnetGroupName": { + "Ref": "ClusterSubnetsDCFA5CB7" + }, + "encrypted": true, + "numberOfNodes": 2, + "publiclyAccessible": false, + "vpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "ClusterSecurityGroup0921994B", + "GroupId" + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.CfnCluster", + "version": "0.0.0" + } + }, + "RedshiftClusterRebooterFunction": { + "id": "RedshiftClusterRebooterFunction", + "path": "aws-cdk-redshift-cluster-update/Cluster/RedshiftClusterRebooterFunction", + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.SingletonFunction", + "version": "0.0.0" + } + }, + "ResourceProvider": { + "id": "ResourceProvider", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider", + "children": { + "framework-onEvent": { + "id": "framework-onEvent", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/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" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/ServiceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/ServiceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86", + "roles": [ + { + "Ref": "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Code": { + "id": "Code", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/Code/Stage", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/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": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/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": "7215c88dd3e638d28329d4538b36cdbfb54233a4d972181795814f8b904d1037.zip" + }, + "role": { + "Fn::GetAtt": [ + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE", + "Arn" + ] + }, + "description": "AWS CDK resource provider framework - onEvent (aws-cdk-redshift-cluster-update/Cluster/ResourceProvider)", + "environment": { + "variables": { + "USER_ON_EVENT_FUNCTION_ARN": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + } + } + }, + "handler": "framework.onEvent", + "runtime": "nodejs14.x", + "timeout": 900 + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/custom-resources.Provider", + "version": "0.0.0" + } + }, + "RedshiftClusterRebooterCustomResource": { + "id": "RedshiftClusterRebooterCustomResource", + "path": "aws-cdk-redshift-cluster-update/Cluster/RedshiftClusterRebooterCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-redshift-cluster-update/Cluster/RedshiftClusterRebooterCustomResource/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/aws-redshift.Cluster", + "version": "0.0.0" + } + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2": { + "id": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/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" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "redshift:DescribeClusters", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "redshift:RebootCluster", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":redshift:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":cluster:", + { + "Ref": "ClusterEB0386A7" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF", + "roles": [ + { + "Ref": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Code": { + "id": "Code", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/Code/Stage", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/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": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/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": "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e.zip" + }, + "role": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs16.x", + "timeout": 900 + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "aws-cdk-redshift-reboot-test": { + "id": "aws-cdk-redshift-reboot-test", + "path": "aws-cdk-redshift-reboot-test", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "aws-cdk-redshift-reboot-test/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.129" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert", + "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" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts index b05188bc300d9..45b71e307a6b8 100644 --- a/packages/@aws-cdk/aws-redshift/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-redshift/test/cluster.test.ts @@ -614,12 +614,142 @@ test('elastic ip address', () => { }); }); +describe('reboot for Parameter Changes', () => { + test('throw error for cluster without parameter group', () => { + // Given + const cluster = new Cluster(stack, 'Redshift', { + masterUser: { + masterUsername: 'admin', + }, + vpc, + }); + cluster.enableRebootForParameterChanges(); + // WHEN + expect(() => Template.fromStack(stack)) + // THEN + .toThrowError(/Cannot enable reboot for parameter changes/); + }); + + test('throw error for cluster with imported parameter group', () => { + // Given + const cluster = new Cluster(stack, 'Redshift', { + masterUser: { + masterUsername: 'admin', + }, + vpc, + parameterGroup: ClusterParameterGroup.fromClusterParameterGroupName(stack, 'foo', 'bar'), + }); + cluster.enableRebootForParameterChanges(); + // WHEN + expect(() => Template.fromStack(stack)) + // THEN + .toThrowError(/Cannot enable reboot for parameter changes/); + }); + + test('not throw error when parameter group is created after enabling reboots', () => { + // Given + const cluster = new Cluster(stack, 'Redshift', { + masterUser: { + masterUsername: 'admin', + }, + vpc, + rebootForParameterChanges: true, + }); + cluster.addToParameterGroup('foo', 'bar'); + // WHEN + expect(() => Template.fromStack(stack)) + // THEN + .not.toThrowError(/Cannot enable reboot for parameter changes/); + }); + + test('not create duplicate resources when reboot feature is enabled multiple times on a cluster', () => { + // Given + const cluster = new Cluster(stack, 'Redshift', { + masterUser: { + masterUsername: 'admin', + }, + vpc, + rebootForParameterChanges: true, + }); + cluster.addToParameterGroup('foo', 'bar'); + //WHEN + cluster.enableRebootForParameterChanges(); + // THEN + Template.fromStack(stack).resourceCountIs('Custom::RedshiftClusterRebooter', 1); + }); + + test('cluster with parameter group', () => { + // Given + const cluster = new Cluster(stack, 'Redshift', { + masterUser: { + masterUsername: 'admin', + }, + vpc, + }); + cluster.addToParameterGroup('foo', 'bar'); + + const cluster2 = new Cluster(stack, 'Redshift2', { + masterUser: { + masterUsername: 'admin', + }, + vpc, + }); + cluster2.addToParameterGroup('foo', 'bar'); + + // WHEN + cluster.enableRebootForParameterChanges(); + cluster2.enableRebootForParameterChanges(); + + //THEN + const template = Template.fromStack(stack); + template.resourceCountIs('Custom::RedshiftClusterRebooter', 2); + template.templateMatches({ + Resources: { + SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5: { + Type: 'AWS::Lambda::Function', + Properties: { + Handler: 'index.handler', + Runtime: 'nodejs16.x', + Timeout: 900, + }, + }, + }, + }); + }); + + test('Custom resource ParametersString property updates', () => { + // Given + const cluster = new Cluster(stack, 'Redshift', { + masterUser: { + masterUsername: 'admin', + }, + vpc, + }); + cluster.addToParameterGroup('foo', 'bar'); + cluster.enableRebootForParameterChanges(); + + // WHEN + cluster.addToParameterGroup('lorem', 'ipsum'); + + //THEN + const template = Template.fromStack(stack); + template.hasResourceProperties('Custom::RedshiftClusterRebooter', { + ParametersString: JSON.stringify( + { + foo: 'bar', + lorem: 'ipsum', + }, + ), + }); + }); +}); + describe('default IAM role', () => { test('Default role not in role list', () => { // GIVEN - const clusterRole1 = new iam.Role(stack, 'clusterRole1', { assumedBy: new iam.ServicePrincipal('redshift.amazonaws.com') } ); - const defaultRole1 = new iam.Role(stack, 'defaultRole1', { assumedBy: new iam.ServicePrincipal('redshift.amazonaws.com') } ); + const clusterRole1 = new iam.Role(stack, 'clusterRole1', { assumedBy: new iam.ServicePrincipal('redshift.amazonaws.com') }); + const defaultRole1 = new iam.Role(stack, 'defaultRole1', { assumedBy: new iam.ServicePrincipal('redshift.amazonaws.com') }); expect(() => { new Cluster(stack, 'Redshift', { @@ -634,7 +764,7 @@ describe('default IAM role', () => { }); test('throws error when default role not attached to cluster when adding default role post creation', () => { - const defaultRole1 = new iam.Role(stack, 'defaultRole1', { assumedBy: new iam.ServicePrincipal('redshift.amazonaws.com') } ); + const defaultRole1 = new iam.Role(stack, 'defaultRole1', { assumedBy: new iam.ServicePrincipal('redshift.amazonaws.com') }); const cluster = new Cluster(stack, 'Redshift', { masterUser: { masterUsername: 'admin', @@ -740,7 +870,7 @@ describe('IAM role', () => { expect(() => // WHEN cluster.addIamRole(role), - // THEN + // THEN ).toThrow(`Role '${role.roleArn}' is already attached to the cluster`); }); }); diff --git a/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/asset.382ba2a8fd0a13f6782aec5543e465f988f5c100f35ed20f90cd96b8ee53f674.bundle/index.js b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/asset.382ba2a8fd0a13f6782aec5543e465f988f5c100f35ed20f90cd96b8ee53f674.bundle/index.js new file mode 100644 index 0000000000000..ffbf23bc9533f --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/asset.382ba2a8fd0a13f6782aec5543e465f988f5c100f35ed20f90cd96b8ee53f674.bundle/index.js @@ -0,0 +1,783 @@ +"use strict"; +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// lib/assertions/providers/lambda-handler/index.ts +var lambda_handler_exports = {}; +__export(lambda_handler_exports, { + handler: () => handler, + isComplete: () => isComplete, + onTimeout: () => onTimeout +}); +module.exports = __toCommonJS(lambda_handler_exports); + +// ../assertions/lib/matcher.ts +var Matcher = class { + static isMatcher(x) { + return x && x instanceof Matcher; + } +}; +var MatchResult = class { + constructor(target) { + this.failures = []; + this.captures = /* @__PURE__ */ new Map(); + this.finalized = false; + this.target = target; + } + push(matcher, path, message) { + return this.recordFailure({ matcher, path, message }); + } + recordFailure(failure) { + this.failures.push(failure); + return this; + } + hasFailed() { + return this.failures.length !== 0; + } + get failCount() { + return this.failures.length; + } + compose(id, inner) { + const innerF = inner.failures; + this.failures.push(...innerF.map((f) => { + return { path: [id, ...f.path], message: f.message, matcher: f.matcher }; + })); + inner.captures.forEach((vals, capture) => { + vals.forEach((value) => this.recordCapture({ capture, value })); + }); + return this; + } + finished() { + if (this.finalized) { + return this; + } + if (this.failCount === 0) { + this.captures.forEach((vals, cap) => cap._captured.push(...vals)); + } + this.finalized = true; + return this; + } + toHumanStrings() { + return this.failures.map((r) => { + const loc = r.path.length === 0 ? "" : ` at ${r.path.join("")}`; + return "" + r.message + loc + ` (using ${r.matcher.name} matcher)`; + }); + } + recordCapture(options) { + let values = this.captures.get(options.capture); + if (values === void 0) { + values = []; + } + values.push(options.value); + this.captures.set(options.capture, values); + } +}; + +// ../assertions/lib/private/matchers/absent.ts +var AbsentMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual !== void 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Received ${actual}, but key should be absent` + }); + } + return result; + } +}; + +// ../assertions/lib/private/type.ts +function getType(obj) { + return Array.isArray(obj) ? "array" : typeof obj; +} + +// ../assertions/lib/match.ts +var Match = class { + static absent() { + return new AbsentMatch("absent"); + } + static arrayWith(pattern) { + return new ArrayMatch("arrayWith", pattern); + } + static arrayEquals(pattern) { + return new ArrayMatch("arrayEquals", pattern, { subsequence: false }); + } + static exact(pattern) { + return new LiteralMatch("exact", pattern, { partialObjects: false }); + } + static objectLike(pattern) { + return new ObjectMatch("objectLike", pattern); + } + static objectEquals(pattern) { + return new ObjectMatch("objectEquals", pattern, { partial: false }); + } + static not(pattern) { + return new NotMatch("not", pattern); + } + static serializedJson(pattern) { + return new SerializedJson("serializedJson", pattern); + } + static anyValue() { + return new AnyMatch("anyValue"); + } + static stringLikeRegexp(pattern) { + return new StringLikeRegexpMatch("stringLikeRegexp", pattern); + } +}; +var LiteralMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partialObjects = options.partialObjects ?? false; + if (Matcher.isMatcher(this.pattern)) { + throw new Error("LiteralMatch cannot directly contain another matcher. Remove the top-level matcher or nest it more deeply."); + } + } + test(actual) { + if (Array.isArray(this.pattern)) { + return new ArrayMatch(this.name, this.pattern, { subsequence: false, partialObjects: this.partialObjects }).test(actual); + } + if (typeof this.pattern === "object") { + return new ObjectMatch(this.name, this.pattern, { partial: this.partialObjects }).test(actual); + } + const result = new MatchResult(actual); + if (typeof this.pattern !== typeof actual) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected type ${typeof this.pattern} but received ${getType(actual)}` + }); + return result; + } + if (actual !== this.pattern) { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected ${this.pattern} but received ${actual}` + }); + } + return result; + } +}; +var ArrayMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.subsequence = options.subsequence ?? true; + this.partialObjects = options.partialObjects ?? false; + } + test(actual) { + if (!Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type array but received ${getType(actual)}` + }); + } + if (!this.subsequence && this.pattern.length !== actual.length) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected array of length ${this.pattern.length} but received ${actual.length}` + }); + } + let patternIdx = 0; + let actualIdx = 0; + const result = new MatchResult(actual); + while (patternIdx < this.pattern.length && actualIdx < actual.length) { + const patternElement = this.pattern[patternIdx]; + const matcher = Matcher.isMatcher(patternElement) ? patternElement : new LiteralMatch(this.name, patternElement, { partialObjects: this.partialObjects }); + const matcherName = matcher.name; + if (this.subsequence && (matcherName == "absent" || matcherName == "anyValue")) { + throw new Error(`The Matcher ${matcherName}() cannot be nested within arrayWith()`); + } + const innerResult = matcher.test(actual[actualIdx]); + if (!this.subsequence || !innerResult.hasFailed()) { + result.compose(`[${actualIdx}]`, innerResult); + 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}` + }); + } + return result; + } +}; +var ObjectMatch = class extends Matcher { + constructor(name, pattern, options = {}) { + super(); + this.name = name; + this.pattern = pattern; + this.partial = options.partial ?? true; + } + test(actual) { + if (typeof actual !== "object" || Array.isArray(actual)) { + return new MatchResult(actual).recordFailure({ + matcher: this, + path: [], + message: `Expected type object but received ${getType(actual)}` + }); + } + const result = new MatchResult(actual); + if (!this.partial) { + for (const a of Object.keys(actual)) { + if (!(a in this.pattern)) { + result.recordFailure({ + matcher: this, + path: [`/${a}`], + message: "Unexpected key" + }); + } + } + } + for (const [patternKey, patternVal] of Object.entries(this.pattern)) { + if (!(patternKey in actual) && !(patternVal instanceof AbsentMatch)) { + result.recordFailure({ + matcher: this, + path: [`/${patternKey}`], + message: `Missing key '${patternKey}' among {${Object.keys(actual).join(",")}}` + }); + continue; + } + const matcher = Matcher.isMatcher(patternVal) ? patternVal : new LiteralMatch(this.name, patternVal, { partialObjects: this.partial }); + const inner = matcher.test(actual[patternKey]); + result.compose(`/${patternKey}`, inner); + } + return result; + } +}; +var SerializedJson = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const result = new MatchResult(actual); + if (getType(actual) !== "string") { + result.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({ + matcher: this, + path: [], + message: `Invalid JSON string: ${actual}` + }); + return result; + } else { + throw err; + } + } + 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; + } +}; +var NotMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const matcher = Matcher.isMatcher(this.pattern) ? this.pattern : new LiteralMatch(this.name, this.pattern); + const innerResult = matcher.test(actual); + const result = new MatchResult(actual); + if (innerResult.failCount === 0) { + result.recordFailure({ + matcher: this, + path: [], + message: `Found unexpected match: ${JSON.stringify(actual, void 0, 2)}` + }); + } + return result; + } +}; +var AnyMatch = class extends Matcher { + constructor(name) { + super(); + this.name = name; + } + test(actual) { + const result = new MatchResult(actual); + if (actual == null) { + result.recordFailure({ + matcher: this, + path: [], + message: "Expected a value but found none" + }); + } + return result; + } +}; +var StringLikeRegexpMatch = class extends Matcher { + constructor(name, pattern) { + super(); + this.name = name; + this.pattern = pattern; + } + test(actual) { + const result = new MatchResult(actual); + const regex = new RegExp(this.pattern, "gm"); + if (typeof actual !== "string") { + result.recordFailure({ + matcher: this, + path: [], + message: `Expected a string, but got '${typeof actual}'` + }); + } + if (!regex.test(actual)) { + result.recordFailure({ + matcher: this, + path: [], + message: `String '${actual}' did not match pattern '${this.pattern}'` + }); + } + return result; + } +}; + +// lib/assertions/providers/lambda-handler/base.ts +var https = __toESM(require("https")); +var url = __toESM(require("url")); +var AWS = __toESM(require("aws-sdk")); +var CustomResourceHandler = class { + constructor(event, context) { + this.event = event; + this.context = context; + this.timedOut = false; + this.timeout = setTimeout(async () => { + await this.respond({ + status: "FAILED", + reason: "Lambda Function Timeout", + data: this.context.logStreamName + }); + this.timedOut = true; + }, context.getRemainingTimeInMillis() - 1200); + this.event = event; + this.physicalResourceId = extractPhysicalResourceId(event); + } + async handle() { + try { + if ("stateMachineArn" in this.event.ResourceProperties) { + const req = { + stateMachineArn: this.event.ResourceProperties.stateMachineArn, + name: this.event.RequestId, + input: JSON.stringify(this.event) + }; + await this.startExecution(req); + return; + } else { + const response = await this.processEvent(this.event.ResourceProperties); + return response; + } + } catch (e) { + console.log(e); + throw e; + } finally { + clearTimeout(this.timeout); + } + } + async handleIsComplete() { + try { + const result = await this.processEvent(this.event.ResourceProperties); + return result; + } catch (e) { + console.log(e); + return; + } finally { + clearTimeout(this.timeout); + } + } + async startExecution(req) { + try { + const sfn = new AWS.StepFunctions(); + await sfn.startExecution(req).promise(); + } finally { + clearTimeout(this.timeout); + } + } + respond(response) { + if (this.timedOut) { + return; + } + const cfResponse = { + Status: response.status, + Reason: response.reason, + PhysicalResourceId: this.physicalResourceId, + StackId: this.event.StackId, + RequestId: this.event.RequestId, + LogicalResourceId: this.event.LogicalResourceId, + NoEcho: false, + Data: response.data + }; + const responseBody = JSON.stringify(cfResponse); + console.log("Responding to CloudFormation", responseBody); + const parsedUrl = url.parse(this.event.ResponseURL); + const requestOptions = { + hostname: parsedUrl.hostname, + path: parsedUrl.path, + method: "PUT", + headers: { "content-type": "", "content-length": responseBody.length } + }; + return new Promise((resolve, reject) => { + try { + const request2 = https.request(requestOptions, resolve); + request2.on("error", reject); + request2.write(responseBody); + request2.end(); + } catch (e) { + reject(e); + } finally { + clearTimeout(this.timeout); + } + }); + } +}; +function extractPhysicalResourceId(event) { + switch (event.RequestType) { + case "Create": + return event.LogicalResourceId; + case "Update": + case "Delete": + return event.PhysicalResourceId; + } +} + +// lib/assertions/providers/lambda-handler/assertion.ts +var AssertionHandler = class extends CustomResourceHandler { + async processEvent(request2) { + let actual = decodeCall(request2.actual); + const expected = decodeCall(request2.expected); + let result; + const matcher = new MatchCreator(expected).getMatcher(); + console.log(`Testing equality between ${JSON.stringify(request2.actual)} and ${JSON.stringify(request2.expected)}`); + const matchResult = matcher.test(actual); + matchResult.finished(); + if (matchResult.hasFailed()) { + result = { + failed: true, + assertion: JSON.stringify({ + status: "fail", + message: [ + ...matchResult.toHumanStrings(), + JSON.stringify(matchResult.target, void 0, 2) + ].join("\n") + }) + }; + if (request2.failDeployment) { + throw new Error(result.assertion); + } + } else { + result = { + assertion: JSON.stringify({ + status: "success" + }) + }; + } + return result; + } +}; +var MatchCreator = class { + constructor(obj) { + this.parsedObj = { + matcher: obj + }; + } + getMatcher() { + try { + const final = JSON.parse(JSON.stringify(this.parsedObj), function(_k, v) { + const nested = Object.keys(v)[0]; + switch (nested) { + case "$ArrayWith": + return Match.arrayWith(v[nested]); + case "$ObjectLike": + return Match.objectLike(v[nested]); + case "$StringLike": + return Match.stringLikeRegexp(v[nested]); + default: + return v; + } + }); + if (Matcher.isMatcher(final.matcher)) { + return final.matcher; + } + return Match.exact(final.matcher); + } catch { + return Match.exact(this.parsedObj.matcher); + } + } +}; +function decodeCall(call) { + if (!call) { + return void 0; + } + try { + const parsed = JSON.parse(call); + return parsed; + } catch (e) { + return call; + } +} + +// lib/assertions/providers/lambda-handler/utils.ts +function decode(object) { + return JSON.parse(JSON.stringify(object), (_k, v) => { + switch (v) { + case "TRUE:BOOLEAN": + return true; + case "FALSE:BOOLEAN": + return false; + default: + return v; + } + }); +} + +// lib/assertions/providers/lambda-handler/sdk.ts +function flatten(object) { + return Object.assign( + {}, + ...function _flatten(child, path = []) { + return [].concat(...Object.keys(child).map((key) => { + let childKey = Buffer.isBuffer(child[key]) ? child[key].toString("utf8") : child[key]; + if (typeof childKey === "string") { + childKey = isJsonString(childKey); + } + return typeof childKey === "object" && childKey !== null ? _flatten(childKey, path.concat([key])) : { [path.concat([key]).join(".")]: childKey }; + })); + }(object) + ); +} +var AwsApiCallHandler = class extends CustomResourceHandler { + async processEvent(request2) { + const AWS2 = require("aws-sdk"); + console.log(`AWS SDK VERSION: ${AWS2.VERSION}`); + if (!Object.prototype.hasOwnProperty.call(AWS2, request2.service)) { + throw Error(`Service ${request2.service} does not exist in AWS SDK version ${AWS2.VERSION}.`); + } + const service = new AWS2[request2.service](); + const response = await service[request2.api](request2.parameters && decode(request2.parameters)).promise(); + console.log(`SDK response received ${JSON.stringify(response)}`); + delete response.ResponseMetadata; + const respond = { + apiCallResponse: response + }; + const flatData = { + ...flatten(respond) + }; + let resp = respond; + if (request2.outputPaths) { + resp = filterKeys(flatData, request2.outputPaths); + } else if (request2.flattenResponse === "true") { + resp = flatData; + } + console.log(`Returning result ${JSON.stringify(resp)}`); + return resp; + } +}; +function filterKeys(object, searchStrings) { + return Object.entries(object).reduce((filteredObject, [key, value]) => { + for (const searchString of searchStrings) { + if (key.startsWith(`apiCallResponse.${searchString}`)) { + filteredObject[key] = value; + } + } + return filteredObject; + }, {}); +} +function isJsonString(value) { + try { + return JSON.parse(value); + } catch { + return value; + } +} + +// lib/assertions/providers/lambda-handler/types.ts +var ASSERT_RESOURCE_TYPE = "Custom::DeployAssert@AssertEquals"; +var SDK_RESOURCE_TYPE_PREFIX = "Custom::DeployAssert@SdkCall"; + +// lib/assertions/providers/lambda-handler/index.ts +async function handler(event, context) { + console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); + const provider = createResourceHandler(event, context); + try { + if (event.RequestType === "Delete") { + await provider.respond({ + status: "SUCCESS", + reason: "OK" + }); + return; + } + const result = await provider.handle(); + if ("stateMachineArn" in event.ResourceProperties) { + console.info('Found "stateMachineArn", waiter statemachine started'); + return; + } else if ("expected" in event.ResourceProperties) { + console.info('Found "expected", testing assertions'); + const actualPath = event.ResourceProperties.actualPath; + const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; + const assertion = new AssertionHandler({ + ...event, + ResourceProperties: { + ServiceToken: event.ServiceToken, + actual, + expected: event.ResourceProperties.expected + } + }, context); + try { + const assertionResult = await assertion.handle(); + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: { + ...assertionResult, + ...result + } + }); + return; + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + } + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: result + }); + } catch (e) { + await provider.respond({ + status: "FAILED", + reason: e.message ?? "Internal Error" + }); + return; + } + return; +} +async function onTimeout(timeoutEvent) { + const isCompleteRequest = JSON.parse(JSON.parse(timeoutEvent.Cause).errorMessage); + const provider = createResourceHandler(isCompleteRequest, standardContext); + await provider.respond({ + status: "FAILED", + reason: "Operation timed out: " + JSON.stringify(isCompleteRequest) + }); +} +async function isComplete(event, context) { + console.log(`Event: ${JSON.stringify({ ...event, ResponseURL: "..." })}`); + const provider = createResourceHandler(event, context); + try { + const result = await provider.handleIsComplete(); + const actualPath = event.ResourceProperties.actualPath; + if (result) { + const actual = actualPath ? result[`apiCallResponse.${actualPath}`] : result.apiCallResponse; + if ("expected" in event.ResourceProperties) { + const assertion = new AssertionHandler({ + ...event, + ResourceProperties: { + ServiceToken: event.ServiceToken, + actual, + expected: event.ResourceProperties.expected + } + }, context); + const assertionResult = await assertion.handleIsComplete(); + if (!(assertionResult == null ? void 0 : assertionResult.failed)) { + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: { + ...assertionResult, + ...result + } + }); + return; + } else { + console.log(`Assertion Failed: ${JSON.stringify(assertionResult)}`); + throw new Error(JSON.stringify(event)); + } + } + await provider.respond({ + status: "SUCCESS", + reason: "OK", + data: result + }); + } else { + console.log("No result"); + throw new Error(JSON.stringify(event)); + } + return; + } catch (e) { + console.log(e); + throw new Error(JSON.stringify(event)); + } +} +function createResourceHandler(event, context) { + if (event.ResourceType.startsWith(SDK_RESOURCE_TYPE_PREFIX)) { + return new AwsApiCallHandler(event, context); + } else if (event.ResourceType.startsWith(ASSERT_RESOURCE_TYPE)) { + return new AssertionHandler(event, context); + } else { + throw new Error(`Unsupported resource type "${event.ResourceType}`); + } +} +var standardContext = { + getRemainingTimeInMillis: () => 9e4 +}; +// Annotate the CommonJS export names for ESM import in node: +0 && (module.exports = { + handler, + isComplete, + onTimeout +}); diff --git a/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/aws-cdk-redshift-cluster-create.assets.json b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/aws-cdk-redshift-cluster-create.assets.json new file mode 100644 index 0000000000000..9d403bee01fcb --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/aws-cdk-redshift-cluster-create.assets.json @@ -0,0 +1,45 @@ +{ + "version": "22.0.0", + "files": { + "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e": { + "source": { + "path": "asset.1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585": { + "source": { + "path": "asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "93a411da5664a42e1702532262aa281227dd5fc1f136148d06a42addd7c763c0": { + "source": { + "path": "aws-cdk-redshift-cluster-create.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "93a411da5664a42e1702532262aa281227dd5fc1f136148d06a42addd7c763c0.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.cluster-reboot.js.snapshot/aws-cdk-redshift-cluster-create.template.json b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/aws-cdk-redshift-cluster-create.template.json new file mode 100644 index 0000000000000..f7c7f21326370 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/aws-cdk-redshift-cluster-create.template.json @@ -0,0 +1,553 @@ +{ + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-create/Vpc" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet1Subnet77A7FDC6": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.0.0/17", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "foobar" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet1RouteTableAF4E5874": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet1RouteTableAssociation502CBE55": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcfoobarSubnet1RouteTableAF4E5874" + }, + "SubnetId": { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet2Subnet85B013AD": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.128.0/17", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "foobar" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet2RouteTable5127598D": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet2RouteTableAssociation5013D70B": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcfoobarSubnet2RouteTable5127598D" + }, + "SubnetId": { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ParameterGroup5E32DECB": { + "Type": "AWS::Redshift::ClusterParameterGroup", + "Properties": { + "Description": "Cluster parameter group for family redshift-1.0", + "ParameterGroupFamily": "redshift-1.0", + "Parameters": [ + { + "ParameterName": "enable_user_activity_logging", + "ParameterValue": "true" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSubnetsDCFA5CB7": { + "Type": "AWS::Redshift::ClusterSubnetGroup", + "Properties": { + "Description": "Subnets for Cluster Redshift cluster", + "SubnetIds": [ + { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + }, + { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSecurityGroup0921994B": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Redshift security group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSecret6368BD0F": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "GenerateSecretString": { + "ExcludeCharacters": "\"@/\\ '", + "GenerateStringKey": "password", + "PasswordLength": 30, + "SecretStringTemplate": "{\"username\":\"admin\"}" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSecretAttachment769E6258": { + "Type": "AWS::SecretsManager::SecretTargetAttachment", + "Properties": { + "SecretId": { + "Ref": "ClusterSecret6368BD0F" + }, + "TargetId": { + "Ref": "ClusterEB0386A7" + }, + "TargetType": "AWS::Redshift::Cluster" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterEB0386A7": { + "Type": "AWS::Redshift::Cluster", + "Properties": { + "ClusterType": "multi-node", + "DBName": "default_db", + "MasterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:username::}}" + ] + ] + }, + "MasterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:password::}}" + ] + ] + }, + "NodeType": "dc2.large", + "AllowVersionUpgrade": true, + "AutomatedSnapshotRetentionPeriod": 1, + "ClusterParameterGroupName": { + "Ref": "ParameterGroup5E32DECB" + }, + "ClusterSubnetGroupName": { + "Ref": "ClusterSubnetsDCFA5CB7" + }, + "Encrypted": true, + "NumberOfNodes": 2, + "PubliclyAccessible": false, + "VpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "ClusterSecurityGroup0921994B", + "GroupId" + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE": { + "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" + ] + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86", + "Roles": [ + { + "Ref": "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterResourceProviderframeworkonEvent15BB3722": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE", + "Arn" + ] + }, + "Description": "AWS CDK resource provider framework - onEvent (aws-cdk-redshift-cluster-create/Cluster/ResourceProvider)", + "Environment": { + "Variables": { + "USER_ON_EVENT_FUNCTION_ARN": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + } + } + }, + "Handler": "framework.onEvent", + "Runtime": "nodejs14.x", + "Timeout": 900 + }, + "DependsOn": [ + "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86", + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterRedshiftClusterRebooterCustomResource773361E1": { + "Type": "Custom::RedshiftClusterRebooter", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "ClusterResourceProviderframeworkonEvent15BB3722", + "Arn" + ] + }, + "ClusterId": { + "Ref": "ClusterEB0386A7" + }, + "ParameterGroupName": { + "Ref": "ParameterGroup5E32DECB" + }, + "ParametersString": "{\"enable_user_activity_logging\":\"true\"}" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525": { + "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" + ] + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "redshift:DescribeClusters", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "redshift:RebootCluster", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":redshift:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":cluster:", + { + "Ref": "ClusterEB0386A7" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF", + "Roles": [ + { + "Ref": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e.zip" + }, + "Role": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs16.x", + "Timeout": 900 + }, + "DependsOn": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF", + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "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.cluster-reboot.js.snapshot/aws-cdk-redshift-cluster-update.assets.json b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/aws-cdk-redshift-cluster-update.assets.json new file mode 100644 index 0000000000000..4349cdb12e9be --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/aws-cdk-redshift-cluster-update.assets.json @@ -0,0 +1,45 @@ +{ + "version": "22.0.0", + "files": { + "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e": { + "source": { + "path": "asset.1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585": { + "source": { + "path": "asset.a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "5a23231417fb67ed1d1d3f790c75060c7ca5f2b45a1e8b532dcaf9d8d40171cd": { + "source": { + "path": "aws-cdk-redshift-cluster-update.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "5a23231417fb67ed1d1d3f790c75060c7ca5f2b45a1e8b532dcaf9d8d40171cd.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.cluster-reboot.js.snapshot/aws-cdk-redshift-cluster-update.template.json b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/aws-cdk-redshift-cluster-update.template.json new file mode 100644 index 0000000000000..a06dc5062ed6b --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/aws-cdk-redshift-cluster-update.template.json @@ -0,0 +1,575 @@ +{ + "Resources": { + "Vpc8378EB38": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.0.0.0/16", + "EnableDnsHostnames": true, + "EnableDnsSupport": true, + "InstanceTenancy": "default", + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-update/Vpc" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet1Subnet77A7FDC6": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.0.0/17", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "foobar" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet1RouteTableAF4E5874": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet1RouteTableAssociation502CBE55": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcfoobarSubnet1RouteTableAF4E5874" + }, + "SubnetId": { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet2Subnet85B013AD": { + "Type": "AWS::EC2::Subnet", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "AvailabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "CidrBlock": "10.0.128.0/17", + "MapPublicIpOnLaunch": false, + "Tags": [ + { + "Key": "aws-cdk:subnet-name", + "Value": "foobar" + }, + { + "Key": "aws-cdk:subnet-type", + "Value": "Isolated" + }, + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet2RouteTable5127598D": { + "Type": "AWS::EC2::RouteTable", + "Properties": { + "VpcId": { + "Ref": "Vpc8378EB38" + }, + "Tags": [ + { + "Key": "Name", + "Value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "VpcfoobarSubnet2RouteTableAssociation5013D70B": { + "Type": "AWS::EC2::SubnetRouteTableAssociation", + "Properties": { + "RouteTableId": { + "Ref": "VpcfoobarSubnet2RouteTable5127598D" + }, + "SubnetId": { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ParameterGroup5E32DECB": { + "Type": "AWS::Redshift::ClusterParameterGroup", + "Properties": { + "Description": "Cluster parameter group for family redshift-1.0", + "ParameterGroupFamily": "redshift-1.0", + "Parameters": [ + { + "ParameterName": "enable_user_activity_logging", + "ParameterValue": "false" + }, + { + "ParameterName": "use_fips_ssl", + "ParameterValue": "true" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSubnetsDCFA5CB7": { + "Type": "AWS::Redshift::ClusterSubnetGroup", + "Properties": { + "Description": "Subnets for Cluster Redshift cluster", + "SubnetIds": [ + { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + }, + { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSecurityGroup0921994B": { + "Type": "AWS::EC2::SecurityGroup", + "Properties": { + "GroupDescription": "Redshift security group", + "SecurityGroupEgress": [ + { + "CidrIp": "0.0.0.0/0", + "Description": "Allow all outbound traffic by default", + "IpProtocol": "-1" + } + ], + "VpcId": { + "Ref": "Vpc8378EB38" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSecret6368BD0F": { + "Type": "AWS::SecretsManager::Secret", + "Properties": { + "GenerateSecretString": { + "ExcludeCharacters": "\"@/\\ '", + "GenerateStringKey": "password", + "PasswordLength": 30, + "SecretStringTemplate": "{\"username\":\"admin\"}" + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterSecretAttachment769E6258": { + "Type": "AWS::SecretsManager::SecretTargetAttachment", + "Properties": { + "SecretId": { + "Ref": "ClusterSecret6368BD0F" + }, + "TargetId": { + "Ref": "ClusterEB0386A7" + }, + "TargetType": "AWS::Redshift::Cluster" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterEB0386A7": { + "Type": "AWS::Redshift::Cluster", + "Properties": { + "ClusterType": "multi-node", + "DBName": "default_db", + "MasterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:username::}}" + ] + ] + }, + "MasterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:password::}}" + ] + ] + }, + "NodeType": "dc2.large", + "AllowVersionUpgrade": true, + "AutomatedSnapshotRetentionPeriod": 1, + "ClusterParameterGroupName": { + "Ref": "ParameterGroup5E32DECB" + }, + "ClusterSubnetGroupName": { + "Ref": "ClusterSubnetsDCFA5CB7" + }, + "Encrypted": true, + "NumberOfNodes": 2, + "PubliclyAccessible": false, + "VpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "ClusterSecurityGroup0921994B", + "GroupId" + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE": { + "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" + ] + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86", + "Roles": [ + { + "Ref": "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterResourceProviderframeworkonEvent15BB3722": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585.zip" + }, + "Role": { + "Fn::GetAtt": [ + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE", + "Arn" + ] + }, + "Description": "AWS CDK resource provider framework - onEvent (aws-cdk-redshift-cluster-update/Cluster/ResourceProvider)", + "Environment": { + "Variables": { + "USER_ON_EVENT_FUNCTION_ARN": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + } + } + }, + "Handler": "framework.onEvent", + "Runtime": "nodejs14.x", + "Timeout": 900 + }, + "DependsOn": [ + "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86", + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "ClusterRedshiftClusterRebooterCustomResource773361E1": { + "Type": "Custom::RedshiftClusterRebooter", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "ClusterResourceProviderframeworkonEvent15BB3722", + "Arn" + ] + }, + "ClusterId": { + "Ref": "ClusterEB0386A7" + }, + "ParameterGroupName": { + "Ref": "ParameterGroup5E32DECB" + }, + "ParametersString": "{\"enable_user_activity_logging\":\"false\",\"use_fips_ssl\":\"true\"}" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525": { + "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" + ] + ] + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": "redshift:DescribeClusters", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "redshift:RebootCluster", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":redshift:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":cluster:", + { + "Ref": "ClusterEB0386A7" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF", + "Roles": [ + { + "Ref": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + } + ] + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e.zip" + }, + "Role": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs16.x", + "Timeout": 900 + }, + "DependsOn": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF", + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + ], + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Outputs": { + "ExportsOutputRefClusterEB0386A796A0E3FE": { + "Value": { + "Ref": "ClusterEB0386A7" + }, + "Export": { + "Name": "aws-cdk-redshift-cluster-reboot-integ:ExportsOutputRefClusterEB0386A796A0E3FE" + } + }, + "ExportsOutputRefParameterGroup5E32DECBB33EA140": { + "Value": { + "Ref": "ParameterGroup5E32DECB" + }, + "Export": { + "Name": "aws-cdk-redshift-cluster-reboot-integ:ExportsOutputRefParameterGroup5E32DECBB33EA140" + } + } + }, + "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.cluster-reboot.js.snapshot/awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.assets.json b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.assets.json new file mode 100644 index 0000000000000..3db8d2f9bd63d --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.assets.json @@ -0,0 +1,32 @@ +{ + "version": "22.0.0", + "files": { + "382ba2a8fd0a13f6782aec5543e465f988f5c100f35ed20f90cd96b8ee53f674": { + "source": { + "path": "asset.382ba2a8fd0a13f6782aec5543e465f988f5c100f35ed20f90cd96b8ee53f674.bundle", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "382ba2a8fd0a13f6782aec5543e465f988f5c100f35ed20f90cd96b8ee53f674.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "02ba7e5975057b784436be8170fb2b40a050d51601ba1ed065a7339ea2cd67ae": { + "source": { + "path": "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "02ba7e5975057b784436be8170fb2b40a050d51601ba1ed065a7339ea2cd67ae.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.cluster-reboot.js.snapshot/awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.template.json b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.template.json new file mode 100644 index 0000000000000..8cb906f08a943 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.template.json @@ -0,0 +1,177 @@ +{ + "Resources": { + "AwsApiCallRedshiftdescribeClusters": { + "Type": "Custom::DeployAssert@SdkCallRedshiftdescribeClusters", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F", + "Arn" + ] + }, + "service": "Redshift", + "api": "describeClusters", + "expected": "{\"$StringLike\":\"in-sync\"}", + "actualPath": "Clusters.0.ClusterParameterGroups.0.ParameterApplyStatus", + "parameters": { + "ClusterIdentifier": { + "Fn::ImportValue": "aws-cdk-redshift-cluster-reboot-integ:ExportsOutputRefClusterEB0386A796A0E3FE" + } + }, + "flattenResponse": "true", + "outputPaths": [ + "Clusters.0.ClusterParameterGroups.0.ParameterApplyStatus" + ], + "salt": "1671057311528" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73": { + "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": [ + { + "Action": [ + "redshift:DescribeClusters" + ], + "Effect": "Allow", + "Resource": [ + "*" + ] + }, + { + "Action": [ + "redshift:DescribeClusterParameters" + ], + "Effect": "Allow", + "Resource": [ + "*" + ] + } + ] + } + } + ] + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Runtime": "nodejs14.x", + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "382ba2a8fd0a13f6782aec5543e465f988f5c100f35ed20f90cd96b8ee53f674.zip" + }, + "Timeout": 120, + "Handler": "index.handler", + "Role": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73", + "Arn" + ] + } + } + }, + "AwsApiCallRedshiftdescribeClusterParameters": { + "Type": "Custom::DeployAssert@SdkCallRedshiftdescribeClusterParameter", + "Properties": { + "ServiceToken": { + "Fn::GetAtt": [ + "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F", + "Arn" + ] + }, + "service": "Redshift", + "api": "describeClusterParameters", + "expected": "{\"$ObjectLike\":{\"Parameters\":{\"$ArrayWith\":[{\"$ObjectLike\":{\"ParameterName\":\"enable_user_activity_logging\",\"ParameterValue\":\"false\"}},{\"$ObjectLike\":{\"ParameterName\":\"use_fips_ssl\",\"ParameterValue\":\"true\"}}]}}}", + "parameters": { + "ParameterGroupName": { + "Fn::ImportValue": "aws-cdk-redshift-cluster-reboot-integ:ExportsOutputRefParameterGroup5E32DECBB33EA140" + }, + "Source": "user" + }, + "flattenResponse": "false", + "salt": "1671057311529" + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + } + }, + "Outputs": { + "AssertionResultsAwsApiCallRedshiftdescribeClusters": { + "Value": { + "Fn::GetAtt": [ + "AwsApiCallRedshiftdescribeClusters", + "assertion" + ] + } + }, + "AssertionResultsAwsApiCallRedshiftdescribeClusterParameters": { + "Value": { + "Fn::GetAtt": [ + "AwsApiCallRedshiftdescribeClusterParameters", + "assertion" + ] + } + } + }, + "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.cluster-reboot.js.snapshot/cdk.out b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/cdk.out new file mode 100644 index 0000000000000..145739f539580 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"22.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/integ.json b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/integ.json new file mode 100644 index 0000000000000..9cdefdeec7bab --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/integ.json @@ -0,0 +1,14 @@ +{ + "version": "22.0.0", + "testCases": { + "aws-cdk-redshift-reboot-test/DefaultTest": { + "stacks": [ + "aws-cdk-redshift-cluster-create", + "aws-cdk-redshift-cluster-update" + ], + "stackUpdateWorkflow": false, + "assertionStack": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert", + "assertionStackName": "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/manifest.json b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/manifest.json new file mode 100644 index 0000000000000..614f41d6c6a65 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/manifest.json @@ -0,0 +1,444 @@ +{ + "version": "22.0.0", + "artifacts": { + "aws-cdk-redshift-cluster-create.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-redshift-cluster-create.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-redshift-cluster-create": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-redshift-cluster-create.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}/93a411da5664a42e1702532262aa281227dd5fc1f136148d06a42addd7c763c0.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-redshift-cluster-create.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" + }, + "stackName": "aws-cdk-redshift-cluster-reboot-integ" + }, + "dependencies": [ + "aws-cdk-redshift-cluster-create.assets" + ], + "metadata": { + "/aws-cdk-redshift-cluster-create/Vpc/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Vpc8378EB38" + } + ], + "/aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet1Subnet77A7FDC6" + } + ], + "/aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet1RouteTableAF4E5874" + } + ], + "/aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet1RouteTableAssociation502CBE55" + } + ], + "/aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet2Subnet85B013AD" + } + ], + "/aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet2RouteTable5127598D" + } + ], + "/aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet2RouteTableAssociation5013D70B" + } + ], + "/aws-cdk-redshift-cluster-create/ParameterGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ParameterGroup5E32DECB" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/Subnets/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSubnetsDCFA5CB7" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/SecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSecurityGroup0921994B" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/Secret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSecret6368BD0F" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/Secret/Attachment/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSecretAttachment769E6258" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterEB0386A7" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterResourceProviderframeworkonEvent15BB3722" + } + ], + "/aws-cdk-redshift-cluster-create/Cluster/RedshiftClusterRebooterCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterRedshiftClusterRebooterCustomResource773361E1" + } + ], + "/aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + } + ], + "/aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF" + } + ], + "/aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5" + } + ], + "/aws-cdk-redshift-cluster-create/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-redshift-cluster-create/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-redshift-cluster-create" + }, + "aws-cdk-redshift-cluster-update.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "aws-cdk-redshift-cluster-update.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "aws-cdk-redshift-cluster-update": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-redshift-cluster-update.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}/5a23231417fb67ed1d1d3f790c75060c7ca5f2b45a1e8b532dcaf9d8d40171cd.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "aws-cdk-redshift-cluster-update.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" + }, + "stackName": "aws-cdk-redshift-cluster-reboot-integ" + }, + "dependencies": [ + "aws-cdk-redshift-cluster-create", + "aws-cdk-redshift-cluster-update.assets" + ], + "metadata": { + "/aws-cdk-redshift-cluster-update/Vpc/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Vpc8378EB38" + } + ], + "/aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet1Subnet77A7FDC6" + } + ], + "/aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet1RouteTableAF4E5874" + } + ], + "/aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet1RouteTableAssociation502CBE55" + } + ], + "/aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2/Subnet": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet2Subnet85B013AD" + } + ], + "/aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2/RouteTable": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet2RouteTable5127598D" + } + ], + "/aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2/RouteTableAssociation": [ + { + "type": "aws:cdk:logicalId", + "data": "VpcfoobarSubnet2RouteTableAssociation5013D70B" + } + ], + "/aws-cdk-redshift-cluster-update/ParameterGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ParameterGroup5E32DECB" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/Subnets/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSubnetsDCFA5CB7" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/SecurityGroup/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSecurityGroup0921994B" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/Secret/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSecret6368BD0F" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/Secret/Attachment/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterSecretAttachment769E6258" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterEB0386A7" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterResourceProviderframeworkonEvent15BB3722" + } + ], + "/aws-cdk-redshift-cluster-update/Cluster/RedshiftClusterRebooterCustomResource/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "ClusterRedshiftClusterRebooterCustomResource773361E1" + } + ], + "/aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + } + ], + "/aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/DefaultPolicy/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF" + } + ], + "/aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5" + } + ], + "/aws-cdk-redshift-cluster-update/Exports/Output{\"Ref\":\"ClusterEB0386A7\"}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputRefClusterEB0386A796A0E3FE" + } + ], + "/aws-cdk-redshift-cluster-update/Exports/Output{\"Ref\":\"ParameterGroup5E32DECB\"}": [ + { + "type": "aws:cdk:logicalId", + "data": "ExportsOutputRefParameterGroup5E32DECBB33EA140" + } + ], + "/aws-cdk-redshift-cluster-update/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-redshift-cluster-update/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-redshift-cluster-update" + }, + "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.assets": { + "type": "cdk:asset-manifest", + "properties": { + "file": "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.assets.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version" + } + }, + "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.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}/02ba7e5975057b784436be8170fb2b40a050d51601ba1ed065a7339ea2cd67ae.json", + "requiresBootstrapStackVersion": 6, + "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", + "additionalDependencies": [ + "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.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": [ + "aws-cdk-redshift-cluster-update", + "awscdkredshiftreboottestDefaultTestDeployAssert1AE11B34.assets" + ], + "metadata": { + "/aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusters/Default/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsApiCallRedshiftdescribeClusters" + } + ], + "/aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusters/AssertionResults": [ + { + "type": "aws:cdk:logicalId", + "data": "AssertionResultsAwsApiCallRedshiftdescribeClusters" + } + ], + "/aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81Role37ABCE73" + } + ], + "/aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler": [ + { + "type": "aws:cdk:logicalId", + "data": "SingletonFunction1488541a7b23466481b69b4408076b81HandlerCD40AE9F" + } + ], + "/aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusterParameters/Default/Default": [ + { + "type": "aws:cdk:logicalId", + "data": "AwsApiCallRedshiftdescribeClusterParameters" + } + ], + "/aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusterParameters/AssertionResults": [ + { + "type": "aws:cdk:logicalId", + "data": "AssertionResultsAwsApiCallRedshiftdescribeClusterParameters" + } + ], + "/aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/BootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "BootstrapVersion" + } + ], + "/aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/CheckBootstrapVersion": [ + { + "type": "aws:cdk:logicalId", + "data": "CheckBootstrapVersion" + } + ] + }, + "displayName": "aws-cdk-redshift-reboot-test/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.cluster-reboot.js.snapshot/tree.json b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/tree.json new file mode 100644 index 0000000000000..f4bf2ad97974e --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.js.snapshot/tree.json @@ -0,0 +1,2041 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "aws-cdk-redshift-cluster-create": { + "id": "aws-cdk-redshift-cluster-create", + "path": "aws-cdk-redshift-cluster-create", + "children": { + "Vpc": { + "id": "Vpc", + "path": "aws-cdk-redshift-cluster-create/Vpc", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/Vpc/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPC", + "aws:cdk:cloudformation:props": { + "cidrBlock": "10.0.0.0/16", + "enableDnsHostnames": true, + "enableDnsSupport": true, + "instanceTenancy": "default", + "tags": [ + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-create/Vpc" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnVPC", + "version": "0.0.0" + } + }, + "foobarSubnet1": { + "id": "foobarSubnet1", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.0.0/17", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "foobar" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Isolated" + }, + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1/Acl", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VpcfoobarSubnet1RouteTableAF4E5874" + }, + "subnetId": { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", + "version": "0.0.0" + } + }, + "foobarSubnet2": { + "id": "foobarSubnet2", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.128.0/17", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "foobar" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Isolated" + }, + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2/Acl", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-redshift-cluster-create/Vpc/foobarSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VpcfoobarSubnet2RouteTable5127598D" + }, + "subnetId": { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.Vpc", + "version": "0.0.0" + } + }, + "ParameterGroup": { + "id": "ParameterGroup", + "path": "aws-cdk-redshift-cluster-create/ParameterGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/ParameterGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Redshift::ClusterParameterGroup", + "aws:cdk:cloudformation:props": { + "description": "Cluster parameter group for family redshift-1.0", + "parameterGroupFamily": "redshift-1.0", + "parameters": [ + { + "parameterName": "enable_user_activity_logging", + "parameterValue": "true" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.CfnClusterParameterGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.ClusterParameterGroup", + "version": "0.0.0" + } + }, + "Cluster": { + "id": "Cluster", + "path": "aws-cdk-redshift-cluster-create/Cluster", + "children": { + "Subnets": { + "id": "Subnets", + "path": "aws-cdk-redshift-cluster-create/Cluster/Subnets", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-redshift-cluster-create/Cluster/Subnets/Default", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Redshift::ClusterSubnetGroup", + "aws:cdk:cloudformation:props": { + "description": "Subnets for Cluster Redshift cluster", + "subnetIds": [ + { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + }, + { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.CfnClusterSubnetGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.ClusterSubnetGroup", + "version": "0.0.0" + } + }, + "SecurityGroup": { + "id": "SecurityGroup", + "path": "aws-cdk-redshift-cluster-create/Cluster/SecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/Cluster/SecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "Redshift security group", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.SecurityGroup", + "version": "0.0.0" + } + }, + "Secret": { + "id": "Secret", + "path": "aws-cdk-redshift-cluster-create/Cluster/Secret", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/Cluster/Secret/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::Secret", + "aws:cdk:cloudformation:props": { + "generateSecretString": { + "passwordLength": 30, + "secretStringTemplate": "{\"username\":\"admin\"}", + "generateStringKey": "password", + "excludeCharacters": "\"@/\\ '" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-secretsmanager.CfnSecret", + "version": "0.0.0" + } + }, + "Attachment": { + "id": "Attachment", + "path": "aws-cdk-redshift-cluster-create/Cluster/Secret/Attachment", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/Cluster/Secret/Attachment/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::SecretTargetAttachment", + "aws:cdk:cloudformation:props": { + "secretId": { + "Ref": "ClusterSecret6368BD0F" + }, + "targetId": { + "Ref": "ClusterEB0386A7" + }, + "targetType": "AWS::Redshift::Cluster" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-secretsmanager.CfnSecretTargetAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-secretsmanager.SecretTargetAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.DatabaseSecret", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/Cluster/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Redshift::Cluster", + "aws:cdk:cloudformation:props": { + "clusterType": "multi-node", + "dbName": "default_db", + "masterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:username::}}" + ] + ] + }, + "masterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:password::}}" + ] + ] + }, + "nodeType": "dc2.large", + "allowVersionUpgrade": true, + "automatedSnapshotRetentionPeriod": 1, + "clusterParameterGroupName": { + "Ref": "ParameterGroup5E32DECB" + }, + "clusterSubnetGroupName": { + "Ref": "ClusterSubnetsDCFA5CB7" + }, + "encrypted": true, + "numberOfNodes": 2, + "publiclyAccessible": false, + "vpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "ClusterSecurityGroup0921994B", + "GroupId" + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.CfnCluster", + "version": "0.0.0" + } + }, + "RedshiftClusterRebooterFunction": { + "id": "RedshiftClusterRebooterFunction", + "path": "aws-cdk-redshift-cluster-create/Cluster/RedshiftClusterRebooterFunction", + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.SingletonFunction", + "version": "0.0.0" + } + }, + "ResourceProvider": { + "id": "ResourceProvider", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider", + "children": { + "framework-onEvent": { + "id": "framework-onEvent", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/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" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/ServiceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/ServiceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86", + "roles": [ + { + "Ref": "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Code": { + "id": "Code", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/Code/Stage", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/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": "aws-cdk-redshift-cluster-create/Cluster/ResourceProvider/framework-onEvent/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": "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585.zip" + }, + "role": { + "Fn::GetAtt": [ + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE", + "Arn" + ] + }, + "description": "AWS CDK resource provider framework - onEvent (aws-cdk-redshift-cluster-create/Cluster/ResourceProvider)", + "environment": { + "variables": { + "USER_ON_EVENT_FUNCTION_ARN": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + } + } + }, + "handler": "framework.onEvent", + "runtime": "nodejs14.x", + "timeout": 900 + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/custom-resources.Provider", + "version": "0.0.0" + } + }, + "RedshiftClusterRebooterCustomResource": { + "id": "RedshiftClusterRebooterCustomResource", + "path": "aws-cdk-redshift-cluster-create/Cluster/RedshiftClusterRebooterCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-redshift-cluster-create/Cluster/RedshiftClusterRebooterCustomResource/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/aws-redshift.Cluster", + "version": "0.0.0" + } + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2": { + "id": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/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" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "redshift:DescribeClusters", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "redshift:RebootCluster", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":redshift:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":cluster:", + { + "Ref": "ClusterEB0386A7" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF", + "roles": [ + { + "Ref": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Code": { + "id": "Code", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/Code/Stage", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/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": "aws-cdk-redshift-cluster-create/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/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": "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e.zip" + }, + "role": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs16.x", + "timeout": 900 + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-cdk-redshift-cluster-create/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-cdk-redshift-cluster-create/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "aws-cdk-redshift-cluster-update": { + "id": "aws-cdk-redshift-cluster-update", + "path": "aws-cdk-redshift-cluster-update", + "children": { + "Vpc": { + "id": "Vpc", + "path": "aws-cdk-redshift-cluster-update/Vpc", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/Vpc/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::VPC", + "aws:cdk:cloudformation:props": { + "cidrBlock": "10.0.0.0/16", + "enableDnsHostnames": true, + "enableDnsSupport": true, + "instanceTenancy": "default", + "tags": [ + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-update/Vpc" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnVPC", + "version": "0.0.0" + } + }, + "foobarSubnet1": { + "id": "foobarSubnet1", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "availabilityZone": { + "Fn::Select": [ + 0, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.0.0/17", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "foobar" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Isolated" + }, + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1/Acl", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet1/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VpcfoobarSubnet1RouteTableAF4E5874" + }, + "subnetId": { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", + "version": "0.0.0" + } + }, + "foobarSubnet2": { + "id": "foobarSubnet2", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2", + "children": { + "Subnet": { + "id": "Subnet", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2/Subnet", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::Subnet", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "availabilityZone": { + "Fn::Select": [ + 1, + { + "Fn::GetAZs": "" + } + ] + }, + "cidrBlock": "10.0.128.0/17", + "mapPublicIpOnLaunch": false, + "tags": [ + { + "key": "aws-cdk:subnet-name", + "value": "foobar" + }, + { + "key": "aws-cdk:subnet-type", + "value": "Isolated" + }, + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnet", + "version": "0.0.0" + } + }, + "Acl": { + "id": "Acl", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2/Acl", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "RouteTable": { + "id": "RouteTable", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2/RouteTable", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::RouteTable", + "aws:cdk:cloudformation:props": { + "vpcId": { + "Ref": "Vpc8378EB38" + }, + "tags": [ + { + "key": "Name", + "value": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnRouteTable", + "version": "0.0.0" + } + }, + "RouteTableAssociation": { + "id": "RouteTableAssociation", + "path": "aws-cdk-redshift-cluster-update/Vpc/foobarSubnet2/RouteTableAssociation", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SubnetRouteTableAssociation", + "aws:cdk:cloudformation:props": { + "routeTableId": { + "Ref": "VpcfoobarSubnet2RouteTable5127598D" + }, + "subnetId": { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSubnetRouteTableAssociation", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.PrivateSubnet", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.Vpc", + "version": "0.0.0" + } + }, + "ParameterGroup": { + "id": "ParameterGroup", + "path": "aws-cdk-redshift-cluster-update/ParameterGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/ParameterGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Redshift::ClusterParameterGroup", + "aws:cdk:cloudformation:props": { + "description": "Cluster parameter group for family redshift-1.0", + "parameterGroupFamily": "redshift-1.0", + "parameters": [ + { + "parameterName": "enable_user_activity_logging", + "parameterValue": "false" + }, + { + "parameterName": "use_fips_ssl", + "parameterValue": "true" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.CfnClusterParameterGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.ClusterParameterGroup", + "version": "0.0.0" + } + }, + "Cluster": { + "id": "Cluster", + "path": "aws-cdk-redshift-cluster-update/Cluster", + "children": { + "Subnets": { + "id": "Subnets", + "path": "aws-cdk-redshift-cluster-update/Cluster/Subnets", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-redshift-cluster-update/Cluster/Subnets/Default", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Redshift::ClusterSubnetGroup", + "aws:cdk:cloudformation:props": { + "description": "Subnets for Cluster Redshift cluster", + "subnetIds": [ + { + "Ref": "VpcfoobarSubnet1Subnet77A7FDC6" + }, + { + "Ref": "VpcfoobarSubnet2Subnet85B013AD" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.CfnClusterSubnetGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.ClusterSubnetGroup", + "version": "0.0.0" + } + }, + "SecurityGroup": { + "id": "SecurityGroup", + "path": "aws-cdk-redshift-cluster-update/Cluster/SecurityGroup", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/Cluster/SecurityGroup/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::EC2::SecurityGroup", + "aws:cdk:cloudformation:props": { + "groupDescription": "Redshift security group", + "securityGroupEgress": [ + { + "cidrIp": "0.0.0.0/0", + "description": "Allow all outbound traffic by default", + "ipProtocol": "-1" + } + ], + "vpcId": { + "Ref": "Vpc8378EB38" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.CfnSecurityGroup", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-ec2.SecurityGroup", + "version": "0.0.0" + } + }, + "Secret": { + "id": "Secret", + "path": "aws-cdk-redshift-cluster-update/Cluster/Secret", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/Cluster/Secret/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::Secret", + "aws:cdk:cloudformation:props": { + "generateSecretString": { + "passwordLength": 30, + "secretStringTemplate": "{\"username\":\"admin\"}", + "generateStringKey": "password", + "excludeCharacters": "\"@/\\ '" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-secretsmanager.CfnSecret", + "version": "0.0.0" + } + }, + "Attachment": { + "id": "Attachment", + "path": "aws-cdk-redshift-cluster-update/Cluster/Secret/Attachment", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/Cluster/Secret/Attachment/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::SecretsManager::SecretTargetAttachment", + "aws:cdk:cloudformation:props": { + "secretId": { + "Ref": "ClusterSecret6368BD0F" + }, + "targetId": { + "Ref": "ClusterEB0386A7" + }, + "targetType": "AWS::Redshift::Cluster" + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-secretsmanager.CfnSecretTargetAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-secretsmanager.SecretTargetAttachment", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.DatabaseSecret", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/Cluster/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Redshift::Cluster", + "aws:cdk:cloudformation:props": { + "clusterType": "multi-node", + "dbName": "default_db", + "masterUsername": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:username::}}" + ] + ] + }, + "masterUserPassword": { + "Fn::Join": [ + "", + [ + "{{resolve:secretsmanager:", + { + "Ref": "ClusterSecret6368BD0F" + }, + ":SecretString:password::}}" + ] + ] + }, + "nodeType": "dc2.large", + "allowVersionUpgrade": true, + "automatedSnapshotRetentionPeriod": 1, + "clusterParameterGroupName": { + "Ref": "ParameterGroup5E32DECB" + }, + "clusterSubnetGroupName": { + "Ref": "ClusterSubnetsDCFA5CB7" + }, + "encrypted": true, + "numberOfNodes": 2, + "publiclyAccessible": false, + "vpcSecurityGroupIds": [ + { + "Fn::GetAtt": [ + "ClusterSecurityGroup0921994B", + "GroupId" + ] + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-redshift.CfnCluster", + "version": "0.0.0" + } + }, + "RedshiftClusterRebooterFunction": { + "id": "RedshiftClusterRebooterFunction", + "path": "aws-cdk-redshift-cluster-update/Cluster/RedshiftClusterRebooterFunction", + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.SingletonFunction", + "version": "0.0.0" + } + }, + "ResourceProvider": { + "id": "ResourceProvider", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider", + "children": { + "framework-onEvent": { + "id": "framework-onEvent", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/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" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/ServiceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/ServiceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "lambda:InvokeFunction", + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + { + "Fn::Join": [ + "", + [ + { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + }, + ":*" + ] + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "policyName": "ClusterResourceProviderframeworkonEventServiceRoleDefaultPolicy525CDD86", + "roles": [ + { + "Ref": "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Code": { + "id": "Code", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/Code/Stage", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/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": "aws-cdk-redshift-cluster-update/Cluster/ResourceProvider/framework-onEvent/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": "a8a62b989c7866e3ad5b24f3eb6228f8ca91ebff5f5c76f1da466f6c805c0585.zip" + }, + "role": { + "Fn::GetAtt": [ + "ClusterResourceProviderframeworkonEventServiceRoleD686A5EE", + "Arn" + ] + }, + "description": "AWS CDK resource provider framework - onEvent (aws-cdk-redshift-cluster-update/Cluster/ResourceProvider)", + "environment": { + "variables": { + "USER_ON_EVENT_FUNCTION_ARN": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac281740AC5", + "Arn" + ] + } + } + }, + "handler": "framework.onEvent", + "runtime": "nodejs14.x", + "timeout": 900 + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/custom-resources.Provider", + "version": "0.0.0" + } + }, + "RedshiftClusterRebooterCustomResource": { + "id": "RedshiftClusterRebooterCustomResource", + "path": "aws-cdk-redshift-cluster-update/Cluster/RedshiftClusterRebooterCustomResource", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-redshift-cluster-update/Cluster/RedshiftClusterRebooterCustomResource/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/aws-redshift.Cluster", + "version": "0.0.0" + } + }, + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2": { + "id": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "@aws-cdk/core.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/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" + } + }, + "DefaultPolicy": { + "id": "DefaultPolicy", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/DefaultPolicy", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/ServiceRole/DefaultPolicy/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Policy", + "aws:cdk:cloudformation:props": { + "policyDocument": { + "Statement": [ + { + "Action": "redshift:DescribeClusters", + "Effect": "Allow", + "Resource": "*" + }, + { + "Action": "redshift:RebootCluster", + "Effect": "Allow", + "Resource": { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":redshift:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":cluster:", + { + "Ref": "ClusterEB0386A7" + } + ] + ] + } + } + ], + "Version": "2012-10-17" + }, + "policyName": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRoleDefaultPolicyF49983EF", + "roles": [ + { + "Ref": "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525" + } + ] + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Policy", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-iam.Role", + "version": "0.0.0" + } + }, + "Code": { + "id": "Code", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/Code/Stage", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/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": "aws-cdk-redshift-cluster-update/SingletonLambda511e207f13df4b8bb632c32b30b65ac2/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": "1b88b7c3e3e0f8d3e27ded1bde51b7a80c75f3d8733872af7952c3a6d902147e.zip" + }, + "role": { + "Fn::GetAtt": [ + "SingletonLambda511e207f13df4b8bb632c32b30b65ac2ServiceRole4BDC9525", + "Arn" + ] + }, + "handler": "index.handler", + "runtime": "nodejs16.x", + "timeout": 900 + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-lambda.Function", + "version": "0.0.0" + } + }, + "Exports": { + "id": "Exports", + "path": "aws-cdk-redshift-cluster-update/Exports", + "children": { + "Output{\"Ref\":\"ClusterEB0386A7\"}": { + "id": "Output{\"Ref\":\"ClusterEB0386A7\"}", + "path": "aws-cdk-redshift-cluster-update/Exports/Output{\"Ref\":\"ClusterEB0386A7\"}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + }, + "Output{\"Ref\":\"ParameterGroup5E32DECB\"}": { + "id": "Output{\"Ref\":\"ParameterGroup5E32DECB\"}", + "path": "aws-cdk-redshift-cluster-update/Exports/Output{\"Ref\":\"ParameterGroup5E32DECB\"}", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.182" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-cdk-redshift-cluster-update/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-cdk-redshift-cluster-update/CheckBootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnRule", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "aws-cdk-redshift-reboot-test": { + "id": "aws-cdk-redshift-reboot-test", + "path": "aws-cdk-redshift-reboot-test", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "aws-cdk-redshift-reboot-test/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.182" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert", + "children": { + "AwsApiCallRedshiftdescribeClusters": { + "id": "AwsApiCallRedshiftdescribeClusters", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusters", + "children": { + "SdkProvider": { + "id": "SdkProvider", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusters/SdkProvider", + "children": { + "AssertionsProvider": { + "id": "AssertionsProvider", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusters/SdkProvider/AssertionsProvider", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.182" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AssertionsProvider", + "version": "0.0.0" + } + }, + "Default": { + "id": "Default", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusters/Default", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusters/Default/Default", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResource", + "version": "0.0.0" + } + }, + "AssertionResults": { + "id": "AssertionResults", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusters/AssertionResults", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AwsApiCall", + "version": "0.0.0" + } + }, + "SingletonFunction1488541a7b23466481b69b4408076b81": { + "id": "SingletonFunction1488541a7b23466481b69b4408076b81", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81", + "children": { + "Staging": { + "id": "Staging", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Staging", + "constructInfo": { + "fqn": "@aws-cdk/core.AssetStaging", + "version": "0.0.0" + } + }, + "Role": { + "id": "Role", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Role", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + }, + "Handler": { + "id": "Handler", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/SingletonFunction1488541a7b23466481b69b4408076b81/Handler", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.182" + } + }, + "AwsApiCallRedshiftdescribeClusterParameters": { + "id": "AwsApiCallRedshiftdescribeClusterParameters", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusterParameters", + "children": { + "SdkProvider": { + "id": "SdkProvider", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusterParameters/SdkProvider", + "children": { + "AssertionsProvider": { + "id": "AssertionsProvider", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusterParameters/SdkProvider/AssertionsProvider", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.182" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AssertionsProvider", + "version": "0.0.0" + } + }, + "Default": { + "id": "Default", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusterParameters/Default", + "children": { + "Default": { + "id": "Default", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusterParameters/Default/Default", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnResource", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.CustomResource", + "version": "0.0.0" + } + }, + "AssertionResults": { + "id": "AssertionResults", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/AwsApiCallRedshiftdescribeClusterParameters/AssertionResults", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnOutput", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.AwsApiCall", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-cdk-redshift-reboot-test/DefaultTest/DeployAssert/BootstrapVersion", + "constructInfo": { + "fqn": "@aws-cdk/core.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-cdk-redshift-reboot-test/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": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.ts b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.ts new file mode 100644 index 0000000000000..2645ee74dd686 --- /dev/null +++ b/packages/@aws-cdk/aws-redshift/test/integ.cluster-reboot.ts @@ -0,0 +1,101 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as cdk from '@aws-cdk/core'; +import * as integ from '@aws-cdk/integ-tests'; +import { Match } from '@aws-cdk/integ-tests'; +import * as constructs from 'constructs'; +import * as redshift from '../lib'; + +/** + * This test does the following + * + * 1. Creates a stack with a Redshift cluster. + * 2. Creates a second stack with the same name to update the parameter group and cause the custom resource to run. + * + * The diff assets flag (used when testing custom resources) has been commented out due to snapshots not properly verifying in CodeBuild. + */ + +const app = new cdk.App(); + + +interface RedshiftRebootStackProps extends cdk.StackProps { + parameterGroupParams: { [name: string]: string }, +} + +const requiredStackName: Partial = { + stackName: 'aws-cdk-redshift-cluster-reboot-integ', +}; + +class RedshiftRebootStack extends cdk.Stack { + + readonly cluster: redshift.Cluster; + readonly parameterGroup: redshift.ClusterParameterGroup; + + constructor(scope: constructs.Construct, id: string, props: RedshiftRebootStackProps) { + props = { ...props, ...requiredStackName }; + super(scope, id, props); + const vpc = new ec2.Vpc(this, 'Vpc', { + subnetConfiguration: [{ + subnetType: ec2.SubnetType.PRIVATE_ISOLATED, + name: 'foobar', + }], + }); + this.parameterGroup = new redshift.ClusterParameterGroup(this, 'ParameterGroup', { + parameters: props.parameterGroupParams, + }); + this.cluster = new redshift.Cluster(this, 'Cluster', { + vpc: vpc, + vpcSubnets: { + subnetType: ec2.SubnetType.PRIVATE_ISOLATED, + }, + masterUser: { + masterUsername: 'admin', + }, + parameterGroup: this.parameterGroup, + rebootForParameterChanges: true, + }); + } +} + +const createStack = new RedshiftRebootStack(app, 'aws-cdk-redshift-cluster-create', { + parameterGroupParams: { enable_user_activity_logging: 'true' }, +}); + +const updateStack = new RedshiftRebootStack(app, 'aws-cdk-redshift-cluster-update', { + parameterGroupParams: { enable_user_activity_logging: 'false', use_fips_ssl: 'true' }, +}); + +updateStack.addDependency(createStack); +const stacks = [createStack, updateStack]; +stacks.forEach(s => { + cdk.Aspects.of(s).add({ + visit(node: constructs.IConstruct) { + if (cdk.CfnResource.isCfnResource(node)) { + node.applyRemovalPolicy(cdk.RemovalPolicy.DESTROY); + } + }, + }); +}); + +const test = new integ.IntegTest(app, 'aws-cdk-redshift-reboot-test', { + testCases: stacks, + stackUpdateWorkflow: false, + // diffAssets: true, +}); + +const describeClusters = test.assertions.awsApiCall('Redshift', 'describeClusters', { ClusterIdentifier: updateStack.cluster.clusterName }); +describeClusters.assertAtPath('Clusters.0.ClusterParameterGroups.0.ParameterGroupName', integ.ExpectedResult.stringLikeRegexp(updateStack.parameterGroup.clusterParameterGroupName)); +describeClusters.assertAtPath('Clusters.0.ClusterParameterGroups.0.ParameterApplyStatus', integ.ExpectedResult.stringLikeRegexp('in-sync')); + +const describeParams = test.assertions.awsApiCall('Redshift', 'describeClusterParameters', + { + ParameterGroupName: updateStack.parameterGroup.clusterParameterGroupName, + Source: 'user', + }, +); +describeParams.expect(integ.ExpectedResult.objectLike({ + Parameters: Match.arrayWith([ + Match.objectLike({ ParameterName: 'enable_user_activity_logging', ParameterValue: 'false' }), + Match.objectLike({ ParameterName: 'use_fips_ssl', ParameterValue: 'true' }), + ]), +})); +app.synth();