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): Customizable class for L1 constructs customization #30800

Open
2 tasks
pahud opened this issue Jul 9, 2024 · 0 comments
Open
2 tasks

feat(core): Customizable class for L1 constructs customization #30800

pahud opened this issue Jul 9, 2024 · 0 comments
Labels
effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. p2

Comments

@pahud
Copy link
Contributor

pahud commented Jul 9, 2024

Describe the feature

We have seen many cases that users are trying to customize some properties for resources generated by CDK behind L2 constructs and it's not easy to achieve that. I was thinking we probably should propose something like the Tags class that builds a Aspect under the hood and iterates the constructs tree for users without having to write the Aspect by themselves.

Use Case

  1. Customize all CustomResource ServiceTimeout behind a specific construct. This PR would allow CustomResource L2 to support ServiceTimeout but for those custom resources created by L2s behind the scene, users would not be able to customize their ServiceTimeouts.

  2. Customize the LoggingConfig of all lambda.Function, including those created by CDK for custom resource providers as described in feat(custom-resource): universal loggingConfig for all custom resource providers #30777.

Proposed Solution

We probably could have a Customizable class just like the Tags class and the API experience would be like:

// make all custom resource behind this scope a 1200 seconds timeout as default
Customizable.of(this).add('AWS::CloudFormation::CustomResource', 'ServiceTimeout', 1200);

// search all custom resources behind this scope, and run user-provided callback function against all of them
Customizable.of(this).bind('AWS::CloudFormation::CustomResource', cb);

// all lambda.Function should have a default LoggingConfig defined, only apply if undefined
Customizable.of(this).add('AWS::Lambda::Function', 'LoggingConfig', myconfig, { overrideIfUndefined: true });

// iterate all lambda.Functions with a custom callback method. In this `cb` function, we can check if `LoggingConfig` is defined, and override the LoggingConfig.LogGroup when necessary.
Customizable.of(this).bind('AWS::Lambda::Function', cb);

Sample

export class Customizable {
    private static readonly customizations: { [key: string]: any } = {};
  
    static of(scope: Construct): Customizable {
      return new Customizable(scope);
    }
  
    private constructor(private readonly scope: Construct) {}
  
    add(resourceType: string, propertyName: string, value: any): void {
      const key = `${resourceType}/${propertyName}`;
      Customizable.customizations[key] = value;
      this.applyCustomizations(resourceType, propertyName);
    }
  
    private applyCustomizations(resourceType: string, propertyName: string): void {
      const constructs = this.scope.node.findAll();
      this.applyCustomizationsRecursively(resourceType, propertyName, constructs);
    }
  
    private applyCustomizationsRecursively(resourceType: string, propertyName: string, constructs: IConstruct[]): void {
      constructs.forEach(c => {
        if (CfnResource.isCfnResource(c)) {
          if (c.cfnResourceType === resourceType) {
            const customization = Customizable.getCustomization(c, propertyName);
            if (customization) {
              c.addPropertyOverride(propertyName, customization);
            }
          } else {
            // it's a CfnResource but not the resource type we need
            // console.log('skipping ' +  c.cfnResourceType)
          }
        } else {
          // if it's not a cfnResource it has to be a construct
          this.applyCustomizationsRecursively(resourceType, propertyName, c.node.children);
        }
      });
    }
  
    static getCustomization(resource: CfnResource, propertyName: string): any {
      const key = `${resource.cfnResourceType}/${propertyName}`;
      return Customizable.customizations[key];
    }
  }
  
  • override the LoggingConfig for all custom resources behind this stack:
new eks.Cluster(this, 'Cluster', {
    version: eks.KubernetesVersion.V1_30,
  });

  // create a shared log group
  this.lambdaSharedLogGroup = new logs.LogGroup(this, id, {
    retention: logs.RetentionDays.NINE_YEARS,
  });

  Customizable.of(this).add('AWS::Lambda::Function', 'LoggingConfig', {
    LogGroup: this.lambdaSharedLogGroup.logGroupName,
  });
  • override the VisibilityTimeout for all sqs queues behind this scope:
Customizable.of(this).add('AWS::SQS::Queue', 'VisibilityTimeout', 300);

Other Information

No response

Acknowledgements

  • I may be able to implement this feature request
  • This feature might incur a breaking change

CDK version used

2.148.0

Environment details (OS name and version, etc.)

all

@pahud pahud added feature-request A feature should be added or improved. needs-triage This issue or PR still needs to be triaged. p2 effort/medium Medium work item – several days of effort and removed needs-triage This issue or PR still needs to be triaged. labels Jul 9, 2024
@pahud pahud changed the title feat(core): Customizable class for constructs customization feat(core): Customizable class for L1 constructs customization Jul 9, 2024
@pahud pahud added needs-reproduction This issue needs reproduction. response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. investigating This issue is being investigated and/or work is in progress to resolve the issue. and removed needs-reproduction This issue needs reproduction. response-requested Waiting on additional info and feedback. Will move to "closing-soon" in 7 days. investigating This issue is being investigated and/or work is in progress to resolve the issue. labels Jul 19, 2024
@pahud pahud added p1 and removed p1 labels Jul 30, 2024
@pahud pahud added p1 and removed p1 labels Jul 30, 2024
@pahud pahud added p1 and removed p1 labels Aug 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
effort/medium Medium work item – several days of effort feature-request A feature should be added or improved. p2
Projects
None yet
Development

No branches or pull requests

1 participant