From b465896671f9e2a318504235d4bbe26bd59d7b63 Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Tue, 13 Sep 2022 10:13:50 +0200 Subject: [PATCH 01/18] Support Terraform CLI parallelism flag --- .../cdktf-cli/lib/models/terraform-cli.ts | 19 +++++++++++++++---- .../cdktf-cli/lib/models/terraform-cloud.ts | 6 ++++-- packages/cdktf-cli/lib/models/terraform.ts | 14 +++++++++++--- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/packages/cdktf-cli/lib/models/terraform-cli.ts b/packages/cdktf-cli/lib/models/terraform-cli.ts index 5198783365..235adb0680 100644 --- a/packages/cdktf-cli/lib/models/terraform-cli.ts +++ b/packages/cdktf-cli/lib/models/terraform-cli.ts @@ -59,7 +59,8 @@ export class TerraformCli implements Terraform { public async plan( destroy = false, - refreshOnly = false + refreshOnly = false, + parallelism = -1 ): Promise { const planFile = "plan"; const options = ["plan", "-input=false", "-out", planFile]; @@ -69,6 +70,9 @@ export class TerraformCli implements Terraform { if (refreshOnly) { options.push("-refresh-only"); } + if (parallelism !== -1) { + options.push(`-parallelism=${parallelism}`); + } await this.setUserAgent(); await exec( terraformBinaryName, @@ -96,6 +100,7 @@ export class TerraformCli implements Terraform { public async deploy( planFile: string, refreshOnly = false, + parallelism = -1, extraOptions: string[] = [] ): Promise { await this.setUserAgent(); @@ -107,10 +112,11 @@ export class TerraformCli implements Terraform { "-input=false", ...extraOptions, + ...(refreshOnly ? ["-refresh-only"] : []), + ...(parallelism > -1 ? [`-parallelism=${parallelism}`] : []), // only appends planFile if not empty // this allows deploying without a plan (as used in watch) ...(planFile ? [planFile] : []), - ...(refreshOnly ? ["-refresh-only"] : []), ], { cwd: this.workdir, env: process.env, signal: this.abortSignal }, this.onStdout("deploy"), @@ -118,11 +124,16 @@ export class TerraformCli implements Terraform { ); } - public async destroy(): Promise { + public async destroy(parallelism = -1): Promise { await this.setUserAgent(); + const options = ["destroy", "-auto-approve", "-input=false"]; + if (parallelism > -1) { + options.push(`-parallelism=${parallelism}`); + } + await exec( terraformBinaryName, - ["destroy", "-auto-approve", "-input=false"], + options, { cwd: this.workdir, env: process.env, signal: this.abortSignal }, this.onStdout("destroy"), this.onStderr("destroy") diff --git a/packages/cdktf-cli/lib/models/terraform-cloud.ts b/packages/cdktf-cli/lib/models/terraform-cloud.ts index b74e008eba..6fc77a5cb5 100644 --- a/packages/cdktf-cli/lib/models/terraform-cloud.ts +++ b/packages/cdktf-cli/lib/models/terraform-cloud.ts @@ -233,7 +233,8 @@ export class TerraformCloud implements Terraform { @BeautifyErrors("Plan") public async plan( destroy = false, - refreshOnly = false + refreshOnly = false, + _parallelism = -1 ): Promise { if (!this.configurationVersionId) throw new Error("Please create a ConfigurationVersion before planning"); @@ -351,7 +352,8 @@ export class TerraformCloud implements Terraform { @BeautifyErrors("Deploy") public async deploy( _planFile: string, - _refreshOnly?: boolean + _refreshOnly?: boolean, + _parallelism?: number ): Promise { const sendLog = this.createTerraformLogHandler("deploy"); if (!this.run) diff --git a/packages/cdktf-cli/lib/models/terraform.ts b/packages/cdktf-cli/lib/models/terraform.ts index dc083d4289..3581039f23 100644 --- a/packages/cdktf-cli/lib/models/terraform.ts +++ b/packages/cdktf-cli/lib/models/terraform.ts @@ -115,9 +115,17 @@ export abstract class AbstractTerraformPlan implements TerraformPlan { export interface Terraform { init: () => Promise; - plan: (destroy: boolean, refreshOnly?: boolean) => Promise; - deploy(planFile: string, refreshOnly?: boolean): Promise; - destroy(): Promise; + plan: ( + destroy: boolean, + refreshOnly?: boolean, + parallelism?: number + ) => Promise; + deploy( + planFile: string, + refreshOnly?: boolean, + parallelism?: number + ): Promise; + destroy(parallelism?: number): Promise; output(): Promise<{ [key: string]: TerraformOutput }>; abort: () => Promise; } From 2f446997ad396c4120b958f90f7749bee7841e46 Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Tue, 13 Sep 2022 10:22:00 +0200 Subject: [PATCH 02/18] Pass along parallelism flag to terraform backend --- packages/cdktf-cli/lib/cdktf-stack.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/cdktf-cli/lib/cdktf-stack.ts b/packages/cdktf-cli/lib/cdktf-stack.ts index 29c86e1ade..28c3e7e45d 100644 --- a/packages/cdktf-cli/lib/cdktf-stack.ts +++ b/packages/cdktf-cli/lib/cdktf-stack.ts @@ -269,12 +269,16 @@ export class CdktfStack { }); } - public async deploy(refreshOnly?: boolean) { + public async deploy(refreshOnly?: boolean, terraformParallelism?: number) { await this.run(async () => { this.updateState({ type: "planning", stackName: this.stack.name }); const terraform = await this.initalizeTerraform({ isSpeculative: false }); - const plan = await terraform.plan(false, refreshOnly); + const plan = await terraform.plan( + false, + refreshOnly, + terraformParallelism + ); this.updateState({ type: "planned", stackName: this.stack.name, plan }); const approved = this.options.autoApprove @@ -288,7 +292,11 @@ export class CdktfStack { this.updateState({ type: "deploying", stackName: this.stack.name }); if (plan.needsApply) { - await terraform.deploy(plan.planFile, refreshOnly); + await terraform.deploy( + plan.planFile, + refreshOnly, + terraformParallelism + ); } const outputs = await terraform.output(); @@ -306,7 +314,7 @@ export class CdktfStack { }); } - public async destroy() { + public async destroy(terraformParallelism = -1) { await this.run(async () => { this.updateState({ type: "planning", stackName: this.stack.name }); const terraform = await this.initalizeTerraform({ isSpeculative: false }); @@ -323,7 +331,7 @@ export class CdktfStack { } this.updateState({ type: "destroying", stackName: this.stack.name }); - await terraform.destroy(); + await terraform.destroy(terraformParallelism); this.updateState({ type: "destroyed", From aa78d4b89e4b5b626c5886d339ff2cd29a44bbcd Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Tue, 13 Sep 2022 12:15:32 +0200 Subject: [PATCH 03/18] Forward parallelism flag, and test --- packages/cdktf-cli/lib/cdktf-project.ts | 25 +++- .../cdktf-cli/test/lib/cdktf-project.test.ts | 117 ++++++++++++++++++ 2 files changed, 137 insertions(+), 5 deletions(-) diff --git a/packages/cdktf-cli/lib/cdktf-project.ts b/packages/cdktf-cli/lib/cdktf-project.ts index 9afd199146..94229228b2 100644 --- a/packages/cdktf-cli/lib/cdktf-project.ts +++ b/packages/cdktf-cli/lib/cdktf-project.ts @@ -284,6 +284,7 @@ export type ExecutionOptions = MultipleStackOptions & { ignoreMissingStackDependencies?: boolean; parallelism?: number; refreshOnly?: boolean; + terraformParallelism?: number; }; export type DiffOptions = SingleStackOptions & { @@ -520,7 +521,8 @@ export class CdktfProject { method: "deploy" | "destroy", next: () => Promise, parallelism: number, - refreshOnly?: boolean + refreshOnly?: boolean, + terraformParallelism?: number ) { // We only support refresh only on deploy, a bit of a leaky abstraction here if (refreshOnly && method !== "deploy") { @@ -540,8 +542,8 @@ export class CdktfProject { break; } method === "deploy" - ? nextRunningExecutor.deploy(refreshOnly) - : nextRunningExecutor.destroy(); + ? nextRunningExecutor.deploy(refreshOnly, terraformParallelism) + : nextRunningExecutor.destroy(terraformParallelism); } catch (e) { // await next() threw an error because a stack failed to apply/destroy // wait for all other currently running stacks to complete before propagating that error @@ -601,7 +603,13 @@ export class CdktfProject { ) : () => getStackWithNoUnmetDependencies(this.stacksToRun); - await this.execute("deploy", next, parallelism, opts.refreshOnly); + await this.execute( + "deploy", + next, + parallelism, + opts.refreshOnly, + opts.terraformParallelism + ); const unprocessedStacks = this.stacksToRun.filter( (executor) => executor.isPending @@ -617,6 +625,7 @@ export class CdktfProject { public async destroy(opts: ExecutionOptions = {}) { const parallelism = opts.parallelism || -1; + const terraformParallelism = opts.terraformParallelism || -1; const stacks = await this.synth(); const stacksToRun = getMultipleStacks(stacks, opts.stackNames, "destroy"); @@ -659,7 +668,13 @@ export class CdktfProject { ) : () => getStackWithNoUnmetDependants(this.stacksToRun); - await this.execute("destroy", next, parallelism); + await this.execute( + "destroy", + next, + parallelism, + false, + terraformParallelism + ); const unprocessedStacks = this.stacksToRun.filter( (executor) => executor.isPending diff --git a/packages/cdktf-cli/test/lib/cdktf-project.test.ts b/packages/cdktf-cli/test/lib/cdktf-project.test.ts index fff563869b..70cef31ed1 100644 --- a/packages/cdktf-cli/test/lib/cdktf-project.test.ts +++ b/packages/cdktf-cli/test/lib/cdktf-project.test.ts @@ -6,6 +6,7 @@ import * as os from "os"; import { CdktfProject, get, init, Language } from "../../lib/index"; import { SynthesizedStack } from "../../lib/synth-stack"; import { getMultipleStacks } from "../../lib/cdktf-project"; +import { exec } from "cdktf-cli/lib/util"; function eventNames(events: any[]) { return events @@ -13,6 +14,16 @@ function eventNames(events: any[]) { .filter((name) => !name.includes("update")); } +jest.mock("cdktf-cli/lib/util", () => { + const originalModule = jest.requireActual("cdktf-cli/lib/util"); + + return { + __esmodule: true, + ...originalModule, + exec: jest.fn().mockImplementation(originalModule.exec), + }; +}); + function installFixturesInWorkingDirectory( { outDir, @@ -88,6 +99,14 @@ describe("CdktfProject", () => { }; }); + beforeEach(() => { + (exec as jest.Mock).mockClear(); + }); + + afterAll(() => { + jest.resetModules(); + }); + it("should be able to create a CdktfProject", () => { const cdktfProject = new CdktfProject({ synthCommand: "npx ts-node main.ts", @@ -211,6 +230,60 @@ describe("CdktfProject", () => { ]); return expect(eventTypes.includes("waiting for approval")).toBeFalsy(); }); + + it("runs without terraform parallelism", async () => { + const events: any[] = []; + const cdktfProject = new CdktfProject({ + synthCommand: "npx ts-node ./main.ts", + ...inNewWorkingDirectory(), + onUpdate: (event) => { + events.push(event); + if (event.type === "waiting for approval") { + event.approve(); + } + }, + }); + + await cdktfProject.deploy({ + stackNames: ["first"], + autoApprove: true, + parallelism: 1, + terraformParallelism: 1, + }); + + const execCalls = (exec as jest.Mock).mock.calls; + const planCall = execCalls.find((call) => call[1][0] === "plan"); + const applyCall = execCalls.find((call) => call[1][0] === "apply"); + expect(planCall[1]).toContain("-parallelism=1"); + expect(applyCall[1]).toContain("-parallelism=1"); + }); + + it("ignores the terraform parallelism flag if negative", async () => { + const events: any[] = []; + const cdktfProject = new CdktfProject({ + synthCommand: "npx ts-node ./main.ts", + ...inNewWorkingDirectory(), + onUpdate: (event) => { + events.push(event); + if (event.type === "waiting for approval") { + event.approve(); + } + }, + }); + + await cdktfProject.deploy({ + stackNames: ["first"], + autoApprove: true, + parallelism: 1, + terraformParallelism: -1, + }); + + const execCalls = (exec as jest.Mock).mock.calls; + const planCall = execCalls.find((call) => call[1][0] === "plan"); + const applyCall = execCalls.find((call) => call[1][0] === "apply"); + expect(planCall[1]).not.toContain("-parallelism=-1"); + expect(applyCall[1]).not.toContain("-parallelism=1"); + }); }); describe("destroy", () => { @@ -268,6 +341,50 @@ describe("CdktfProject", () => { ]); return expect(eventTypes.includes("waiting for approval")).toBeFalsy(); }); + + it("passes the terraform parallelism flag to terraform", async () => { + const events: any[] = []; + const cdktfProject = new CdktfProject({ + synthCommand: "npx ts-node ./main.ts", + ...inNewWorkingDirectory(), + onUpdate: (event) => { + events.push(event); + }, + }); + + await cdktfProject.destroy({ + stackNames: ["second"], + autoApprove: true, + parallelism: 1, + terraformParallelism: 1, + }); + + const execCalls = (exec as jest.Mock).mock.calls; + const destroyCall = execCalls.find((call) => call[1][0] === "destroy"); + expect(destroyCall[1]).toContain("-parallelism=1"); + }); + + it("doesn't pass the terraform parallelism flag if negative", async () => { + const events: any[] = []; + const cdktfProject = new CdktfProject({ + synthCommand: "npx ts-node ./main.ts", + ...inNewWorkingDirectory(), + onUpdate: (event) => { + events.push(event); + }, + }); + + await cdktfProject.destroy({ + stackNames: ["second"], + autoApprove: true, + parallelism: 1, + terraformParallelism: -1, + }); + + const execCalls = (exec as jest.Mock).mock.calls; + const destroyCall = execCalls.find((call) => call[1][0] === "destroy"); + expect(destroyCall[1]).not.toContain("-parallelism=-1"); + }); }); describe("multi-stack", () => { From fb1f385aa8dd76f8e82d67c30615f1deaf883b0e Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Tue, 13 Sep 2022 12:17:07 +0200 Subject: [PATCH 04/18] Accept and forward terraformParallelism flag from CLI --- packages/cdktf-cli/bin/cmds/deploy.ts | 6 ++++++ packages/cdktf-cli/bin/cmds/destroy.ts | 6 ++++++ packages/cdktf-cli/bin/cmds/handlers.ts | 2 ++ packages/cdktf-cli/bin/cmds/ui/deploy.tsx | 3 +++ packages/cdktf-cli/bin/cmds/ui/destroy.tsx | 3 +++ 5 files changed, 20 insertions(+) diff --git a/packages/cdktf-cli/bin/cmds/deploy.ts b/packages/cdktf-cli/bin/cmds/deploy.ts index 73aec43d08..2ee13d869b 100644 --- a/packages/cdktf-cli/bin/cmds/deploy.ts +++ b/packages/cdktf-cli/bin/cmds/deploy.ts @@ -67,6 +67,12 @@ class Command extends BaseCommand { boolean: true, desc: 'Select the "refresh only" planning mode, which checks whether remote objects still match the outcome of the most recent Terraform apply but does not propose any actions to undo any changes made outside of Terraform.', }) + .option("terraform-parallelism", { + type: "number", + required: false, + desc: "Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform.", + default: -1, + }) .showHelpOnFail(true); public async handleCommand(argv: any) { diff --git a/packages/cdktf-cli/bin/cmds/destroy.ts b/packages/cdktf-cli/bin/cmds/destroy.ts index e88b03cf15..803f2c3206 100644 --- a/packages/cdktf-cli/bin/cmds/destroy.ts +++ b/packages/cdktf-cli/bin/cmds/destroy.ts @@ -48,6 +48,12 @@ class Command extends BaseCommand { desc: "Number of concurrent CDKTF stacks to run. Defaults to infinity, denoted by -1", default: -1, }) + .option("terraform-parallelism", { + type: "number", + required: false, + desc: "Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform.", + default: -1, + }) .showHelpOnFail(true); public async handleCommand(argv: any) { diff --git a/packages/cdktf-cli/bin/cmds/handlers.ts b/packages/cdktf-cli/bin/cmds/handlers.ts index 6e15134056..c08620a1d8 100644 --- a/packages/cdktf-cli/bin/cmds/handlers.ts +++ b/packages/cdktf-cli/bin/cmds/handlers.ts @@ -114,6 +114,7 @@ export async function deploy(argv: any) { const stacks = argv.stacks; const includeSensitiveOutputs = argv.outputsFileIncludeSensitiveOutputs; const refreshOnly = argv.refreshOnly; + const terraformParallelism = argv.terraformParallelism; let outputsPath: string | undefined = undefined; // eslint-disable-next-line @typescript-eslint/no-empty-function @@ -137,6 +138,7 @@ export async function deploy(argv: any) { argv.ignoreMissingStackDependencies || false, parallelism: argv.parallelism, refreshOnly, + terraformParallelism, }) ); } diff --git a/packages/cdktf-cli/bin/cmds/ui/deploy.tsx b/packages/cdktf-cli/bin/cmds/ui/deploy.tsx index b0eb4ba0c2..b1f9bdb610 100644 --- a/packages/cdktf-cli/bin/cmds/ui/deploy.tsx +++ b/packages/cdktf-cli/bin/cmds/ui/deploy.tsx @@ -56,6 +56,7 @@ interface DeployConfig { ignoreMissingStackDependencies?: boolean; parallelism?: number; refreshOnly?: boolean; + terraformParallelism?: number; } export const Deploy = ({ @@ -68,6 +69,7 @@ export const Deploy = ({ ignoreMissingStackDependencies, parallelism, refreshOnly, + terraformParallelism, }: DeployConfig): React.ReactElement => { const [outputs, setOutputs] = useState(); const { status, logEntries } = useCdktfProject( @@ -79,6 +81,7 @@ export const Deploy = ({ ignoreMissingStackDependencies, parallelism, refreshOnly, + terraformParallelism, }); if (onOutputsRetrieved) { diff --git a/packages/cdktf-cli/bin/cmds/ui/destroy.tsx b/packages/cdktf-cli/bin/cmds/ui/destroy.tsx index fc191e210c..2d31767c54 100644 --- a/packages/cdktf-cli/bin/cmds/ui/destroy.tsx +++ b/packages/cdktf-cli/bin/cmds/ui/destroy.tsx @@ -15,6 +15,7 @@ interface DestroyConfig { autoApprove: boolean; ignoreMissingStackDependencies?: boolean; parallelism?: number; + terraformParallelism?: number; } export const Destroy = ({ @@ -24,6 +25,7 @@ export const Destroy = ({ autoApprove, ignoreMissingStackDependencies, parallelism, + terraformParallelism, }: DestroyConfig): React.ReactElement => { const { status, logEntries } = useCdktfProject( { outDir, synthCommand }, @@ -33,6 +35,7 @@ export const Destroy = ({ autoApprove, ignoreMissingStackDependencies, parallelism, + terraformParallelism, }) ); From 413c7860420375724475f61139eb1be9c27bc3e2 Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Wed, 14 Sep 2022 10:49:55 +0200 Subject: [PATCH 05/18] Update help text --- packages/cdktf-cli/bin/cmds/deploy.ts | 5 ++++- packages/cdktf-cli/bin/cmds/destroy.ts | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/cdktf-cli/bin/cmds/deploy.ts b/packages/cdktf-cli/bin/cmds/deploy.ts index 2ee13d869b..d50b849c17 100644 --- a/packages/cdktf-cli/bin/cmds/deploy.ts +++ b/packages/cdktf-cli/bin/cmds/deploy.ts @@ -56,6 +56,8 @@ class Command extends BaseCommand { default: false, }) .option("parallelism", { + // Note: This parallelism doesn't affect the underlying Terraform traversal parallelism + // That is done by `terraform-parallelism` type: "number", required: false, desc: "Number of concurrent CDKTF stacks to run. Defaults to infinity, denoted by -1", @@ -70,7 +72,8 @@ class Command extends BaseCommand { .option("terraform-parallelism", { type: "number", required: false, - desc: "Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform.", + desc: "Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend", + // Setting value to negative will prevent it from being forwarded to terraform as an argument default: -1, }) .showHelpOnFail(true); diff --git a/packages/cdktf-cli/bin/cmds/destroy.ts b/packages/cdktf-cli/bin/cmds/destroy.ts index 803f2c3206..8d132d1568 100644 --- a/packages/cdktf-cli/bin/cmds/destroy.ts +++ b/packages/cdktf-cli/bin/cmds/destroy.ts @@ -51,7 +51,8 @@ class Command extends BaseCommand { .option("terraform-parallelism", { type: "number", required: false, - desc: "Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform.", + desc: "Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend", + // Setting value to negative will prevent it from being forwarded to terraform as an argument default: -1, }) .showHelpOnFail(true); From 90fead7fcd14c306c50ea3585b170e4507a6f0ed Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Wed, 14 Sep 2022 10:58:58 +0200 Subject: [PATCH 06/18] Minor readability cleanups --- packages/cdktf-cli/bin/cmds/handlers.ts | 16 ++++--- packages/cdktf-cli/lib/cdktf-project.ts | 55 +++++++++++-------------- 2 files changed, 34 insertions(+), 37 deletions(-) diff --git a/packages/cdktf-cli/bin/cmds/handlers.ts b/packages/cdktf-cli/bin/cmds/handlers.ts index c08620a1d8..76a0ee19d8 100644 --- a/packages/cdktf-cli/bin/cmds/handlers.ts +++ b/packages/cdktf-cli/bin/cmds/handlers.ts @@ -115,6 +115,9 @@ export async function deploy(argv: any) { const includeSensitiveOutputs = argv.outputsFileIncludeSensitiveOutputs; const refreshOnly = argv.refreshOnly; const terraformParallelism = argv.terraformParallelism; + const ignoreMissingStackDependencies = + argv.ignoreMissingStackDependencies || false; + const parallelism = argv.parallelism; let outputsPath: string | undefined = undefined; // eslint-disable-next-line @typescript-eslint/no-empty-function @@ -134,9 +137,8 @@ export async function deploy(argv: any) { autoApprove, onOutputsRetrieved, outputsPath, - ignoreMissingStackDependencies: - argv.ignoreMissingStackDependencies || false, - parallelism: argv.parallelism, + ignoreMissingStackDependencies, + parallelism, refreshOnly, terraformParallelism, }) @@ -152,6 +154,9 @@ export async function destroy(argv: any) { const outDir = argv.output; const autoApprove = argv.autoApprove; const stacks = argv.stacks; + const ignoreMissingStackDependencies = + argv.ignoreMissingStackDependencies || false; + const parallelism = argv.parallelism; await renderInk( React.createElement(Destroy, { @@ -159,9 +164,8 @@ export async function destroy(argv: any) { targetStacks: stacks, synthCommand: command, autoApprove, - ignoreMissingStackDependencies: - argv.ignoreMissingStackDependencies || false, - parallelism: argv.parallelism, + ignoreMissingStackDependencies, + parallelism, }) ); } diff --git a/packages/cdktf-cli/lib/cdktf-project.ts b/packages/cdktf-cli/lib/cdktf-project.ts index 94229228b2..4b000439d7 100644 --- a/packages/cdktf-cli/lib/cdktf-project.ts +++ b/packages/cdktf-cli/lib/cdktf-project.ts @@ -534,38 +534,31 @@ export class CdktfProject { const runningStacks = this.stacksToRun.filter((stack) => stack.isRunning); if (runningStacks.length >= maxParallelRuns) { await Promise.race(runningStacks.map((s) => s.currentWorkPromise)); - } else { - try { - const nextRunningExecutor = await next(); - if (!nextRunningExecutor) { - // In this case we have no pending stacks, but we also can not find a new executor - break; - } - method === "deploy" - ? nextRunningExecutor.deploy(refreshOnly, terraformParallelism) - : nextRunningExecutor.destroy(terraformParallelism); - } catch (e) { - // await next() threw an error because a stack failed to apply/destroy - // wait for all other currently running stacks to complete before propagating that error - logger.debug( - "Encountered an error while awaiting stack to finish", - e - ); - const openStacks = this.stacksToRun.filter( - (ex) => ex.currentWorkPromise - ); - logger.debug( - "Waiting for still running stacks to finish:", - openStacks - ); - await Promise.allSettled( - openStacks.map((ex) => ex.currentWorkPromise) - ); - logger.debug( - "Done waiting for still running stacks. All pending work finished" - ); - throw e; + continue; + } + + try { + const nextRunningExecutor = await next(); + if (!nextRunningExecutor) { + // In this case we have no pending stacks, but we also can not find a new executor + break; } + method === "deploy" + ? nextRunningExecutor.deploy(refreshOnly, terraformParallelism) + : nextRunningExecutor.destroy(terraformParallelism); + } catch (e) { + // await next() threw an error because a stack failed to apply/destroy + // wait for all other currently running stacks to complete before propagating that error + logger.debug("Encountered an error while awaiting stack to finish", e); + const openStacks = this.stacksToRun.filter( + (ex) => ex.currentWorkPromise + ); + logger.debug("Waiting for still running stacks to finish:", openStacks); + await Promise.allSettled(openStacks.map((ex) => ex.currentWorkPromise)); + logger.debug( + "Done waiting for still running stacks. All pending work finished" + ); + throw e; } } From 742bf0ee4bbbf0841ffbaba08e5de22a232ffa84 Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Wed, 14 Sep 2022 11:48:00 +0200 Subject: [PATCH 07/18] Massaging the types a bit more to be explicit --- packages/cdktf-cli/lib/cdktf-project.ts | 59 +++++++++++-------------- 1 file changed, 26 insertions(+), 33 deletions(-) diff --git a/packages/cdktf-cli/lib/cdktf-project.ts b/packages/cdktf-cli/lib/cdktf-project.ts index 4b000439d7..fd0bde9639 100644 --- a/packages/cdktf-cli/lib/cdktf-project.ts +++ b/packages/cdktf-cli/lib/cdktf-project.ts @@ -279,18 +279,22 @@ export type MultipleStackOptions = { stackNames?: string[]; }; -export type ExecutionOptions = MultipleStackOptions & { +export type AutoApproveOptions = { autoApprove?: boolean; - ignoreMissingStackDependencies?: boolean; - parallelism?: number; - refreshOnly?: boolean; - terraformParallelism?: number; }; export type DiffOptions = SingleStackOptions & { refreshOnly?: boolean; }; +export type MutationOptions = MultipleStackOptions & + AutoApproveOptions & { + refreshOnly?: boolean; + ignoreMissingStackDependencies?: boolean; + parallelism?: number; + terraformParallelism?: number; + }; + type LogMessage = { stackName: string; messageWithConstructPath?: string; @@ -453,7 +457,7 @@ export class CdktfProject { public getStackExecutor( stack: SynthesizedStack, - opts: ExecutionOptions = {} + opts: AutoApproveOptions = {} ) { const enhanceLogMessage = createEnhanceLogMessage(stack); const onLog = this.bufferWhileWaitingForApproval(this.onLog); @@ -520,16 +524,15 @@ export class CdktfProject { private async execute( method: "deploy" | "destroy", next: () => Promise, - parallelism: number, - refreshOnly?: boolean, - terraformParallelism?: number + opts: MutationOptions ) { // We only support refresh only on deploy, a bit of a leaky abstraction here - if (refreshOnly && method !== "deploy") { + if (opts.refreshOnly && method !== "deploy") { throw Errors.Internal(`Refresh only is only supported on deploy`); } - const maxParallelRuns = parallelism === -1 ? Infinity : parallelism; + const maxParallelRuns = + !opts.parallelism || opts.parallelism < 0 ? Infinity : opts.parallelism; while (this.stacksToRun.filter((stack) => stack.isPending).length > 0) { const runningStacks = this.stacksToRun.filter((stack) => stack.isRunning); if (runningStacks.length >= maxParallelRuns) { @@ -544,8 +547,11 @@ export class CdktfProject { break; } method === "deploy" - ? nextRunningExecutor.deploy(refreshOnly, terraformParallelism) - : nextRunningExecutor.destroy(terraformParallelism); + ? nextRunningExecutor.deploy( + opts.refreshOnly, + opts.terraformParallelism + ) + : nextRunningExecutor.destroy(opts.terraformParallelism); } catch (e) { // await next() threw an error because a stack failed to apply/destroy // wait for all other currently running stacks to complete before propagating that error @@ -571,8 +577,7 @@ export class CdktfProject { await ensureAllSettledBeforeThrowing(Promise.all(currentWork), currentWork); } - public async deploy(opts: ExecutionOptions = {}) { - const parallelism = opts.parallelism || -1; + public async deploy(opts: MutationOptions = {}) { const stacks = await this.synth(); const stacksToRun = getMultipleStacks(stacks, opts.stackNames, "deploy"); if (!opts.ignoreMissingStackDependencies) { @@ -596,13 +601,7 @@ export class CdktfProject { ) : () => getStackWithNoUnmetDependencies(this.stacksToRun); - await this.execute( - "deploy", - next, - parallelism, - opts.refreshOnly, - opts.terraformParallelism - ); + await this.execute("deploy", next, opts); const unprocessedStacks = this.stacksToRun.filter( (executor) => executor.isPending @@ -616,9 +615,7 @@ export class CdktfProject { } } - public async destroy(opts: ExecutionOptions = {}) { - const parallelism = opts.parallelism || -1; - const terraformParallelism = opts.terraformParallelism || -1; + public async destroy(opts: MutationOptions = {}) { const stacks = await this.synth(); const stacksToRun = getMultipleStacks(stacks, opts.stackNames, "destroy"); @@ -661,13 +658,7 @@ export class CdktfProject { ) : () => getStackWithNoUnmetDependants(this.stacksToRun); - await this.execute( - "destroy", - next, - parallelism, - false, - terraformParallelism - ); + await this.execute("destroy", next, opts); const unprocessedStacks = this.stacksToRun.filter( (executor) => executor.isPending @@ -695,7 +686,9 @@ export class CdktfProject { } this.stacksToRun = stacksToRun.map((stack) => - this.getStackExecutor(stack, opts) + // Options are empty, because MultipleStackOptions doesn't have any relevant + // options for `getStackExecutor`, hence defaults are fine + this.getStackExecutor(stack, {}) ); const outputs = await Promise.all( From 51fb350ce5ac8357fff978ad58d6d90bdbdc6d4a Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Wed, 14 Sep 2022 11:59:00 +0200 Subject: [PATCH 08/18] Add warnings to terraform-cloud backend --- packages/cdktf-cli/lib/models/terraform-cloud.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/cdktf-cli/lib/models/terraform-cloud.ts b/packages/cdktf-cli/lib/models/terraform-cloud.ts index 6fc77a5cb5..69f6bbd9a0 100644 --- a/packages/cdktf-cli/lib/models/terraform-cloud.ts +++ b/packages/cdktf-cli/lib/models/terraform-cloud.ts @@ -234,6 +234,7 @@ export class TerraformCloud implements Terraform { public async plan( destroy = false, refreshOnly = false, + // Parallelism is ignored as custom parallelism is not supported by TFC yet _parallelism = -1 ): Promise { if (!this.configurationVersionId) @@ -353,6 +354,7 @@ export class TerraformCloud implements Terraform { public async deploy( _planFile: string, _refreshOnly?: boolean, + // Parallelism is ignored as custom parallelism is not supported by TFC yet _parallelism?: number ): Promise { const sendLog = this.createTerraformLogHandler("deploy"); @@ -456,7 +458,7 @@ export class TerraformCloud implements Terraform { this.organizationName, this.workspaceName ); - } catch (e) { + } catch (e: any) { if (e.response?.status === 404) { // return a more descriptive error message as http response is not descriptive enough // will not be touched by BeautifyErrors decorator From 25f066478e17b1fe8174cd4b0501d62bc3e93c49 Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Wed, 14 Sep 2022 13:17:29 +0200 Subject: [PATCH 09/18] Fix usage of ExecutionOptions in watch --- packages/cdktf-cli/lib/watch.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/cdktf-cli/lib/watch.ts b/packages/cdktf-cli/lib/watch.ts index 3b7cc6b6ee..3e2391be70 100644 --- a/packages/cdktf-cli/lib/watch.ts +++ b/packages/cdktf-cli/lib/watch.ts @@ -4,7 +4,7 @@ import path from "path"; import { CdktfProject, CdktfProjectOptions, - ExecutionOptions, + MutationOptions, } from "./cdktf-project"; import { Errors } from "./errors"; import * as fs from "fs"; @@ -93,7 +93,7 @@ export type State = export async function watch( projectOptions: CdktfProjectOptions, - executionOptions: ExecutionOptions, + mutationOptions: MutationOptions, abortSignal: AbortSignal, onStateChange: (newState: State) => void ) { @@ -122,7 +122,7 @@ export async function watch( }); const abort = () => project.hardAbort(); abortSignal.addEventListener("abort", abort); - await project.deploy(executionOptions); + await project.deploy(mutationOptions); abortSignal.removeEventListener("abort", abort); logger.debug("cdktf deploy finished"); From fa2d9241fc058921dad5caeab50e250487a394a9 Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Wed, 14 Sep 2022 13:23:35 +0200 Subject: [PATCH 10/18] Check for non-negative value for parallelism --- packages/cdktf-cli/lib/models/terraform-cli.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cdktf-cli/lib/models/terraform-cli.ts b/packages/cdktf-cli/lib/models/terraform-cli.ts index 235adb0680..40c7cd8c71 100644 --- a/packages/cdktf-cli/lib/models/terraform-cli.ts +++ b/packages/cdktf-cli/lib/models/terraform-cli.ts @@ -70,7 +70,7 @@ export class TerraformCli implements Terraform { if (refreshOnly) { options.push("-refresh-only"); } - if (parallelism !== -1) { + if (parallelism > -1) { options.push(`-parallelism=${parallelism}`); } await this.setUserAgent(); From 9e45d0d66400164cfa2d1e59d3e96b096d8ea8bc Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Fri, 16 Sep 2022 15:32:21 +0200 Subject: [PATCH 11/18] Add terraform parallelism flag to missing commands --- packages/cdktf-cli/bin/cmds/diff.ts | 7 +++++++ packages/cdktf-cli/bin/cmds/handlers.ts | 4 ++++ packages/cdktf-cli/bin/cmds/ui/diff.tsx | 9 ++++++++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/cdktf-cli/bin/cmds/diff.ts b/packages/cdktf-cli/bin/cmds/diff.ts index 4c81b7c325..cd58f08cb0 100644 --- a/packages/cdktf-cli/bin/cmds/diff.ts +++ b/packages/cdktf-cli/bin/cmds/diff.ts @@ -38,6 +38,13 @@ class Command extends BaseCommand { boolean: true, desc: 'Select the "refresh only" planning mode, which checks whether remote objects still match the outcome of the most recent Terraform apply but does not propose any actions to undo any changes made outside of Terraform.', }) + .option("terraform-parallelism", { + type: "number", + required: false, + desc: "Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend", + // Setting value to negative will prevent it from being forwarded to terraform as an argument + default: -1, + }) .showHelpOnFail(true); public async handleCommand(argv: any) { diff --git a/packages/cdktf-cli/bin/cmds/handlers.ts b/packages/cdktf-cli/bin/cmds/handlers.ts index 76a0ee19d8..2a89998a2e 100644 --- a/packages/cdktf-cli/bin/cmds/handlers.ts +++ b/packages/cdktf-cli/bin/cmds/handlers.ts @@ -157,6 +157,7 @@ export async function destroy(argv: any) { const ignoreMissingStackDependencies = argv.ignoreMissingStackDependencies || false; const parallelism = argv.parallelism; + const terraformParallelism = argv.terraformParallelism; await renderInk( React.createElement(Destroy, { @@ -166,6 +167,7 @@ export async function destroy(argv: any) { autoApprove, ignoreMissingStackDependencies, parallelism, + terraformParallelism, }) ); } @@ -179,6 +181,7 @@ export async function diff(argv: any) { const outDir = argv.output; const stack = argv.stack; const refreshOnly = argv.refreshOnly; + const terraformParallelism = argv.terraformParallelism; await renderInk( React.createElement(Diff, { @@ -186,6 +189,7 @@ export async function diff(argv: any) { refreshOnly, targetStack: stack, synthCommand: command, + terraformParallelism, }) ); } diff --git a/packages/cdktf-cli/bin/cmds/ui/diff.tsx b/packages/cdktf-cli/bin/cmds/ui/diff.tsx index f8e855e933..b01b388e64 100644 --- a/packages/cdktf-cli/bin/cmds/ui/diff.tsx +++ b/packages/cdktf-cli/bin/cmds/ui/diff.tsx @@ -8,6 +8,7 @@ interface DiffConfig { targetStack?: string; synthCommand: string; refreshOnly?: boolean; + terraformParallelism?: number; } export const Diff = ({ @@ -15,10 +16,16 @@ export const Diff = ({ targetStack, synthCommand, refreshOnly, + terraformParallelism, }: DiffConfig): React.ReactElement => { const { status, logEntries } = useCdktfProject( { outDir, synthCommand }, - (project) => project.diff({ stackName: targetStack, refreshOnly }) + (project) => + project.diff({ + stackName: targetStack, + refreshOnly, + terraformParallelism, + }) ); return ( From e878475bb78ad689fdf55c90cb01e24d45e26651 Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Fri, 16 Sep 2022 15:33:12 +0200 Subject: [PATCH 12/18] Make the function signatures more consistent --- packages/cdktf-cli/lib/cdktf-project.ts | 3 ++- packages/cdktf-cli/lib/cdktf-stack.ts | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/cdktf-cli/lib/cdktf-project.ts b/packages/cdktf-cli/lib/cdktf-project.ts index fd0bde9639..31faf64b09 100644 --- a/packages/cdktf-cli/lib/cdktf-project.ts +++ b/packages/cdktf-cli/lib/cdktf-project.ts @@ -285,6 +285,7 @@ export type AutoApproveOptions = { export type DiffOptions = SingleStackOptions & { refreshOnly?: boolean; + terraformParallelism?: number; }; export type MutationOptions = MultipleStackOptions & @@ -513,7 +514,7 @@ export class CdktfProject { const stack = this.getStackExecutor( getSingleStack(stacks, opts?.stackName, "diff") ); - await stack.diff({ refreshOnly: opts?.refreshOnly }); + await stack.diff(opts?.refreshOnly, opts?.terraformParallelism); if (!stack.currentPlan) throw Errors.External( `Stack failed to plan: ${stack.stack.name}. Please check the logs for more information.` diff --git a/packages/cdktf-cli/lib/cdktf-stack.ts b/packages/cdktf-cli/lib/cdktf-stack.ts index 28c3e7e45d..345e4c9624 100644 --- a/packages/cdktf-cli/lib/cdktf-stack.ts +++ b/packages/cdktf-cli/lib/cdktf-stack.ts @@ -258,12 +258,16 @@ export class CdktfStack { this.currentWorkPromise = undefined; } - public async diff({ refreshOnly }: { refreshOnly?: boolean }) { + public async diff(refreshOnly?: boolean, terraformParallelism?: number) { await this.run(async () => { this.updateState({ type: "planning", stackName: this.stack.name }); const terraform = await this.initalizeTerraform({ isSpeculative: true }); - const plan = await terraform.plan(false, refreshOnly); + const plan = await terraform.plan( + false, + refreshOnly, + terraformParallelism + ); this.currentPlan = plan; this.updateState({ type: "planned", stackName: this.stack.name, plan }); }); @@ -314,7 +318,7 @@ export class CdktfStack { }); } - public async destroy(terraformParallelism = -1) { + public async destroy(terraformParallelism?: number) { await this.run(async () => { this.updateState({ type: "planning", stackName: this.stack.name }); const terraform = await this.initalizeTerraform({ isSpeculative: false }); From efea5b396ba0fceec5d8e4331d746c0b13d496da Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Fri, 16 Sep 2022 15:33:39 +0200 Subject: [PATCH 13/18] Typescript doesn't like it when errors are typed --- packages/cdktf-cli/lib/models/terraform-cloud.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cdktf-cli/lib/models/terraform-cloud.ts b/packages/cdktf-cli/lib/models/terraform-cloud.ts index 69f6bbd9a0..23b84b8133 100644 --- a/packages/cdktf-cli/lib/models/terraform-cloud.ts +++ b/packages/cdktf-cli/lib/models/terraform-cloud.ts @@ -458,7 +458,7 @@ export class TerraformCloud implements Terraform { this.organizationName, this.workspaceName ); - } catch (e: any) { + } catch (e) { if (e.response?.status === 404) { // return a more descriptive error message as http response is not descriptive enough // will not be touched by BeautifyErrors decorator From a3fc315098ad5a54b4a201d874f2ece00b19ae9f Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Fri, 16 Sep 2022 15:34:13 +0200 Subject: [PATCH 14/18] Refactor out the terraform parallelism tests, and make them a tiny bit faster by mocking --- .../cdktf-cli/test/lib/cdktf-project.test.ts | 117 -------- .../test/lib/terraform-parallelism.test.ts | 256 ++++++++++++++++++ 2 files changed, 256 insertions(+), 117 deletions(-) create mode 100644 packages/cdktf-cli/test/lib/terraform-parallelism.test.ts diff --git a/packages/cdktf-cli/test/lib/cdktf-project.test.ts b/packages/cdktf-cli/test/lib/cdktf-project.test.ts index 70cef31ed1..fff563869b 100644 --- a/packages/cdktf-cli/test/lib/cdktf-project.test.ts +++ b/packages/cdktf-cli/test/lib/cdktf-project.test.ts @@ -6,7 +6,6 @@ import * as os from "os"; import { CdktfProject, get, init, Language } from "../../lib/index"; import { SynthesizedStack } from "../../lib/synth-stack"; import { getMultipleStacks } from "../../lib/cdktf-project"; -import { exec } from "cdktf-cli/lib/util"; function eventNames(events: any[]) { return events @@ -14,16 +13,6 @@ function eventNames(events: any[]) { .filter((name) => !name.includes("update")); } -jest.mock("cdktf-cli/lib/util", () => { - const originalModule = jest.requireActual("cdktf-cli/lib/util"); - - return { - __esmodule: true, - ...originalModule, - exec: jest.fn().mockImplementation(originalModule.exec), - }; -}); - function installFixturesInWorkingDirectory( { outDir, @@ -99,14 +88,6 @@ describe("CdktfProject", () => { }; }); - beforeEach(() => { - (exec as jest.Mock).mockClear(); - }); - - afterAll(() => { - jest.resetModules(); - }); - it("should be able to create a CdktfProject", () => { const cdktfProject = new CdktfProject({ synthCommand: "npx ts-node main.ts", @@ -230,60 +211,6 @@ describe("CdktfProject", () => { ]); return expect(eventTypes.includes("waiting for approval")).toBeFalsy(); }); - - it("runs without terraform parallelism", async () => { - const events: any[] = []; - const cdktfProject = new CdktfProject({ - synthCommand: "npx ts-node ./main.ts", - ...inNewWorkingDirectory(), - onUpdate: (event) => { - events.push(event); - if (event.type === "waiting for approval") { - event.approve(); - } - }, - }); - - await cdktfProject.deploy({ - stackNames: ["first"], - autoApprove: true, - parallelism: 1, - terraformParallelism: 1, - }); - - const execCalls = (exec as jest.Mock).mock.calls; - const planCall = execCalls.find((call) => call[1][0] === "plan"); - const applyCall = execCalls.find((call) => call[1][0] === "apply"); - expect(planCall[1]).toContain("-parallelism=1"); - expect(applyCall[1]).toContain("-parallelism=1"); - }); - - it("ignores the terraform parallelism flag if negative", async () => { - const events: any[] = []; - const cdktfProject = new CdktfProject({ - synthCommand: "npx ts-node ./main.ts", - ...inNewWorkingDirectory(), - onUpdate: (event) => { - events.push(event); - if (event.type === "waiting for approval") { - event.approve(); - } - }, - }); - - await cdktfProject.deploy({ - stackNames: ["first"], - autoApprove: true, - parallelism: 1, - terraformParallelism: -1, - }); - - const execCalls = (exec as jest.Mock).mock.calls; - const planCall = execCalls.find((call) => call[1][0] === "plan"); - const applyCall = execCalls.find((call) => call[1][0] === "apply"); - expect(planCall[1]).not.toContain("-parallelism=-1"); - expect(applyCall[1]).not.toContain("-parallelism=1"); - }); }); describe("destroy", () => { @@ -341,50 +268,6 @@ describe("CdktfProject", () => { ]); return expect(eventTypes.includes("waiting for approval")).toBeFalsy(); }); - - it("passes the terraform parallelism flag to terraform", async () => { - const events: any[] = []; - const cdktfProject = new CdktfProject({ - synthCommand: "npx ts-node ./main.ts", - ...inNewWorkingDirectory(), - onUpdate: (event) => { - events.push(event); - }, - }); - - await cdktfProject.destroy({ - stackNames: ["second"], - autoApprove: true, - parallelism: 1, - terraformParallelism: 1, - }); - - const execCalls = (exec as jest.Mock).mock.calls; - const destroyCall = execCalls.find((call) => call[1][0] === "destroy"); - expect(destroyCall[1]).toContain("-parallelism=1"); - }); - - it("doesn't pass the terraform parallelism flag if negative", async () => { - const events: any[] = []; - const cdktfProject = new CdktfProject({ - synthCommand: "npx ts-node ./main.ts", - ...inNewWorkingDirectory(), - onUpdate: (event) => { - events.push(event); - }, - }); - - await cdktfProject.destroy({ - stackNames: ["second"], - autoApprove: true, - parallelism: 1, - terraformParallelism: -1, - }); - - const execCalls = (exec as jest.Mock).mock.calls; - const destroyCall = execCalls.find((call) => call[1][0] === "destroy"); - expect(destroyCall[1]).not.toContain("-parallelism=-1"); - }); }); describe("multi-stack", () => { diff --git a/packages/cdktf-cli/test/lib/terraform-parallelism.test.ts b/packages/cdktf-cli/test/lib/terraform-parallelism.test.ts new file mode 100644 index 0000000000..1413e3e198 --- /dev/null +++ b/packages/cdktf-cli/test/lib/terraform-parallelism.test.ts @@ -0,0 +1,256 @@ +import path from "path"; +import * as fs from "fs-extra"; +import os from "os"; +import { CdktfProject, init, Language, get } from "../../lib/index"; +import { exec } from "cdktf-cli/lib/util"; + +jest.mock("cdktf-cli/lib/util", () => { + const originalModule = jest.requireActual("cdktf-cli/lib/util"); + + return { + __esmodule: true, + ...originalModule, + // exec: jest.fn().mockImplementation(originalModule.exec), + exec: jest.fn().mockImplementation(async (_binary, args) => { + // Fake "show" to ensure we perform apply + if (args[0] !== "show") { + return Promise.resolve(JSON.stringify({})); + } + return Promise.resolve( + JSON.stringify({ + resource_changes: [ + { + address: "null_resource.first_test_83862C81", + mode: "managed", + type: "null_resource", + name: "first_test_83862C81", + provider_name: "registry.terraform.io/hashicorp/null", + change: { + actions: ["create"], + before: null, + after: { triggers: null }, + after_unknown: { id: true }, + before_sensitive: false, + after_sensitive: {}, + }, + }, + ], + }) + ); + }), + }; +}); +let inNewWorkingDirectory: () => { + workingDirectory: string; + outDir: string; +}; + +jest.setTimeout(30000); +describe("terraform parallelism", () => { + beforeAll(async () => { + const workingDirectory = fs.mkdtempSync(path.join(os.tmpdir(), "cdktf.")); + await init({ + destination: workingDirectory, + templatePath: path.join(__dirname, "../../templates/typescript"), + projectId: "test", + projectInfo: { + Description: "cdktf-api-test", + Name: "cdktf-api-test", + }, + sendCrashReports: false, + dist: path.join(__dirname, "../../../../dist"), + }); + + fs.copyFileSync( + path.resolve(__dirname, "fixtures/default/main.ts.fixture"), + path.resolve(workingDirectory, "main.ts") + ); + fs.copyFileSync( + path.resolve(__dirname, "fixtures/default/cdktf.json"), + path.resolve(workingDirectory, "cdktf.json") + ); + + await get({ + constraints: [ + { + name: "null", + version: "3.1.0", + source: "null", + fqn: "hashicorp/null", + }, + ], + constructsOptions: { + codeMakerOutput: path.resolve(workingDirectory, ".gen"), + targetLanguage: Language.TYPESCRIPT, + }, + }); + + inNewWorkingDirectory = function inNewWorkingDirectory() { + const wd = fs.mkdtempSync(path.join(os.tmpdir(), "cdktf.")); + const outDir = path.resolve(wd, "out"); + + fs.copySync(workingDirectory, wd); + + return { + workingDirectory: wd, + outDir, + }; + }; + }); + beforeEach(() => { + (exec as jest.Mock).mockClear(); + }); + afterAll(() => { + jest.resetModules(); + }); + + describe("terraform parallelism flag in deploy", () => { + it("passes the terraform parallelism flag to terraform", async () => { + const events: any[] = []; + const cdktfProject = new CdktfProject({ + synthCommand: "npx ts-node main.ts", + ...inNewWorkingDirectory(), + onUpdate: (event) => { + events.push(event); + if (event.type === "waiting for approval") { + event.approve(); + } + }, + }); + + await cdktfProject.deploy({ + stackNames: ["first"], + autoApprove: true, + parallelism: 1, + terraformParallelism: 1, + }); + + const execCalls = (exec as jest.Mock).mock.calls; + const planCall = execCalls.find((call) => call[1][0] === "plan"); + const applyCall = execCalls.find((call) => call[1][0] === "apply"); + expect(planCall[1]).toContain("-parallelism=1"); + expect(applyCall[1]).toContain("-parallelism=1"); + }); + + it("ignores the terraform parallelism flag if negative", async () => { + const events: any[] = []; + const cdktfProject = new CdktfProject({ + synthCommand: "npx ts-node ./main.ts", + ...inNewWorkingDirectory(), + onUpdate: (event) => { + events.push(event); + if (event.type === "waiting for approval") { + event.approve(); + } + }, + }); + + await cdktfProject.deploy({ + stackNames: ["first"], + autoApprove: true, + parallelism: 1, + terraformParallelism: -1, + }); + + const execCalls = (exec as jest.Mock).mock.calls; + const planCall = execCalls.find((call) => call[1][0] === "plan"); + const applyCall = execCalls.find((call) => call[1][0] === "apply"); + expect(planCall[1]).not.toContain("-parallelism=-1"); + expect(applyCall[1]).not.toContain("-parallelism=1"); + }); + }); + + describe("terraform parallelism flag in destroy", () => { + it("passes the terraform parallelism flag to terraform", async () => { + const events: any[] = []; + const cdktfProject = new CdktfProject({ + synthCommand: "npx ts-node ./main.ts", + ...inNewWorkingDirectory(), + onUpdate: (event) => { + events.push(event); + }, + }); + + await cdktfProject.destroy({ + stackNames: ["second"], + autoApprove: true, + parallelism: 1, + terraformParallelism: 1, + }); + + const execCalls = (exec as jest.Mock).mock.calls; + const destroyCall = execCalls.find((call) => call[1][0] === "destroy"); + expect(destroyCall[1]).toContain("-parallelism=1"); + }); + + it("doesn't pass the terraform parallelism flag if negative", async () => { + const events: any[] = []; + const cdktfProject = new CdktfProject({ + synthCommand: "npx ts-node ./main.ts", + ...inNewWorkingDirectory(), + onUpdate: (event) => { + events.push(event); + }, + }); + + await cdktfProject.destroy({ + stackNames: ["second"], + autoApprove: true, + parallelism: 1, + terraformParallelism: -1, + }); + + const execCalls = (exec as jest.Mock).mock.calls; + const destroyCall = execCalls.find((call) => call[1][0] === "destroy"); + expect(destroyCall[1]).not.toContain("-parallelism=-1"); + }); + }); + + describe("terraform parallelism flag in diff", () => { + it("passes the terraform parallelism flag to terraform", async () => { + const events: any[] = []; + const cdktfProject = new CdktfProject({ + synthCommand: "npx ts-node main.ts", + ...inNewWorkingDirectory(), + onUpdate: (event) => { + events.push(event); + if (event.type === "waiting for approval") { + event.approve(); + } + }, + }); + + await cdktfProject.diff({ + stackName: "first", + terraformParallelism: 1, + }); + + const execCalls = (exec as jest.Mock).mock.calls; + const planCall = execCalls.find((call) => call[1][0] === "plan"); + expect(planCall[1]).toContain("-parallelism=1"); + }); + + it("ignores the terraform parallelism flag if negative", async () => { + const events: any[] = []; + const cdktfProject = new CdktfProject({ + synthCommand: "npx ts-node ./main.ts", + ...inNewWorkingDirectory(), + onUpdate: (event) => { + events.push(event); + if (event.type === "waiting for approval") { + event.approve(); + } + }, + }); + + await cdktfProject.diff({ + stackName: "first", + terraformParallelism: -1, + }); + + const execCalls = (exec as jest.Mock).mock.calls; + const planCall = execCalls.find((call) => call[1][0] === "plan"); + expect(planCall[1]).not.toContain("-parallelism=-1"); + }); + }); +}); From fd4e3874aae004cb15edb4a041295939838d8adc Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Fri, 16 Sep 2022 15:42:35 +0200 Subject: [PATCH 15/18] Add terraform-parallelism flag to watch --- packages/cdktf-cli/bin/cmds/handlers.ts | 4 ++++ packages/cdktf-cli/bin/cmds/ui/watch.tsx | 3 +++ packages/cdktf-cli/bin/cmds/watch.ts | 7 +++++++ 3 files changed, 14 insertions(+) diff --git a/packages/cdktf-cli/bin/cmds/handlers.ts b/packages/cdktf-cli/bin/cmds/handlers.ts index 2a89998a2e..680b16ab22 100644 --- a/packages/cdktf-cli/bin/cmds/handlers.ts +++ b/packages/cdktf-cli/bin/cmds/handlers.ts @@ -333,6 +333,8 @@ export async function watch(argv: any) { const outDir = argv.output; const autoApprove = argv.autoApprove; const stacks = argv.stacks; + const terraformParallelism = argv.terraformParallelism; + const parallelism = argv.parallelism; if (!autoApprove) { console.error( @@ -347,6 +349,8 @@ export async function watch(argv: any) { targetStacks: stacks, synthCommand: command, autoApprove, + terraformParallelism, + parallelism, }) ); } diff --git a/packages/cdktf-cli/bin/cmds/ui/watch.tsx b/packages/cdktf-cli/bin/cmds/ui/watch.tsx index 5464abe858..e0be0e6b22 100644 --- a/packages/cdktf-cli/bin/cmds/ui/watch.tsx +++ b/packages/cdktf-cli/bin/cmds/ui/watch.tsx @@ -10,6 +10,7 @@ interface WatchConfig { parallelism?: number; synthCommand: string; autoApprove: boolean; + terraformParallelism?: number; } export const Watch = ({ @@ -18,6 +19,7 @@ export const Watch = ({ synthCommand, autoApprove, parallelism, + terraformParallelism, }: WatchConfig): React.ReactElement => { const [logEntryId, setLogEntryId] = useState(0); const [logEntries, setLogEntries] = useState([]); @@ -57,6 +59,7 @@ export const Watch = ({ autoApprove, stackNames: targetStacks, parallelism, + terraformParallelism, }, ac.signal, (state) => { diff --git a/packages/cdktf-cli/bin/cmds/watch.ts b/packages/cdktf-cli/bin/cmds/watch.ts index a5e1b03509..da557839b6 100644 --- a/packages/cdktf-cli/bin/cmds/watch.ts +++ b/packages/cdktf-cli/bin/cmds/watch.ts @@ -43,6 +43,13 @@ class Command extends BaseCommand { desc: "Number of concurrent CDKTF stacks to run. Defaults to infinity, denoted by -1", default: -1, }) + .option("terraform-parallelism", { + type: "number", + required: false, + desc: "Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend", + // Setting value to negative will prevent it from being forwarded to terraform as an argument + default: -1, + }) .showHelpOnFail(true); public async handleCommand(argv: any) { From 1e9300ec62f0c67ad82f4918dda1dc85c410f439 Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Fri, 16 Sep 2022 15:59:54 +0200 Subject: [PATCH 16/18] Update commands help --- website/docs/cdktf/cli-reference/commands.mdx | 106 ++++++++++-------- 1 file changed, 61 insertions(+), 45 deletions(-) diff --git a/website/docs/cdktf/cli-reference/commands.mdx b/website/docs/cdktf/cli-reference/commands.mdx index 7f85054962..f4b0c37b4b 100644 --- a/website/docs/cdktf/cli-reference/commands.mdx +++ b/website/docs/cdktf/cli-reference/commands.mdx @@ -130,27 +130,30 @@ $ cdktf deploy --help **Help Output** ``` -cdktf deploy [OPTIONS] +cdktf deploy [stacks...] Deploy the given stacks Positionals: - stacks Deploy stacks matching the given ids. Required when more than one stack is present in the app [array] [required] [default: []] + stacks Deploy stacks matching the given ids. Required when more than one stack is present in the app [array] [default: []] Options: - --version Show version number [boolean] - --disable-plugin-cache-env Dont set TF_PLUGIN_CACHE_DIR automatically. This is useful when the plugin cache is configured differently. Supported using the env - CDKTF_DISABLE_PLUGIN_CACHE_ENV. [boolean] [default: false] - --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] - -a, --app Command to use in order to execute cdktf app [required] [default: "npx ts-node main.ts"] - -o, --output Output directory for the synthesized Terraform config [required] [default: "cdktf.out"] - --auto-approve Auto approve [boolean] [default: false] - --outputs-file Path to file where stack outputs will be written as JSON [string] - --outputs-file-include-sensitive-outputs Whether to include sensitive outputs in the output file [boolean] [default: false] - --ignore-missing-stack-dependencies Don't check if all stacks specified in the command have their dependencies included as well [boolean] [default: false] - --parallelism Number of concurrent CDKTF stacks to run. Defaults to infinity, denoted by -1 [number] [default: -1] - -h, --help Show help [boolean] -``` + --version Show version number [boolean] + --disable-plugin-cache-env Dont set TF_PLUGIN_CACHE_DIR automatically. This is useful when the plugin cache is configured differently. Supported using the env CDKTF_DISABLE_PLUGIN_CACHE_ENV. [boolean] [default: false] + --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] + -a, --app Command to use in order to execute cdktf app [required] + -o, --output Output directory for the synthesized Terraform config [required] [default: "cdktf.out"] + --auto-approve Auto approve [boolean] [default: false] + --outputs-file Path to file where stack outputs will be written as JSON [string] + --outputs-file-include-sensitive-outputs Whether to include sensitive outputs in the output file [boolean] [default: false] + --ignore-missing-stack-dependencies Don't check if all stacks specified in the command have their dependencies included as well [boolean] [default: false] + --parallelism Number of concurrent CDKTF stacks to run. Defaults to infinity, denoted by -1 [number] [default: -1] + --refresh-only Select the "refresh only" planning mode, which checks whether remote objects still match the outcome of the most recent Terraform apply but does not propose any actions to undo any changes made outside of Terraform. [boolean] [default: false] + --terraform-parallelism Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend [number] [default: -1] + -h, --help Show help [boolean] +``` + +~> **Note:** The `parallelism` flag has a different behavior than the [terraform parallelism flag](https://www.terraform.io/cli/commands/apply#parallelism-n). To set the custom terraform parallelism flag, please use the `--terraform-parallelism` flag instead. **Examples** @@ -199,26 +202,28 @@ $ cdktf destroy --help Help output: ``` -cdktf destroy [OPTIONS] +cdktf destroy [stacks..] Destroy the given stacks Positionals: - stacks Destroy stacks matching the given ids. Required when more than one stack is present in the app [array] [required] [default: []] + stacks Destroy stacks matching the given ids. Required when more than one stack is present in the app [array] [default: []] Options: - --version Show version number [boolean] - --disable-plugin-cache-env Dont set TF_PLUGIN_CACHE_DIR automatically. This is useful when the plugin cache is configured differently. Supported using the env CDKTF_DISABLE_PLUGIN_CACHE_ENV. - [boolean] [default: false] - --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] - -a, --app Command to use in order to execute cdktf app [required] [default: "npx ts-node main.ts"] - -o, --output Output directory for the synthesized Terraform config [required] [default: "cdktf.out"] - --auto-approve Auto approve [boolean] [default: false] - --ignore-missing-stack-dependencies Don't check if all stacks specified in the command have their dependencies included as well [boolean] [default: false] - --parallelism Number of concurrent CDKTF stacks to run. Defaults to infinity, denoted by -1 [number] [default: -1] - -h, --help Show help [boolean] + --version Show version number [boolean] + --disable-plugin-cache-env Dont set TF_PLUGIN_CACHE_DIR automatically. This is useful when the plugin cache is configured differently. Supported using the env CDKTF_DISABLE_PLUGIN_CACHE_ENV. [boolean] [default: false] + --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] + -a, --app Command to use in order to execute cdktf app [required] + -o, --output Output directory for the synthesized Terraform config [required] [default: "cdktf.out"] + --auto-approve Auto approve [boolean] [default: false] + --ignore-missing-stack-dependencies Don't check if all stacks specified in the command have their dependencies included as well [boolean] [default: false] + --parallelism Number of concurrent CDKTF stacks to run. Defaults to infinity, denoted by -1 [number] [default: -1] + --terraform-parallelism Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend [number] [default: -1] + -h, --help Show help [boolean] ``` +~> **Note:** The `parallelism` flag has a different behavior than the [terraform parallelism flag](https://www.terraform.io/cli/commands/apply#parallelism-n). To set the custom terraform parallelism flag, please use the `--terraform-parallelism` flag instead. + **Examples** Destroy an application. @@ -264,18 +269,27 @@ $ cdktf diff --help Help output: ``` -cdktf diff [OPTIONS] +cdktf diff [stack] Perform a diff (terraform plan) for the given stack +Positionals: + stack Diff stack which matches the given id only. Required when more than one stack is present in the app [string] + Options: - --version Show version number [boolean] - --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] - --app, -a Command to use in order to execute cdktf app [required] - --output, -o Output directory [required] [default: "cdktf.out"] - -h, --help Show help [boolean] + --version Show version number [boolean] + --disable-plugin-cache-env Dont set TF_PLUGIN_CACHE_DIR automatically. This is useful when the plugin cache is configured differently. Supported using the env CDKTF_DISABLE_PLUGIN_CACHE_ENV. [boolean] [default: false] + --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] + -a, --app Command to use in order to execute cdktf app [required] + -o, --output Output directory for the synthesized Terraform config [required] [default: "cdktf.out"] + --refresh-only Select the "refresh only" planning mode, which checks whether remote objects still match the outcome of the most recent Terraform apply but does not propose any actions to undo any changes made outside of Terraform. + [boolean] [default: false] + --terraform-parallelism Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend [number] [default: -1] + -h, --help Show help [boolean] ``` +~> **Note:** The `parallelism` flag has a different behavior than the [terraform parallelism flag](https://www.terraform.io/cli/commands/plan#parallelism-n). To set the custom terraform parallelism flag, please use the `--terraform-parallelism` flag instead. + Examples: Generate a diff for a given application. @@ -484,24 +498,26 @@ $ cdktf watch --help **Help Output** ``` -cdktf watch [OPTIONS] +cdktf watch [stacks..] [experimental] Watch for file changes and automatically trigger a deploy Positionals: - stacks Deploy stacks matching the given ids. Required when more than one stack is present in the app [array] [required] [default: []] + stacks Deploy stacks matching the given ids. Required when more than one stack is present in the app [array] [default: []] Options: - --version Show version number [boolean] - --disable-plugin-cache-env Dont set TF_PLUGIN_CACHE_DIR automatically. This is useful when the plugin cache is configured differently. Supported using the env CDKTF_DISABLE_PLUGIN_CACHE_ENV. - [boolean] [default: false] - --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] - -a, --app Command to use in order to execute cdktf app [required] [default: "npx ts-node main.ts"] - -o, --output Output directory for the synthesized Terraform config [required] [default: "cdktf.out"] - --auto-approve Auto approve [boolean] [default: false] - --parallelism Number of concurrent CDKTF stacks to run. Defaults to infinity, denoted by -1 [number] [default: -1] - -h, --help Show help [boolean] -``` + --version Show version number [boolean] + --disable-plugin-cache-env Dont set TF_PLUGIN_CACHE_DIR automatically. This is useful when the plugin cache is configured differently. Supported using the env CDKTF_DISABLE_PLUGIN_CACHE_ENV. [boolean] [default: false] + --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] + -a, --app Command to use in order to execute cdktf app [required] + -o, --output Output directory for the synthesized Terraform config [required] [default: "cdktf.out"] + --auto-approve Auto approve [boolean] [default: false] + --parallelism Number of concurrent CDKTF stacks to run. Defaults to infinity, denoted by -1 [number] [default: -1] + --terraform-parallelism Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend [number] [default: -1] + -h, --help Show help [boolean] +``` + +~> **Note:** The `parallelism` flag has a different behavior than the [terraform parallelism flag](https://www.terraform.io/cli/commands/apply#parallelism-n). To set the custom terraform parallelism flag, please use the `--terraform-parallelism` flag instead. **Examples** From ad4e9396bbce675702d46d3a0bb2d7b4147c1efd Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Wed, 12 Oct 2022 14:56:03 +0200 Subject: [PATCH 17/18] update cli output to not talk about graph traversals --- packages/cdktf-cli/bin/cmds/deploy.ts | 2 +- packages/cdktf-cli/bin/cmds/destroy.ts | 2 +- packages/cdktf-cli/bin/cmds/diff.ts | 2 +- packages/cdktf-cli/bin/cmds/watch.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/cdktf-cli/bin/cmds/deploy.ts b/packages/cdktf-cli/bin/cmds/deploy.ts index d50b849c17..a7ca072154 100644 --- a/packages/cdktf-cli/bin/cmds/deploy.ts +++ b/packages/cdktf-cli/bin/cmds/deploy.ts @@ -72,7 +72,7 @@ class Command extends BaseCommand { .option("terraform-parallelism", { type: "number", required: false, - desc: "Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend", + desc: "Forwards value as the `-parallelism` flag to Terraform. By default, the this flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend", // Setting value to negative will prevent it from being forwarded to terraform as an argument default: -1, }) diff --git a/packages/cdktf-cli/bin/cmds/destroy.ts b/packages/cdktf-cli/bin/cmds/destroy.ts index 8d132d1568..a705cf2e80 100644 --- a/packages/cdktf-cli/bin/cmds/destroy.ts +++ b/packages/cdktf-cli/bin/cmds/destroy.ts @@ -51,7 +51,7 @@ class Command extends BaseCommand { .option("terraform-parallelism", { type: "number", required: false, - desc: "Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend", + desc: "Forwards value as the `-parallelism` flag to Terraform. By default, the this flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend", // Setting value to negative will prevent it from being forwarded to terraform as an argument default: -1, }) diff --git a/packages/cdktf-cli/bin/cmds/diff.ts b/packages/cdktf-cli/bin/cmds/diff.ts index cd58f08cb0..96193f78d9 100644 --- a/packages/cdktf-cli/bin/cmds/diff.ts +++ b/packages/cdktf-cli/bin/cmds/diff.ts @@ -41,7 +41,7 @@ class Command extends BaseCommand { .option("terraform-parallelism", { type: "number", required: false, - desc: "Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend", + desc: "Forwards value as the `-parallelism` flag to Terraform. By default, the this flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend", // Setting value to negative will prevent it from being forwarded to terraform as an argument default: -1, }) diff --git a/packages/cdktf-cli/bin/cmds/watch.ts b/packages/cdktf-cli/bin/cmds/watch.ts index da557839b6..3ff5fe1333 100644 --- a/packages/cdktf-cli/bin/cmds/watch.ts +++ b/packages/cdktf-cli/bin/cmds/watch.ts @@ -46,7 +46,7 @@ class Command extends BaseCommand { .option("terraform-parallelism", { type: "number", required: false, - desc: "Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend", + desc: "Forwards value as the `-parallelism` flag to Terraform. By default, the this flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend", // Setting value to negative will prevent it from being forwarded to terraform as an argument default: -1, }) From cdf3a2e449441cc727974e568eed57018cea658c Mon Sep 17 00:00:00 2001 From: Mutahhir Hayat Date: Wed, 12 Oct 2022 15:02:38 +0200 Subject: [PATCH 18/18] Update flag documentation in commands --- website/docs/cdktf/cli-reference/commands.mdx | 87 +++++++++---------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/website/docs/cdktf/cli-reference/commands.mdx b/website/docs/cdktf/cli-reference/commands.mdx index f4b0c37b4b..eabe1cf45b 100644 --- a/website/docs/cdktf/cli-reference/commands.mdx +++ b/website/docs/cdktf/cli-reference/commands.mdx @@ -135,22 +135,22 @@ cdktf deploy [stacks...] Deploy the given stacks Positionals: - stacks Deploy stacks matching the given ids. Required when more than one stack is present in the app [array] [default: []] + stacks Deploy stacks matching the given ids. Required when more than one stack is present in the app [array] [default: []] Options: - --version Show version number [boolean] - --disable-plugin-cache-env Dont set TF_PLUGIN_CACHE_DIR automatically. This is useful when the plugin cache is configured differently. Supported using the env CDKTF_DISABLE_PLUGIN_CACHE_ENV. [boolean] [default: false] - --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] - -a, --app Command to use in order to execute cdktf app [required] - -o, --output Output directory for the synthesized Terraform config [required] [default: "cdktf.out"] - --auto-approve Auto approve [boolean] [default: false] - --outputs-file Path to file where stack outputs will be written as JSON [string] - --outputs-file-include-sensitive-outputs Whether to include sensitive outputs in the output file [boolean] [default: false] - --ignore-missing-stack-dependencies Don't check if all stacks specified in the command have their dependencies included as well [boolean] [default: false] - --parallelism Number of concurrent CDKTF stacks to run. Defaults to infinity, denoted by -1 [number] [default: -1] + --version Show version number [boolean] + --disable-plugin-cache-env Dont set TF_PLUGIN_CACHE_DIR automatically. This is useful when the plugin cache is configured differently. Supported using the env CDKTF_DISABLE_PLUGIN_CACHE_ENV. [boolean] [default: false] + --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] + -a, --app Command to use in order to execute cdktf app [required] + -o, --output Output directory for the synthesized Terraform config [required] [default: "cdktf.out"] + --auto-approve Auto approve [boolean] [default: false] + --outputs-file Path to file where stack outputs will be written as JSON [string] + --outputs-file-include-sensitive-outputs Whether to include sensitive outputs in the output file [boolean] [default: false] + --ignore-missing-stack-dependencies Don't check if all stacks specified in the command have their dependencies included as well [boolean] [default: false] + --parallelism Number of concurrent CDKTF stacks to run. Defaults to infinity, denoted by -1 [number] [default: -1] --refresh-only Select the "refresh only" planning mode, which checks whether remote objects still match the outcome of the most recent Terraform apply but does not propose any actions to undo any changes made outside of Terraform. [boolean] [default: false] - --terraform-parallelism Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend [number] [default: -1] - -h, --help Show help [boolean] + --terraform-parallelism Forwards value as the `-parallelism` flag to Terraform. By default, the this flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend [number] [default: -1] + -h, --help Show help [boolean] ``` ~> **Note:** The `parallelism` flag has a different behavior than the [terraform parallelism flag](https://www.terraform.io/cli/commands/apply#parallelism-n). To set the custom terraform parallelism flag, please use the `--terraform-parallelism` flag instead. @@ -207,19 +207,19 @@ cdktf destroy [stacks..] Destroy the given stacks Positionals: - stacks Destroy stacks matching the given ids. Required when more than one stack is present in the app [array] [default: []] + stacks Destroy stacks matching the given ids. Required when more than one stack is present in the app [array] [default: []] Options: - --version Show version number [boolean] - --disable-plugin-cache-env Dont set TF_PLUGIN_CACHE_DIR automatically. This is useful when the plugin cache is configured differently. Supported using the env CDKTF_DISABLE_PLUGIN_CACHE_ENV. [boolean] [default: false] - --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] - -a, --app Command to use in order to execute cdktf app [required] - -o, --output Output directory for the synthesized Terraform config [required] [default: "cdktf.out"] - --auto-approve Auto approve [boolean] [default: false] - --ignore-missing-stack-dependencies Don't check if all stacks specified in the command have their dependencies included as well [boolean] [default: false] - --parallelism Number of concurrent CDKTF stacks to run. Defaults to infinity, denoted by -1 [number] [default: -1] - --terraform-parallelism Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend [number] [default: -1] - -h, --help Show help [boolean] + --version Show version number [boolean] + --disable-plugin-cache-env Dont set TF_PLUGIN_CACHE_DIR automatically. This is useful when the plugin cache is configured differently. Supported using the env CDKTF_DISABLE_PLUGIN_CACHE_ENV. [boolean] [default: false] + --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] + -a, --app Command to use in order to execute cdktf app [required] + -o, --output Output directory for the synthesized Terraform config [required] [default: "cdktf.out"] + --auto-approve Auto approve [boolean] [default: false] + --ignore-missing-stack-dependencies Don't check if all stacks specified in the command have their dependencies included as well [boolean] [default: false] + --parallelism Number of concurrent CDKTF stacks to run. Defaults to infinity, denoted by -1 [number] [default: -1] + --terraform-parallelism Forwards value as the `-parallelism` flag to Terraform. By default, the this flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend [number] [default: -1] + -h, --help Show help [boolean] ``` ~> **Note:** The `parallelism` flag has a different behavior than the [terraform parallelism flag](https://www.terraform.io/cli/commands/apply#parallelism-n). To set the custom terraform parallelism flag, please use the `--terraform-parallelism` flag instead. @@ -274,18 +274,17 @@ cdktf diff [stack] Perform a diff (terraform plan) for the given stack Positionals: - stack Diff stack which matches the given id only. Required when more than one stack is present in the app [string] + stack Diff stack which matches the given id only. Required when more than one stack is present in the app [string] Options: - --version Show version number [boolean] - --disable-plugin-cache-env Dont set TF_PLUGIN_CACHE_DIR automatically. This is useful when the plugin cache is configured differently. Supported using the env CDKTF_DISABLE_PLUGIN_CACHE_ENV. [boolean] [default: false] - --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] - -a, --app Command to use in order to execute cdktf app [required] - -o, --output Output directory for the synthesized Terraform config [required] [default: "cdktf.out"] - --refresh-only Select the "refresh only" planning mode, which checks whether remote objects still match the outcome of the most recent Terraform apply but does not propose any actions to undo any changes made outside of Terraform. - [boolean] [default: false] - --terraform-parallelism Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend [number] [default: -1] - -h, --help Show help [boolean] + --version Show version number [boolean] + --disable-plugin-cache-env Dont set TF_PLUGIN_CACHE_DIR automatically. This is useful when the plugin cache is configured differently. Supported using the env CDKTF_DISABLE_PLUGIN_CACHE_ENV. [boolean] [default: false] + --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] + -a, --app Command to use in order to execute cdktf app [required] + -o, --output Output directory for the synthesized Terraform config [required] [default: "cdktf.out"] + --refresh-only Select the "refresh only" planning mode, which checks whether remote objects still match the outcome of the most recent Terraform apply but does not propose any actions to undo any changes made outside of Terraform. [boolean] [default: false] + --terraform-parallelism Forwards value as the `-parallelism` flag to Terraform. By default, the this flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend [number] [default: -1] + -h, --help Show help [boolean] ``` ~> **Note:** The `parallelism` flag has a different behavior than the [terraform parallelism flag](https://www.terraform.io/cli/commands/plan#parallelism-n). To set the custom terraform parallelism flag, please use the `--terraform-parallelism` flag instead. @@ -503,18 +502,18 @@ cdktf watch [stacks..] [experimental] Watch for file changes and automatically trigger a deploy Positionals: - stacks Deploy stacks matching the given ids. Required when more than one stack is present in the app [array] [default: []] + stacks Deploy stacks matching the given ids. Required when more than one stack is present in the app [array] [default: []] Options: - --version Show version number [boolean] - --disable-plugin-cache-env Dont set TF_PLUGIN_CACHE_DIR automatically. This is useful when the plugin cache is configured differently. Supported using the env CDKTF_DISABLE_PLUGIN_CACHE_ENV. [boolean] [default: false] - --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] - -a, --app Command to use in order to execute cdktf app [required] - -o, --output Output directory for the synthesized Terraform config [required] [default: "cdktf.out"] - --auto-approve Auto approve [boolean] [default: false] - --parallelism Number of concurrent CDKTF stacks to run. Defaults to infinity, denoted by -1 [number] [default: -1] - --terraform-parallelism Customize number of parallel graph traversals by Terraform. By default, the parallelism flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend [number] [default: -1] - -h, --help Show help [boolean] + --version Show version number [boolean] + --disable-plugin-cache-env Dont set TF_PLUGIN_CACHE_DIR automatically. This is useful when the plugin cache is configured differently. Supported using the env CDKTF_DISABLE_PLUGIN_CACHE_ENV. [boolean] [default: false] + --log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string] + -a, --app Command to use in order to execute cdktf app [required] + -o, --output Output directory for the synthesized Terraform config [required] [default: "cdktf.out"] + --auto-approve Auto approve [boolean] [default: false] + --parallelism Number of concurrent CDKTF stacks to run. Defaults to infinity, denoted by -1 [number] [default: -1] + --terraform-parallelism Forwards value as the `-parallelism` flag to Terraform. By default, the this flag is not forwarded to Terraform. Note: This flag is not supported by remote / cloud backend [number] [default: -1] + -h, --help Show help [boolean] ``` ~> **Note:** The `parallelism` flag has a different behavior than the [terraform parallelism flag](https://www.terraform.io/cli/commands/apply#parallelism-n). To set the custom terraform parallelism flag, please use the `--terraform-parallelism` flag instead.