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

fix(core): use default account/region when environment is not specified #2867

Merged
merged 2 commits into from
Jun 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions packages/@aws-cdk/cdk/lib/stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -505,17 +505,24 @@ export class Stack extends Construct implements ITaggable {
*/
private parseEnvironment(env: Environment = {}) {
// if an environment property is explicitly specified when the stack is
// created, it will be used as concrete values for all intents.
const region = env.region;
const account = env.account;
// created, it will be used as concrete values for all intents. if not, use
// tokens for account and region but they do not need to be scoped, the only
// situation in which export/fn::importvalue would work if { Ref:
// "AWS::AccountId" } is the same for provider and consumer anyway.
const region = env.region || Aws.region;
const account = env.account || Aws.accountId;

// temporary fix for #2853, eventually behavior will be based on #2866.
// set the cloud assembly manifest environment spec of this stack to use the
// default account/region from the toolkit in case account/region are undefined or
// unresolved (i.e. tokens).
const envAccount = !Token.isUnresolved(account) ? account : Context.getDefaultAccount(this) || 'unknown-account';
const envRegion = !Token.isUnresolved(region) ? region : Context.getDefaultRegion(this) || 'unknown-region';

// account and region do not need to be scoped, the only situation in which
// export/fn::importvalue would work if { Ref: "AWS::AccountId" } is the
// same for provider and consumer anyway.
return {
account: account || Aws.accountId,
region: region || Aws.region,
environment: EnvironmentUtils.format(account || 'unknown-account', region || 'unknown-region')
environment: EnvironmentUtils.format(envAccount, envRegion)
};
}

Expand Down Expand Up @@ -651,9 +658,11 @@ function cfnElements(node: IConstruct, into: CfnElement[] = []): CfnElement[] {
import { Arn, ArnComponents } from './arn';
import { CfnElement } from './cfn-element';
import { CfnResource, TagType } from './cfn-resource';
import { Context } from './context';
import { CfnReference } from './private/cfn-reference';
import { Aws, ScopedAws } from './pseudo';
import { ITaggable, TagManager } from './tag-manager';
import { Token } from './token';

/**
* Find all resources in a set of constructs
Expand Down
139 changes: 138 additions & 1 deletion packages/@aws-cdk/cdk/test/test.environment.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DEFAULT_ACCOUNT_CONTEXT_KEY, DEFAULT_REGION_CONTEXT_KEY } from '@aws-cdk/cx-api';
import cxapi = require('@aws-cdk/cx-api');
import { Test } from 'nodeunit';
import { App, Stack, Token } from '../lib';
import { App, Aws, Stack, Token } from '../lib';

export = {
'By default, environment region and account are not defined and resolve to intrinsics'(test: Test) {
Expand Down Expand Up @@ -40,4 +41,140 @@ export = {

test.done();
},

'environment defaults': {
'default-account-unknown-region'(test: Test) {
// GIVEN
const app = new App();

// WHEN
app.node.setContext(cxapi.DEFAULT_ACCOUNT_CONTEXT_KEY, 'my-default-account');
const stack = new Stack(app, 'stack');

// THEN
test.deepEqual(stack.resolve(stack.account), { Ref: 'AWS::AccountId' }); // TODO: after we implement #2866 this should be 'my-default-account'
test.deepEqual(stack.resolve(stack.region), { Ref: 'AWS::Region' });
test.deepEqual(app.synth().getStack(stack.stackName).environment, {
account: 'my-default-account',
region: 'unknown-region',
name: 'aws://my-default-account/unknown-region'
});

test.done();
},

'default-account-explicit-region'(test: Test) {
// GIVEN
const app = new App();

// WHEN
app.node.setContext(cxapi.DEFAULT_ACCOUNT_CONTEXT_KEY, 'my-default-account');
const stack = new Stack(app, 'stack', { env: { region: 'explicit-region' }});

// THEN
test.deepEqual(stack.resolve(stack.account), { Ref: 'AWS::AccountId' }); // TODO: after we implement #2866 this should be 'my-default-account'
test.deepEqual(stack.resolve(stack.region), 'explicit-region');
test.deepEqual(app.synth().getStack(stack.stackName).environment, {
account: 'my-default-account',
region: 'explicit-region',
name: 'aws://my-default-account/explicit-region'
});

test.done();
},

'explicit-account-explicit-region'(test: Test) {
// GIVEN
const app = new App();

// WHEN
app.node.setContext(cxapi.DEFAULT_ACCOUNT_CONTEXT_KEY, 'my-default-account');
const stack = new Stack(app, 'stack', { env: {
account: 'explicit-account',
region: 'explicit-region'
}});

// THEN
test.deepEqual(stack.resolve(stack.account), 'explicit-account');
test.deepEqual(stack.resolve(stack.region), 'explicit-region');
test.deepEqual(app.synth().getStack(stack.stackName).environment, {
account: 'explicit-account',
region: 'explicit-region',
name: 'aws://explicit-account/explicit-region'
});

test.done();
},

'default-account-default-region'(test: Test) {
// GIVEN
const app = new App();

// WHEN
app.node.setContext(cxapi.DEFAULT_ACCOUNT_CONTEXT_KEY, 'my-default-account');
app.node.setContext(cxapi.DEFAULT_REGION_CONTEXT_KEY, 'my-default-region');
const stack = new Stack(app, 'stack');

// THEN
test.deepEqual(stack.resolve(stack.account), { Ref: 'AWS::AccountId' }); // TODO: after we implement #2866 this should be 'my-default-account'
test.deepEqual(stack.resolve(stack.region), { Ref: 'AWS::Region' }); // TODO: after we implement #2866 this should be 'my-default-region'
test.deepEqual(app.synth().getStack(stack.stackName).environment, {
account: 'my-default-account',
region: 'my-default-region',
name: 'aws://my-default-account/my-default-region'
});

test.done();
},

'token-account-token-region-no-defaults'(test: Test) {
// GIVEN
const app = new App();

// WHEN
app.node.setContext(cxapi.DEFAULT_ACCOUNT_CONTEXT_KEY, 'my-default-account');
app.node.setContext(cxapi.DEFAULT_REGION_CONTEXT_KEY, 'my-default-region');
const stack = new Stack(app, 'stack', {
env: {
account: Aws.accountId,
region: Aws.region
}
});

// THEN
test.deepEqual(stack.resolve(stack.account), { Ref: 'AWS::AccountId' });
test.deepEqual(stack.resolve(stack.region), { Ref: 'AWS::Region' });
test.deepEqual(app.synth().getStack(stack.stackName).environment, {
account: 'my-default-account',
region: 'my-default-region',
name: 'aws://my-default-account/my-default-region'
});

test.done();
},

'token-account-token-region-with-defaults'(test: Test) {
// GIVEN
const app = new App();

// WHEN
const stack = new Stack(app, 'stack', {
env: {
account: Aws.accountId,
region: Aws.region
}
});

// THEN
test.deepEqual(stack.resolve(stack.account), { Ref: 'AWS::AccountId' });
test.deepEqual(stack.resolve(stack.region), { Ref: 'AWS::Region' });
test.deepEqual(app.synth().getStack(stack.stackName).environment, {
account: 'unknown-account',
region: 'unknown-region',
name: 'aws://unknown-account/unknown-region'
});

test.done();
}
},
};