Skip to content

Commit c1fd796

Browse files
committed
Make lazy rendering a feature of the tag manager
1 parent 97d1331 commit c1fd796

File tree

2 files changed

+48
-15
lines changed

2 files changed

+48
-15
lines changed

packages/@aws-cdk/aws-logs/lib/log-retention.ts

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ export class LogRetention extends CoreConstruct {
130130
*/
131131
class LogRetentionFunction extends CoreConstruct implements cdk.ITaggable {
132132
public readonly functionArn: cdk.Reference;
133-
readonly cfnFunction: cdk.CfnResource;
134133

135134
tags: cdk.TagManager = new cdk.TagManager(cdk.TagType.KEY_VALUE, 'AWS::Lambda::Function');
136135

@@ -157,7 +156,7 @@ class LogRetentionFunction extends CoreConstruct implements cdk.ITaggable {
157156
}));
158157

159158
// Lambda function
160-
this.cfnFunction = new cdk.CfnResource(this, 'Resource', {
159+
const resource = new cdk.CfnResource(this, 'Resource', {
161160
type: 'AWS::Lambda::Function',
162161
properties: {
163162
Handler: 'index.handler',
@@ -167,27 +166,19 @@ class LogRetentionFunction extends CoreConstruct implements cdk.ITaggable {
167166
S3Key: asset.s3ObjectKey,
168167
},
169168
Role: role.roleArn,
169+
Tags: this.tags.renderedTags,
170170
},
171171
});
172-
this.functionArn = this.cfnFunction.getAtt('Arn');
172+
this.functionArn = resource.getAtt('Arn');
173173

174174
// Function dependencies
175175
role.node.children.forEach((child) => {
176176
if (cdk.CfnResource.isCfnResource(child)) {
177-
this.cfnFunction.addDependsOn(child);
177+
resource.addDependsOn(child);
178178
}
179179
if (cdk.Construct.isConstruct(child) && child.node.defaultChild && cdk.CfnResource.isCfnResource(child.node.defaultChild)) {
180-
this.cfnFunction.addDependsOn(child.node.defaultChild);
180+
resource.addDependsOn(child.node.defaultChild);
181181
}
182182
});
183183
}
184-
185-
prepare() {
186-
// Because we're using a CfnResource to avoid a cyclic dependency on aws-lambda
187-
// we lose the automatic application of tags. We have to add them again manually.
188-
// This has to be done in the prepare phase, after Tag Aspects have applied.
189-
if (this.tags.hasTags()) {
190-
this.cfnFunction.addPropertyOverride('Tags', this.tags.renderTags());
191-
}
192-
}
193184
}

packages/@aws-cdk/core/lib/tag-manager.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { TagType } from './cfn-resource';
22
import { CfnTag } from './cfn-tag';
3+
import { Lazy } from './lazy';
4+
import { IResolvable } from './resolvable';
35

46
interface Tag {
57
key: string;
@@ -228,7 +230,32 @@ export interface TagManagerOptions {
228230
}
229231

230232
/**
231-
* TagManager facilitates a common implementation of tagging for Constructs.
233+
* TagManager facilitates a common implementation of tagging for Constructs
234+
*
235+
* Normally, you do not need to use this class, as the CloudFormation specification
236+
* will indicate which resources are taggable. However, sometimes you will need this
237+
* to make custom resources taggable. Used `tagManager.renderedTags` to obtain a
238+
* value that will resolve to the tags at synthesis time.
239+
*
240+
* @example
241+
* import * as cdk from '@aws-cdk/core';
242+
*
243+
* class MyConstruct extends cdk.Resource implements cdk.ITaggable {
244+
* public readonly tags = new cdk.TagManager(cdk.TagType.KEY_VALUE, 'Whatever::The::Type');
245+
*
246+
* constructor(scope: cdk.Construct, id: string) {
247+
* super(scope, id);
248+
*
249+
* new cdk.CfnResource(this, 'Resource', {
250+
* type: 'Whatever::The::Type',
251+
* properties: {
252+
* // ...
253+
* Tags: this.tags.renderedTags,
254+
* },
255+
* });
256+
* }
257+
* }
258+
*
232259
*/
233260
export class TagManager {
234261

@@ -247,6 +274,14 @@ export class TagManager {
247274
*/
248275
public readonly tagPropertyName: string;
249276

277+
/**
278+
* A lazy value that represents the rendered tags at synthesis time
279+
*
280+
* If you need to make a custom construct taggable, use the value of this
281+
* property to pass to the `tags` property of the underlying construct.
282+
*/
283+
public readonly renderedTags: IResolvable;
284+
250285
private readonly tags = new Map<string, Tag>();
251286
private readonly priorities = new Map<string, number>();
252287
private readonly tagFormatter: ITagFormatter;
@@ -260,6 +295,8 @@ export class TagManager {
260295
this._setTag(...this.tagFormatter.parseTags(tagStructure, this.initialTagPriority));
261296
}
262297
this.tagPropertyName = options.tagPropertyName || 'tags';
298+
299+
this.renderedTags = Lazy.any({ produce: () => this.renderTags() });
263300
}
264301

265302
/**
@@ -287,6 +324,11 @@ export class TagManager {
287324

288325
/**
289326
* Renders tags into the proper format based on TagType
327+
*
328+
* This method will eagerly render the tags currently applied. In
329+
* most cases, you should be using `tagManager.renderedTags` instead,
330+
* which will return a `Lazy` value that will resolve to the correct
331+
* tags at synthesis time.
290332
*/
291333
public renderTags(): any {
292334
return this.tagFormatter.formatTags(this.sortedTags);

0 commit comments

Comments
 (0)