TerraformのBuilt-in関数や小ネタのあんちょこを作った
このブログを一言で
TerraformのBuilt-in関数の説明や動作例、小ネタをまとめてみたかったので、重い腰あげてみたよ。
今後も順次メンテしていくよ。
関数(順不同)
参考:Built-in Functions
以下によく使う関数の動作例を記載していきます。
Collection Function
flatten関数
flattenは配列で入れ子になっているものを平準化します。
# flatten
variable "example_list_of_lists" {
default = [["a", "b"], ["c", "d"], ["e", "f"]]
}
output "as_list_of_lists" {
value = var.example_list_of_lists
}
output "as_flattened_list" {
value = flatten(var.example_list_of_lists)
}
Changes to Outputs:
as_list_of_lists = [
[
"a",
"b",
],
[
"c",
"d",
],
[
"e",
"f",
],
]
as_flattened_list = [
"a",
"b",
"c",
"d",
"e",
"f",
]
以下のように、list(object)の場合、env, subnet, ami, instanceのように要素を同じ階層にすることが可能です。
locals {
default = [
{
name = "dev"
subnets = ["10.0.1.0/24", "10.0.2.0/24"]
ami = "ami-12345678"
instance = "t3.micro"
},
{
name = "prod"
subnets = ["10.0.11.0/24", "10.0.12.0/24"]
ami = "ami-87654321"
instance = "t3.small"
}
]
# flattenで「環境 × サブネット」の組み合わせを1次元にする
instances = flatten([
for env in local.default : [
for sn in env.subnets : {
env = env.name
subnet = sn
ami = env.ami
instance = env.instance
}
]
])
}
output "instances" {
value = local.instances
}
Changes to Outputs:
instances = [
{
ami = "ami-12345678"
env = "dev"
instance = "t3.micro"
subnet = "10.0.1.0/24"
},
{
ami = "ami-12345678"
env = "dev"
instance = "t3.micro"
subnet = "10.0.2.0/24"
},
{
ami = "ami-87654321"
env = "prod"
instance = "t3.small"
subnet = "10.0.11.0/24"
},
{
ami = "ami-87654321"
env = "prod"
instance = "t3.small"
subnet = "10.0.12.0/24"
},
]
これは、以下のようにfor_eachで利用できます。
for_eachでmapを生成し、EC2を作成することも可能です。
resource "aws_vpc" "this" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "this"
}
}
resource "aws_subnet" "this" {
# キーの重複があるため、独自キーを作成して、map化する
for_each = {
for v in local.instances : "${v.env}-${v.subnet}" => v
}
vpc_id = aws_vpc.this.id
cidr_block = each.value.subnet
tags = {
Name = "${each.value.env}-subnet"
}
}
resource "aws_instance" "this" {
# キーの重複があるため、独自キーを作成して、map化する
for_each = {
for v in local.instances : "${v.env}-${v.subnet}" => v
}
ami = each.value.ami
instance_type = each.value.instance
subnet_id = aws_subnet.this[each.key].id
tags = {
Name = "${each.value.env}-instance"
}
}
merge関数
複数のmapを結合して、重複を除いた形で出力します。
複数のKeyが重複している場合は、後続のKeyが優先されます。
variable "map1" {
default = {
a = 1
b = 2
}
}
variable "map2" {
default = {
b = 20
c = 30
}
}
output "merged_map" {
value = merge(var.map1, var.map2)
}
Changes to Outputs:
merged_map = {
a = 1
b = 20
c = 30
}
setintersection関数
複数のsetの重複を出力します。
locals {
list1 = ["a", "b", "c"]
list2 = ["b", "c", "d"]
intersection = setintersection(toset(local.list1), toset(local.list2))
}
output "intersection" {
value = local.intersection
}
Changes to Outputs:
intersection = [
"b",
"c",
]
index関数
listの要素番号を返します。
locals {
my_list = ["a", "b", "c"]
my_index = index(local.my_list, "b")
}
output "my_index" {
value = local.my_index
}
Changes to Outputs:
my_index = 1
keys関数
mapのKeyを返します。
locals {
example_map = {
a = 1
b = 2
c = 3
}
example_keys = keys(local.example_map)
}
output "example_keys" {
value = local.example_keys
}
Changes to Outputs:
example_keys = [
"a",
"b",
"c",
]
values関数
mapのValueを返します。
locals {
example_map = {
a = 1
b = 2
c = 3
}
example_values = values(local.example_map)
}
output "example_values" {
value = local.example_values
}
Changes to Outputs:
example_values = [
1,
2,
3,
]
length関数
set, list, mapの長さを返します。
locals {
my_list = ["a", "b", "c"]
my_length = length(local.my_list)
}
output "my_length" {
value = local.my_length
}
Changes to Outputs:
my_length = 3
Type Conversion Function
toset/tolist関数
for_eachはsetかmapしか受け付けないため、tosetでlistをsetに変換する場合に使われることが多い。逆にtolist関数はsetをlistに変換します。
locals {
example_set = toset(["a", "b", "c"])
example_list = tolist(local.example_set)
}
❯ terraform console
> type(local.example_set)
set(string)
> type(local.example_list)
list(string)
IP Network Function
cidrsubnet関数
CIDRを順番に生成する便利な関数。
CIDR計算が不要となる、かつ計算ミスをしなくても良くなるためSubnetを複数作成する場合に便利。
構文はcidrsubnet(prefix, newbits, netnum)。
prefix: ベースとなる CIDR(例: "10.0.0.0/16")
newbits: 追加で借りるビット数(例: 6 → /16 が /22 になる)
netnum: 生成するサブネットの番号(0, 1, 2...)
例:
cidrsubnet("10.0.0.0/16", 6, 0) → 10.0.0.0/22
cidrsubnet("10.0.0.0/16", 6, 1) → 10.0.4.0/22
locals {
base_cidr = "10.0.0.0/16"
new_bits = 6
}
output "subnet_cidr1" {
value = cidrsubnet(local.base_cidr, local.new_bits, 0)
}
output "subnet_cidr2" {
value = cidrsubnet(local.base_cidr, local.new_bits, 1)
}
output "subnet_cidr3" {
value = cidrsubnet(local.base_cidr, local.new_bits, 2)
}
output "subnet_cidr4" {
value = cidrsubnet(local.base_cidr, local.new_bits, 3)
}
Changes to Outputs:
subnet_cidr1 = "10.0.0.0/22"
subnet_cidr2 = "10.0.4.0/22"
subnet_cidr3 = "10.0.8.0/22"
subnet_cidr4 = "10.0.12.0/22"
小ネタ
動的にmapを作成する
locals {
subnets = [
"10.0.0.0/24",
"10.0.1.0/24",
"10.0.2.0/24",
]
azs = [
"ap-northeast-1a",
"ap-northeast-1c",
"ap-northeast-1d",
]
}
locals {
from_az_to_public_subnet = { for i, subnet in local.subnets :
local.azs[i] => subnet
}
}
output "test" {
value = local.from_az_to_public_subnet
}
Changes to Outputs:
test = {
ap-northeast-1a = "10.0.0.0/24"
ap-northeast-1c = "10.0.1.0/24"
ap-northeast-1d = "10.0.2.0/24"
}
Availability Zonesに均等にサブネットを配置する例
locals {
azs = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
subnets = [
"10.0.1.0/24",
"10.0.2.0/24",
"10.0.3.0/24",
"10.0.4.0/24",
"10.0.5.0/24",
"10.0.6.0/24"
]
number_of_azs = length(local.azs)
subnet_az_map = [
for subnet in local.subnets : {
cidr = subnet
az = local.azs[index(local.subnets, subnet) % local.number_of_azs]
}
]
}
output "subnet_az_map" {
value = local.subnet_az_map
}
Changes to Outputs:
subnet_az_map = [
{
az = "ap-northeast-1a"
cidr = "10.0.1.0/24"
},
{
az = "ap-northeast-1c"
cidr = "10.0.2.0/24"
},
{
az = "ap-northeast-1d"
cidr = "10.0.3.0/24"
},
{
az = "ap-northeast-1a"
cidr = "10.0.4.0/24"
},
{
az = "ap-northeast-1c"
cidr = "10.0.5.0/24"
},
{
az = "ap-northeast-1d"
cidr = "10.0.6.0/24"
},
]
Discussion