04. 型
Terraform は型を持っています。値を厳密に書ける言語ほど、apply 前にミスを気付けます。型の階層を 1 度頭に入れると、variable の宣言や data の出力を読むのが格段に楽になります。
型の全体像
type
├── string / number / bool ← プリミティブ
├── list(T) / set(T) / map(T) ← コレクション(中身は同じ型)
├── tuple([T1, T2, ...]) ← 構造型(順序固定、要素ごとに型違い OK)
├── object({a=T1, b=T2, ...}) ← 構造型(名前付き、属性ごとに型違い OK)
└── any ← 何でも(型推論を投げる)
プリミティブ型
variable "name" { type = string } # "hello"
variable "size" { type = number } # 30, 6.5
variable "enabled" { type = bool } # true / false
文字列と数値は自動変換されます("15" → 15)。これが効きすぎて気付かないバグを生むこともあるので、type は明示しておくのが吉。
コレクション型(list / set / map)
list(T)
順序付きの並び。インデックス(0 始まり)でアクセス。
variable "azs" {
type = list(string)
default = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
}
# var.azs[0] == "ap-northeast-1a"
set(T)
順序なし、重複なし。for_each や、aws_iam_role_policy_attachment のような「一意な集合」を扱う時に便利。
variable "users" {
type = set(string)
default = ["alice", "bob", "carol"]
}
map(T)
キー(string)と値(T 型)のペア。タグなどでよく使う。
variable "tags" {
type = map(string)
default = {
Project = "hcl-guide"
Env = "dev"
}
}
# var.tags["Project"] == "hcl-guide"
構造型(object / tuple)
コレクション型は「中身が全部同じ型」が前提でした。属性ごとに違う型を持つときは 構造型 を使います。
object
variable "user" {
type = object({
name = string
age = number
is_admin = bool
languages = list(string)
})
default = {
name = "Alice"
age = 30
is_admin = true
languages = ["ja", "en"]
}
}
# var.user.name == "Alice"
tuple
順序固定の異種コレクション。要素数も型も完全に決まっている。
variable "coord" {
type = tuple([number, number, string])
default = [35.6812, 139.7671, "Tokyo"]
}
# var.coord[0] == 35.6812
実務では tuple よりも object のほうが自己説明的で使われやすいです。
optional() で省略可能属性
object 型の属性を「省略してよい」と宣言できます。デフォルト値も指定可能。
variable "subnets" {
type = list(object({
cidr_block = string
availability_zone = string
is_public = optional(bool, false) # 省略時 false
tags = optional(map(string)) # 省略時 null
}))
}
# 呼び出し側
# subnets = [
# { cidr_block = "10.0.1.0/24", availability_zone = "ap-northeast-1a", is_public = true },
# { cidr_block = "10.0.2.0/24", availability_zone = "ap-northeast-1c" } ← is_public 省略
# ]
よく効く場面
モジュールの入力変数で、「ほぼデフォルトでよくて、たまに上書きしたい」 パターンに最適。
optional() がないと、呼び出し側にすべての属性を書かせる羽目になる。
any(最終手段)
型推論を放棄するキーワード。便利そうに見えますが、型エラーを apply まで遅延させるだけ なので公式は控えめにと言っています。
variable "config" {
type = any
}
使うべき場面: 別システムにそのまま JSON で流すような、「中身を Terraform で見ない」値。
型変換
近い型は自動変換されます。明示的に変換したい時は関数で:
tostring(123) # "123"
tonumber("3.14") # 3.14
tobool("true") # true
tolist(["a", "b"]) # list(string)
toset(["a", "a"]) # set(string) ← 重複排除
tomap({a = 1, b = 2}) # map(number)