From e443a23270401e8c281d92f4788563a9e9809654 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 22 Oct 2018 19:13:52 +0200 Subject: [PATCH 1/5] feat(aws-cdk): add CDK app version negotiation 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. --- packages/@aws-cdk/cdk/lib/app.ts | 1 + packages/@aws-cdk/cx-api/lib/cxapi.ts | 22 ++++++++++++++++++++ packages/@aws-cdk/cx-api/lib/index.ts | 1 + packages/aws-cdk/bin/cdk.ts | 30 ++++++++++++++++++++++++++- packages/aws-cdk/package.json | 1 + 5 files changed, 54 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/cdk/lib/app.ts b/packages/@aws-cdk/cdk/lib/app.ts index ee861781761f0..f3e7c6a90ff8a 100644 --- a/packages/@aws-cdk/cdk/lib/app.ts +++ b/packages/@aws-cdk/cdk/lib/app.ts @@ -43,6 +43,7 @@ export class App extends Root { } const result: cxapi.SynthesizeResponse = { + version: cxapi.PROTO_RESPONSE_VERSION, stacks: this.synthesizeStacks(Object.keys(this.stacks)), runtime: this.collectRuntimeInformation() }; diff --git a/packages/@aws-cdk/cx-api/lib/cxapi.ts b/packages/@aws-cdk/cx-api/lib/cxapi.ts index 9835ffd765500..f0ef41a59256b 100644 --- a/packages/@aws-cdk/cx-api/lib/cxapi.ts +++ b/packages/@aws-cdk/cx-api/lib/cxapi.ts @@ -4,6 +4,24 @@ import { Environment } from './environment'; +/** + * Bump this to the library version if and only if the CX protocol changes. + * + * We could also have used 1, 2, 3, ... here to indicate protocol versions, but + * those then still need to be mapped to software versions to be useful. So we + * might as well use the software version as protocol version and immediately + * generate a useful error message from this. + * + * Note the following: + * + * - The versions are not compared in a semver way, they are used as + * opaque ordered tokens. + * - The version needs to be set to the NEXT releasable version when it's + * updated (as the current verison in package.json has already been released!) + * - The request does not have versioning yet, only the response. + */ +export const PROTO_RESPONSE_VERSION = '0.14.0'; + export const OUTFILE_NAME = 'cdk.out'; export const OUTDIR_ENV = 'CDK_OUTDIR'; export const CONTEXT_ENV = 'CDK_CONTEXT_JSON'; @@ -21,6 +39,10 @@ export interface MissingContext { } export interface SynthesizeResponse { + /** + * Protocol version + */ + version: string; stacks: SynthesizedStack[]; runtime?: AppRuntime; } diff --git a/packages/@aws-cdk/cx-api/lib/index.ts b/packages/@aws-cdk/cx-api/lib/index.ts index 6077a01aa9581..620d30fdd66df 100644 --- a/packages/@aws-cdk/cx-api/lib/index.ts +++ b/packages/@aws-cdk/cx-api/lib/index.ts @@ -1,2 +1,3 @@ export * from './cxapi'; +export * from './cdk-api'; export * from './environment'; diff --git a/packages/aws-cdk/bin/cdk.ts b/packages/aws-cdk/bin/cdk.ts index 27a9e21451ab7..c0702a771d763 100644 --- a/packages/aws-cdk/bin/cdk.ts +++ b/packages/aws-cdk/bin/cdk.ts @@ -9,6 +9,7 @@ import YAML = require('js-yaml'); import minimatch = require('minimatch'); import os = require('os'); import path = require('path'); +import semver = require('semver'); import util = require('util'); import yargs = require('yargs'); import cdkUtil = require('../lib/util'); @@ -469,7 +470,7 @@ async function initCommandLine() { const response = await fs.readJson(outfile); debug(response); - return response; + return versionCheckResponse(response); } finally { debug('Removing outdir', outdir); await fs.remove(outdir); @@ -508,7 +509,34 @@ async function initCommandLine() { }); } } + } + + /** + * Look at the type of response we get and upgrade it to the latest expected version + */ + function versionCheckResponse(response: cxapi.SynthesizeResponse): cxapi.SynthesizeResponse { + if (!response.version) { + // tslint:disable-next-line:max-line-length + throw new Error(`CDK Framework >= ${cxapi.PROTO_RESPONSE_VERSION} is required in order to interact with this version of the Toolkit.`); + } + + const frameworkVersion = semver.coerce(response.version); + const toolkitVersion = semver.coerce(cxapi.PROTO_RESPONSE_VERSION); + + if (semver.gt(frameworkVersion, toolkitVersion)) { + throw new Error(`CDK Toolkit >= ${response.version} is required in order to interact with this program.`); + } + + if (semver.lt(frameworkVersion, toolkitVersion)) { + // Toolkit protocol is newer than the framework version, and we KNOW the + // version. This is a scenario in which we could potentially do some + // upgrading of the request in the future. + // + // For now though, we simply reject old responses. + throw new Error(`CDK Framework >= ${cxapi.PROTO_RESPONSE_VERSION} is required in order to interact with this version of the Toolkit.`); + } + return response; } /** diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 31ad390cfb164..72a28a6470ebf 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -39,6 +39,7 @@ "@types/request": "^2.47.1", "@types/uuid": "^3.4.3", "@types/yargs": "^8.0.3", + "@types/semver": "^5.5.0", "cdk-build-tools": "^0.13.0", "mockery": "^2.1.0", "pkglint": "^0.13.0" From 14b4376c28a1cae87b9e80d06631e61ccbe44d78 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 23 Oct 2018 10:09:04 +0200 Subject: [PATCH 2/5] Remove trailing import --- packages/@aws-cdk/cx-api/lib/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/@aws-cdk/cx-api/lib/index.ts b/packages/@aws-cdk/cx-api/lib/index.ts index 620d30fdd66df..6077a01aa9581 100644 --- a/packages/@aws-cdk/cx-api/lib/index.ts +++ b/packages/@aws-cdk/cx-api/lib/index.ts @@ -1,3 +1,2 @@ export * from './cxapi'; -export * from './cdk-api'; export * from './environment'; From 740620717cf83dcb3e2add7e1bbee5f28bf40f77 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Tue, 23 Oct 2018 10:32:58 +0200 Subject: [PATCH 3/5] Assert that parsing succeeded --- packages/aws-cdk/bin/cdk.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/aws-cdk/bin/cdk.ts b/packages/aws-cdk/bin/cdk.ts index c0702a771d763..256a5d3bc6b61 100644 --- a/packages/aws-cdk/bin/cdk.ts +++ b/packages/aws-cdk/bin/cdk.ts @@ -523,6 +523,9 @@ async function initCommandLine() { const frameworkVersion = semver.coerce(response.version); const toolkitVersion = semver.coerce(cxapi.PROTO_RESPONSE_VERSION); + // Should not happen, but I don't trust this library 100% either, so let's check for it to be safe + if (!frameworkVersion || !toolkitVersion) { throw new Error('SemVer library could not parse versions'); } + if (semver.gt(frameworkVersion, toolkitVersion)) { throw new Error(`CDK Toolkit >= ${response.version} is required in order to interact with this program.`); } @@ -530,7 +533,7 @@ async function initCommandLine() { if (semver.lt(frameworkVersion, toolkitVersion)) { // Toolkit protocol is newer than the framework version, and we KNOW the // version. This is a scenario in which we could potentially do some - // upgrading of the request in the future. + // upgrading of the response in the future. // // For now though, we simply reject old responses. throw new Error(`CDK Framework >= ${cxapi.PROTO_RESPONSE_VERSION} is required in order to interact with this version of the Toolkit.`); From 0e006a5f9d871eaa46aa20f1008ce358370abc09 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Wed, 24 Oct 2018 16:30:26 +0200 Subject: [PATCH 4/5] Update test failure --- packages/@aws-cdk/cdk/test/test.app.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/@aws-cdk/cdk/test/test.app.ts b/packages/@aws-cdk/cdk/test/test.app.ts index 9b8d7325e1203..177ac8682219d 100644 --- a/packages/@aws-cdk/cdk/test/test.app.ts +++ b/packages/@aws-cdk/cdk/test/test.app.ts @@ -69,7 +69,9 @@ export = { response.stacks.forEach(s => delete s.metadata); delete response.runtime; - test.deepEqual(response, { stacks: + test.deepEqual(response, { + version: '0.14.0', + stacks: [ { name: 'stack1', environment: { name: '12345/us-east-1', From fbdeec319ccdc9dfbcc93fa076115d162f409a3d Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Thu, 25 Oct 2018 11:54:08 +0200 Subject: [PATCH 5/5] Add explicit dependency on used 'semver' package --- packages/aws-cdk/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/aws-cdk/package.json b/packages/aws-cdk/package.json index 72a28a6470ebf..c768a563aa33e 100644 --- a/packages/aws-cdk/package.json +++ b/packages/aws-cdk/package.json @@ -59,6 +59,7 @@ "promptly": "^0.2.0", "proxy-agent": "^3.0.1", "request": "^2.83.0", + "semver": "^5.5.0", "source-map-support": "^0.5.6", "yargs": "^9.0.1" },