-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Adding an aspect to Bucket with S3 notifications leads to an error #33943
Comments
Attaching a zip file with repro project: |
probably related to #33460 Investigating. |
I assume it is related to that PR, but I'm not sure why should it break anything. |
Per my understanding, it wouldn't work.
Again, woudn't work because I add aspects inside my aspect (if I understand feature flag description correctly).
Per my understanding, |
Let me write a equivalent typescript CDK app to reproduce this. |
Original Reproducible Codewith % grep "@aws-cdk/core:aspectStabilization" cdk.json import { Stack, StackProps, Aspects, Tags, IAspect } from 'aws-cdk-lib';
import { Construct, IConstruct } from 'constructs';
import { Bucket, EventType } from 'aws-cdk-lib/aws-s3';
import { Function, Runtime, Code } from 'aws-cdk-lib/aws-lambda';
import { S3EventSourceV2 } from 'aws-cdk-lib/aws-lambda-event-sources';
export class S3AspectNotificationStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const bucket = new Bucket(this, 'test-bucket', {
bucketName: 'test-bucket-aspect-notification'
});
const lambdaFunction = new Function(this, 'test-function', {
functionName: 'test-function-aspect-notification',
handler: 'index.handler',
runtime: Runtime.NODEJS_22_X,
code: Code.fromInline('exports.handler = function() { }')
});
lambdaFunction.addEventSource(new S3EventSourceV2(bucket, {
events: [EventType.OBJECT_CREATED]
}));
Aspects.of(this).add(new TagNameAspect(), { priority: 10 });
}
}
class TagNameAspect implements IAspect {
public visit(node: IConstruct): void {
let name: string | null = null;
if (node instanceof Bucket) {
name = 'test-bucket-name';
}
// Auto-generated names start with $, we skip them.
if (name !== null) {
Tags.of(node).add('Name', name.toLowerCase(), { priority: 10 });
}
}
} On
So this essentially reproduces your original issue. Now, if we make it this way export class S3AspectNotificationStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const bucket = new Bucket(this, 'test-bucket', {
bucketName: 'test-bucket-aspect-notification'
});
const lambdaFunction = new Function(this, 'test-function', {
functionName: 'test-function-aspect-notification',
handler: 'index.handler',
runtime: Runtime.NODEJS_22_X,
code: Code.fromInline('exports.handler = function() { }')
});
lambdaFunction.addEventSource(new S3EventSourceV2(bucket, {
events: [EventType.OBJECT_CREATED]
}));
Aspects.of(this).add(new TagNameAspect(), { priority: 600 });
}
}
class TagNameAspect implements IAspect {
public visit(node: IConstruct): void {
let name: string | null = null;
if (node instanceof Bucket) {
name = 'test-bucket-name';
}
if (name !== null) {
Tags.of(node).add('Name', name.toLowerCase(), { priority: 600 });
}
}
} It would still fail.
This is because SolutionsOption 1:disable % grep "@aws-cdk/core:aspectStabilization" cdk.json
Option 2:As you can't use class TagNameAspect implements IAspect {
public visit(node: IConstruct): void {
if (node instanceof Bucket) {
// Access the underlying CloudFormation resource
const cfnBucket = node.node.defaultChild as CfnBucket;
// Add the tag directly to the CFN resource
cfnBucket.addPropertyOverride('Tags', [
{ Key: 'Name', Value: 'test-bucket-name'.toLowerCase() }
]);
}
}
} This should work. Full Code export class S3AspectNotificationStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const bucket = new Bucket(this, 'test-bucket', {
bucketName: 'test-bucket-aspect-notification'
});
const lambdaFunction = new Function(this, 'test-function', {
functionName: 'test-function-aspect-notification',
handler: 'index.handler',
runtime: Runtime.NODEJS_22_X,
code: Code.fromInline('exports.handler = function() { }')
});
lambdaFunction.addEventSource(new S3EventSourceV2(bucket, {
events: [EventType.OBJECT_CREATED]
}));
Aspects.of(this).add(new TagNameAspect(), { priority: 600 });
}
}
class TagNameAspect implements IAspect {
public visit(node: IConstruct): void {
if (node instanceof Bucket) {
// Access the underlying CloudFormation resource
const cfnBucket = node.node.defaultChild as CfnBucket;
// Add the tag directly to the CFN resource
cfnBucket.addPropertyOverride('Tags', [
{ Key: 'Name', Value: 'test-bucket-name'.toLowerCase() }
]);
}
}
} verify it: % cdk synth S3AspectNotificationStack | grep -A5 "Type: AWS::S3::Bucket"
Type: AWS::S3::Bucket
Properties:
BucketName: test-bucket-aspect-notification
Tags:
- Key: Name
Value: test-bucket-name Let me know if it works for you. |
It looks quite ugly, especially considering that adding tags is one of the main use-cases, according to docs. Anyway, my main question is - is this a bug? Should aspectStibilization be able to order aspects according to their priorities? |
@Dreamescaper Thank you for raising your concern. When
I think the primary concern is the error checking and throwing. It would be great if CDK can handle it internally without throwing the error. I am bringing this up to the team for inputs here. |
My main concern is actually with Sorting part. Why doesn't it work here? My aspect has the highest priority, yet the aspect with lower priority is applied first. |
The reason is that the Aspect with lowest priority doesn't exist yet when sorting happens. So what happens is:
The fix would be to give your own aspect a priority of 200 (or lower) as well. The old behavior is that we used to warn "hey this might not do what you expect" and proceed anyway. The new behavior is to make sure we strictly follow priority order, and fail if we cannot, to make sure that we don't run into cases where behavior doesn't follow contract but happens to work for some people and doesn't work for others. I'm in doubt on whether or not to make changes to make this easier. The only "fix" I can think of is to give tagging aspects a priority of 500 or higher, so that "default" priority aspects can add them without any further configuration; I'm not sure whether that would be helpful or confusing (since they are technically mutating, but wouldn't have mutating priority anymore). |
As you can see from repro code, my aspect has a priority of 10. |
I see. Yes it should. My apologies, I was too quick in reading. I'll have a closer look. |
Confusingly:
This priority has nothing to do with Aspect priority unfortunately. It is Tagging priority. I see we need to change naming here. |
I'm talking about this line: Aspects.Of(this).Add(new TagNameAspect(), new AspectOptions { Priority = 10 }); |
Yep, I understand. |
Found it! Thanks for reporting, and sorry for misunderstanding initially: #33979 |
Comments on closed issues and PRs are hard for our team to see. |
1 similar comment
Comments on closed issues and PRs are hard for our team to see. |
Describe the bug
In our setup we use an aspect, which adds common tags to most of the resources (like "Name" tag).
Unfortunately, this aspect stopped working after update to 2.181.0 .
Regression Issue
Last Known Working CDK Version
2.180.0
Expected Behavior
Tags should be applied, CDK should be executed successfully.
Current Behavior
'Error: Cannot invoke Aspect Tag with priority 200 on node CdkReproStack/test-bucket/Notifications: an Aspect Object with a lower priority (500) was already invoked on this node.'
Reproduction Steps
Possible Solution
No response
Additional Information/Context
No response
CDK CLI Version
2.1004.0
Framework Version
v2.186.0
Node.js Version
v22.5.1
OS
AmazonLinux
Language
.NET
Language Version
net8.0
Other information
I have tried adding
@aws-cdk/core:aspectStabilization
feature flag, but it changes nothing.The text was updated successfully, but these errors were encountered: