Skip to content

Commit db4e718

Browse files
authored
feat(aws-cdk): add CDK app version negotiation (#988)
Tag the CDK app output with a version, so that the Toolkit can compare the sent and expected versions and complain if there's a mismatch. Fixes #891.
1 parent a83ac5f commit db4e718

File tree

5 files changed

+60
-2
lines changed

5 files changed

+60
-2
lines changed

packages/@aws-cdk/cdk/lib/app.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export class App extends Root {
4343
}
4444

4545
const result: cxapi.SynthesizeResponse = {
46+
version: cxapi.PROTO_RESPONSE_VERSION,
4647
stacks: this.synthesizeStacks(Object.keys(this.stacks)),
4748
runtime: this.collectRuntimeInformation()
4849
};

packages/@aws-cdk/cdk/test/test.app.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ export = {
6969
response.stacks.forEach(s => delete s.metadata);
7070
delete response.runtime;
7171

72-
test.deepEqual(response, { stacks:
72+
test.deepEqual(response, {
73+
version: '0.14.0',
74+
stacks:
7375
[ { name: 'stack1',
7476
environment:
7577
{ name: '12345/us-east-1',

packages/@aws-cdk/cx-api/lib/cxapi.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,24 @@
44

55
import { Environment } from './environment';
66

7+
/**
8+
* Bump this to the library version if and only if the CX protocol changes.
9+
*
10+
* We could also have used 1, 2, 3, ... here to indicate protocol versions, but
11+
* those then still need to be mapped to software versions to be useful. So we
12+
* might as well use the software version as protocol version and immediately
13+
* generate a useful error message from this.
14+
*
15+
* Note the following:
16+
*
17+
* - The versions are not compared in a semver way, they are used as
18+
* opaque ordered tokens.
19+
* - The version needs to be set to the NEXT releasable version when it's
20+
* updated (as the current verison in package.json has already been released!)
21+
* - The request does not have versioning yet, only the response.
22+
*/
23+
export const PROTO_RESPONSE_VERSION = '0.14.0';
24+
725
export const OUTFILE_NAME = 'cdk.out';
826
export const OUTDIR_ENV = 'CDK_OUTDIR';
927
export const CONTEXT_ENV = 'CDK_CONTEXT_JSON';
@@ -21,6 +39,10 @@ export interface MissingContext {
2139
}
2240

2341
export interface SynthesizeResponse {
42+
/**
43+
* Protocol version
44+
*/
45+
version: string;
2446
stacks: SynthesizedStack[];
2547
runtime?: AppRuntime;
2648
}

packages/aws-cdk/bin/cdk.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import YAML = require('js-yaml');
99
import minimatch = require('minimatch');
1010
import os = require('os');
1111
import path = require('path');
12+
import semver = require('semver');
1213
import util = require('util');
1314
import yargs = require('yargs');
1415
import cdkUtil = require('../lib/util');
@@ -469,7 +470,7 @@ async function initCommandLine() {
469470
470471
const response = await fs.readJson(outfile);
471472
debug(response);
472-
return response;
473+
return versionCheckResponse(response);
473474
} finally {
474475
debug('Removing outdir', outdir);
475476
await fs.remove(outdir);
@@ -508,7 +509,37 @@ async function initCommandLine() {
508509
});
509510
}
510511
}
512+
}
513+
514+
/**
515+
* Look at the type of response we get and upgrade it to the latest expected version
516+
*/
517+
function versionCheckResponse(response: cxapi.SynthesizeResponse): cxapi.SynthesizeResponse {
518+
if (!response.version) {
519+
// tslint:disable-next-line:max-line-length
520+
throw new Error(`CDK Framework >= ${cxapi.PROTO_RESPONSE_VERSION} is required in order to interact with this version of the Toolkit.`);
521+
}
522+
523+
const frameworkVersion = semver.coerce(response.version);
524+
const toolkitVersion = semver.coerce(cxapi.PROTO_RESPONSE_VERSION);
525+
526+
// Should not happen, but I don't trust this library 100% either, so let's check for it to be safe
527+
if (!frameworkVersion || !toolkitVersion) { throw new Error('SemVer library could not parse versions'); }
528+
529+
if (semver.gt(frameworkVersion, toolkitVersion)) {
530+
throw new Error(`CDK Toolkit >= ${response.version} is required in order to interact with this program.`);
531+
}
532+
533+
if (semver.lt(frameworkVersion, toolkitVersion)) {
534+
// Toolkit protocol is newer than the framework version, and we KNOW the
535+
// version. This is a scenario in which we could potentially do some
536+
// upgrading of the response in the future.
537+
//
538+
// For now though, we simply reject old responses.
539+
throw new Error(`CDK Framework >= ${cxapi.PROTO_RESPONSE_VERSION} is required in order to interact with this version of the Toolkit.`);
540+
}
511541
542+
return response;
512543
}
513544
514545
/**

packages/aws-cdk/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"@types/request": "^2.47.1",
4040
"@types/uuid": "^3.4.3",
4141
"@types/yargs": "^8.0.3",
42+
"@types/semver": "^5.5.0",
4243
"cdk-build-tools": "^0.13.0",
4344
"mockery": "^2.1.0",
4445
"pkglint": "^0.13.0"
@@ -58,6 +59,7 @@
5859
"promptly": "^0.2.0",
5960
"proxy-agent": "^3.0.1",
6061
"request": "^2.83.0",
62+
"semver": "^5.5.0",
6163
"source-map-support": "^0.5.6",
6264
"yargs": "^9.0.1"
6365
},

0 commit comments

Comments
 (0)