Terraformの型と式

目次

Terraformの型

プリミティブ型

この型は他の型から作成されていない単純な型です。typeキーワードによって表されます。

  • 文字列型 (string)
    • Unicode文字が指定できる。
    • 長文は “EOF”修飾子で指定可能。
variable "hoge" {
  type = string
}
hoge = "fuga" # or
hoge = <<EOF
長文...
EOF
  • 数値型 (number)
    • 数値、小数値の両方が利用できる。
variable "hoge" {
  type = number
}
hoge = 123 # or
hoge = 3.14
  • 真偽値 (bool)
    • 条件付きロジックで使用できる。
variable "hoge" {
  type = bool
}
hoge = true
  • 暗黙的な型変換
    • Terraformは異なる型であっても条件が合えば型変換が行われます。
    • 変換例
variable "hoge" {
  type = bool
}
hoge = "true" # OK

variable "fuga" {
  type = number
}
fuga = "100" # OK

variable "piyo" {
  type = string
}
fuga = 100 # OK

複合型

コレクション型

  • 他の型の複数の値を1つの値としてまとめることができる。

  • コレクション内の値の型を要素型といい、全ての要素型は同じである。

  • コンストラクタの引数で指定する。

  • list

    • 宣言: list(type), list は list(any)の省略形だが、後方互換性のためであるため、型の指定をすること。
    • 各値はインデックス数値で指定可能。
variable "hoge" {
  type = list(string)
}
hoge = ["us-west-1a", "us-west-1c"]
hoge[1] # = "us-west-1c"
  • map
    • 宣言: map(type), map は map(any)の省略形。
    • キーは文字列または数字が指定可能。
variable "hoge" {
  type = map(number)
}
hoge = {
  key = 1
  1 = 3.14
}
hoge.key # 1
hoge.1 # 3.14
  • set
    • 宣言: set(type)
    • 要素は一意性を持つ。
variable "hoge" {
  type = set(number)
}

構造型

  • object
    • KeyValueごとに別の型を持つコレクション
variable "hoge" {
  type = object({
    key1 = string
    key2 = number
  })
}
hoge = {
  key1 = "bar"
  key2 = 100
}
  • tuple
    • 異なる要素型を持つ固定調コレクション
variable "hoge" {
  type = tuple([string, number, bool])
}
hoge = ["bar", 100, true]

複合型の組み合わせ

list, objectなどの複合型は組み合わて利用することができます。

variable "hoge" {
  type = list(object{
    key1 = string
    key2 = number
  })
}
hoge = [
  {
    key1 = "bar"
    key2 = 100
  },
  ...
]

補足

通常の利用においてはリストとタプル、マップとオブジェクトは混同して利用されることが多いです。 これらの区別を行うのは、モジュールの入力の型を制限したい場合に有用です。

特殊な値

  • null

    • 不在や省略を表す値
    • NULL は条件式で有用で、条件が満たされない場合に動的に引数を省略することができる。
  • any

    • 任意の型を表す。
    • ただし、list(any) は同じ要素型である必要があるように、複合型は型ごとに制約があるので、その制約に従う必要がある。

Terraformの式

演算子

算術演算子

  • 足し算: a + b
  • 引き算: a - b
  • 掛け算: a * b
  • 割り算: a / b
  • 剰余算: a % b
  • 反転: -a = a * -1

等号

  • 等しい: a == b
  • 異なる: a != b

構造体の比較では型が明確でない場合において、予期しない結果になる可能性がある。

例えば var.list == [] はvar.listが空リストであれば真を返すように見えるかもしれないが、実際には [] は タプル型の値を構築するので、偽が返ります。 このような場合では length(var.list) == 0 と書くべきでしょう。

比較演算子

  • a < b
  • a < = b
  • a > b
  • a > = b

論理演算子

  • AまたはB: a || b
  • AかつB: a && b
  • 否定: !a

関数

Terraformの組み込み関数は多数ありますが、以下の通り共通した構文となっています。

<FUNCTION NAME>(<ARGUMENT 1>, <ARGUMENT 2>)

min(55, 3453, 2) # 2

組み込み関数一覧

引数の展開

関数の引数にリストまたはタプル型を渡したい場合は、展開記法(...)を利用することでそのまま利用できます。

min([5, 10, 1]...) # 1

For式

  • 他言語のMap関数のように、要素型を別の型に変換することができる。
  • for式はlist, map, set, object, tupleの複合型で利用可能。
    • 参照された要素型のKeyとValueはそれぞれ変数として格納される。(Keyは省略可)
  • listに利用する場合は、インデックス番号がkeyとして参照可能。(変数名はi or idxとするのが慣例)
  • 出力する型はfor式を囲む記号で変更ができる。
    • [ ] ではタプルを、 { } ではオブジェクトを出力する。

以下の例は、list型のhogeの各string要素をupper関数で大文字にしたタプル型を生成する。

variable "hoge" {
  type = list(string)
  default = ["a", "b"]
}

[for v in var.hoge : upper(v)] # ["A", "B"]
variable "hoge" {
  type = map(string)
  default = {
    "key" = huga
  }
}

[for k, v in var.hoge : "${k}_${v}"] # ["key_fuga"]
{for s in var.hoge : s => upper(s) } # { "key": "FUGA" }

フィルタリング

  • for式で if を含めると要素をフィルターすることができます。
variable "users" {
  type = map(object({
    is_admin = bool
  }))
}

locals {
  admin_users = {
    for name, user in var.users : name => user
    if user.is_admin
  }
  regular_users = {
    for name, user in var.users : name => user
    if !user.is_admin
  }
}

要素の並び順

  • for式は順書のある型に変換できるので、順序のないコレクション要素で利用する際は暗黙の順序を選択する必要がある。
    • map, objectの場合は、キー名, 属性名でソートされます。
    • 文字列型の場合は、文字列でソートされます。
    • その他のコレクションは任意の順序でソートされます。そのため順序付けされていないことを明示的に表すためにfor式の結果をset型に変換しておくことをおすすめします。
toset([for e in var.set : e.example])

要素のグループ化

  • for式でobject型を出力するとき、キー名は一意である必要がありますが、式の結果が重複する可能性がある場合はグループ化を行い対応します。

例えば、ユーザー名をキーとするmapがあり、バリューにroleを示すobjectを持つ変数があるとき、for式でロールごとにユーザー名をまとめる場合、ロール名がキーとして重複しますが、for式でグループ化表記(...)を用いるととで対処できます。

variable "users" {
  type = map(object({
    role = string
  }))
  default = {
    "taro" = {
      role: "general"
    }
    "zijo" = {
      role: "admin"
    }
    "hanako" = {
      role: "general"
    }
  }
}
locals {
  users_by_role = {
    for name, user in var.users : user.role => name...
  }
}
# result
{
  "admin": [
    "zijo"
  ],
  "general": [
    "taro",
    "hanako"
  ]
}

ダイナミックブロック

  • 通常、リソースブロックはリテラルまたは変数の値の参照によるパラメータ指定を行いますが、コレクションの各要素を反映したブロックの定義はダイナミックブロックを用いて行うことができます。
  • for式に似た挙動で、リソースブロックまたはネストされたブロックを生成することができます。
  • 利用できるブロックは、リソースタイプ、データソース、プロバイダ、プロビジョナーに属する引数です。
resource "aws_elastic_beanstalk_environment" "tfenvtest" {
  name                = "tf-test-name"
  application         = "${aws_elastic_beanstalk_application.tftest.name}"
  solution_stack_name = "64bit Amazon Linux 2018.03 v2.11.4 running Go 1.12.6"

  dynamic "setting" {
    for_each = var.settings
    content {
      namespace = setting.value["namespace"]
      name = setting.value["name"]
      value = setting.value["value"]
    }
  }
}
  • dynamic表記に続いてブロックの種類のラベル(例では”setting”)を指定する。
  • for_eachに反復可能なコレクションを指定します。ネストさせたいブロックごとに1つの要素を持つコレクションでなければならない。
  • contentブロックでコレクションの各要素の変数を使用できる。デフォルトではラベル名が変数として割り当てられています。参照できる値はkey, valueです。
    • setを用いる場合はkey, valueが同じ値となります。