【Terraform】変数でよく見るmap(object)って？

よく変数の定義でmap(object())となっているのを見るので、どういうことなのかを調べた結果を共有。
# 結論
Object型で構造化した変数を、mapでコレクションとして扱っている。このようにすることで変数の管理がしやすくなり、少ない記述でたくさんのリソースを一気にプロビジョニングできる。
# 前提
oci_core_instance(https://registry.terraform.io/providers/oracle/oci/latest/docs/resources/core_instance)
の一部で説明。
# Objectを用いないとどうなるか
Objectを用いず変数を羅列すると、variables.tfは以下のようになる。
```hcl
variable "availability_domain" {
  type = string
}
variable "display_name" {
  type = string
}
variable "shape" {
  type = string
}
variable "source_details_source_type" {
  type = string
}
variable "source_details_source_id" {
  type = string
}
variable "create_vnic_details_assign_public_ip" {
  type = bool
}
variable "create_vnic_details_subnet_id" {
  type = string
}
variable "shape_config_baseline_ocpu_utilization" {
  type = string
}
variable "shape_config_memory_in_gbs" {
  type = string
}
variable "shape_config_ocpus" {
  type = string
}
variable "metadata_ssh_authorized_keys" {
  type = string
}
variable "metadata_user_data" {
  type = string
}
```
たくさんの変数が羅列されており、どの変数とどの変数が関連するものかがぱっと見でわかりにくく、管理が難しくなる。
# Objectを用いると...
上記のような変数たちを、Objectを用いて書き直すと以下のようにできる。
```hcl
variable "instances" {
  type = object({
    availability_domain = string
    display_name        = string
    shape               = string
    source_details = object({
      source_id = string
    })
    create_vnic_details = object({
      assign_public_ip = bool
      subnet_id        = string
    })
    shape_config = object({
      baseline_ocpu_utilization = string
      memory_in_gbs             = string
      ocpus                     = string
    })
    metadata = object({
      ssh_authorized_keys = string
      user_data           = string
    })
  })
}
```
これで、各変数がどういった値なのかがぱっと見でわかるようになった。
# mapを用いないとどうなるか
ではこの状態でインスタンスを二つプロビジョニングすることを考えてみる。すると、下記のようにvariables.tfを書く必要がある。
```hcl
variable "instance1" {
  type = object({
    availability_domain = string
    display_name        = string
    shape               = string
    source_details = object({
      source_id = string
    })
    create_vnic_details = object({
      assign_public_ip = bool
      subnet_id        = string
    })
    shape_config = object({
      baseline_ocpu_utilization = string
      memory_in_gbs             = string
      ocpus                     = string
    })
    metadata = object({
      ssh_authorized_keys = string
      user_data           = string
    })
  })
}
variable "instance2" {
  type = object({
    availability_domain = string
    display_name        = string
    shape               = string
    source_details = object({
      source_id = string
    })
    create_vnic_details = object({
      assign_public_ip = bool
      subnet_id        = string
    })
    shape_config = object({
      baseline_ocpu_utilization = string
      memory_in_gbs             = string
      ocpus                     = string
    })
    metadata = object({
      ssh_authorized_keys = string
      user_data           = string
    })
  })
}
```
これでは明らかに冗長になっている。
# mapを用いると...
上記の冗長な変数を、mapを用いてきれいに書き直してみる。
```hcl
variable "instances" {
  type = map(object({
    availability_domain = string
    display_name        = string
    shape               = string
    source_details = object({
      source_id = string
    })
    create_vnic_details = object({
      assign_public_ip = bool
      subnet_id        = string
    })
    shape_config = object({
      baseline_ocpu_utilization = string
      memory_in_gbs             = string
      ocpus                     = string
    })
    metadata = object({
      ssh_authorized_keys = string
      user_data           = string
    })
  }))
}
```
変数の定義はObject型の定義にmap()を追加するだけでOK。変数の中身を設定するときは、以下のように設定できる。
```hcl
instances = {
  instance01 = {
    availability_domain = ....
    display_name = ....
    shape = ....
    source_details = {
      source_id = ....
      source_type = ....
    }
    shape_config = {
      baseline_ocpu_utilization = ....
      memory_in_gbs = ....
      ocpus = ....
    }
    metadat = {
      ssh_authorized_keys = ....
      user_data = ....
    }
  }
  instance02 = {
    #同様に記述
  }
}
 ```
 このようにすることで、モジュールを呼び出すときは、以下のように呼び出せる。
 ```hcl
 module "instance" {
  source         = #モジュールの場所
  compartment_id = #各モジュール共通の変数は切り出す
  instances      = var.instances
}
```
このように、モジュール呼び出しの部分が非常にシンプルに記述できる。