Skip to content

Commit

Permalink
Merge pull request #796 from hashicorp/tf-to-cdk
Browse files Browse the repository at this point in the history
feat(cli): implement hcl2cdk conversion
  • Loading branch information
DanielMSchmidt authored Jul 26, 2021
2 parents 2dcf9c9 + 8916cfc commit 1389f7b
Show file tree
Hide file tree
Showing 29 changed files with 4,814 additions and 453 deletions.
1 change: 1 addition & 0 deletions .github/workflows/pr-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
lib
cli
hcl2json
hcl2cdk
tests
examples
readme
Expand Down
111 changes: 81 additions & 30 deletions docs/cli-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,23 @@ $ cdktf --help
Help output:

```
cdktf [command]
Commands:
cdktf deploy [OPTIONS] Deploy the given stack
cdktf destroy [OPTIONS] Destroy the given stack
cdktf diff [OPTIONS] Perform a diff (terraform plan) for the given stack
cdktf get [OPTIONS] Generate CDK Constructs for Terraform providers and modules.
cdktf init [OPTIONS] Create a new cdktf project from a template.
cdktf login Retrieves an API token to connect to Terraform Cloud.
cdktf synth [OPTIONS] Synthesizes Terraform code for the given app in a directory. [aliases: synthesize]
cdktf convert [OPTIONS] Converts a single file of HCL configuration to Terraform CDK. Takes the file to be converted on stdin.
cdktf deploy [stack] [OPTIONS] Deploy the given stack [aliases: apply]
cdktf destroy [stack] [OPTIONS] Destroy the given stack
cdktf diff [stack] [OPTIONS] Perform a diff (terraform plan) for the given stack [aliases: plan]
cdktf get [OPTIONS] Generate CDK Constructs for Terraform providers and modules.
cdktf init [OPTIONS] Create a new cdktf project from a template.
cdktf list [OPTIONS] List stacks in app.
cdktf login Retrieves an API token to connect to Terraform Cloud.
cdktf synth [stack] [OPTIONS] Synthesizes Terraform code for the given app in a directory. [aliases: synthesize]
Options:
--version Show version number [boolean]
--disable-logging Dont write log files. Supported using the env CDKTF_DISABLE_LOGGING. [boolean] [default: true]
--log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string]
-h, --help Show help [boolean]
--version Show version number [boolean]
--disable-logging Dont write log files. Supported using the env CDKTF_DISABLE_LOGGING. [boolean] [default: true]
--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]
-h, --help Show help [boolean]
Options can be specified via environment variables with the "CDKTF_" prefix (e.g. "CDKTF_OUTPUT")
```
Expand All @@ -43,13 +44,19 @@ If running in automated environments, the dynamic CLI output rendering can be fo

## Available commands

- [get](#cdktf-get)
- [init](#cdktf-init)
- [synth](#cdktf-synth)
- [diff](#cdktf-diff)
- [deploy](#cdktf-deploy)
- [destroy](#cdktf-destroy)
- [login](#cdktf-login)
- [cdktf-cli](#cdktf-cli)
- [Install](#install)
- [Usage](#usage)
- [CI environment](#ci-environment)
- [Available commands](#available-commands)
- [cdktf get](#cdktf-get)
- [cdktf init](#cdktf-init)
- [cdktf synth](#cdktf-synth)
- [cdktf diff](#cdktf-diff)
- [cdktf deploy](#cdktf-deploy)
- [cdktf destroy](#cdktf-destroy)
- [cdktf login](#cdktf-login)
- [cdktf convert](#cdktf-convert)

### cdktf get

Expand Down Expand Up @@ -110,16 +117,25 @@ cdktf init [OPTIONS]
Create a new cdktf project from a template.
Options:
--version Show version number [boolean]
--disable-logging Dont write log files. Supported using the env CDKTF_DISABLE_LOGGING. [boolean] [default: true]
--log-level Which log level should be written. Only supported via setting the env CDKTF_LOG_LEVEL [string]
--template The template name to be used to create a new project. [string] [choices: "python", "typescript", "java", "csharp", "go"]
--project-name The name of the project. [string]
--project-description The description of the project. [string]
--dist Install dependencies from a "dist" directory (for development) [string]
--local Use local remote state storage for generated Terraform. [boolean] [default: false]
--cdktf-version The cdktf version to use while creating a new project. [string] [default: "0.0.0"]
-h, --help Show help [boolean]
--version Show version number [boolean]
--disable-logging Dont write log files. Supported using the env CDKTF_DISABLE_LOGGING.
[boolean] [default: true]
--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]
--template The template to be used to create a new project. Either URL to zip file or one of the
built-in templates: ["csharp", "go", "java", "python", "python-pip", "typescript"]
[string]
--project-name The name of the project. [string]
--project-description The description of the project. [string]
--dist Install dependencies from a "dist" directory (for development) [string]
--local Use local state storage for generated Terraform. [boolean] [default: false]
--cdktf-version The cdktf version to use while creating a new project. [string] [default: "0.0.0"]
--from-terraform-project Use a terraform project as the basis, CDK constructs will be generated based on the
.tf files in the path [string]
-h, --help Show help [boolean]
```

Examples:
Expand All @@ -136,6 +152,12 @@ Create a new Python project and use a specific version of the `cdktf` package.
$ cdktf init --template="python" --cdktf-version="0.0.1"
```

Create a new Typescript project from an existing Terraform codebase. Please be aware that only Typescript is currently supported and that there are [some known limitations](../packages/@cdktf/hcl2cdk/README.md#known-limitations).

```bash
$ cdktf init --template="typescript" --from-terraform-project /path/to/terraform/project
```

### cdktf synth

This command synthesizes Terraform configuration for an application.
Expand Down Expand Up @@ -320,3 +342,32 @@ Fetch an API token from Terraform Cloud.
```bash
$ cdktf login
```

### cdktf convert

This command converts Terraform configuration written in HCL to CDK configuration that does the same in the language of your choice. The convert functionality only covers Terraform 1.0, everything below is not guaranteed to be working. There is also functionality not covered for Terraform 1.0, please see [the known limitations](../packages/@cdktf/hcl2cdk/README.md#known-limitations).

```
cdktf convert [OPTIONS]
Converts a single file of HCL configuration to Terraform CDK. Takes the file to be converted on stdin.
Options:
--version Show version number [boolean]
--disable-logging Dont write log files. Supported using the env CDKTF_DISABLE_LOGGING.
[boolean] [default: true]
--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]
--language [choices: "typescript", "python", "csharp", "java"] [default: "typescript"]
-h, --help Show help [boolean]
```

Examples:

- Convert a local file: `cat main.tf | cdktf convert > imported.ts`
- Convert HCL in your clipboard to Python on OSX: `pbpaste | cdktf convert --language python | pbcopy`

There are some known limitations, please [check them out at the @cdktf/hcl2cdk package](../packages/@cdktf/hcl2cdk/README.md#known-limitations).
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"examples:integration:go": "test/run-against-dist tools/build-examples-sequential.sh go",
"pretest": "prettier --check .",
"test": "lerna run --scope cdktf* --scope @cdktf* test",
"watch": "lerna run --parallel --stream --scope cdktf* watch-preserve-output",
"watch": "lerna run --parallel --stream --scope @cdktf/* --scope cdktf* watch-preserve-output",
"link-packages": "lerna exec --scope cdktf* --scope @cdktf* yarn link",
"integration": "cd test && ./run-against-dist npx jest --runInBand",
"integration:typescript": "cd test && ./run-against-dist npx jest --runInBand typescript",
Expand Down
4 changes: 4 additions & 0 deletions packages/@cdktf/hcl2cdk/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
**/*.d.ts.map
**/*.js.map
tsconfig.tsbuildinfo
!tsconfig.json
79 changes: 79 additions & 0 deletions packages/@cdktf/hcl2cdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# @cdktf/hcl2cdk

Uses `@cdktf/hcl2cdk` to transform HCL configuration to CDK constructs.

## Usage

```sh
yarn install @cdktf/hcl2cdk
```

### Convert HCL strings to Constructs

```ts
import { convert } from "@cdktf/hcl2cdk";

const hcl = `
variable "name" {
description = "Name to be used on all the resources as identifier"
type = string
default = ""
}
`(async () => {
const ts = await convert(hcl, { language: "typescript" });
console.log(ts.imports); // just the necessary imports
console.log(ts.code); // just the constructs
console.log(ts.all); // code with imports
})();

// =>
import * as cdktf from "cdktf";

new cdktf.TerraformVariable(this, "imageId", {
type: "string",
default: "ami-abcde123",
description: "What AMI to use to create an instance",
});
```

### Convert a project

```ts
import { convertProject, getTerraformConfigFromDir } from "@cdktf/hcl2json";

(async () => {
await convertProject(
getTerraformConfigFromDir("/path/to/terraform/project"),
"/path/to/cdktf-init/project",
{ language: "typescript" } // Currently we only support Typescript for project conversion
);
})();
```

This transforms your Terraform project into a CDK for Terraform project, besides the resource naming within Terraform the deployed resources should not differ between `terraform plan` and `cdktf plan`.

## Known Limitations

### Terraform Expressions are of the wrong TS/Java/C# type

When working with typed languages the converter can run into problems where the Terraform Expression evaluates to a certain type but it's encoded in a string. Therefore the type checker of the language detects a type mismatch, resulting in an compilation error. These problems need to be manually solved by adding a typecast. One example would be:

```ts
{
// Typescript expects a boolean here, but a string is passed
booleanProperty:
( // This Terraform expression evaluates to a boolean as required by the property
`\${${shouldBeTrue.value} ? true : false}`
as boolean // We need to cast the type so that Typescript understand the right type is being passed
);
}
```

### Providers guessed can be not functional

If your HCL includes providers that are not mentioned under `required_providers` we infer the name, e.g. if you use the `datadog_dashboard` resource we infer the provider `datadog` which is right, but the namespace is missing, for DataDog it would be `datadog/datadog`. Instead we will try to use `hashicorp/datadog` and fail because this provider is not known to the registry.
Please see the [required providers docs](https://www.terraform.io/docs/language/providers/requirements.html#requiring-providers) for more information on how to specify providers.

### Local Modules and Files

We don't move modules or files for you, if you reference local modules you have to move them so that the relative paths are correct. If you want to make use of files you need to wrap them in a [`TerraformAsset`](../../docs/working-with-cdk-for-terraform/terraform-assets.md) before using them.
14 changes: 14 additions & 0 deletions packages/@cdktf/hcl2cdk/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module.exports = {
"roots": [
"<rootDir>/test"
],
testMatch: ['**/*.test.ts', '**/*.test.tsx'],
"transform": {
"^.+\\.tsx?$": "ts-jest"
},
moduleFileExtensions: [
"js",
"ts",
"tsx"
],
}
Loading

0 comments on commit 1389f7b

Please sign in to comment.