BioErrorLog Tech Blog

試行錯誤の記録

Terraformのone()関数の振る舞いを理解する

Terraformのone()関数の挙動を整理します。

はじめに

Terraformにはone()関数が用意されています。

端的すぎる命名ということもありパッと挙動がわからなかったので、整理してまとめます。

one()関数の振る舞いを理解する

one()関数の仕様

ドキュメントを引用すると、

one takes a list, set, or tuple value with either zero or one elements. If the collection is empty, one returns null. Otherwise, one returns the first element. If there are two or more elements then one will return an error.

とあります。

つまり、

  • one()関数はcollection(list, set, tuple)を引数に受け取る
  • 引数のcollectionが空の場合、one()関数はnullを返す
  • 引数のcollectionが1つの要素を持つ場合、one()関数はその値を返す
  • 引数のcollectionが2つ以上の要素を持つ場合、one()関数はエラーを返す

という挙動です。

一言でいうなら、「要素数が1か0のcollentionに対してのみ使い、要素数が1ならその値を返す関数」です。

具体例

実際の実行例をいくつか見てみます。

# 引数のcollectionが空の場合、one()関数は`null`を返す
> one([])
null

> one(toset([]))
null
# 引数のcollectionが1つの要素を持つ場合、one()関数はその値を返す
> one(["hello"])
"hello"

> one(toset(["hello"]))
"hello"
# 引数のcollectionが2つ以上の要素を持つ場合、one()関数はエラーを返す
> one(["hello", "world"])
╷
│ Error: Invalid function argument
│ 
│   on <console-input> line 1:
│   (source code not available)
│ 
│ Invalid value for "list" parameter: must be a list, set, or tuple value with either zero or one elements.
╵

> one(toset(["hello","world"]))
╷
│ Error: Invalid function argument
│ 
│   on <console-input> line 1:
│   (source code not available)
│ 
│ Invalid value for "list" parameter: must be a list, set, or tuple value with either zero or one elements.

このように2つ以上の要素を持つcollentionを引数に渡すと、「0か1つの要素を持つlist/set/tupleしか引数に受け取れません」とのエラーが吐かれます。

one()関数の使いどころ

このように絶妙に複雑なone関数、一見使い所が見当たらないようにも感じますが、しっかり活躍する場面があります。

Terraformでは、count条件を利用して「ある条件下ではリソースを1つ作成し、そうでない場合は作成しない」という制御パターンがしばしば用いられます。

このような制御下で作成されたリソースを参照する際に、one()関数は有用です。

variable "include_ec2_instance" {
  type    = bool
  default = true
}

resource "aws_instance" "example" {
  count = var.include_ec2_instance ? 1 : 0

  # (other resource arguments...)
}

output "instance_ip_address" {
  value = one(aws_instance.example[*].private_ip)
}

Ref. one - Functions - Configuration Language | Terraform | HashiCorp Developer

count = var.include_ec2_instance ? 1 : 0部分で、resourceの作成数を0か1に条件制御しています。

そこでone(aws_instance.example[*].private_ip)とすることで、作成数が1のときはその作成されたリソースのprivate_ipを、作成数が0の時はnullを返す、という制御が可能です。

逆にone()関数を利用せず、素朴に

output "instance_ip_address" {
  value = aws_instance.example[0].private_ip
}

とした場合、作成数が0の場合にエラーが起きてしまいます。 (aws_instance.example[0]が存在しないため)

おわりに

Terraformのone()関数の挙動を整理しました。

用法容量を適切にしつつ、うまく活用していきたいところです。

以上、どなたかの参考になれば幸いです。

[関連記事]

www.bioerrorlog.work

www.bioerrorlog.work

www.bioerrorlog.work

参考

one - Functions - Configuration Language | Terraform | HashiCorp Developer