Skip to content

Commit

Permalink
feat(core): generalization of dependencies (#1583)
Browse files Browse the repository at this point in the history
Constructs can now take a dependency on any other construct.

Before, only `Resource`s could take dependencies, and they would depend
on `IDependable` which had to be implemented explicitly. In this change
we generalize the concept of dependencies from construct trees to other
construct trees; all constructs now take dependencies and also implement
`IDependable`.  The semantics are that any resource in the depending
tree will depend on all resources in the depended tree.

Dependencies are cross-stack aware

If you take a dependency on a construct in another stack, the dependency
does not get rendered in the template, but is instead added as a
dependency between stacks.

Fixes #1568, fixes #95.

BREAKING CHANGE: `resource.addDependency()` has been moved onto
`ConstructNode`. You now write `resource.node.addDependency()`. VPC's
`internetDependency` has been moved to the subnets as
`internetConnectivityEstablished`. Target Group's
`loadBalancerAssociationDependencies` has been renamed to
`loadBalancerAttached`.
  • Loading branch information
rix0rrr authored Feb 4, 2019
1 parent 7cdbcec commit 53e6825
Show file tree
Hide file tree
Showing 73 changed files with 500 additions and 564 deletions.
6 changes: 2 additions & 4 deletions examples/cdk-examples-typescript/custom-resource/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ interface DemoResourceProps {
failCreate?: boolean;
}

class DemoResource extends cdk.Construct implements cdk.IDependable {
public readonly dependencyElements: cdk.IDependable[];
class DemoResource extends cdk.Construct {
public readonly response: string;

constructor(scope: cdk.Construct, id: string, props: DemoResourceProps) {
Expand All @@ -36,7 +35,6 @@ class DemoResource extends cdk.Construct implements cdk.IDependable {
});

this.response = resource.getAtt('Response').toString();
this.dependencyElements = [resource];
}
}

Expand Down Expand Up @@ -91,7 +89,7 @@ class FailAfterCreatingStack extends cdk.Stack {
});

// Make sure the rollback gets triggered only after the custom resource has been fully created.
bucket.addDependency(resource);
bucket.node.addDependency(resource);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class ResourceOverridesExample extends cdk.Stack {
// This is how to specify resource options such as dependencies, metadata, update policy
//

bucketResource.addDependency(otherBucket.node.findChild('Resource') as cdk.Resource);
bucketResource.node.addDependency(otherBucket.node.findChild('Resource') as cdk.Resource);
bucketResource.options.metadata = { MetadataKey: 'MetadataValue' };
bucketResource.options.updatePolicy = {
autoScalingRollingUpdate: {
Expand Down
20 changes: 4 additions & 16 deletions packages/@aws-cdk/aws-apigateway/lib/deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,13 @@ export interface DeploymentProps {
* Furthermore, since a deployment does not reference any of the REST API
* resources and methods, CloudFormation will likely provision it before these
* resources are created, which means that it will represent a "half-baked"
* model. Use the `addDependency(dep)` method to circumvent that. This is done
* model. Use the `node.addDependency(dep)` method to circumvent that. This is done
* automatically for the `restApi.latestDeployment` deployment.
*/
export class Deployment extends cdk.Construct implements cdk.IDependable {
export class Deployment extends cdk.Construct {
public readonly deploymentId: string;
public readonly api: IRestApi;

/**
* Allows taking a dependency on this construct.
*/
public readonly dependencyElements = new Array<cdk.IDependable>();

private readonly resource: LatestDeploymentResource;

constructor(scope: cdk.Construct, id: string, props: DeploymentProps) {
Expand All @@ -79,15 +74,6 @@ export class Deployment extends cdk.Construct implements cdk.IDependable {

this.api = props.api;
this.deploymentId = new cdk.Token(() => this.resource.deploymentId).toString();
this.dependencyElements.push(this.resource);
}

/**
* Adds a dependency for this deployment. Should be called by all resources and methods
* so they are provisioned before this Deployment.
*/
public addDependency(dep: cdk.IDependable) {
this.resource.addDependency(dep);
}

/**
Expand Down Expand Up @@ -182,5 +168,7 @@ class LatestDeploymentResource extends CfnDeployment {

this.lazyLogicalId = this.originalLogicalId + md5.digest("hex");
}

super.prepare();
}
}
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-apigateway/lib/method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export class Method extends cdk.Construct {

const deployment = props.resource.resourceApi.latestDeployment;
if (deployment) {
deployment.addDependency(resource);
deployment.node.addDependency(resource);
deployment.addToLogicalId({ method: methodProps });
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-apigateway/lib/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export class Resource extends cdk.Construct implements IRestApiResource {

const deployment = props.parent.resourceApi.latestDeployment;
if (deployment) {
deployment.addDependency(resource);
deployment.node.addDependency(resource);
deployment.addToLogicalId({ resource: resourceProps });
}

Expand Down
18 changes: 3 additions & 15 deletions packages/@aws-cdk/aws-apigateway/lib/restapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export interface RestApiProps extends ResourceOptions {
* By default, the API will automatically be deployed and accessible from a
* public endpoint.
*/
export class RestApi extends cdk.Construct implements cdk.IDependable, IRestApi {
export class RestApi extends cdk.Construct implements IRestApi {
/**
* Imports an existing REST API resource.
* @param parent Parent construct
Expand All @@ -177,11 +177,6 @@ export class RestApi extends cdk.Construct implements cdk.IDependable, IRestApi
*/
public latestDeployment?: Deployment;

/**
* Allows taking a dependency on this construct.
*/
public readonly dependencyElements = new Array<cdk.IDependable>();

/**
* API Gateway stage that points to the latest deployment (if defined).
*
Expand Down Expand Up @@ -226,16 +221,9 @@ export class RestApi extends cdk.Construct implements cdk.IDependable, IRestApi
this.configureCloudWatchRole(resource);
}

this.dependencyElements.push(resource);
if (this.latestDeployment) {
this.dependencyElements.push(this.latestDeployment);
}
if (this.deploymentStage) {
this.dependencyElements.push(this.deploymentStage);
}

// configure the "root" resource
this.root = {
get dependencyRoots() { return [this]; },
node: this.node,
addResource: (pathPart: string, options?: ResourceOptions) => {
return new Resource(this, pathPart, { parent: this.root, pathPart, ...options });
Expand Down Expand Up @@ -372,7 +360,7 @@ export class RestApi extends cdk.Construct implements cdk.IDependable, IRestApi
cloudWatchRoleArn: role.roleArn
});

resource.addDependency(apiResource);
resource.node.addDependency(apiResource);
}
}

Expand Down
4 changes: 1 addition & 3 deletions packages/@aws-cdk/aws-apigateway/lib/stage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,8 @@ export interface MethodDeploymentOptions {
cacheDataEncrypted?: boolean;
}

export class Stage extends cdk.Construct implements cdk.IDependable {
export class Stage extends cdk.Construct {
public readonly stageName: string;
public readonly dependencyElements = new Array<cdk.IDependable>();

private readonly restApi: IRestApi;

Expand Down Expand Up @@ -170,7 +169,6 @@ export class Stage extends cdk.Construct implements cdk.IDependable {

this.stageName = resource.ref;
this.restApi = props.deployment.api;
this.dependencyElements.push(resource);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -530,8 +530,8 @@
"booksapibooksGETA776447A",
"booksapibooksPOSTF6C6559D",
"booksapibooksbookid5264BCA2",
"booksapibooksbookidGETCCE21986",
"booksapibooksbookidDELETE214F4059"
"booksapibooksbookidDELETE214F4059",
"booksapibooksbookidGETCCE21986"
]
},
"booksapiDeploymentStageprod55D8E03E": {
Expand Down Expand Up @@ -837,7 +837,9 @@
"Ref": "AWS::Region"
},
".",
{ "Ref": "AWS::URLSuffix" },
{
"Ref": "AWS::URLSuffix"
},
"/",
{
"Ref": "booksapiDeploymentStageprod55D8E03E"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@
"Ref": "AWS::Region"
},
".",
{ "Ref": "AWS::URLSuffix" },
{
"Ref": "AWS::URLSuffix"
},
"/",
{
"Ref": "myapiDeploymentStageprod298F01AF"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
},
"DependsOn": [
"myapiv113487378",
"myapiv1toysA55FCBC4",
"myapiv1toysGET7348114D",
"myapiv1toysPOST55128058",
"myapiv1toysPUT59AFBBC2",
"myapiv1appliances507FEFF4",
"myapiv1appliancesGET8FE872EC",
"myapiv1books1D4BE6C1",
"myapiv1booksGETC6B996D0",
"myapiv1booksPOST53E2832E"
"myapiv1booksPOST53E2832E",
"myapiv1toysA55FCBC4",
"myapiv1toysGET7348114D",
"myapiv1toysPOST55128058",
"myapiv1toysPUT59AFBBC2"
],
"DeletionPolicy": "Retain"
},
Expand Down Expand Up @@ -602,7 +602,9 @@
"Ref": "AWS::Region"
},
".",
{ "Ref": "AWS::URLSuffix" },
{
"Ref": "AWS::URLSuffix"
},
"/",
{
"Ref": "myapiDeploymentStagebeta96434BEB"
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-apigateway/test/test.deployment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export = {
const dep = new cdk.Resource(stack, 'MyResource', { type: 'foo' });

// WHEN
deployment.addDependency(dep);
deployment.node.addDependency(dep);

expect(stack).to(haveResource('AWS::ApiGateway::Deployment', {
DependsOn: [ "MyResource" ],
Expand Down
Loading

0 comments on commit 53e6825

Please sign in to comment.