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

feat(cdk): transparent cross-stack references #1436

Merged
merged 44 commits into from
Jan 9, 2019
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
7b97ebb
Fix tag manager tests to use resolve(token) instead of token.resolve()
rix0rrr Sep 29, 2018
1f938cf
Introduce StackAwareToken, make all pseudos Stack-Aware.
rix0rrr Sep 29, 2018
929b003
Merge branch 'master' into huijbers/x-stack-references
Dec 18, 2018
d02e16d
Remove concept of freezing
Dec 18, 2018
ac062fc
Add explicit preprocessor step for references
Dec 18, 2018
935fd82
Get rid of "context" parameter for Token resolution
Dec 18, 2018
9f40aa2
Make refs and attributes Stack-aware
Dec 21, 2018
c1d4dc1
Create tests for things I'll have to do later
Dec 21, 2018
5d85318
Fix core tests
Dec 26, 2018
4219539
Merge branch 'master' into huijbers/x-stack-references
rix0rrr Dec 28, 2018
d8876bf
Remove CloudFormationToken
rix0rrr Dec 28, 2018
0a724b4
Rename StackAwareCloudFormationToken -> StackAwareToken
rix0rrr Dec 28, 2018
445805f
CloudFormationConcat is no longer configurable, but just the default
rix0rrr Dec 28, 2018
cc928f8
Remove sourceStack argument to substitution
rix0rrr Dec 28, 2018
3cb539f
Make JSII happy
rix0rrr Dec 28, 2018
0840d76
Make Pseudo parameters (StackId etc.) attributes of Stack
rix0rrr Dec 28, 2018
73353c0
Add cdk deployment ordering; WIP - fighting with dependency cycles
rix0rrr Dec 28, 2018
f161a4d
Reorganizing to get rid of cycles, add integ test
rix0rrr Dec 31, 2018
7a105e9
Merge remote-tracking branch 'origin/master' into huijbers/x-stack-re…
rix0rrr Jan 4, 2019
ba3a4db
Rename StackAwareToken => CfnReference
rix0rrr Jan 4, 2019
8093361
Move resolve() into the context of a Construct, and hide the global m…
rix0rrr Jan 4, 2019
6330ab5
Introduce concept of references and use it to implement cross-stack refs
rix0rrr Jan 4, 2019
2c224c4
Fix some bugs
rix0rrr Jan 4, 2019
b17d811
More context attachments trying to make the tests work
rix0rrr Jan 4, 2019
a8e00d9
More work to get tests to pass
rix0rrr Jan 7, 2019
eef74a5
Also generate private (tools) packages in global tsconfig
Jan 7, 2019
5978c6b
Fix examples
Jan 7, 2019
996f998
Merge branch 'master' into huijbers/x-stack-references
Jan 8, 2019
e0ec521
Review comments
rix0rrr Jan 8, 2019
3a0d5b5
Fix compilation
rix0rrr Jan 8, 2019
1d5388d
Review comments
rix0rrr Jan 8, 2019
3ee48f7
Undo more refactoring breakage
rix0rrr Jan 8, 2019
d1b3c22
Fold ArnUtils.fromComponents() and ArnUtils.parse() into Stack
rix0rrr Jan 8, 2019
85cc4d2
Missing commit
rix0rrr Jan 8, 2019
8e64bc2
Replace construct library's use of CloudFormationJSON with stringifyJ…
rix0rrr Jan 8, 2019
5694b9c
Remove additional scope argument for IAM policies
rix0rrr Jan 8, 2019
d1a643e
Merge remote-tracking branch 'origin/master' into huijbers/x-stack-re…
rix0rrr Jan 8, 2019
12854e6
arnFromComponents() -> formatArn()
rix0rrr Jan 8, 2019
c7d4314
Move logic for collecting tokens to token layer
Jan 8, 2019
d2a656f
validate() is now protected
Jan 8, 2019
fdeaa55
Move protected() methods down in source
Jan 8, 2019
00cbe07
Call validateTree() instead of protected validate() in tests
Jan 8, 2019
0346946
Fix test
Jan 8, 2019
34bfb34
Fix another test
Jan 8, 2019
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
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-apigateway/lib/restapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ export enum EndpointType {
Private = 'PRIVATE'
}

export class RestApiUrl extends cdk.CloudFormationToken { }
export class RestApiUrl extends cdk.Token { }
rix0rrr marked this conversation as resolved.
Show resolved Hide resolved

class ImportedRestApi extends cdk.Construct implements IRestApi {
public restApiId: string;
Expand Down
4 changes: 3 additions & 1 deletion packages/@aws-cdk/aws-apigateway/lib/stage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import cdk = require('@aws-cdk/cdk');
import { Stack } from '@aws-cdk/cdk';
import { CfnStage } from './apigateway.generated';
import { Deployment } from './deployment';
import { IRestApi } from './restapi';
Expand Down Expand Up @@ -173,7 +174,8 @@ export class Stage extends cdk.Construct implements cdk.IDependable {
if (!path.startsWith('/')) {
throw new Error(`Path must begin with "/": ${path}`);
}
return `https://${this.restApi.restApiId}.execute-api.${new cdk.AwsRegion()}.amazonaws.com/${this.stageName}${path}`;
const stack = Stack.find(this);
return `https://${this.restApi.restApiId}.execute-api.${stack.region}.${stack.urlSuffix}/${this.stageName}${path}`;
}

private renderMethodSettings(props: StageProps): CfnStage.MethodSettingProperty[] | undefined {
Expand Down
4 changes: 3 additions & 1 deletion packages/@aws-cdk/aws-cloudtrail/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,15 @@ export class CloudTrail extends cdk.Construct {
const s3bucket = new s3.Bucket(this, 'S3', {encryption: s3.BucketEncryption.Unencrypted});
const cloudTrailPrincipal = "cloudtrail.amazonaws.com";

const stack = cdk.Stack.find(this);

s3bucket.addToResourcePolicy(new iam.PolicyStatement()
.addResource(s3bucket.bucketArn)
.addActions('s3:GetBucketAcl')
.addServicePrincipal(cloudTrailPrincipal));

s3bucket.addToResourcePolicy(new iam.PolicyStatement()
.addResource(s3bucket.arnForObjects(`AWSLogs/${new cdk.AwsAccountId()}/*`))
.addResource(s3bucket.arnForObjects(`AWSLogs/${stack.accountId}/*`))
.addActions("s3:PutObject")
.addServicePrincipal(cloudTrailPrincipal)
.setCondition("StringEquals", {'s3:x-amz-acl': "bucket-owner-full-control"}));
Expand Down
8 changes: 4 additions & 4 deletions packages/@aws-cdk/aws-cloudwatch/lib/graph.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AwsRegion } from "@aws-cdk/cdk";
import cdk = require('@aws-cdk/cdk');
import { Alarm } from "./alarm";
import { Metric } from "./metric";
import { parseStatistic } from './util.statistic';
Expand Down Expand Up @@ -73,7 +73,7 @@ export class AlarmWidget extends ConcreteWidget {
properties: {
view: 'timeSeries',
title: this.props.title,
region: this.props.region || new AwsRegion(),
region: this.props.region || new cdk.Token({ Ref: 'AWS::Region' }),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason not to use stack.region here?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we should still provide something like Aws.region and Aws.accountId for people to be able to explicitly use these pseudo parameters? Or even Stack.region and Stack.accountId

annotations: {
alarms: [this.props.alarm.alarmArn]
},
Expand Down Expand Up @@ -150,7 +150,7 @@ export class GraphWidget extends ConcreteWidget {
properties: {
view: 'timeSeries',
title: this.props.title,
region: this.props.region || new AwsRegion(),
region: this.props.region || new cdk.Token({ Ref: 'AWS::Region' }),
metrics: (this.props.left || []).map(m => metricJson(m, 'left')).concat(
(this.props.right || []).map(m => metricJson(m, 'right'))),
annotations: {
Expand Down Expand Up @@ -197,7 +197,7 @@ export class SingleValueWidget extends ConcreteWidget {
properties: {
view: 'singleValue',
title: this.props.title,
region: this.props.region || new AwsRegion(),
region: this.props.region || new cdk.Token({ Ref: 'AWS::Region' }),
metrics: this.props.metrics.map(m => metricJson(m, 'left'))
}
}];
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-codebuild/test/test.codebuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -857,7 +857,7 @@ export = {
environment: {
environmentVariables: {
FOO: { value: '1234' },
BAR: { value: `111${new cdk.CloudFormationToken({ twotwotwo: '222' })}`, type: codebuild.BuildEnvironmentVariableType.ParameterStore }
BAR: { value: `111${new cdk.Token({ twotwotwo: '222' })}`, type: codebuild.BuildEnvironmentVariableType.ParameterStore }
}
},
environmentVariables: {
Expand Down
3 changes: 2 additions & 1 deletion packages/@aws-cdk/aws-codecommit/lib/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,8 @@ class ImportedRepository extends RepositoryBase {
}

private repositoryCloneUrl(protocol: 'https' | 'ssh'): string {
return `${protocol}://git-codecommit.${new cdk.AwsRegion()}.${new cdk.AwsURLSuffix()}/v1/repos/${this.repositoryName}`;
const stack = cdk.Stack.find(this);
rix0rrr marked this conversation as resolved.
Show resolved Hide resolved
return `${protocol}://git-codecommit.${stack.region}.${stack.urlSuffix}/v1/repos/${this.repositoryName}`;
}
}

Expand Down
10 changes: 5 additions & 5 deletions packages/@aws-cdk/aws-codedeploy/lib/deployment-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,9 +310,9 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupBase {

this._autoScalingGroups = props.autoScalingGroups || [];
this.installAgent = props.installAgent === undefined ? true : props.installAgent;
const region = new cdk.AwsRegion().toString();
const stack = cdk.Stack.find(this);
this.codeDeployBucket = s3.Bucket.import(this, 'CodeDeployBucket', {
bucketName: `aws-codedeploy-${region}`,
bucketName: `aws-codedeploy-${stack.region}`,
});
for (const asg of this._autoScalingGroups) {
this.addCodeDeployAgentInstallUserData(asg);
Expand Down Expand Up @@ -387,7 +387,7 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupBase {

this.codeDeployBucket.grantRead(asg.role, 'latest/*');

const region = (new cdk.AwsRegion()).toString();
const stack = cdk.Stack.find(this);
switch (asg.osType) {
case ec2.OperatingSystemType.Linux:
asg.addUserData(
Expand All @@ -405,7 +405,7 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupBase {
'$PKG_CMD install -y awscli',
'TMP_DIR=`mktemp -d`',
'cd $TMP_DIR',
`aws s3 cp s3://aws-codedeploy-${region}/latest/install . --region ${region}`,
`aws s3 cp s3://aws-codedeploy-${stack.region}/latest/install . --region ${stack.region}`,
'chmod +x ./install',
'./install auto',
'rm -fr $TMP_DIR',
Expand All @@ -414,7 +414,7 @@ export class ServerDeploymentGroup extends ServerDeploymentGroupBase {
case ec2.OperatingSystemType.Windows:
asg.addUserData(
'Set-Variable -Name TEMPDIR -Value (New-TemporaryFile).DirectoryName',
`aws s3 cp s3://aws-codedeploy-${region}/latest/codedeploy-agent.msi $TEMPDIR\\codedeploy-agent.msi`,
`aws s3 cp s3://aws-codedeploy-${stack.region}/latest/codedeploy-agent.msi $TEMPDIR\\codedeploy-agent.msi`,
'$TEMPDIR\\codedeploy-agent.msi /quiet /l c:\\temp\\host-agent-install-log.txt',
);
break;
Expand Down
6 changes: 3 additions & 3 deletions packages/@aws-cdk/aws-codepipeline-api/lib/artifact.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CloudFormationToken, Construct } from "@aws-cdk/cdk";
import { Construct, Token } from "@aws-cdk/cdk";
import { Action } from "./action";

/**
Expand Down Expand Up @@ -72,9 +72,9 @@ export class ArtifactPath {
}

function artifactAttribute(artifact: Artifact, attributeName: string) {
return new CloudFormationToken(() => ({ 'Fn::GetArtifactAtt': [artifact.name, attributeName] })).toString();
return new Token(() => ({ 'Fn::GetArtifactAtt': [artifact.name, attributeName] })).toString();
}

function artifactGetParam(artifact: Artifact, jsonFile: string, keyName: string) {
return new CloudFormationToken(() => ({ 'Fn::GetParam': [artifact.name, jsonFile, keyName] })).toString();
return new Token(() => ({ 'Fn::GetParam': [artifact.name, jsonFile, keyName] })).toString();
}
15 changes: 14 additions & 1 deletion packages/@aws-cdk/aws-ec2/lib/vpc-ref.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Construct, IDependable } from "@aws-cdk/cdk";
import { Construct, IDependable, Stack } from "@aws-cdk/cdk";
import { subnetName } from './util';

export interface IVpcSubnet extends IDependable {
Expand Down Expand Up @@ -54,6 +54,11 @@ export interface IVpcNetwork extends IDependable {
*/
readonly availabilityZones: string[];

/**
* Region where this VPC is located
*/
readonly vpcRegion: string;

/**
* Take a dependency on internet connectivity having been added to this VPC
*
Expand Down Expand Up @@ -250,6 +255,14 @@ export abstract class VpcNetworkBase extends Construct implements IVpcNetwork {
public internetDependency(): IDependable {
return new DependencyList(this.internetDependencies);
}

/**
* The region where this VPC is defined
*/
public get vpcRegion(): string {
return Stack.find(this).region;
}

}

/**
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-ec2/lib/vpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { NetworkBuilder } from './network-util';
import { DEFAULT_SUBNET_NAME, ExportSubnetGroup, ImportSubnetGroup, subnetId } from './util';
import { VpcNetworkProvider, VpcNetworkProviderProps } from './vpc-network-provider';
import { IVpcNetwork, IVpcSubnet, SubnetType, VpcNetworkBase, VpcNetworkImportProps, VpcPlacementStrategy, VpcSubnetImportProps } from './vpc-ref';

/**
* Name tag constant
*/
Expand Down
3 changes: 2 additions & 1 deletion packages/@aws-cdk/aws-ecs/lib/log-drivers/aws-log-driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,13 @@ export class AwsLogDriver extends LogDriver {
* Return the log driver CloudFormation JSON
*/
public renderLogDriver(): CfnTaskDefinition.LogConfigurationProperty {
const stack = cdk.Stack.find(this);
return {
logDriver: 'awslogs',
options: removeEmpty({
'awslogs-group': this.logGroup.logGroupName,
'awslogs-stream-prefix': this.props.streamPrefix,
'awslogs-region': `${new cdk.AwsRegion()}`,
'awslogs-region': stack.region,
'awslogs-datetime-format': this.props.datetimeFormat,
'awslogs-multiline-pattern': this.props.multilinePattern,
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export class ApplicationLoadBalancer extends BaseLoadBalancer implements IApplic

// FIXME: can't use grantPut() here because that only takes IAM objects, not arbitrary principals
bucket.addToResourcePolicy(new iam.PolicyStatement()
.addPrincipal(new iam.AccountPrincipal(account))
.addPrincipal(new iam.AccountPrincipal(this, account))
.addAction('s3:PutObject')
.addResource(bucket.arnForObjects(prefix || '', '*')));
}
Expand Down
28 changes: 14 additions & 14 deletions packages/@aws-cdk/aws-iam/lib/policy-document.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AwsAccountId, AwsPartition, Token } from '@aws-cdk/cdk';
import cdk = require('@aws-cdk/cdk');

export class PolicyDocument extends Token {
export class PolicyDocument extends cdk.Token {
private statements = new Array<PolicyStatement>();

/**
Expand Down Expand Up @@ -81,8 +81,8 @@ export class ArnPrincipal extends PolicyPrincipal {
}

export class AccountPrincipal extends ArnPrincipal {
constructor(public readonly accountId: any) {
super(`arn:${new AwsPartition()}:iam::${accountId}:root`);
constructor(public readonly anchor: cdk.Construct, public readonly accountId: any) {
rix0rrr marked this conversation as resolved.
Show resolved Hide resolved
super(`arn:${new cdk.Aws(anchor).partition}:iam::${accountId}:root`);
}
}

Expand Down Expand Up @@ -136,8 +136,8 @@ export class FederatedPrincipal extends PolicyPrincipal {
}

export class AccountRootPrincipal extends AccountPrincipal {
constructor() {
super(new AwsAccountId());
constructor(anchor: cdk.Construct) {
super(anchor, new cdk.Aws(anchor).accountId);
}
}

Expand Down Expand Up @@ -201,7 +201,7 @@ export class CompositePrincipal extends PolicyPrincipal {
/**
* Represents a statement in an IAM policy document.
*/
export class PolicyStatement extends Token {
export class PolicyStatement extends cdk.Token {
private action = new Array<any>();
private principal: { [key: string]: any[] } = {};
private resource = new Array<any>();
Expand Down Expand Up @@ -250,12 +250,12 @@ export class PolicyStatement extends Token {
return this.addPrincipal(new ArnPrincipal(arn));
}

public addArnPrincipal(arn: string): this {
return this.addAwsPrincipal(arn);
public addAwsAccountPrincipal(anchor: cdk.Construct, accountId: string): this {
return this.addPrincipal(new AccountPrincipal(anchor, accountId));
}

public addAwsAccountPrincipal(accountId: string): this {
return this.addPrincipal(new AccountPrincipal(accountId));
public addArnPrincipal(arn: string): this {
return this.addAwsPrincipal(arn);
}

public addServicePrincipal(service: string): this {
Expand All @@ -266,8 +266,8 @@ export class PolicyStatement extends Token {
return this.addPrincipal(new FederatedPrincipal(federated, conditions));
}

public addAccountRootPrincipal(): this {
return this.addPrincipal(new AccountRootPrincipal());
public addAccountRootPrincipal(anchor: cdk.Construct): this {
return this.addPrincipal(new AccountRootPrincipal(anchor));
}

public addCanonicalUserPrincipal(canonicalUserId: string): this {
Expand Down Expand Up @@ -363,7 +363,7 @@ export class PolicyStatement extends Token {
}

public limitToAccount(accountId: string): PolicyStatement {
return this.addCondition('StringEquals', new Token(() => {
return this.addCondition('StringEquals', new cdk.Token(() => {
return { 'sts:ExternalId': accountId };
}));
}
Expand Down
6 changes: 3 additions & 3 deletions packages/@aws-cdk/aws-iam/lib/util.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { CloudFormationToken } from '@aws-cdk/cdk';
import { Token } from '@aws-cdk/cdk';
import { Policy } from './policy';

const MAX_POLICY_NAME_LEN = 128;

export function undefinedIfEmpty<T>(f: () => T[]): CloudFormationToken {
return new CloudFormationToken(() => {
export function undefinedIfEmpty<T>(f: () => T[]): Token {
return new Token(() => {
const array = f();
return (array && array.length > 0) ? array : undefined;
});
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-iam/test/example.external-id.lit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class ExampleConstruct extends cdk.Construct {

/// !show
const role = new iam.Role(this, 'MyRole', {
assumedBy: new iam.AccountPrincipal('123456789012'),
assumedBy: new iam.AccountPrincipal(this, '123456789012'),
externalId: 'SUPPLY-ME',
});
/// !hide
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-iam/test/integ.role.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ policy.attachToRole(role);

// Role with an external ID
new Role(stack, 'TestRole2', {
assumedBy: new AccountRootPrincipal(),
assumedBy: new AccountRootPrincipal(stack),
externalId: 'supply-me',
});

Expand Down
Loading