Last active
March 7, 2024 05:05
-
-
Save foriequal0/f1f4ea279fb64836e5fb38efefa133d7 to your computer and use it in GitHub Desktop.
CDK StableNameStack
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { CfnElement, CfnResource, Stack } from "@aws-cdk/core"; | |
import { makeUniqueId } from "@aws-cdk/core/lib/private/uniqueid"; | |
import { Node } from "constructs"; | |
import * as assert from "assert"; | |
const PINNED_RESOURCE_NAMES_CONTEXT_KEY = "pinnedLogicalIds"; | |
type PinnedLogicalIds = { [segment: string]: PinnedLogicalIds | string }; | |
export class StableNameStack extends Stack { | |
protected allocateLogicalId(element: CfnElement): string { | |
const pinnedLogicalIds: PinnedLogicalIds = Node.of(this).tryGetContext(PINNED_RESOURCE_NAMES_CONTEXT_KEY) ?? {}; | |
if (CfnResource.isCfnResource(element)) { | |
const path = element.node.path; | |
const found = find(pinnedLogicalIds, path.split("/"), element); | |
if (found) { | |
return found; | |
} | |
} | |
return super.allocateLogicalId(element); | |
} | |
} | |
function find(pinnedLogicalIds: PinnedLogicalIds, pathSegments: string[], resource: CfnResource): string | undefined { | |
// You can match type with "!AWS::EC2::VPC", or "!EC2::VPC", or "!VPC", if it is not ambiguous | |
const typeSegments = resource.cfnResourceType.split("::"); | |
for (let i = typeSegments.length - 1; i >= 0; i--) { | |
const tails = typeSegments.slice(i).join("::"); | |
const findByType = pinnedLogicalIds[`!${tails}`]; | |
if (findByType !== undefined) { | |
assert(typeof findByType === "string"); | |
return findByType; | |
} | |
} | |
for (let i = pathSegments.length; i > 0; i--) { | |
const prefix = pathSegments.slice(0, i).join("/"); | |
const rest = pathSegments.slice(i); | |
const lookup = pinnedLogicalIds[prefix]; | |
if (typeof lookup === "string") { | |
if (lookup.startsWith("@")) { | |
// path prefix rewrite | |
const path = lookup.slice(1).split("/"); | |
return makeUniqueId([...path, ...rest]); | |
} | |
return lookup; | |
} else if (lookup !== undefined) { | |
const found = find(lookup, rest, resource); | |
if (found) { | |
return found; | |
} | |
} | |
} | |
return undefined; | |
} |
Got it, so what I would recommend is overriding Stack.allocateLogicalId
.
Thanks 👍
I'll share my modification:
if (typeof lookup === 'string') {
if (lookup.startsWith('@')) {
// path prefix rewrite
- const path = lookup.slice(1).split("/");
+ const path = lookup.slice(1).split("/").filter(s => !!s);
return makeUniqueId([...path, ...rest]);
}
return lookup;
to handle configuration like:
{
"context": {
"pinnedLogicalIds": {
"Stack/A": "@"
}
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I wanted to rename all resources in a construct tree, and wanted to make less changes as possible. What would be different with it?