Skip to content

Commit

Permalink
fix(core): exportValue does not work on number attributes (#19818)
Browse files Browse the repository at this point in the history
Number attributes go through two levels of encoding:

- L1: because of lack of type information, all attributes are assumed to
  be `string`s, so we do `Token.asString(new CfnReference(...))`.
- L2: we recast select attributes to numbers by doing `Token.asNumber()`.

The end result is a Token that looks like:

```ts
asNumber(Intrinsic(asString(CfnReference({ 'Fn::GetAtt': [...] }))))
```

When we do `Tokenization.reverse()` on the number, we only reverse
the *first* encoding one layer, leaving us with an `Intrinsic` instead
of the original `CfnReference`. `exportValue()` then rejects the value
as not being the right type of token.

Solution: before encoding, try to decode the given value so we always
encode the innermost token, and not any of the inbetween ones.

Fixes #19537.


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
rix0rrr committed Apr 8, 2022
1 parent 87786f4 commit 12459ca
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 3 deletions.
2 changes: 1 addition & 1 deletion packages/@aws-cdk/assertions/lib/private/outputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export function hasOutput(template: Template, logicalId: string, props: any): st
}

if (result.closestResult === undefined) {
return `No outputs named ${logicalId} found in the template.`;
return `No outputs named ${logicalId} found in the template (found: ${Object.keys(section).join(', ')})`;
}

return [
Expand Down
3 changes: 1 addition & 2 deletions packages/@aws-cdk/aws-docdb/test/endpoint.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Token } from '@aws-cdk/core';
import { Endpoint } from '../lib';

// A numeric CDK token (see: https://docs.aws.amazon.com/cdk/latest/guide/tokens.html#tokens_number)
const CDK_NUMERIC_TOKEN = -1.8881545897087626e+289;
const CDK_NUMERIC_TOKEN = Token.asNumber({ Ref: 'abc' });

describe('Endpoint', () => {
test('accepts tokens for the port value', () => {
Expand Down
21 changes: 21 additions & 0 deletions packages/@aws-cdk/aws-rds/test/serverless-cluster.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,27 @@ describe('serverless cluster', () => {
vpcSubnets,
})).toThrow(/A VPC is required to use vpcSubnets in ServerlessCluster. Please add a VPC or remove vpcSubnets/);
});

test('can call exportValue on endpoint.port', () => {
// GIVEN
const stack = new cdk.Stack();
const vpc = new ec2.Vpc(stack, 'VPC');
const cluster = new ServerlessCluster(stack, 'Database', {
engine: DatabaseClusterEngine.AURORA_MYSQL,
credentials: { username: 'admin' },
vpc,
});

// WHEN
stack.exportValue(cluster.clusterEndpoint.port);

// THEN
const template = Template.fromStack(stack);
template.hasOutput('ExportsOutputFnGetAttDatabaseB269D8BBEndpointPort3ACB3F51', {
Value: { 'Fn::GetAtt': ['DatabaseB269D8BB', 'Endpoint.Port'] },
Export: { Name: 'Default:ExportsOutputFnGetAttDatabaseB269D8BBEndpointPort3ACB3F51' },
});
});
});

function testStack(app?: cdk.App, id?: string): cdk.Stack {
Expand Down
4 changes: 4 additions & 0 deletions packages/@aws-cdk/core/lib/token.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ export class Token {
* Return a resolvable representation of the given value
*/
public static asAny(value: any): IResolvable {
// First, reverse any encoding that was already done (so we end up with an IResolvable
// if it was a token).
value = Tokenization.reverse(value) ?? value;
// Then, either return the IResolvable we resolved to, or wrap in an Intrinsic
return isResolvableObject(value) ? value : new Intrinsic(value);
}

Expand Down
15 changes: 15 additions & 0 deletions packages/@aws-cdk/core/test/tokens.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,21 @@ describe('tokens', () => {
expect(resolved).toEqual({ value: 123 });
});

test('Tokens are still reversible after having been encoded multiple times', () => {
// GIVEN
const original = new Intrinsic(123);

// WHEN
let x: any = original;
x = Token.asString(x);
x = Token.asNumber(x);
x = Token.asList(x);
x = Token.asString(x);

// THEN
expect(Tokenization.reverse(x)).toBe(original);
});

test('regex detects all stringifications of encoded tokens', () => {
expect(stringContainsNumberTokens(`${createTokenDouble(0)}`)).toBeTruthy();
expect(stringContainsNumberTokens(`${createTokenDouble(Math.pow(2, 48) - 1)}`)).toBeTruthy(); // MAX_ENCODABLE_INTEGER
Expand Down

0 comments on commit 12459ca

Please sign in to comment.