Terraform 0.12.0 がリリースされ、すでに 0.12.1 がリリースされました。 いくつかのTerraform 環境で随時0.11.14 から 0.12.0 にアップグレードしているのですが、その中で AzureRM Provider に関して少し困ったのでメモしておきます。
目次
TL;DR
基本は、Upgrade Guide をみること。
~破壊的変更として、タグの一部を無視できなくなっているので、タグすべてを無視して直変更なりで一時しのぎが良さそう。~ 0.12.3 で対処が入ったので一部無視が可能になり互換性とれるようになりました。
tfenv を入れておくとめちゃめちゃ捗るので、これまで入れてなかった人はこれを気に入れておくとよいです。
操作環境
私は普段、Terraform を5つの環境で動作できるように組んでいます。*1 もっぱらGitHub PR でのCI連携をするので、Docker(Atlantis) なのですが環境によっては Azure Cloud Shell が最も利用しやすい場合はこちらを利用します。
- Windows 10 Desktop
- WSL Ubuntu 18.04
- macOS 10.14 Mojave
- Azure CloudShell
- Docker Container (Atlantis)
さて、Azure Cloud Shell 環境はTerraform をはじめとする各種ツールが組み込みで入っており、ツールのアップグレードも勝手にされます。 つまり、おもむろにバージョンが上がります。
運用面を除外すると便利です。 一方で、0.12.0 のような破壊的変更が加わったタイミングでは、ツールのアップデート時に速やかに追随できるように整えておくのも重要になります。
今回は、0.11.14 なterraform 構成をCloudShell で当てようとしたタイミングで0.12.0にアップグレードされており*2 サクッと対応する必要があったのでした。
アップグレードの流れ
- tfenv で0.11.14 にしておいて、
terrafrom 0.12checklist
で確認とエラーを潰していく - Provider が0.12に対応していない場合があるので、バージョンを上げて 0.12でinit できるかで確認する
- tfenvで0.12.0 (あるいは0.12.1)にして、
terraform 0.12upgrade
をかけて微妙に拾えてなかったシンタックスの変更を潰す 0.12upgrade で変更されないModuleが中にはいるので、手でちまちま治す。 terraform plan
かけて変更でなかればまず大丈夫- atlantis など適用環境で terraform apply かけて出力を確認して終わり
よく引っかかる変更点
先に、0.12 の変更点だけ見ておくといいです。
さて、次のものは度々0.12.0にアップグレード対応するたびに、あぁまたこれかという感じで引っ掛かります。
Provider not support 0.12
単純にアップグレードすればok なことが多いですが、サポートされているかの確認はしましょう。
azurerm provider なら次のようにかなり細かく出ています。
Argument names must not be quoted
Terraform 0.11.14までは、map や リソース内のblock・map のハンドルが微妙にゆるふわでした。 これが、0.12 から比較的しっかり見るようになっています。
結果、例えばこういったmap 宣言が0.11.14まではokでしたが、
locals { common_tags { environment = "${var.ENV}" } }
0.12.0 からは、 =
が必須になっています。
locals { common_tags = { environment = var.ENV } }
あるいは、AzureRM Provider の azurerm_function_app などが提供する identity ブロックもそうです。
0.11.14まではこれがokでした。
identity = { type = "SystemAssigned" }
0.12.0 からはこうなります。
identity { type = "SystemAssigned" }
Resource の Deprecation
たとえば、azurerm provider の data resource である azurerm_builtin_role_definition
は deprecate が予定されており、azurerm_role_definition
を使うように促されます。
0.11.14 まで
data "azurerm_builtin_role_definition" "contributor" { name = "Contributor" }
data "azurerm_role_definition" "contributor" { name = "Contributor" }
Resource の返す型から値取り出し時の注意
list
たとえば、azurerm_fucntion_app リソースが返す identity から principal_id を取得することを考えてみましょう。
これは次で 0.11.14 / 0.12 ともにとれます。
output identity { value = "${lookup(azurerm_function_app.main.identity[0], "principal_id")}" }
しかし、モジュールの外でこの形式で取りたいがために、次のようにリストにラップしていると 0.12.0 では破壊的変更となります。
// Output of Module output identity { value = ["${azurerm_function_app.main.identity}"] }
0.11.14 まではこのようにして、identity の list からmap で拾えば取れましたが、0.12.0 では取れません。
// Get Principal from module output output "api_functionapp_msi_identity" { value = "${lookup(module.functionapp.identity[0], "principal_id")}" }
この小細工は意味ないので当初示した例に直しましょう。
このエラーのときに原因がぱっとわからなかったのできびしい。
破壊的変更
0.12.0 で、解消できていない破壊的変更が一件ありますが、これは0.12.3 で解消しました。
lifecycle / ignore_changes blocking upgrade from 0.11 to 0.12 · Issue #21433 · hashicorp/terraform
これは、構文が terraform 0.12upgrade
で変わっていない場合、Attribute name required: Dot must be followed by attribute name.というエラーがでます。
ref: terraform 0.12 remote state : Attribute name required · Issue #20835 · hashicorp/terraform
どんな問題かざっくりいうと、「ignore_changes でattirbuteベースで指定するようになったが、これまで無視していたものが0.12.0 でignoreされなくなった」というものです。
私が直面したのは、Azure Web Apps の appsettings のignore ができないことでした。kubernetes のタグも同じ問題があります。
0.12.0 Error: Attribute name required · Issue #21444 · hashicorp/terraform
Issue の中にある通り、全体の無視はできます。
ignore_changes = [ tags ]
ignore_changes = [ appsettings ]
しかし、その一部だけ無視できません。これはIssueに提示されている tags["kubernetes.io"]
が A static variable reference is required.
でできないことでもわかります。
というか、ignore_changes は静的な指定しかできないのは0.11でもその前からもそうなのに、この回答者はトンチンカンなこと言っててもんにょりなので、もう少し真面目にどうなるのか知りたいです。
なお、TBD 0.12.1 となっていますが 0.12.1 はすでに出ているため、いったんは運用回避しかなさそうです。terraform で値変更せず、コンソールで直変更..... 事故臭しかない。
うれしい構文変化
変数への型の明示
変数の型が増えました。 特に、list や map が変わったのはうれしいでしょう。
文字列だけしかないmap でも、これまで次のような宣言でした。
type = "map"
これが次のように宣言可能になりました。
type = map(string)
うれしいですね。map(list(string)) とかも行けますね。 map(list) が0.11は言語制約上かなり厳しいものがあったので、こういう型制約は言語の表現力、拡張性に寄与するのでうれしいです。
lookup から要素アクセスへ
map の value に対して key でアクセスするときに lookup をしてきましたが、0.12 から[key]
でアクセスが可能になりました。
つまり、0.11まで書いていた次のようなコードが
${lookup(map, "key")}
次のように変わります。
map["key"]
プログラムと違って、ない場合を考慮する必要がなくなければそこで落ちるという割り切りがインフラにはあるので、こういうキーアクセスはちょうどよいです。 lookup 撲滅しました。
VSCode の terraform plugin 対応
hcl2 に追随していないのでIssueが上がっていましたが、すでにPRがマージされたので、もうじきでるんじゃないでしょうか。