From e443a23270401e8c281d92f4788563a9e9809654 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Mon, 22 Oct 2018 19:13:52 +0200 Subject: [PATCH] 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"