「Upgrading to Terraform v0.12」を実施した際の備忘録メモ


## はじめに

主に公式ドキュメントを参考に、Terraform v0.11系からv0.12系へアップグレードした際の備忘録メモになります。
[Upgrading to Terraform v0.12](https://www.terraform.io/upgrade-guides/0-12.html)

また、今回アップグレードを行なったのはこちらのリポジトリをforkしたリポジトリです。
https://github.com/collectivehealth/terraform-emr-spark-example

## 手順

1. tfenvでv0.11.14とv0.12系を用意
3. `terraform 0.12checklist`でアップグレード事前チェック
4. v0.12系にバージョンアップして`terraform init`を実行
5. `terraform 0.12upgrade`で構文置換

## 各手順のメモ

### tfenvでv0.11.14とv0.12系を用意

tfenvを使うとバージョンの切り替えが簡単に行えるため、これを使います。
https://github.com/tfutils/tfenv

```
$ tfenv install 0.11.14
$ tfenv install 0.12.6
$ tfenv use 0.11.14
$ tfenv list
  0.12.6
* 0.11.14 (set by /usr/local/Cellar/tfenv/1.0.1/version)
```

また、tfファイルをv0.11.14に対応させておきます。

### `terraform 0.12checklist`でアップグレード事前チェック

v0.11.14には`0.12checklist`というコマンドがあり、このコマンドを利用してv0.12系にアップグレードする前に事前チェックを行います。

```
$ terraform 0.12checklist
After analyzing this configuration and working directory, 
we have identified some necessary steps that we recommend you take before upgrading to Terraform v0.12:

- [ ] Upgrade provider "aws" to version 2.40.0 or newer.
  
  No currently-installed version is compatible with Terraform 0.12. 
To upgrade, set the version constraint for this provider as follows and then run `terraform init`:
  
      version = "~> 2.40.0"

- [ ] Upgrade provider "random" to version 2.2.1 or newer.
  
  No currently-installed version is compatible with Terraform 0.12. 
To upgrade, set the version constraint for this provider as follows and then run `terraform init`:
  
      version = "~> 2.2.1"

- [ ] Upgrade provider "template" to version 2.1.2 or newer.
  
  No currently-installed version is compatible with Terraform 0.12. 
To upgrade, set the version constraint for this provider as follows and then run `terraform init`:
  
      version = "~> 2.1.2"

- [ ] Upgrade provider "tls" to version 2.1.1 or newer.
  
  No currently-installed version is compatible with Terraform 0.12. 
To upgrade, set the version constraint for this provider as follows and then run `terraform init`:
  
      version = "~> 2.1.1"

# Module `"bootstrap"`

# Module `"emr"`

# Module `"lb"`

# Module `"s3"`

# Module `"sec"`

# Module `"sgs"`

Taking these steps before upgrading to Terraform v0.12 will simplify the upgrade process by avoiding syntax errors and other compatibility problems.
```

今回は4つのProviderがv0.12系と互換性がないとのことだったので、バージョン制約を指示通りに変更し、`terraform init`を実施しました。
問題がなくなると以下のメッセージが表示されます。


```
Looks good! We did not detect any problems that ought to be
addressed before upgrading to Terraform v0.12.

This tool is not perfect though, so please check the v0.12 upgrade
guide for additional guidance, and for next steps:
    https://www.terraform.io/upgrade-guides/0-12.html
```


### v0.12系にバージョンアップして`terraform init`を実行

tfenvでバージョン切り替えて、

```
$ tfenv use 0.12.6
$ tfenv list
* 0.12.6 (set by /usr/local/Cellar/tfenv/1.0.1/version)
  0.11.14
```

`terraform init`を実行。

```
$ terraform init
There are some problems with the configuration, described below.

The Terraform configuration must be valid before initialization so that
Terraform can determine which modules and providers need to be installed.

Error: Extraneous label for provider

  on config.tf line 5, in provider "aws" "aws":
   5: provider "aws" "aws" {

Only 1 labels (name) are expected for provider blocks.


Error: Extraneous label for provider

  on config.tf line 10, in provider "random" "random":
  10: provider "random" "random" {

Only 1 labels (name) are expected for provider blocks.


Error: Extraneous label for provider

  on config.tf line 14, in provider "template" "template":
  14: provider "template" "template" {

Only 1 labels (name) are expected for provider blocks.


Error: Extraneous label for provider

  on config.tf line 18, in provider "archive" "archive":
  18: provider "archive" "archive" {

Only 1 labels (name) are expected for provider blocks.


Error: Extraneous label for provider

  on config.tf line 22, in provider "tls" "tls":
  22: provider "tls" "tls" {

Only 1 labels (name) are expected for provider blocks.


Error: Extraneous label for provider

  on config.tf line 26, in provider "http" "http":
  26: provider "http" "http" {

Only 1 labels (name) are expected for provider blocks.


Error: Extraneous label for provider

  on config.tf line 30, in provider "local" "local":
  30: provider "local" "local" {

Only 1 labels (name) are expected for provider blocks.
```

providerブロックが互換性のないコードとなっていたため、修正しました。

```diff:awsのprovider
-provider "aws" "aws" {
+provider "aws" {
```

### `terraform 0.12upgrade`で構文置換

v0.12系には`0.12upgrade`というコマンドがあり、このコマンドを利用してv0.12系の構文への置換を行います。

```
$ terraform 0.12upgrade

This command will rewrite the configuration files in the given directory so
that they use the new syntax features from Terraform v0.12, and will identify
any constructs that may need to be adjusted for correct operation with
Terraform v0.12.

We recommend using this command in a clean version control work tree, so that
you can easily see the proposed changes as a diff against the latest commit.
If you have uncommited changes already present, we recommend aborting this
command and dealing with them before running this command again.

Would you like to upgrade the module in the current directory?
  Only 'yes' will be accepted to confirm.

  Enter a value: 
```

`yes`と入力することで、書き換えが実行されます。
完了すると以下のメッセージが表示されます。

```
Upgrade complete!

The configuration files were upgraded successfully. Use your version control
system to review the proposed changes, make any necessary adjustments, and
then commit.
```

アップグレードがすでに済んでいると以下のようなエラーが出ます。

```
$ terraform 0.12upgrade

Error: Module already upgraded

  on versions.tf line 3, in terraform:
   3:   required_version = ">= 0.12"

The module in directory . has a version constraint that suggests it has
already been upgraded for v0.12. If this is incorrect, either remove this
constraint or override this heuristic with the -force argument. Upgrading a
module that was already upgraded may change the meaning of that module.
```

今回はありませんでしたが、手動で変更しないといけない箇所があったりするとのことです。
また、`0.12upgrade`コマンドで不便な点としては、以下が挙げられます。

- ファイル末尾に空行が追加されてしまう
    - https://github.com/hashicorp/terraform/issues/21428
- カレントディレクトリのtfファイルしか変更してくれない
- 実行したディレクトリに`versions.tf`が作成される

## Providerのアップグレード

`terraform init`コマンドに`-upgrade`オプションを指定することで、バージョン制約を満たす最新のプロバイダにアップグレードすることができます。

```
$ terraform init -upgrade
Upgrading modules...
- bootstrap in modules/bootstrap
- emr in modules/emr
- lb in modules/lb
- s3 in modules/s3
- sec in modules/sec
- sgs in modules/sgs

Initializing the backend...

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "archive" (hashicorp/archive) 1.3.0...
- Downloading plugin for provider "tls" (hashicorp/tls) 2.1.1...
- Downloading plugin for provider "http" (hashicorp/http) 1.1.1...
- Downloading plugin for provider "local" (hashicorp/local) 1.4.0...
- Downloading plugin for provider "aws" (hashicorp/aws) 2.40.0...
- Downloading plugin for provider "random" (hashicorp/random) 2.2.1...
- Downloading plugin for provider "template" (hashicorp/template) 2.1.2...
```

## 参考

Terraform 0.12がリリースされたのでアップグレードしてみた
https://dev.classmethod.jp/tool/terraform-upgrade-from-0-11-to-0-12/

Terraform職人入門: 日々の運用で学んだ知見を淡々とまとめる
https://qiita.com/minamijoyo/items/1f57c62bed781ab8f4d7