Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(cli): throw an error if a user tries to create a new project with TFC on an old TF version #2062

Merged
merged 5 commits into from
Aug 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ A very minor change in the interface names for provisioners occured [to support
- `ILocalExecProvisioner` to `LocalExecProvisioner`
- `IRemoteExecProvisioner` to `RemoteExecProvisioner`

Another very minor change is that we now use the `CloudBackend` by default when running cdktf init. This requires Terraform >=1.1, therefore an error is thrown on `cdktf init` if you want to use Terraform Cloud and are on an older version. Already existing projects are not affected and you can use `cdktf init --local` and configure the `RemoteBackend` if you need to use an older version.

### fix

- fix(hcl2json): add fs-extra to dependencies [\#2040](https://github.com/hashicorp/terraform-cdk/pull/2040)
Expand Down
15 changes: 12 additions & 3 deletions packages/cdktf-cli/bin/cmds/helper/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import { init, Project } from "../../../lib";
import { askForCrashReportingConsent } from "../../../lib/error-reporting";
import ciDetect from "@npmcli/ci-detect";
import { isInteractiveTerminal } from "./check-environment";
import { getTerraformVersion } from "./terraform-check";
import * as semver from "semver";

const chalkColour = new chalk.Instance();

Expand Down Expand Up @@ -77,13 +79,21 @@ export async function runInit(argv: Options) {
console.log(chalkColour`{yellow Note: By supplying '--local' option you have chosen local storage mode for storing the state of your stack.
This means that your Terraform state file will be stored locally on disk in a file 'terraform.<STACK NAME>.tfstate' in the root of your project.}`);
}
const isRemote = token != "";

// Check if template was specified by the user
let template = "";
if (argv.template) {
template = argv.template;
}

const tfVersion = await getTerraformVersion();
if (tfVersion && semver.lt(tfVersion, "1.1.0") && isRemote) {
throw Errors.Usage(
`Terraform version ${tfVersion} is not supported for remote configuration. We use the CloudBackend to configure the connection to Terraform Cloud, which is only supported in Terraform 1.1 and higher. Please upgrade to version 1.1.0 or higher or use the local mode by passing --local (afterwards you can use the RemoteBackend to work with Terraform Cloud without upgrading your Terraform version.`
);
}

// Gather information about the template and the project
const templateInfo = await getTemplate(template);
telemetryData.template = templateInfo.Name;
Expand Down Expand Up @@ -111,9 +121,8 @@ This means that your Terraform state file will be stored locally on disk in a fi
throw new Error(`Missing organization name in project info`);
}

// Check if token is set so we can set up Terraform Cloud workspace
// only set with the '--local' option is specified the user.
if (token != "") {
// Set up a Terraform Cloud workspace if the user opted-in
if (isRemote) {
telemetryData.isRemote = Boolean(token);
console.log(
chalkColour`\n{whiteBright Setting up remote state backend and workspace in Terraform Cloud.}`
Expand Down
44 changes: 28 additions & 16 deletions packages/cdktf-cli/bin/cmds/helper/terraform-check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,13 @@ import { SynthesizedStack } from "../../../lib/synth-stack";
import { existsSync } from "fs-extra";
import * as path from "path";
import { AbortController } from "node-abort-controller"; // polyfill until we update to node 14
import { logger } from "../../../lib/logging";

const MIN_SUPPORTED_VERSION = "0.13.0";
const MIN_SUPPORTED_VERSION = "1.0.0";
ansgarm marked this conversation as resolved.
Show resolved Hide resolved
const VERSION_REGEXP = /Terraform v\d+.\d+.\d+/;

export const terraformCheck = async (): Promise<void> => {
export const getTerraformVersion = async (): Promise<string | null> => {
try {
if (existsSync(path.join(process.cwd(), "terraform.tfstate"))) {
throw new Error(`
CDK for Terraform now supports multiple stacks!
Found 'terraform.tfstate' Terraform state file. Please rename it to match the stack name. Learn more https://cdk.tf/multiple-stacks
`);
}

// We're abusing the TerraformCli class here,
// hence we need to construct this object.
// Only the `workingDirectory` is releveant here.
Expand All @@ -35,14 +29,32 @@ export const terraformCheck = async (): Promise<void> => {
const terraformVersion = await terraform.version();
const terraformVersionMatches = terraformVersion.match(VERSION_REGEXP);

if (terraformVersionMatches !== null) {
// Should always be the first match found in the string
const cleanTerraformVersion = semver.clean(
terraformVersionMatches[0].substring(
terraformVersionMatches[0].indexOf("v")
)
);
if (terraformVersionMatches === null) {
return null;
}
// Should always be the first match found in the string
return semver.clean(
terraformVersionMatches[0].substring(
terraformVersionMatches[0].indexOf("v")
)
);
} catch (e) {
logger.info(`Unable to determine Terraform version: ${e}`);
return null;
}
};

export const terraformCheck = async (): Promise<void> => {
try {
if (existsSync(path.join(process.cwd(), "terraform.tfstate"))) {
throw new Error(`
CDK for Terraform now supports multiple stacks!
Found 'terraform.tfstate' Terraform state file. Please rename it to match the stack name. Learn more https://cdk.tf/multiple-stacks
`);
}
const cleanTerraformVersion = await getTerraformVersion();

if (cleanTerraformVersion !== null) {
if (
cleanTerraformVersion &&
semver.lt(cleanTerraformVersion, MIN_SUPPORTED_VERSION)
Expand Down