Skip to content

Commit

Permalink
feat: tfupdate
Browse files Browse the repository at this point in the history
  • Loading branch information
jrottenberg committed Feb 20, 2022
1 parent 71647bb commit b4ee836
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 2 deletions.
12 changes: 11 additions & 1 deletion .pre-commit-hooks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
- id: checkov
name: Checkov
description: Runs checkov on Terraform templates.
entry: hooks/checkov -d .
entry: checkov -d .
language: python
pass_filenames: false
always_run: false
Expand All @@ -111,3 +111,13 @@
files: \.tf$
exclude: \.terraform\/.*$
require_serial: true

- id: tfupdate
name: tfupdate
description: Runs tfupdate on Terraform templates.
language: script
entry: hooks/tfupdate.sh
require_serial: true
files: \.tf$
pass_filenames: false
args: ["terraform"]
74 changes: 73 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ If you are using `pre-commit-terraform` already or want to support its developme
* [terraform_tfsec](#terraform_tfsec)
* [terraform_validate](#terraform_validate)
* [terrascan](#terrascan)
* [tfupdate](#tfupdate)
* [Authors](#authors)
* [License](#license)

Expand Down Expand Up @@ -224,7 +225,8 @@ There are several [pre-commit](https://pre-commit.com/) hooks to keep Terraform
| `terraform_validate` | Validates all Terraform configuration files. [Hook notes](#terraform_validate) | - |
| `terragrunt_fmt` | Reformat all [Terragrunt](https://github.com/gruntwork-io/terragrunt) configuration files (`*.hcl`) to a canonical format. | `terragrunt` |
| `terragrunt_validate` | Validates all [Terragrunt](https://github.com/gruntwork-io/terragrunt) configuration files (`*.hcl`) | `terragrunt` |
| `terrascan` | [terrascan](https://github.com/accurics/terrascan) Detect compliance and security violations. [Hook notes](#terrascan) | `terrascan` |
| `terrascan` | [terrascan](https://github.com/accurics/terrascan) Detect compliance and security violations. [Hook notes](#terrascan) | `terrascan` |
| `tfupdate` | [tfupdate](https://github.com/minamijoyo/tfupdate) Update version constraints of Terraform core, providers, and modules. [Hook notes](#tfupdate) | `tfupdate` |
<!-- markdownlint-enable no-inline-html -->

Check the [source file](https://github.com/antonbabenko/pre-commit-terraform/blob/master/.pre-commit-hooks.yaml) to know arguments used for each hook.
Expand Down Expand Up @@ -551,6 +553,55 @@ Example:

**Warning:** If you use Terraform workspaces, DO NOT use this workaround ([details](https://github.com/antonbabenko/pre-commit-terraform/issues/203#issuecomment-918791847)). Wait to [`force-init`](https://github.com/antonbabenko/pre-commit-terraform/issues/224) option implementation.

5. `terraform_validate` in a repo with Terraform module, written using Terraform 0.15+ and which uses provider `configuration_aliases` ([Provider Aliases Within Modules](https://www.terraform.io/language/modules/develop/providers#provider-aliases-within-modules)), errors out.

When running the hook against Terraform code where you have provider `configuration_aliases` defined in a `required_providers` configuration block, terraform will throw an error like:
>
>
> Error: Provider configuration not present
> To work with <resource> its original provider configuration at provider["registry.terraform.io/hashicorp/aws"].<provider_alias> is required, but it has been removed. This occurs when a provider configuration is removed while
> objects created by that provider still exist in the state. Re-add the provider configuration to destroy <resource>, after which you can remove the provider configuration again.

This is a [known issue](https://github.com/hashicorp/terraform/issues/28490) with Terraform and how providers are initialized in Terraform 0.15 and later. To work around this you can add an `exclude` parameter to the configuration of `terraform_validate` hook like this:
```yaml
- id: terraform_validate
exclude: [^/]+$
```
This will exclude the root directory from being processed by this hook. Then add a subdirectory like "examples" or "tests" and put an example implementation in place that defines the providers with the proper aliases, and this will give you validation of your module through the example. If instead you are using this with multiple modules in one repository you'll want to set the path prefix in the regular expression, such as `exclude: modules/offendingmodule/[^/]+$`.

Alternately, you can use [terraform-config-inspect](https://github.com/hashicorp/terraform-config-inspect) and use a variant of [this script](https://github.com/bendrucker/terraform-configuration-aliases-action/blob/main/providers.sh) to generate a providers file at runtime:

```bash
terraform-config-inspect --json . | jq -r '
[.required_providers[].aliases]
| flatten
| del(.[] | select(. == null))
| reduce .[] as $entry (
{};
.provider[$entry.name] //= [] | .provider[$entry.name] += [{"alias": $entry.alias}]
)
' | tee aliased-providers.tf.json
```

Save it as `.generate-providers.sh` in the root of your repository and add a `pre-commit` hook to run it before all other hooks, like so:
```yaml
- repos:
- repo: local
hooks:
- id: generate-terraform-providers
name: generate-terraform-providers
require_serial: true
entry: .generate-providers.sh
language: script
files: \.tf(vars)?$
pass_filenames: false
- repo: https://github.com/pre-commit/pre-commit-hooks
[...]
```

**Note:** The latter method will leave an "aliased-providers.tf.json" file in your repo. You will either want to automate a way to clean this up or add it to your `.gitignore` or both.

### terrascan

1. `terrascan` supports custom arguments so you can pass supported flags like `--non-recursive` and `--policy-type` to disable recursive inspection and set the policy type respectively:
Expand All @@ -568,6 +619,27 @@ Example:
3. Use `--skip-rules="ruleID1,ruleID2"` parameter to skip one or more rules globally while scanning (e.g.: `--args=--skip-rules="ruleID1,ruleID2"`).
4. Use the syntax `#ts:skip=RuleID optional_comment` inside a resource to skip the rule for that resource.

### tfupdate

Out of the box tfupdate will pin the terraform version

```yaml
- id: tfupdate
```

But you can pass `tfupdate` custom commands like `provider ${PROVIDER_NAME}` :

```yaml
- id: tfupdate
name: tfupdate terraform
- id: tfupdate
name: tfupdate provider vsphere
args:
- provider
- vsphere
```
See the `tfupdate --help` command line help for available options. No need to pass `--recursive .` as it is added automatically

## Authors

This repository is managed by [Anton Babenko](https://github.com/antonbabenko) with help from these awesome contributors:
Expand Down
26 changes: 26 additions & 0 deletions hooks/tfupdate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -eo pipefail

# shellcheck disable=SC2155 # No way to assign to readonly variable in separate lines
readonly SCRIPT_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]}")")"
# shellcheck source=_common.sh
source "$SCRIPT_DIR/_common.sh"

function main {
common::initialize "$SCRIPT_DIR"
tfupdate_ "$@"
}

#######################################################################
# tfupdate_
#######################################################################
function tfupdate_ {
local -r args=$*
# pass the arguments to hook
# shellcheck disable=SC2086 # Double quote to prevent globbing and word splitting.
tfupdate ${args} --recursive .
local exit_code=$?
return $exit_code
}

[ "${BASH_SOURCE[0]}" != "$0" ] || main "$@"

0 comments on commit b4ee836

Please sign in to comment.