Skip to content

Commit

Permalink
Don't fail on a concatenated ARN
Browse files Browse the repository at this point in the history
  • Loading branch information
rix0rrr committed Feb 16, 2021
1 parent cd7802a commit bf00d02
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 3 deletions.
5 changes: 4 additions & 1 deletion packages/@aws-cdk/core/lib/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,10 @@ export abstract class Resource extends CoreConstruct implements IResource {
* If the given value is NOT a Reference, just return a simple Lazy.
*/
function mimicReference(refSource: any, producer: IStringProducer): string {
const reference = Tokenization.reverse(refSource);
const reference = Tokenization.reverse(refSource, {
// If this is an ARN concatenation, just fail to extract a reference.
failConcat: false,
});
if (!Reference.isReference(reference)) {
return Lazy.uncachedString(producer);
}
Expand Down
25 changes: 23 additions & 2 deletions packages/@aws-cdk/core/lib/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,16 @@ export class Tokenization {
*
* In case of a string, the string must not be a concatenation.
*/
public static reverse(x: any): IResolvable | undefined {
public static reverse(x: any, options: ReverseOptions = {}): IResolvable | undefined {
if (Tokenization.isResolvable(x)) { return x; }
if (typeof x === 'string') { return Tokenization.reverseCompleteString(x); }
if (typeof x === 'string') {
if (options.failConcat === false) {
// Handle this specially because reverseCompleteString might fail
const fragments = Tokenization.reverseString(x);
return fragments.length === 1 ? fragments.firstToken : undefined;
}
return Tokenization.reverseCompleteString(x);
}
if (Array.isArray(x)) { return Tokenization.reverseList(x); }
if (typeof x === 'number') { return Tokenization.reverseNumber(x); }
return undefined;
Expand Down Expand Up @@ -220,6 +227,20 @@ export class Tokenization {
}
}

/**
* Options for the 'reverse()' operation
*/
export interface ReverseOptions {
/**
* Fail if the given string is a concatenation
*
* If `false`, just return `undefined`.
*
* @default true
*/
readonly failConcat?: boolean;
}

/**
* Options to the resolve() operation
*
Expand Down
39 changes: 39 additions & 0 deletions packages/@aws-cdk/core/test/cross-environment-token.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,11 @@ test.each([undefined, 'SomeName'])('stack.exportValue() on name attributes with
expect(templateA).toEqual(templateM);
});

test('can instantiate resource with constructed physicalname ARN', () => {
const stack = new Stack();
new MyResourceWithConstructedArnAttribute(stack, 'Resource');
});

class MyResource extends Resource {
public readonly arn: string;
public readonly name: string;
Expand All @@ -293,3 +298,37 @@ class MyResource extends Resource {
});
}
}

/**
* Some resources build their own Arn attribute by constructing strings
*
* This will be because the L1 doesn't expose a `{ Fn::GetAtt: ['Arn'] }`.
*
* They won't be able to `exportValue()` it, but it shouldn't crash.
*/
class MyResourceWithConstructedArnAttribute extends Resource {
public readonly arn: string;
public readonly name: string;

constructor(scope: Construct, id: string, physicalName?: string) {
super(scope, id, { physicalName });

const res = new CfnResource(this, 'Resource', {
type: 'My::Resource',
properties: {
resourceName: this.physicalName,
},
});

this.name = this.getResourceNameAttribute(res.ref.toString());
this.arn = this.getResourceArnAttribute(Stack.of(this).formatArn({
resource: 'my-resource',
resourceName: res.ref.toString(),
service: 'myservice',
}), {
resource: 'my-resource',
resourceName: this.physicalName,
service: 'myservice',
});
}
}

0 comments on commit bf00d02

Please sign in to comment.