Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(core): configure SNS topics to receive stack events on the Stack construct #30551

Merged
merged 59 commits into from
Aug 13, 2024
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
48f5b63
working basic implementation
comcalvi Jun 11, 2024
f05b908
Merge branch 'main' of github.com:aws/aws-cdk into comcalvi/notificat…
comcalvi Jun 12, 2024
868cb1f
Merge branch 'main' of github.com:aws/aws-cdk into comcalvi/notificat…
comcalvi Jun 12, 2024
f5c930b
fix
comcalvi Jun 12, 2024
662697d
don't skip deploy if stack notifications arnrns have changed
comcalvi Jun 12, 2024
bc0afea
more changes
comcalvi Jun 12, 2024
b3a5716
cleanup
comcalvi Jun 12, 2024
4b88b03
most tests working
comcalvi Jun 13, 2024
af40c5e
toolkit tests
comcalvi Jun 13, 2024
ffaf14e
docs
comcalvi Jun 13, 2024
055d496
remove the bad cast, it is evil
comcalvi Jun 13, 2024
fc184cc
cleanup
comcalvi Jun 13, 2024
fac1245
Merge branch 'main' of github.com:aws/aws-cdk into comcalvi/notificat…
comcalvi Jun 13, 2024
5e606af
silly licenses
comcalvi Jun 13, 2024
180066b
newline\n...
comcalvi Jun 13, 2024
2bc9320
foo
comcalvi Jun 13, 2024
e9f9fa4
small change to trigger test pipeline
comcalvi Jun 14, 2024
48b8e49
destroy fix hopefully
comcalvi Jun 17, 2024
effc510
jest......
comcalvi Jun 17, 2024
8e7fc27
tests...jest....
comcalvi Jun 17, 2024
e3f2a5c
ok, fine then...
comcalvi Jun 17, 2024
8cd8f6e
logging for this at this point
comcalvi Jun 18, 2024
f605e1d
throw the error then
comcalvi Jun 18, 2024
8848d0a
type error
comcalvi Jun 18, 2024
c5201ed
man this is painful
comcalvi Jun 18, 2024
6c6616e
woowoowoowoo
comcalvi Jun 18, 2024
d5b9a80
selector
comcalvi Jun 19, 2024
c718b20
jest
comcalvi Jun 19, 2024
335d6dd
jest
comcalvi Jun 19, 2024
cbde013
jest
comcalvi Jun 19, 2024
e9b0ddf
jest
comcalvi Jun 19, 2024
8bd64ea
cloud assem
comcalvi Jun 20, 2024
83cc722
wowzers
comcalvi Jun 20, 2024
2c9884f
asm
comcalvi Jun 20, 2024
2539c9c
asm
comcalvi Jun 20, 2024
ad71122
asm
comcalvi Jun 20, 2024
45357e1
asm
comcalvi Jun 20, 2024
abd6dc4
finally fixed it......
comcalvi Jun 21, 2024
178e712
fixed
comcalvi Jun 21, 2024
4fbdaa4
done
comcalvi Jun 21, 2024
d1bf1a0
code teleports to a different line in the file
comcalvi Jun 21, 2024
67188db
toolkit test
comcalvi Jun 21, 2024
f00ed25
toolkit
comcalvi Jun 21, 2024
a20f0e7
Merge branch 'main' of github.com:aws/aws-cdk into comcalvi/notificat…
comcalvi Jun 24, 2024
c885502
Merge branch 'main' of github.com:aws/aws-cdk into comcalvi/notificat…
comcalvi Jul 2, 2024
c38e7a4
wowowo cli integ test
comcalvi Jul 2, 2024
f79368f
integ-fix
comcalvi Jul 2, 2024
b03209d
fix deploy all test
comcalvi Jul 2, 2024
22bb7e8
wowowo
comcalvi Jul 2, 2024
bf5deb9
fixing the cli test framework
comcalvi Jul 10, 2024
95e8dac
fix
comcalvi Jul 10, 2024
4331c91
fix the busted test
comcalvi Jul 12, 2024
f4c65a2
fix
comcalvi Jul 12, 2024
f704997
Merge branch 'main' of github.com:aws/aws-cdk into comcalvi/notificat…
comcalvi Jul 15, 2024
b1c116e
typo
comcalvi Aug 12, 2024
0bc224f
Merge branch 'main' of github.com:aws/aws-cdk into comcalvi/notificat…
comcalvi Aug 12, 2024
79b2e7d
changes:
comcalvi Aug 12, 2024
e933382
fix
comcalvi Aug 13, 2024
c308c5a
Merge branch 'main' into comcalvi/notification-arns
mergify[bot] Aug 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions packages/@aws-cdk/cli-lib-alpha/THIRD_PARTY_LICENSES
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ The @aws-cdk/cli-lib-alpha package includes the following third-party software/l

----------------

** @jsii/check-node@1.97.0 - https://www.npmjs.com/package/@jsii/check-node/v/1.97.0 | Apache-2.0
** @jsii/check-node@1.98.0 - https://www.npmjs.com/package/@jsii/check-node/v/1.98.0 | Apache-2.0
jsii
Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.

Expand Down Expand Up @@ -266,7 +266,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

----------------

** ajv@8.12.0 - https://www.npmjs.com/package/ajv/v/8.12.0 | MIT
** ajv@8.13.0 - https://www.npmjs.com/package/ajv/v/8.13.0 | MIT
The MIT License (MIT)

Copyright (c) 2015-2021 Evgeny Poberezkin
Expand Down Expand Up @@ -493,7 +493,7 @@ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH RE

----------------

** aws-sdk@2.1596.0 - https://www.npmjs.com/package/aws-sdk/v/2.1596.0 | Apache-2.0
** aws-sdk@2.1610.0 - https://www.npmjs.com/package/aws-sdk/v/2.1610.0 | Apache-2.0
AWS SDK for JavaScript
Copyright 2012-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.

Expand Down Expand Up @@ -691,7 +691,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI

----------------

** cdk-from-cfn@0.156.0 - https://www.npmjs.com/package/cdk-from-cfn/v/0.156.0 | MIT OR Apache-2.0
** cdk-from-cfn@0.159.0 - https://www.npmjs.com/package/cdk-from-cfn/v/0.159.0 | MIT OR Apache-2.0

----------------

Expand Down
66 changes: 62 additions & 4 deletions packages/@aws-cdk/cx-api/FEATURE_FLAGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ Flags come in three types:
| [@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2](#aws-cdkaws-codepipelinedefaultpipelinetypetov2) | Enables Pipeline to set the default pipeline type to V2. | 2.133.0 | (default) |
| [@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope](#aws-cdkaws-kmsreducecrossaccountregionpolicyscope) | When enabled, IAM Policy created from KMS key grant will reduce the resource scope to this key only. | 2.134.0 | (fix) |
| [@aws-cdk/aws-eks:nodegroupNameAttribute](#aws-cdkaws-eksnodegroupnameattribute) | When enabled, nodegroupName attribute of the provisioned EKS NodeGroup will not have the cluster name prefix. | 2.139.0 | (fix) |
| [@aws-cdk/aws-ec2:ebsDefaultGp3Volume](#aws-cdkaws-ec2ebsdefaultgp3volume) | When enabled, the default volume type of the EBS volume will be GP3 | V2NEXT | (default) |
| [@aws-cdk/aws-ec2:ebsDefaultGp3Volume](#aws-cdkaws-ec2ebsdefaultgp3volume) | When enabled, the default volume type of the EBS volume will be GP3 | 2.140.0 | (default) |
| [@aws-cdk/pipelines:reduceAssetRoleTrustScope](#aws-cdkpipelinesreduceassetroletrustscope) | Remove the root account principal from PipelineAssetsFileRole trust policy | 2.141.0 | (default) |
| [@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm](#aws-cdkaws-ecsremovedefaultdeploymentalarm) | When enabled, remove default deployment alarm settings | 2.143.0 | (default) |
| [@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault](#aws-cdkcustom-resourceslogapiresponsedatapropertytruedefault) | When enabled, the custom resource used for `AwsCustomResource` will configure the `logApiResponseData` property as true by default | 2.145.0 | (fix) |

<!-- END table -->

Expand Down Expand Up @@ -128,7 +131,9 @@ The following json shows the current recommended set of flags, as `cdk init` wou
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
"@aws-cdk/aws-eks:nodegroupNameAttribute": true,
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true,
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false
}
}
```
Expand Down Expand Up @@ -171,6 +176,7 @@ are migrating a v1 CDK project to v2, explicitly set any of these flags which do
| [@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId](#aws-cdkaws-apigatewayusageplankeyorderinsensitiveid) | Allow adding/removing multiple UsagePlanKeys independently | (fix) | 1.98.0 | `false` | `true` |
| [@aws-cdk/aws-lambda:recognizeVersionProps](#aws-cdkaws-lambdarecognizeversionprops) | Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`. | (fix) | 1.106.0 | `false` | `true` |
| [@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2\_2021](#aws-cdkaws-cloudfrontdefaultsecuritypolicytlsv12_2021) | Enable this feature flag to have cloudfront distributions use the security policy TLSv1.2_2021 by default. | (fix) | 1.117.0 | `false` | `true` |
| [@aws-cdk/pipelines:reduceAssetRoleTrustScope](#aws-cdkpipelinesreduceassetroletrustscope) | Remove the root account principal from PipelineAssetsFileRole trust policy | (default) | | `false` | `true` |

<!-- END diff -->

Expand All @@ -185,7 +191,8 @@ Here is an example of a `cdk.json` file that restores v1 behavior for these flag
"@aws-cdk/aws-rds:lowercaseDbIdentifier": false,
"@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": false,
"@aws-cdk/aws-lambda:recognizeVersionProps": false,
"@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": false
"@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": false,
"@aws-cdk/pipelines:reduceAssetRoleTrustScope": false
}
}
```
Expand Down Expand Up @@ -1293,9 +1300,60 @@ When this featuer flag is enabled, the default volume type of the EBS volume wil
| Since | Default | Recommended |
| ----- | ----- | ----- |
| (not in v1) | | |
| V2NEXT | `false` | `true` |
| 2.140.0 | `false` | `true` |

**Compatibility with old behavior:** Pass `volumeType: EbsDeviceVolumeType.GENERAL_PURPOSE_SSD` to `Volume` construct to restore the previous behavior.


### @aws-cdk/pipelines:reduceAssetRoleTrustScope

*Remove the root account principal from PipelineAssetsFileRole trust policy* (default)

When this feature flag is enabled, the root account principal will not be added to the trust policy of asset role.
When this feature flag is disabled, it will keep the root account principal in the trust policy.


| Since | Default | Recommended |
| ----- | ----- | ----- |
| (not in v1) | | |
| 2.141.0 | `true` | `true` |

**Compatibility with old behavior:** Disable the feature flag to add the root account principal back


### @aws-cdk/aws-ecs:removeDefaultDeploymentAlarm

*When enabled, remove default deployment alarm settings* (default)

When this featuer flag is enabled, remove the default deployment alarm settings when creating a AWS ECS service.


| Since | Default | Recommended |
| ----- | ----- | ----- |
| (not in v1) | | |
| 2.143.0 | `false` | `true` |

**Compatibility with old behavior:** Set AWS::ECS::Service 'DeploymentAlarms' manually to restore the previous behavior.


### @aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault

*When enabled, the custom resource used for `AwsCustomResource` will configure the `logApiResponseData` property as true by default* (fix)

This results in 'logApiResponseData' being passed as true to the custom resource provider. This will cause the custom resource handler to receive an 'Update' event. If you don't
have an SDK call configured for the 'Update' event and you're dependent on specific SDK call response data, you will see this error from CFN:

CustomResource attribute error: Vendor response doesn't contain <attribute-name> attribute in object. See https://github.com/aws/aws-cdk/issues/29949) for more details.

Unlike most feature flags, we don't recommend setting this feature flag to true. However, if you're using the 'AwsCustomResource' construct with 'logApiResponseData' as true in
the event object, then setting this feature flag will keep this behavior. Otherwise, setting this feature flag to false will trigger an 'Update' event by removing the 'logApiResponseData'
property from the event object.


| Since | Default | Recommended |
| ----- | ----- | ----- |
| (not in v1) | | |
| 2.145.0 | `false` | `false` |


<!-- END details -->
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ export interface AwsCloudFormationStackProperties {
*/
readonly tags?: { [id: string]: string };

/**
* SNS Notification ARNs that should receive CloudFormation Stack Events.
*
* @default - No notification arns
*/
readonly notificationArns?: string[];

/**
* The name to use for the CloudFormation stack.
* @default - name derived from artifact ID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,12 @@
"type": "string"
}
},
"notificationArns": {
"type": "array",
"items": {
"type": "string"
}
},
"stackName": {
"description": "The name to use for the CloudFormation stack. (Default - name derived from artifact ID)",
"type": "string"
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":"36.0.0"}
{"version":"37.0.0"}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export function addStackArtifactToAssembly(
terminationProtection: stack.terminationProtection,
tags: nonEmptyDict(stack.tags.tagValues()),
validateOnSynth: session.validateOnSynth,
notificationArns: (stack as any)._notificationArns,
...stackProps,
...stackNameProperty,
};
Expand Down
15 changes: 15 additions & 0 deletions packages/aws-cdk-lib/core/lib/stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@ export interface StackProps {
*/
readonly tags?: { [key: string]: string };

/**
* SNS Topic ARNs that will receive stack events.
*
* @default wowowowowo
*/
readonly notificationArns?: string[];

/**
* Synthesis method to use while deploying this stack
*
Expand Down Expand Up @@ -364,6 +371,13 @@ export class Stack extends Construct implements ITaggable {
*/
public readonly _crossRegionReferences: boolean;

/**
* SNS Notification ARNs to receive stack events.
*
* @internal
*/
public readonly _notificationArns: string[];

/**
* Logical ID generation strategy
*/
Expand Down Expand Up @@ -450,6 +464,7 @@ export class Stack extends Construct implements ITaggable {
throw new Error(`Stack name must be <= 128 characters. Stack name: '${this._stackName}'`);
}
this.tags = new TagManager(TagType.KEY_VALUE, 'aws:cdk:stack', props.tags);
this._notificationArns = props.notificationArns ?? [];

if (!VALID_STACK_NAME_REGEX.test(this.stackName)) {
throw new Error(`Stack name must match the regular expression: ${VALID_STACK_NAME_REGEX.toString()}, got '${this.stackName}'`);
Expand Down
15 changes: 15 additions & 0 deletions packages/aws-cdk-lib/core/test/stack.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2075,6 +2075,21 @@ describe('stack', () => {
expect(asm.getStackArtifact(stack2.artifactId).tags).toEqual(expected);
});

test('stack notification arns are reflected in the stack artifact properties', () => {
// GIVEN
const NOTIFICATION_ARNS = ['arn:aws:sns:bermuda-triangle-1337:123456789012:MyTopic'];
const app = new App({ stackTraces: false });
const stack1 = new Stack(app, 'stack1', {
notificationArns: NOTIFICATION_ARNS,
});

// THEN
const asm = app.synth();
const expected = { foo: 'bar' };

expect(asm.getStackArtifact(stack1.artifactId).notificationArns).toEqual(NOTIFICATION_ARNS);
});

test('Termination Protection is reflected in Cloud Assembly artifact', () => {
// if the root is an app, invoke "synth" to avoid double synthesis
const app = new App();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ export class CloudFormationStackArtifact extends CloudArtifact {
*/
public readonly tags: { [id: string]: string };

/**
* SNS Topics that will receive stack events.
*/
public readonly notificationArns: string[];

/**
* The physical name of this stack.
*/
Expand Down Expand Up @@ -158,6 +163,7 @@ export class CloudFormationStackArtifact extends CloudArtifact {
// We get the tags from 'properties' if available (cloud assembly format >= 6.0.0), otherwise
// from the stack metadata
this.tags = properties.tags ?? this.tagsFromMetadata();
this.notificationArns = properties.notificationArns ?? [];
this.assumeRoleArn = properties.assumeRoleArn;
this.assumeRoleExternalId = properties.assumeRoleExternalId;
this.cloudFormationExecutionRoleArn = properties.cloudFormationExecutionRoleArn;
Expand Down
18 changes: 18 additions & 0 deletions packages/aws-cdk-lib/cx-api/test/stack-artifact.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,24 @@ afterEach(() => {
rimraf(builder.outdir);
});

test('read notification arns from artifact properties', () => {
// GIVEN
const NOTIFICATION_ARNS = ['arn:aws:sns:bermuda-triangle-1337:123456789012:MyTopic'];
builder.addArtifact('Stack', {
...stackBase,
properties: {
...stackBase.properties,
notificationArns: NOTIFICATION_ARNS,
},
});

// WHEN
const assembly = builder.buildAssembly();

// THEN
expect(assembly.getStackByName('Stack').notificationArns).toEqual(NOTIFICATION_ARNS);
});

test('read tags from artifact properties', () => {
// GIVEN
builder.addArtifact('Stack', {
Expand Down
10 changes: 10 additions & 0 deletions packages/aws-cdk/lib/api/deploy-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,16 @@ async function canSkipDeploy(
return false;
}

function arrayEquals(a: any[], b: any[]): boolean {
return a.every(item => b.includes(item)) && b.every(item => a.includes(item));
}

// Notification arns have changed
if (!arrayEquals(cloudFormationStack.notificationArns, deployStackOptions.notificationArns ?? [])) {
debug(`${deployName}: notification arns have changed`);
return false;
}

// Termination protection has been updated
if (!!deployStackOptions.stack.terminationProtection !== !!cloudFormationStack.terminationProtection) {
debug(`${deployName}: termination protection has been updated`);
Expand Down
11 changes: 10 additions & 1 deletion packages/aws-cdk/lib/api/util/cloudformation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,12 +138,21 @@ export class CloudFormationStack {
/**
* The stack's current tags
*
* Empty list of the stack does not exist
* Empty list if the stack does not exist
*/
public get tags(): CloudFormation.Tags {
return this.stack?.Tags || [];
}

/**
* SNS Topic ARNs that will receive stack events.
*
* Empty list if the stack does not exist
*/
public get notificationArns(): CloudFormation.NotificationARNs {
return this.stack?.NotificationARNs ?? [];
}

/**
* Return the names of all current parameters to the stack
*
Expand Down
23 changes: 12 additions & 11 deletions packages/aws-cdk/lib/cdk-toolkit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ export class CdkToolkit {
let changeSet = undefined;

if (options.changeSet) {

let stackExists = false;
try {
stackExists = await this.props.deployments.stackExists({
Expand Down Expand Up @@ -214,14 +213,6 @@ export class CdkToolkit {
return this.watch(options);
}

if (options.notificationArns) {
options.notificationArns.map( arn => {
if (!validateSnsTopicArn(arn)) {
throw new Error(`Notification arn ${arn} is not a valid arn for an SNS topic`);
}
});
}

const startSynthTime = new Date().getTime();
const stackCollection = await this.selectStacksForDeploy(options.selector, options.exclusively,
options.cacheCloudAssembly, options.ignoreNoStacks);
Expand Down Expand Up @@ -318,7 +309,17 @@ export class CdkToolkit {
}
}

const stackIndex = stacks.indexOf(stack)+1;
let notificationArns: string[] = [];
notificationArns = notificationArns.concat(options.notificationArns ?? []);
notificationArns = notificationArns.concat(stack.notificationArns);

notificationArns.map(arn => {
if (!validateSnsTopicArn(arn)) {
throw new Error(`Notification arn ${arn} is not a valid arn for an SNS topic`);
}
});

const stackIndex = stacks.indexOf(stack) + 1;
print('%s: deploying... [%s/%s]', chalk.bold(stack.displayName), stackIndex, stackCollection.stackCount);
const startDeployTime = new Date().getTime();

Expand All @@ -335,7 +336,7 @@ export class CdkToolkit {
roleArn: options.roleArn,
toolkitStackName: options.toolkitStackName,
reuseAssets: options.reuseAssets,
notificationArns: options.notificationArns,
notificationArns,
tags,
execute: options.execute,
changeSetName: options.changeSetName,
Expand Down
Loading
Loading