Skip to content

Commit

Permalink
Merge pull request #331 from hashicorp/prebuilt-providers
Browse files Browse the repository at this point in the history
Streamline Usage of Prebuilt Providers
  • Loading branch information
skorfmann authored Aug 24, 2020
2 parents 8b17ea7 + 52cf934 commit 4c4dd9c
Show file tree
Hide file tree
Showing 28 changed files with 531 additions and 13 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Choose a language:
## Documentation

* Install and run a quick start tutorial at [HashiCorp Learn](https://learn.hashicorp.com/terraform/cdktf/cdktf-install)
* Using CDK for Terraform CLI for importing Terraform [modules and providers](./docs/working-with-cdk-for-terraform/importing-providers-and-modules.md).
* Using CDK for Terraform CLI for importing Terraform [modules and providers](./docs/working-with-cdk-for-terraform/using-providers-and-modules.md).
* Explore the CDK for Terraform [CLI](./docs/cli-commands.md).
* Defining Terraform [outputs](./docs/working-with-cdk-for-terraform/terraform-outputs.md).
* Using Terraform [remote backend](./docs/working-with-cdk-for-terraform/remote-backend.md).
Expand Down
145 changes: 145 additions & 0 deletions docs/working-with-cdk-for-terraform/cdktf-json.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
# cdktf.json Configuration File

With the `cdktf.json` in your project root directory you can configure the behaviour of the Terraform CDK CLI:

## Specification

```ts
export enum Language {
TYPESCRIPT = 'typescript',
PYTHON = 'python',
DOTNET = 'dotnet', // not yet supported
JAVA = 'java', // not yet supported
}

export interface Config {
readonly app?: string; // The command to run in order to synthesize the code to Terraform compatible JSON
readonly language?: Language; // Target language for building provider or module bindings. Currently supported: `typescript` or `python`
readonly output: string; // Default: 'cdktf.out'. Where the synthesized JSON should go. Also will be the working directory for Terraform operations
readonly codeMakerOutput: string; // Default: '.gen'. Path where generated provider bindings will be rendered to.
readonly terraformProviders?: string[]; // Terraform Providers to build
readonly terraformModules?: string[]; // Terraform Modules to build
}
```

### Terraform Providers and Modules

The [following specifications](https://www.terraform.io/docs/configuration/provider-requirements.html#requiring-providers) schema should be followed for providers and modules

[source](https://www.terraform.io/docs/configuration/provider-requirements.html#source-addresses)@[version](https://www.terraform.io/docs/configuration/provider-requirements.html#version-constraints)

#### For HashiCorp maintained providers

Official HashiCorp [maintained providers](https://registry.terraform.io/browse/providers?tier=official) (e.g. `aws`, `google` or `azurerm`) can be specified in a short version like this: `"aws@~> 2.0"`

#### 3rd Party Providers

Community providers have to provide a fully qualified name, e.g. to define the Docker provider: `terraform-providers/docker@~> 2.0`

#### Modules

Similar to 3rd Party providers, the full registry namespace should be provided. Please note that only modules from the registry are supported at this point.

## Examples

### Minimal Configuration

A minimal configuration would define `app` only. This is useful, when planning to use [prebuilt providers](https://github.com/terraform-cdk-providers) and therefore no provider or modules bindings should be generated.

```json
{
"app": "npm run --silent compile && node main.js"
}
```

### Changing Code Output Directories

This will synthesize JSON into `my-workdir` and all Terraform operations - such as `deploy` or `destroy` - will be performed in this directory.

```json
{
"app": "npm run --silent compile && node main.js",
"output": "my-workdir",
}
```

### Building Providers

With this `terraformProviders` configuration, a `cdktf get` will build the latest AWS provider within the 2.X version range. The generated code will be saved into `.gen` by default. This can be adjusted with `codeMakerOutput`, see other examples below.

```json
{
"language": "typescript",
"app": "npm run --silent compile && node main.js",
"terraformProviders": [
"aws@~> 2.0"
]
}
```

### Building Modules

With this `terraformModules` configuration, a `cdktf get` will build the latest `terraform-aws-modules/vpc/aws` module from the Terraform Registry. The generated code will be saved into `.gen` by default. This can be adjusted with `codeMakerOutput` - see other examples below.

```json
{
"language": "typescript",
"app": "npm run --silent compile && node main.js",
"terraformModules": [
"terraform-aws-modules/vpc/aws"
]
}
```

### Building Providers & Modules

This combines examples above, a `cdktf get` will build both the AWS provider and the latest `terraform-aws-modules/vpc/aws` module from the Terraform Registry.

```json
{
"language": "typescript",
"app": "npm run --silent compile && node main.js",
"terraformModules": [
"terraform-aws-modules/vpc/aws"
],
"terraformProviders": [
"aws@~> 2.0"
]
}
```

### Building Multiple Providers

It's possible to build multiple providers or modules as well.

```json
{
"language": "typescript",
"app": "npm run --silent compile && node main.js",
"terraformProviders": [
"null",
"aws",
"google",
"azurerm",
"kubernetes",
"consul",
"vault",
"nomad",
]
}
```

### Building Providers in Custom Directory

This will generate the `aws` provider bindings in the folder `./imports`. This is used in the Python template, to make it easier to reference the generated classes.

```json
{
"language": "python",
"app": "pipenv run ./main.py",
"terraformProviders": [
"aws@~> 2.0"
],
"codeMakerOutput": "imports"
}
```
Original file line number Diff line number Diff line change
@@ -1,4 +1,26 @@
# Importing Providers and Modules
# Using Providers and Modules

## Prebuilt Providers

To improve the general user experience around provider imports and to allow building further abstractions on top of the Terraform provider bindings, a few popular providers are offered as prebuilt packages. At the moment the following providers are built and published to NPM / PyPi on a regular basis automatically.

- [AWS Provider](https://github.com/terraform-cdk-providers/cdktf-provider-aws)
- [Google Provider](https://github.com/terraform-cdk-providers/cdktf-provider-google)
- [Azure Provider](https://github.com/terraform-cdk-providers/cdktf-provider-azurerm)
- [Kubernetes Provider](https://github.com/terraform-cdk-providers/cdktf-provider-kubernetes)
- [Docker Provider](https://github.com/terraform-cdk-providers/cdktf-provider-docker)
- [Github Provider](https://github.com/terraform-cdk-providers/cdktf-provider-github)
- [Null Provider](https://github.com/terraform-cdk-providers/cdktf-provider-null)

Please check the [Terraform CDK Providers](https://github.com/terraform-cdk-providers) organization as well for an up to date list. As these are normal NPM / PyPI packages, they can be used as any other dependency.

e.g. in Typescript / Node:

```
npm install -a @cdktf/provider-aws
```

## Importing Providers and Modules

CDK for Terraform allows you to import Terraform [providers](https://www.terraform.io/docs/providers/index.html) and [modules](https://www.terraform.io/docs/modules/index.html) to your project
using this workflow.
Expand Down Expand Up @@ -31,7 +53,7 @@ new MyStack(app, 'hello-terraform');
app.synth();
```

The project also has the `cdktf.json` file that defines what providers and modules are being used by the project.
The project also has the [cdktf.json](./cdktf-json.md) file that defines what providers and modules are being used by the project.

```bash
vim cdktf.json
Expand Down Expand Up @@ -183,4 +205,4 @@ cdktf synth --json
}
}

```
```
4 changes: 4 additions & 0 deletions examples/typescript/aws-prebuilt/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.gen
cdktf.out
terraform.tfstate*
!tsconfig.json
15 changes: 15 additions & 0 deletions examples/typescript/aws-prebuilt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Typescript AWS with Prebuilt Provider

A CDK for Terraform application in TypeScript using the prebuilt [AWS provider](https://github.com/terraform-cdk-providers/cdktf-provider-aws).

## Usage

Install project dependencies:

```shell
yarn install
```

You can now edit the [main.ts](./main.ts) file if you want to modify any code.

Perform a `cdktf diff` to get a plan of what would be deployed.
3 changes: 3 additions & 0 deletions examples/typescript/aws-prebuilt/cdktf.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"app": "npm run --silent compile && node main.js"
}
49 changes: 49 additions & 0 deletions examples/typescript/aws-prebuilt/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Construct } from 'constructs';
import { App, TerraformStack, TerraformOutput } from 'cdktf';
import { DataAwsRegion, AwsProvider, DynamodbTable, SnsTopic } from '@cdktf/provider-aws'

export class HelloTerra extends TerraformStack {
constructor(scope: Construct, id: string) {
super(scope, id);

new AwsProvider(this, 'aws', {
region: 'eu-central-1'
})

const region = new DataAwsRegion(this, 'region')

const table = new DynamodbTable(this, 'Hello', {
name: `my-first-table-${region.name}`,
hashKey: 'temp',
attribute: [
{ name: 'id', type: 'S' },
],
billingMode: "PAY_PER_REQUEST"
});

table.addOverride('hash_key', 'id')
// table.addOverride('hash_key', 'foo')
table.addOverride('lifecycle', { create_before_destroy: true })

const topicCount = 1
const topics = [...Array(topicCount).keys()].map((i) => {
return new SnsTopic(this, `Topic${i}`, {
displayName: `my-first-sns-topic${i}`
});
})

new TerraformOutput(this, 'table_name', {
value: table.name
})

topics.forEach((topic, i) => {
new TerraformOutput(this, `sns_topic${i}`, {
value: topic.name
})
})
}
}

const app = new App();
new HelloTerra(app, 'hello-terra');
app.synth();
21 changes: 21 additions & 0 deletions examples/typescript/aws-prebuilt/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "@examples/typescript-aws-prebuilt",
"version": "0.0.0",
"main": "index.js",
"license": "MPL-2.0",
"scripts": {
"build": "tsc",
"compile": "tsc --pretty",
"synth": "cdktf synth"
},
"devDependencies": {
"@types/node": "^14.0.26",
"cdktf-cli": "0.0.0",
"typescript": "^3.9.7"
},
"dependencies": {
"@cdktf/provider-aws": "^0.0.19",
"cdktf": "0.0.0",
"constructs": "^3.0.0"
}
}
33 changes: 33 additions & 0 deletions examples/typescript/aws-prebuilt/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"compilerOptions": {
"alwaysStrict": true,
"charset": "utf8",
"declaration": true,
"experimentalDecorators": true,
"inlineSourceMap": true,
"inlineSources": true,
"lib": [
"es2018"
],
"module": "CommonJS",
"noEmitOnError": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"resolveJsonModule": true,
"strict": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"stripInternal": true,
"target": "ES2018"
},
"include": [
"**/*.ts"
],
"exclude": [
"node_modules"
]
}
18 changes: 18 additions & 0 deletions examples/typescript/aws-prebuilt/yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


"@types/node@^13.1.1":
version "13.1.4"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.4.tgz#4cfd90175a200ee9b02bd6b1cd19bc349741607e"
integrity sha512-Lue/mlp2egZJoHXZr4LndxDAd7i/7SQYhV0EjWfb/a4/OZ6tuVwMCVPiwkU5nsEipxEf7hmkSU7Em5VQ8P5NGA==

constructs@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/constructs/-/constructs-2.0.1.tgz#274d6b8ce6a698813495c444466b0c745349ddb5"
integrity sha512-edR85YFGI9TBT9byAo5vAfI0PRi+jFGzinwN3RAJwKfv6Yc9x9kALYfoEmgotp95qT7/k/iUQWHrH9BMJeqpdg==

typescript@^3.7.4:
version "3.7.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.4.tgz#1743a5ec5fef6a1fa9f3e4708e33c81c73876c19"
integrity sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==
2 changes: 1 addition & 1 deletion packages/cdktf-cli/bin/cmds/synth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class Command implements yargs.CommandModule {
const outdir = argv.output;
const jsonOutput = argv.json;

if (!await fs.pathExists(config.codeMakerOutput)) {
if (config.checkCodeMakerOutput && !await fs.pathExists(config.codeMakerOutput)) {
console.error(`ERROR: synthesis failed, run "cdktf get" to generate providers in ${config.codeMakerOutput}`);
process.exit(1);
}
Expand Down
6 changes: 6 additions & 0 deletions packages/cdktf-cli/lib/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ const DEFAULTS = {
codeMakerOutput: '.gen'
}

function isPresent(input: string[] | undefined): boolean {
return Array.isArray(input) && input.length > 0
}

export interface Config {
readonly app?: string;
Expand All @@ -16,6 +19,7 @@ export interface Config {
readonly codeMakerOutput: string;
readonly terraformProviders?: string[];
readonly terraformModules?: string[];
checkCodeMakerOutput?: boolean;
}

export function readConfigSync(): Config {
Expand All @@ -28,5 +32,7 @@ export function readConfigSync(): Config {
};
}

config.checkCodeMakerOutput = isPresent(config.terraformModules) || isPresent(config.terraformProviders)

return config;
}
Loading

0 comments on commit 4c4dd9c

Please sign in to comment.