快轉到主要內容

Terraform Flatten 函數的使用範例

·2 分鐘
賴炳維
作者
賴炳維
畢業後,進入 devops 領域。目前擔任 SRE 工程師,專注於系統可靠性和自動化。喜歡探索新技術,並致力於提升系統性能和穩定性。
目錄

基本用法
#

flatten 接受一個 list,會將 list 中所有的 list 元素替換成 list 的內容。

> flatten([["a", "b"], [], ["c"]])
["a", "b", "c"]

使用情境
#

在 terraform中,常常會定義巢狀的 variable,例如:

variable "networks" {
  type = map(object({
    cidr_block = string
    subnets = map(object({ cidr_block = string }))
  }))
  default = {
    "private" = {
      cidr_block = "10.1.0.0/16"
      subnets = {
        "db1" = {
          cidr_block = "10.1.0.0/24"
        }
        "db2" = {
          cidr_block = "10.1.1.0/24"
        }
      }
    },
    "public" = {
      cidr_block = "10.2.0.0/16"
      subnets = {
        "webserver" = {
          cidr_block = "10.2.1.0/24"
        }
        "email_server" = {
          cidr_block = "10.2.2.0/24"
        }
      }
    }
    "dmz" = {
      cidr_block = "10.3.0.0/16"
      subnets = {
        "firewall" = {
          cidr_block = "10.3.1.0/24"
        }
      }
    }
  }
}

可以看到網路的變數使用了巢狀的結構定義了 networks與 subnets,頂層的 network 涵蓋了 subnet 的資訊,這樣的樹狀結構是很常有的。

如果是對網路的 resource區塊,我們可以直接使用這個變數:

resource "aws_vpc" "example" {
  for_each = var.networks

  cidr_block = each.value.cidr_block
}

對於子網路的 resource區塊,我們需要將結構做扁平化處理。

locals {
  # flatten 確保此局部值是一個扁平的 list[object{}],而不是 list[list[object{}]]
  network_subnets = flatten([
    for network_key, network in var.networks : [
      for subnet_key, subnet in network.subnets : {
        network_key = network_key
        subnet_key  = subnet_key
        network_id  = aws_vpc.example[network_key].id
        cidr_block  = subnet.cidr_block
      }
    ]
  ])
}

locals.network_subnets 實際展開的結果:

network_subnets = [
  {
    network_key = "private"
    subnet_key  = "db1"
    network_id  = aws_vpc.example["private"].id
    cidr_block  = "10.1.0.0/24"
  },
  {
    network_key = "private"
    subnet_key  = "db2"
    network_id  = aws_vpc.example["private"].id
    cidr_block  = "10.1.1.0/24"
  },
  {
    network_key = "public"
    subnet_key  = "webserver"
    network_id  = aws_vpc.example["public"].id
    cidr_block  = "10.2.1.0/24"
  },
  {
    network_key = "public"
    subnet_key  = "email_server"
    network_id  = aws_vpc.example["public"].id
    cidr_block  = "10.2.2.0/24"
  },
  {
    network_key = "dmz"
    subnet_key  = "firewall"
    network_id  = aws_vpc.example["dmz"].id
    cidr_block  = "10.3.1.0/24"
  }
]

接著將 locals.network_subnets帶入到 subnets的 resource做使用:

resource "aws_subnet" "example" {
  # local.network_subnets 是一個 list,先將它轉換成 map,這裡使用 network_key與 subnet_key組成唯一的 key值
  for_each = tomap({
    for subnet in local.network_subnets : "${subnet.network_key}.${subnet.subnet_key}" => subnet
  })

  vpc_id            = each.value.network_id
  availability_zone = each.value.subnet_key
  cidr_block        = each.value.cidr_block
}

參考文件
#

相關文章