Terraformのdefaults Function

Terraform 0.15から導入されたdefaultsですが、まだまだ洗練されていないところが多くてまだ少し使いづらいですね。とはいえ、なんとなく直感的にすっきり書けるので、個人的にはやはり期待大です。

モジュール書くときにコードがすっきりするので視認性がいいんじゃないかなぁと思います。

簡単に使い方を。まあドキュメント読めばいいんですが。

terraform.tf

terraform {
  experiments = [module_variable_optional_attrs]
}

module_variable_optional_attrsはdefaultsに直接的にかかわるものではありませんが、structureにoptionalが使えるようになります。これによって、structureを定義して、その要素をOptionalにすることができるようになります。未定義でもOKってやつですね。

defaults使いたい、って時点で未定義の値をdefaultsでオーバーライト(本当は逆のほうがすっきりするんですが)したい、ということになるので、まああったほうが便利です。ただ、experimentsでわかる通り、まだ実験段階の機構なのでproduct環境に使うのはちょっと。

で、variablesを定義します。

variables.tf

variable "ec2" {
  type = object({
    spot = optional(bool)
    scaling = optional(number)
    max = optional(number)
    min = optional(number)
    volume_size = optional(number)
    volume_type = optional(string)
    volume_iops = optional(number)
  })
}

Structureだけ定義するので、本来なら全要素をtfvarsなどで定義しないといけません。が、今回はoptionalをつけているので、ないならないで問題なしとして進んでくれることとなります。

では、defaultsも定義していきましょう。

locals.tf

locals {
  ec2 = defaults(var.ec2,{
    spot = false
    scaling = 2
    max = 5
    min = 1
    volume_size = 20
    volume_type = "gp3"
    volume_iops = 3000
  })
}

これでec2が未定義の場合のデフォルト値セットが行われます。localsでやるのはうちの仕掛けとしてもとてもありがたい、というか基本的にこの形でvar.hogehogeを使わないので、とてもマッチします。

では最後に、outputsを書いて

outputs.tf

output "ec2" {
  value = local.ec2
}

実行してみます。

ec2 = {
"max" = 5
"min" = 1
"scaling" = 3
"spot" = false
"volume_iops" = 3000
"volume_size" = 20
"volume_type" = "gp3"
}

問題ないですね。じゃあ、とりあえず何か上書きましょう。

terraform apply -var=”ec2={max=10}”

こんな感じですね。もちろん、terraform.tfvarとか使ってもOKです。

ec2 = {
"max" = 10
"min" = 1
"scaling" = 2
"spot" = false
"volume_iops" = 3000
"volume_size" = 20
"volume_type" = "gp3"
}

local.ec2.maxだけ上書かれましたね。従来ですとこのオーバーライトを起こすとec2={max=10}だけになってしまうわけですが、defaultsによってデフォルト値が埋め込まれるわけです。

terraform apply -var="ec2={scaling=10,max=15,volume_size=50}"

ec2 = {
"max" = 15
"min" = 1
"scaling" = 10
"spot" = false
"volume_iops" = 3000
"volume_size" = 50
"volume_type" = "gp3"
}

 

複数個所書き換えても問題ないですね。ただ、何が使いにくいか、というとStructureにoptional(list(string))とかoptional(map(string))とか書いた場合がちょっと正しく動かないんです。細かいことはこのスレッドでやってるんですが、Terraformの内部の変数の保持状態的には正しい動作っぽいんですが、直感的ではない、というところは認識されていて、修正予定のようです。

mergeやcoalescelistを用いて同等の処理を書く方法も書かれていますので、localsへの落とし込みでやればいいんですが、もっと素直に書けるようになったときにdefaultsで書きたいところかなぁと思います。

なかなか便利な機能で、多機能なmodule作るときとか、ちょっとデカめのいろいろを書いてるとすっきり書けるので助かります。

1.0以降はあまり大きな変化はありませんが、やはり0.15での変化は大きいですね。0.15以降のステートメントで書いておけば、しばらくリファクタリングをサボれそうなので、ひとまず頑張ろうと思います!