Terraform でループして複数のリソースを作成する

TerraformでListの変数を使ってループさせたい時がある。

例えば、ユーザアカウントを複数作りたいとき。

以下のようなリソース定義を必要な分だけ書かないといけない。10個あったら10個。メッチャ大変。

resource "aws_iam_user" "developer" {

name = "foo"
path = "/developer"
}

普通に考えて、変数を定義してループさせたくなる。

まず変数を定義する。あとは、コイツを上手く回す方法を考える。

variable "developer" {

default = ["aoki0", "aoki1", "aoki2"]
}


リソースを複数作成する

リソースにはcountというパラメータがあり、この値を指定するとn個のリソースを作成してくれる。便利。

resource "aws_iam_user" "developer" {

count = 3
name = "aoki"
path = "/developer"
}

すると、3つの aws_iam_user が作成される。

+ aws_iam_user.developer.0

arn: "<computed>"
force_destroy: "false"
name: "aoki"
path: "/developer"
unique_id: "<computed>"

+ aws_iam_user.developer.1
arn: "<computed>"
force_destroy: "false"
name: "aoki"
path: "/developer"
unique_id: "<computed>"

+ aws_iam_user.developer.2
arn: "<computed>"
force_destroy: "false"
name: "aoki"
path: "/developer"
unique_id: "<computed>"

Plan: 3 to add, 0 to change, 0 to destroy.

しかし、2つの課題がある。

- 生成する数(3)をハードコーディングしてる

- name が全部同じ


変数に指定されたリストの長さを取得する

Terraformには length というリストの長さを取得する関数がある。

こいつを、利用してリスト長分のリソースを作成する。

resource "aws_iam_user" "developer" {

count = "${ length( var.developer ) }"
name = "aoki"
path = "/developer"
}

いい感じ。

+ aws_iam_user.developer.0

+ aws_iam_user.developer.1
+ aws_iam_user.developer.2
Plan: 3 to add, 0 to change, 0 to destroy.


リストの要素を利用する

リストの要素を取得するには element という関数、

現在のインデックスを取得するには count.index が使える。

これを、埋め込みたい箇所に "${}" でくくって記述する。

resource "aws_iam_user" "developer" {

count = "${ length( var.developer ) }"
name = "${element(var.developer, count.index)}"
path = "/developer"
}

ちゃんと、値も個数も設定ファイルから取得できた。

+ aws_iam_user.developer.0

name: "aoki0"
+ aws_iam_user.developer.1
name: "aoki1"
+ aws_iam_user.developer.2
name: "aoki2"
Plan: 3 to add, 0 to change, 0 to destroy.

あとは、nameも上手く取得したい。


MapのListも使える

変数の値を次のようにして、Listで回せばイロイロできそう。

ips = [

{ name = "foo", ip = "aaa.bbb.ccc.ddd/32", description = "foo IP" },
{ name = "bar", ip = "bbb.bbb.ccc.ddd/32", description = "bar IP" },
{ name = "baz", ip = "ccc.bbb.ccc.ddd/32", description = "baz IP" }
]

と、いいたいところなんですが、GitHubにIssueが上がっていて、現在(2016/11/29)使えない😢。


zipmap

対処療法として、二つのListを用意してzipmapで無理やり結合する。

# tfvars

names = ["foo", "bar", "baz"]
ips = [
"aaa.bbb.ccc.ddd/32",
"bbb.bbb.ccc.ddd/32",
"ccc.bbb.ccc.ddd/32"
]

zipmap は二つのリストをzippingする。

たとえば、前述したnamesipsをzipすると、

{

foo = "aaa.bbb.ccc.ddd/32",
bar = "bbb.bbb.ccc.ddd/32",
baz = "ccc.bbb.ccc.ddd/32"
}

となる。

はやくIssueが解決されて欲しい。


References