@joshwycuff/terrascript-plugin-terraform
TypeScript icon, indicating that this package has built-in type declarations

1.0.2 • Public • Published

terrascript-plugin-terraform

Terrascript plugin for additional Terraform functionality.

Install

npm install @joshwycuff/terrascript-plugin-terraform --save-dev
yarn add @joshwycuff/terrascript-plugin-terraform --dev

Usage

Place the plugin name in the plugins key of the top-level terrascript.yml.

plugins:
  - "@joshwycuff/terrascript-plugin-terraform"

Basic Configuration

Configuration of the Terraform plugin for Terrascript is set under the terraform key.

terraform:
  # shorthandTerraformCommand: tf
  # shorthandTerraformSubcommands: true
  • shorthandTerraformCommand allows the definition of a shorthand (or alias) terraform command (e.g. tf).
  • shorthandTerraformSubcommands allows terraform subcommands to be run directly without specifying the top-level terraform command at all (e.g. terraform init -> init).

The Terraform plugin also adds additional hooks specifically for Terraform actions. These occur at the same time as the beforeAction and afterAction hooks.

hooks:
  beforeTerraform:        # runs before any terraform command
  afterTerraform:         # runs after any terraform command
  beforeTerraformApply:   # runs before terraform apply
  afterTerraformApply:    # runs after terraform apply
  beforeTerraformDestroy: # runs before terraform destroy
  afterTerraformDestroy:  # runs after terraform destroy

Technically, the plugin supports beforeTerraform{subcommand} and afterTerraform{subcommand} for any Terraform subcommand. Those above are just the most common.

Walk-through

When specifying shorthandTerraformSubcommands as true, terraform actions can be defined in shorthand as well.

plugins:
  - "@joshwycuff/terrascript-plugin-terraform"
terraform:
  shorthandTerraformSubcommands: true
targets:
  dev:
actions:
  build:
    - init
    - plan
    - apply

You can specify Terraform input variables which can be effectively combined with Terrascript template expressions.

plugins:
  - "@joshwycuff/terrascript-plugin-terraform"
terraform:
  shorthandTerraformSubcommands: true
  tfVars:
    environment: "{{ target.name }}"
targets:
  dev:
terrascript dev apply
# `terraform apply -var=environment=dev`

You can specify Terraform variable definitions (.tfvars) files in the config section as well.

plugins:
  - "@joshwycuff/terrascript-plugin-terraform"
terraform:
  shorthandTerraformSubcommands: true
  tfVarsFiles:
    - "tfvars/{{ target.name }}.tfvars"
targets:
  dev:
terrascript dev apply
# `terraform apply -var-file=tfvars/dev.tfvars`

Tired of typing -auto-approve or plan on using this in CI/CD?

plugins:
  - "@joshwycuff/terrascript-plugin-terraform"
terraform:
  shorthandTerraformSubcommands: true
  autoApprove: true
targets:
  dev:
terrascript dev apply
# `terraform apply -auto-approve`

Want to specify auto-approve for only apply or destroy commands?

plugins:
  - "@joshwycuff/terrascript-plugin-terraform"
terraform:
  autoApproveApply: true
  autoApproveDestroy: true
targets:
  dev:

You can dynamically configure your remote backend in the config block.

# main.tf
terraform {
    backend "s3" {}
}
plugins:
  - "@joshwycuff/terrascript-plugin-terraform"
terraform:
  shorthandTerraformSubcommands: true
  autoApprove: true
  backendConfig:
    profile: my-profile
    region: us-east-1
    bucket: my-remote-state-bucket
    key: "project/{{ target.name }}/terraform.tfstate"
    dynamodb_table: my-remote-state-lock-table
targets:
  dev:
  prod:
hooks:
  # This hook is useful when running multiple targets which have different backend configurations.
  beforeTerraform: init -reconfigure
terrascript "*" apply
# `terraform init -reconfigure \
#     -backend-config=profile=my-profile \
#     -backend-config=region=us-east-1 \
#     -backend-config=bucket=my-remote-state-bucket \
#     -backend-config=key=project/dev/terraform.tfstate \
#     -backend-config=dynamodb_table=my-remote-state-lock-table`
# `terraform apply -auto-approve`
# `terraform init -reconfigure \
#     -backend-config=profile=my-profile \
#     -backend-config=region=us-east-1 \
#     -backend-config=bucket=my-remote-state-bucket \
#     -backend-config=key=project/prod/terraform.tfstate \
#     -backend-config=dynamodb_table=my-remote-state-lock-table`
# `terraform apply -auto-approve`
Subprojects

What if I have a bunch of Terraform projects?

Let's say we have a project structure like this:

.
├── terrascript.yml
└── infrastructure/
    ├── subproject1/
    │   ├── terrascript.yml
    │   ├── main.tf
    │   └── ...
    └── subproject2/
        ├── terrascript.yml
        ├── main.tf
        └── ...

And the terrascript.yml files look like this:

# ./terrascript.yml
plugins:
  - "@joshwycuff/terrascript-plugin-terraform"
terraform:
  shorthandTerraformSubcommands: true
subprojects:
  subproject1: ./infrastructure/subproject1/
  subproject2: ./infrastructure/subproject2/
# ./infrastructure/subproject1/terrascript.yml
targets:
  dev:
  prod:
# ./infrastructure/subproject2/terrascript.yml
targets:
  dev:
  prod:

To run the dev target for just subproject1:

terrascript subproject1/dev apply

To run the dev target for all subprojects:

terrascript dev apply

To run all targets for all subprojects:

terrascript "*" apply

Note that since the top-level terrascript.yml does not contain any targets, these commands are not run there. It simply passes the commands down to its subprojects.

Also note that glob patterns apply to both subprojects and targets.

Inheritance

Subprojects inherit yaml configuration from parent projects. This applies to every supported key with the notable exceptions of subprojects and targets. This means that backendConfig (and pretty much anything else) set in the top-level terrascript.yml file is also found in lower-level subprojects at runtime. Values in subprojects override inherited values (just as target-level values will override everything else).

Let's make a more complicated project.

.
├── terrascript.yml
└── infrastructure/
    ├── subproject1/
    │   ├── terrascript.yml
    │   ├── subproject1a/
    │   │   ├── terrascript.yml
    │   │   ├── main.tf
    │   │   └── ...
    │   └── subproject1b/
    │       ├── terrascript.yml
    │       ├── main.tf
    │       └── ...
    └── subproject2/
        ├── terrascript.yml
        ├── subproject2a/
        │   ├── terrascript.yml
        │   ├── main.tf
        │   └── ...
        └── subproject2b/
            ├── terrascript.yml
            ├── main.tf
            └── ...

The terrascript files might look something like:

# ./terrascript.yml
# Note that the key below has no special significance to Terraform or Terrascript. It's simply a
# stored value that gets passed down via inheritance and is useful for templating (as you can see
# in the backend key below).
projectName: project
subprojects:
  subproject1: ./infrastructure/subproject1/
  subproject2: ./infrastructure/subproject2/
config:
  autoApprove: true
  backendConfig:
    profile: my-profile
    region: us-east-1
    bucket: my-remote-state-bucket
    # this key would come out to something like: project/subproject1/subproject1a/dev/terraform.tfstate
    key: "{{ spec.projectName }}/{{ spec.subprojectName }}/{{ spec.name }}/{{ target.name }}/terraform.tfstate"
    dynamodb_table: my-remote-state-lock-table
  tfVars:
    environment: "{{ target.name }}" # This input variable would apply to every subproject.
hooks:
  # This hook is useful when running multiple targets which have different backend configurations.
  beforeTarget: init -reconfigure
# ./subproject1/terrascript.yml
subprojectName: subproject1
subprojects:
  subproject1a: ./subproject1a/
  subproject1b: ./subproject1b/
config:
  tfVars:
    someName: someValue # this is an input variable that applies to all of subproject1 including its subprojects
# ./subproject1/subproject1a/terrascript.yml
config:
  tfVars:
    someNameFor1a: someValueFor1a # this is an input variable that applies only to subproject1a
targets:
  dev:
  prod:

You can see that this project has a more nested structure where different subprojects have different configuration needs but there are common elements that can be templated and passed down through inheritance.

Now, let's say you want to run a command for just subproject1a:

terrascript subproject1/subproject1a/dev apply # note that we don't need to init since we've got that hook

What if, for some reason, I wanted to run a command for only subprojects ending in "b"?

terrascript "*/*b/dev" apply  # note that the quotes are needed because of the asterisks

Can I run dev for all subprojects? Yep.

terrascript dev apply

Can I run every target for every subproject? Yep.

terrascript "*" apply
Just so you know, the terraform commands that were automated with that last command look like this...
cd ./infrastructure/subproject1/subproject1a/
terraform init -reconfigure \
    -backend-config=profile=my-profile \
    -backend-config=region=us-east-1 \
    -backend-config=bucket=my-remote-state-bucket \
    -backend-config=key=project/subproject1/subproject1a/dev/terraform.tfstate \
    -backend-config=dynamodb_table=my-remote-state-lock-table
terraform apply -auto-approve \
    -var=environment=dev \
    -var=someName=someValue \
    -var=someNameFor1a=someValueFor1a
terraform init -reconfigure \
    -backend-config=profile=my-profile \
    -backend-config=region=us-east-1 \
    -backend-config=bucket=my-remote-state-bucket \
    -backend-config=key=project/subproject1/subproject1a/prod/terraform.tfstate \
    -backend-config=dynamodb_table=my-remote-state-lock-table
terraform apply -auto-approve \
    -var=environment=prod \
    -var=someName=someValue \
    -var=someNameFor1a=someValueFor1a
cd ../../infrastructure/subproject1/subproject1b/
terraform init -reconfigure \
    -backend-config=profile=my-profile \
    -backend-config=region=us-east-1 \
    -backend-config=bucket=my-remote-state-bucket \
    -backend-config=key=project/subproject1/subproject1b/dev/terraform.tfstate \
    -backend-config=dynamodb_table=my-remote-state-lock-table
terraform apply -auto-approve \
    -var=environment=dev \
    -var=someName=someValue
terraform init -reconfigure \
    -backend-config=profile=my-profile \
    -backend-config=region=us-east-1 \
    -backend-config=bucket=my-remote-state-bucket \
    -backend-config=key=project/subproject1/subproject1b/prod/terraform.tfstate \
    -backend-config=dynamodb_table=my-remote-state-lock-table
terraform apply -auto-approve \
    -var=environment=prod \
    -var=someName=someValue
cd ../../infrastructure/subproject2/subproject2a/
terraform init -reconfigure \
    -backend-config=profile=my-profile \
    -backend-config=region=us-east-1 \
    -backend-config=bucket=my-remote-state-bucket \
    -backend-config=key=project/subproject2/subproject2a/dev/terraform.tfstate \
    -backend-config=dynamodb_table=my-remote-state-lock-table
terraform apply -auto-approve \
    -var=environment=dev
terraform init -reconfigure \
    -backend-config=profile=my-profile \
    -backend-config=region=us-east-1 \
    -backend-config=bucket=my-remote-state-bucket \
    -backend-config=key=project/subproject2/subproject2a/prod/terraform.tfstate \
    -backend-config=dynamodb_table=my-remote-state-lock-table
terraform apply -auto-approve \
    -var=environment=prod
cd ../../infrastructure/subproject2/subproject2b/
terraform init -reconfigure \
    -backend-config=profile=my-profile \
    -backend-config=region=us-east-1 \
    -backend-config=bucket=my-remote-state-bucket \
    -backend-config=key=project/subproject2/subproject2b/dev/terraform.tfstate \
    -backend-config=dynamodb_table=my-remote-state-lock-table
terraform apply -auto-approve \
    -var=environment=dev
terraform init -reconfigure \
    -backend-config=profile=my-profile \
    -backend-config=region=us-east-1 \
    -backend-config=bucket=my-remote-state-bucket \
    -backend-config=key=project/subproject2/subproject2b/prod/terraform.tfstate \
    -backend-config=dynamodb_table=my-remote-state-lock-table
terraform apply -auto-approve \
    -var=environment=prod

Readme

Keywords

none

Package Sidebar

Install

npm i @joshwycuff/terrascript-plugin-terraform

Weekly Downloads

9

Version

1.0.2

License

ISC

Unpacked Size

25.2 kB

Total Files

9

Last publish

Collaborators

  • joshwycuff