Terraform組み込み関数・演算子紹介
一人Terraform Advent Calendar
この記事は一人Terraform Advent Calendarの4日目の記事です。
- 一人Terraform Advent Calendar
- Terraform組み込み関数・演算子紹介
- 演算子解説
- 組み込み関数解説
- cidrhost(iprange, hostnum)
- concat(list1, list2, ...)
- contains(list, element)
- element(list, index)
- format(format, args, ...)
- index(list, elem)
- join(delim, list)
- length(list)
- list(items, ...)
- lookup(map, key, [default])
- map(key, value, ...)
- merge(map1, map2, ...)
- split(delim, string)
- timestamp()
- title(string)
- values(map)
- さいごに
Terraform組み込み関数・演算子紹介
Terraformは、HCLが持つ組み込み関数と演算子を利用してレシピの高度な抽象化を可能としています。一般的なプログラミング言語に用意されているような関数・演算子と同様に扱うことができ、より柔軟にインフラを運用することができます。
紹介する組み込み関数・演算子
この記事では、よく使うものや便利なものをいくつかピックアップして紹介します。全ての関数・演算子を参照したい場合は上記公式ドキュメントの説明を読んでください。
- 組み込み関数
- cidrhost(iprange, hostnum)
- concat(list1, list2, ...)
- contains(list, element)
- element(list, index)
- format(format, args, ...)
- index(list, elem)
- join(delim, list)
- length(list)
- list(items, ...)
- lookup(map, key, [default])
- map(key, value, ...)
- merge(map1, map2, ...)
- split(delim, string)
- timestamp()
- title(string)
- values(map)
- 演算子
演算子解説
四則演算
+
, -
, *
, /
, %
(integerのみ)がサポートされています。
# integer add = "${1 + 2 + 3}" # add = 6 sub = "${10 - 5}" # sub = 5 mul = "${2 * 5}" # mul = 10 div = "${10 / 5}" # div = 2 mod = "${11 % 3}" # mod = 2 # float add_f= "${1.5 + 2.5 + 3.5}" # add_f = 7.5 sub_f = "${10 - 4.5}" # sub_f = 5.5 mul_f = "${2.5 * 5}" # mul_f = 12.5 div_f = "${12.5 / 5.0}" # div_f = 2.5
等価演算子
==
, !=
がサポートされています。
true_result_eq = "${1 == 1}" # true_result_eq = true false_result_eq = "${1 == 2}" # false_result_eq = false true_result_ne = "${1 != 2}" # true_result_ne = true false_result_ne = "${1 != 1}" # false_result_ne = false
比較演算子
>
, <
, >=
, <=
が数値型にのみサポートされています。
result_gt = "${10 > 10}" # result_gt = false result_ge = "${10 >= 10}" # result_ge = true result_lt = "${5 < 10}" # result_lt = true result_le = "${10 <= 5}" # result_le = false
二値論理演算子
&&
, ||
, !
がboolean型にのみサポートされています
true_result_and = "${true && true}" # true_result_and = true false_result_and = "${truel && false}" # false_result_and = false true_result_or = "${true || false}" # true_result_or = true fasle_result_or = "${false || false}" # false_result_or = false true_result_unary = "${true && ! false}" # true_result_unary = true false_result_unary = "${!(true || false)}" # false_result_unary = false
三項演算子
一般的な三項演算子の文法でsome_bool ? true_val : false_val
のような形で書くことができます。some_bool
にはboolean型の値を渡すようにしてください。
true_cond = "${true ? 10 : 0}" # true_cond = 10 false_cond = "${false ? 10 : 0}" # false_cond = 0
組み込み関数解説
cidrhost(iprange, hostnum)
iprange
で与えられたCIDRブロック内で有効なIPアドレスのうちhostnum
番目のIPアドレスを返します。hostnum
が負の値の場合は後ろから数えてIPアドレスを返します。
ip_addr_1 = "${cidrhost("192.168.0.0/16", 10)}" # ip_addr_1 = "192.168.0.10" ip_addr_2 = "${cidrhost("192.168.0.0/16", -10)}" # ip_addr_2 = "192.168.255.246"
concat(list1, list2, ...)
引数で与えられたlist型の値を全て結合したlistを返します。
concat_list = "${concat(list(1, 2, 3, 4, 5), list(6, 7, 8, 9, 10))}" # concat_list = "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"
contains(list, element)
list
がelement
を要素として含んでいる場合にtrue
を返します。
true_contain = "${contains(list(1, 2, 3, 4, 5), 1)}" # true_contain = true
element(list, index)
list
のindex
番目の値を返します。list[index - 1]
と同じ挙動です。ネストされたリストに対しては正常に振る舞いません。
item = "${element(list(1, 10, 100, 1000, 10000), 3)}" # item = 100 (1オリジン)
format(format, args, ...)
一般的なフォーマットストリングと同じ使い方です。Go言語のfmtパッケージにあるSprintf()
を使って実装されているので、サポートされている記法もそれに準拠しています。
fmt - The Go Programming Language
str_1 = "${format("https://%s.%s", "example", "com")}" # str_1 = "https://example.com" str_2 = "${format("my_%s_%03d", "ec2_instance", 5)}" # str_2 = "my_ec2_instance_005"
index(list, elem)
element(list, index)
の逆で、list
の中の指定された要素のindexを返します。ネストされたリストに対しては正常に振る舞いません。
item_index = "${index(list(1, 10, 100, 1000, 10000), 100)}" # item_index = 2 (0オリジン)
join(delim, list)
list
の要素をdelim
を区切り文字にして結合した文字列を返します。ネストされたリストに対しては正常に振る舞いません。
joined = "${join(" ", list("Come", "on", "baby", "America"))}" # joined = "Come on baby America"
length(list)
list
の要素数を返します。ネストされているリストは1として数えられます。
len_1 = "${length(list(1, 2, 3, 4, 5))}" len_1 = 5 len_2 = "${length(list(list(1, 2, 3), list(4, 5, 6)))}" len_2 = 2
list(items, ...)
引数で受け取った値をlistにして返します。
list_1 = "${list(1, 2, 3, 4, 5)}" # list_1 = [1, 2, 3, 4, 5] list_2 = "${list(list(1, 2, 3), list(4, 5, 6))}" # list_2 = [[1, 2, 3], [4, 5, 6]]
lookup(map, key, [default])
map
の中でkey
に対応する値を返します。key
がない場合はエラーになりますが、default
が定義されている場合はdefault
を返します。
some_map = { "hoge": "fuga", "foo": "bar" } val_1 = "${lookup(some_map, "hoge")}" # val_1 = "fuga" val_2 = "${lookup(some_map, "fuu", "Not Found")}" # val_2 = "Not Found"
map(key, value, ...)
2N個の引数を受け取り、奇数番目の引数にそれぞれ次の引数の値を対応づけてmapを生成し返します。奇数番目のkey
になる引数は全てstring型でなければなりません。
map_1 = "${map("key_1", "val_1")}" # map_1 = {"key_1": "val_1"} map_2 = "${map("key_1", "val_1", "key_2", "val_2")}" # map_2 = {"key_1": "val_1", "key_2": "val_2"}
merge(map1, map2, ...)
2つ以上のmapを結合したmapを返します。keyが重複している場合、対応する値は順に上書きされていきます。
merged_map_1 = "${merge(map("key_1", "val_1"), map("key_2", "val_2"))}" # merged_map_1 = {"key_1": "val_1", "key_2": "val_2"} merged_map_2 = "${merge(map("key_1", "val_1"), map("key_1", "val_2"))}" # merged_map_2 = {"key_1": "val_2"}
split(delim, string)
join(delim, list)
とは逆にstring
をdelim
で区切った文字列のリストを返します。
split_str_1 = "${split(",", "a,b,c,d,e")}" # split_str_1 = ["a", "b", "c", "d", "e"] split_str_2 = "${split(".", "a,b,c,d,e")}" # split_str_2 = ["a,b,c,d,e"]
timestamp()
関数がコールされたときのタイムスタンプを返します。実行の度に値が変わるので、リソースの作成日時をタグ付けしたい場合やリソースの更新日時を常に記録しておきたいような場合に有用です。
time = "${timestamp()}" # time = time = 2018-12-03T22:58:10Z
title(string)
引数のstring
に含まれる全ての単語の頭文字を大文字にした文字列を返します。アルファベットと数字とアンダースコア(_
)以外のアスキー文字は文章のセパレータとして認識され、セパレータの前後の文字列は全て別々の単語としてパースされます。
title_1 = "${title("this is a sample comment")}" # title_1 = "This Is A Sample Comment" title_2 = "${title("a1a_a")}" # title_2 = "A1a_a" title_3 = "${title("a`a~a!a@a#a$a%a^a&a*a(a)a-a=a+a[a{a]a}a|a;a:a'a,a<a.a>a/a?a")}" # title_3 = "A`A~A!A@A#A$A%A^A&A*A(A)A-A=A+A[A{A]A}A|A;A:A'A,A<A.A>A/A?A"
values(map)
引数のmap
が持つkeyに対応する全ての値をリストにして返します。
values = "${values(map("key_1", "value_1", "key_2", "value_2"))}" # values = ["values_1", "values_2"]
さいごに
まだTerraform自体にバグがいくつか見つかったり、HCL自体に起因するバグがあるせいで関数が予期しない挙動をすることも多々あります。複雑なロジックを仕込むときにはdry-runをするなどして期待通りの値になっているかどうか確認することをオススメします。