Terraform 0.12の差分: Input Variable編

Terraform 0.12における差分を学習していった結果をまとめていきたいと思います。
まずは [Inuput Variable](https://www.terraform.io/docs/configuration/variables.html) 編です。

ちなみに、新旧比較。

- 0.12 : https://www.terraform.io/docs/configuration/variables.html
- 0.11 : https://www.terraform.io/docs/configuration-0-11/variables.html#description

## Typeが増えた

指定可能なものがやたらと増えてますね。

|0.11|0.12|
|:--|:--|
|string, map, list| string, number, bool <br/>list([TYPE]),<br/>set([TYPE]),<br/>map([TYPE])<br/>object( { [ATTR] = [TYPE], ... } ),<br/>tuple([TYPE]) |


詳しくは [こちら](https://www.terraform.io/docs/configuration/types.html) ということらしいので、これを読みながら実際に試して行きます。

また別で書かれているのだと思いますが、 `${ }` が不要になってますね。（有名な話ですが）

- 0.11まで : `${var.xxxx}`
- 0.12から : `var.xxxx`

0.11だと [Interpolation Syntax](https://www.terraform.io/docs/configuration-0-11/interpolation.html)に書かれているのですが、0.12だとどこにあるのだろう。

ちなみに0.12のHCL2は、vscodeのextensionが対応してませんね。
vscode上は赤線出てエラー扱いになっちゃいますがTerraform上は動くので問題ありませんが。

### type = bool

#### main.tf

```go
variable "admin_state_up" {
  type    = bool
  default = false
}


resource "ecl_network_network_v2" "nw_1" {
  name           = "net_1"
  admin_state_up = var.admin_state_up
}
```

#### apply時のコマンド

```bash
terraform apply -var 'admin_state_up=false'
```

#### 表示されたplan

```bash
  # ecl_network_network_v2.nw_1 will be created
  + resource "ecl_network_network_v2" "nw_1" {
      + admin_state_up = false
      + id             = (known after apply)
      + name           = "net_1"
      + plane          = "data"
      + region         = (known after apply)
      + shared         = (known after apply)
      + status         = (known after apply)
      + subnets        = (known after apply)
      + tenant_id      = (known after apply)
    }
```

### 利用したリソース情報

- [ecl_network_network_v2](https://github.com/nttcom/terraform-provider-ecl/blob/master/ecl/resource_ecl_network_network_v2.go#L32-L36)

### 実際に作られたリソース

```python
+----------------+--------------------------------------+
| Field          | Value                                |
+----------------+--------------------------------------+
| admin_state_up | False                                |
| description    |                                      |
| id             | <uuid>                               |
| name           | net_1                                |
| plane          | data                                 |
| project_id     |                                      |
| shared         | False                                | <-- Falseになっている
| status         | ACTIVE                               |
| subnets        |                                      |
| tags           | {}                                   |
+----------------+--------------------------------------+
```

### type = list(string)

#### main.tf

```go
variable "dns_servers" {
  type    = list(string)
  default = []
}


resource "ecl_network_network_v2" "nw_1" {
  name = "net_1"
}

resource "ecl_network_subnet_v2" "sub_1" {
  name            = "sub_1"
  network_id      = ecl_network_network_v2.nw_1.id
  dns_nameservers = var.dns_servers
  cidr            = "192.168.1.0/24"
}
```

#### apply時のコマンド

```bash
terraform apply -var 'dns_servers=["8.8.8.8", "8.8.4.4"]'
```

#### 表示されたplan

```bash
  # ecl_network_network_v2.nw_1 will be created
  + resource "ecl_network_network_v2" "nw_1" {
      + admin_state_up = (known after apply)
      + id             = (known after apply)
      + name           = "net_1"
      + plane          = "data"
      + region         = (known after apply)
      + shared         = (known after apply)
      + status         = (known after apply)
      + subnets        = (known after apply)
      + tenant_id      = (known after apply)
    }

  # ecl_network_subnet_v2.sub_1 will be created
  + resource "ecl_network_subnet_v2" "sub_1" {
      + cidr              = "192.168.1.0/24"
      + dns_nameservers   = [
          + "8.8.8.8",
          + "8.8.4.4",
        ]
      + enable_dhcp       = (known after apply)
      + gateway_ip        = (known after apply)
      + id                = (known after apply)
      + ip_version        = 4
      + ipv6_address_mode = (known after apply)
      + ipv6_ra_mode      = (known after apply)
      + name              = "sub_1"
      + network_id        = (known after apply)
      + region            = (known after apply)
      + status            = (known after apply)
      + tenant_id         = (known after apply)

      + allocation_pools {
          + end   = (known after apply)
          + start = (known after apply)
        }
    }
```

#### 実際に作られたリソース

```python
+-------------------+--------------------------------------------------------+
| Field             | Value                                                  |
+-------------------+--------------------------------------------------------+
| allocation_pools  | [{u'start': u'192.168.1.2', u'end': u'192.168.1.254'}] |
| cidr              | 192.168.1.0/24                                         |
| description       |                                                        |
| dns_nameservers   | [u'8.8.8.8', u'8.8.4.4']                               | <-- ここ
| enable_dhcp       | True                                                   |
| gateway_ip        | 192.168.1.1                                            |
| host_routes       | []                                                     |
| id                | <uuid>                                                 |
| ip_version        | 4                                                      |
| ipv6_address_mode | None                                                   |
| ipv6_ra_mode      | None                                                   |
| name              | sub_1                                                  |
| network_id        | <uuid>                                                 |
| ntp_servers       | []                                                     |
| project_id        |                                                        |
| status            | ACTIVE                                                 |
| tags              | {}                                                     |
+-------------------+--------------------------------------------------------+
```

#### 利用したリソース情報

- [ecl_network_network_v2](https://github.com/nttcom/terraform-provider-ecl/blob/master/ecl/resource_ecl_network_network_v2.go)
- [ecl_network_subbet_v2](https://github.com/nttcom/terraform-provider-ecl/blob/master/ecl/resource_ecl_network_subnet_v2.go#L57-L62)


### type = map(string)

従来のmapと同じでしょうけどね。

#### main.tf

```go
variable "tags" {
  type    = map(string)
  default = {}
}


resource "ecl_network_network_v2" "nw_1" {
  name = "net_1"
}

resource "ecl_network_subnet_v2" "sub_1" {
  name       = "sub_1"
  network_id = ecl_network_network_v2.nw_1.id
  cidr       = "192.168.1.0/24"
  tags       = var.tags
}
```

#### apply時のコマンド

```bash
terraform apply -var 'tags={"k1": "v1", "k2": "v2"}'
```

#### 表示されたplan

```bash
  # ecl_network_network_v2.nw_1 will be created
  + resource "ecl_network_network_v2" "nw_1" {
      + admin_state_up = (known after apply)
      + id             = (known after apply)
      + name           = "net_1"
      + plane          = "data"
      + region         = (known after apply)
      + shared         = (known after apply)
      + status         = (known after apply)
      + subnets        = (known after apply)
      + tenant_id      = (known after apply)
    }

  # ecl_network_subnet_v2.sub_1 will be created
  + resource "ecl_network_subnet_v2" "sub_1" {
      + cidr              = "192.168.1.0/24"
      + dns_nameservers   = (known after apply)
      + enable_dhcp       = (known after apply)
      + gateway_ip        = (known after apply)
      + id                = (known after apply)
      + ip_version        = 4
      + ipv6_address_mode = (known after apply)
      + ipv6_ra_mode      = (known after apply)
      + name              = "sub_1"
      + network_id        = (known after apply)
      + region            = (known after apply)
      + status            = (known after apply)
      + tags              = {
          + "k1" = "v1"
          + "k2" = "v2"
        }
      + tenant_id         = (known after apply)

      + allocation_pools {
          + end   = (known after apply)
          + start = (known after apply)
        }
    }
```

#### 実際に作られたリソース

```python
+-------------------+--------------------------------------------------------+
| Field             | Value                                                  |
+-------------------+--------------------------------------------------------+
| allocation_pools  | [{u'start': u'192.168.1.2', u'end': u'192.168.1.254'}] |
| cidr              | 192.168.1.0/24                                         |
| description       |                                                        |
| dns_nameservers   | []                                                     |
| enable_dhcp       | True                                                   |
| gateway_ip        | 192.168.1.1                                            |
| host_routes       | []                                                     |
| id                | <uuid>                                                 |
| ip_version        | 4                                                      |
| ipv6_address_mode | None                                                   |
| ipv6_ra_mode      | None                                                   |
| name              | sub_1                                                  |
| network_id        | <uuid>                                                 |
| ntp_servers       | []                                                     |
| project_id        |                                                        |
| status            | ACTIVE                                                 |
| tags              | {u'k2': u'v2', u'k1': u'v1'}                           | <-- ここ
+-------------------+--------------------------------------------------------+
```

#### 利用したリソース情報

- [ecl_network_network_v2](https://github.com/nttcom/terraform-provider-ecl/blob/master/ecl/resource_ecl_network_network_v2.go)
- [ecl_network_subbet_v2](https://github.com/nttcom/terraform-provider-ecl/blob/master/ecl/resource_ecl_network_subnet_v2.go#L137-L140)


### type = set(string)

#### main.tf

```go
variable "tags" {
  type    = set(string)
  default = []
}


resource "ecl_imagestorages_image_v2" "image_1" {
  name             = "image_1"
  local_file_path  = "./image.txt"
  tags             = var.tags
  container_format = "bare"
  disk_format      = "qcow2"
}
```

#### apply時のコマンド

```bash
% terraform apply -var 'tags=["tag1", "tag1", "tag2"]' <-- "tag1" をあえて２回与えてみた
```

#### 表示されたplan

```bash
  # ecl_imagestorages_image_v2.image_1 will be created
  + resource "ecl_imagestorages_image_v2" "image_1" {
      + checksum         = (known after apply)
      + container_format = "bare"
      + created_at       = (known after apply)
      + disk_format      = "qcow2"
      + file             = (known after apply)
      + id               = (known after apply)
      + local_file_path  = "./image.txt"
      + metadata         = (known after apply)
      + min_disk_gb      = 0
      + min_ram_mb       = 0
      + name             = "image_1"
      + owner            = (known after apply)
      + properties       = (known after apply)
      + protected        = false
      + region           = (known after apply)
      + schema           = (known after apply)
      + size_bytes       = (known after apply)
      + status           = (known after apply)
      + tags             = [
          + "tag1", <-- 重複して与えても、setなので自動的にユニークになるっぽい
          + "tag2",
        ]
      + update_at        = (known after apply)
      + verify_checksum  = true
      + visibility       = "private"
    }
```

#### 実際に作られたリソース

```python
+-------------------+--------------------------------------------------------+
| Field             | Value                                                  |
+-------------------+--------------------------------------------------------+
| allocation_pools  | [{u'start': u'192.168.1.2', u'end': u'192.168.1.254'}] |
| cidr              | 192.168.1.0/24                                         |
| description       |                                                        |
| dns_nameservers   | []                                                     |
| enable_dhcp       | True                                                   |
| gateway_ip        | 192.168.1.1                                            |
| host_routes       | []                                                     |
| id                | <uuid>                                                 |
| ip_version        | 4                                                      |
| ipv6_address_mode | None                                                   |
| ipv6_ra_mode      | None                                                   |
| name              | sub_1                                                  |
| network_id        | <uuid>                                                 |
| ntp_servers       | []                                                     |
| project_id        |                                                        |
| status            | ACTIVE                                                 |
| tags              | {u'k2': u'v2', u'k1': u'v1'}                           | <-- ここ
+-------------------+--------------------------------------------------------+
```

#### 利用したリソース情報

- [ecl_network_network_v2](https://github.com/nttcom/terraform-provider-ecl/blob/master/ecl/resource_ecl_network_network_v2.go)
- [ecl_network_subbet_v2](https://github.com/nttcom/terraform-provider-ecl/blob/master/ecl/resource_ecl_network_subnet_v2.go#L137-L140)

### type = object

引数にオブジェクトが使える・・・。

うーん、これはどういうときに使うのが良いのだろう・・・と悩んでしまいましたがとりあえずやってみます。
なにかしらリクエストBODYを用意しておいて、それをそのままTerraformに渡したい。しかも別用途にも使えるし一石二鳥・・・みたいなときに使うのですかね。

#### main.tf

```go
variable "obj" {
  type = object({ name = string, tags = map(string) })
  default = {
    name = "net_1"
    tags = {
      k1 = "v1"
      k2 = "v2"
    }
  }
}


resource "ecl_network_network_v2" "nw_1" {
  name = var.obj.name
  tags = var.obj.tags
}
```

#### apply時のコマンド

```bash
terraform apply -var 'obj={"name": "net_1_var", "tags": {"k2": "v2"}}'
```

#### 表示されたplan

```bash
  # ecl_network_network_v2.nw_1 will be created
  + resource "ecl_network_network_v2" "nw_1" {
      + admin_state_up = (known after apply)
      + id             = (known after apply)
      + name           = "net_1_var"
      + plane          = "data"
      + region         = (known after apply)
      + shared         = (known after apply)
      + status         = (known after apply)
      + subnets        = (known after apply)
      + tags           = {
          + "k2" = "v2"
        }
      + tenant_id      = (known after apply)
    }
```

#### 実際に作られたリソース

```python
+----------------+--------------------------------------+
| Field          | Value                                |
+----------------+--------------------------------------+
| admin_state_up | True                                 |
| description    |                                      |
| id             | <uuid>                               |
| name           | net_1_var                            |
| plane          | data                                 |
| project_id     |                                      |
| shared         | False                                |
| status         | ACTIVE                               |
| subnets        |                                      |
| tags           | {u'k2': u'v2'}                       |
+----------------+--------------------------------------+
```

#### 利用したリソース情報

- [ecl_network_network_v2](https://github.com/nttcom/terraform-provider-ecl/blob/master/ecl/resource_ecl_network_network_v2.go)


### type = tuple([string])

tupleの場合、予め指定したタイプおよび要素数に完全合致しないとだめということのようですね。
例えば `list(string)` は任意の要素数を含めますが、 `tuple` でそれをやるとだめっぽい。
pythonのtuple, listとはちょっと違うようですね意味合いが。

#### main.tf

```go
variable "dns_servers" {
  type    = tuple([string, string])
  default = ["0.0.0.0", "1.1.1.1"]  // まぁ適当に・・・
}


resource "ecl_network_network_v2" "nw_1" {
  name = "net_1"
}

resource "ecl_network_subnet_v2" "sub_1" {
  network_id      = ecl_network_network_v2.nw_1.id
  dns_nameservers = var.dns_servers
  cidr            = "192.168.1.0/24"
}
```

#### apply時のコマンド

```bash
terraform apply -var 'dns_servers=["8.8.8.8", "8.8.4.4"]'
```

ここで、要素数が超過していたりすると以下のエラーになるようですね。

```bash
% terraform apply -var 'dns_servers=["8.8.8.8", "8.8.4.4", "3.3.3.3"]'

Error: Invalid value for input variable

The argument -var="dns_servers=..." does not contain a valid value for
variable "dns_servers": tuple required.
```

#### 表示されたplan

```bash
  # ecl_network_network_v2.nw_1 will be created
  + resource "ecl_network_network_v2" "nw_1" {
      + admin_state_up = (known after apply)
      + id             = (known after apply)
      + name           = "net_1"
      + plane          = "data"
      + region         = (known after apply)
      + shared         = (known after apply)
      + status         = (known after apply)
      + subnets        = (known after apply)
      + tenant_id      = (known after apply)
    }

  # ecl_network_subnet_v2.sub_1 will be created
  + resource "ecl_network_subnet_v2" "sub_1" {
      + cidr              = "192.168.1.0/24"
      + dns_nameservers   = [
          + "8.8.8.8",
          + "8.8.4.4",
        ]
      + enable_dhcp       = (known after apply)
      + gateway_ip        = (known after apply)
      + id                = (known after apply)
      + ip_version        = 4
      + ipv6_address_mode = (known after apply)
      + ipv6_ra_mode      = (known after apply)
      + network_id        = (known after apply)
      + region            = (known after apply)
      + status            = (known after apply)
      + tenant_id         = (known after apply)

      + allocation_pools {
          + end   = (known after apply)
          + start = (known after apply)
        }
    }
```

#### 実際に作られたリソース

```python
+-------------------+--------------------------------------------------------+
| Field             | Value                                                  |
+-------------------+--------------------------------------------------------+
| allocation_pools  | [{u'start': u'192.168.1.2', u'end': u'192.168.1.254'}] |
| cidr              | 192.168.1.0/24                                         |
| description       |                                                        |
| dns_nameservers   | [u'8.8.8.8', u'8.8.4.4']                               |
| enable_dhcp       | True                                                   |
| gateway_ip        | 192.168.1.1                                            |
| host_routes       | []                                                     |
| id                | <uuid>                                                 |
| ip_version        | 4                                                      |
| ipv6_address_mode | None                                                   |
| ipv6_ra_mode      | None                                                   |
| name              |                                                        |
| network_id        | <uuid>                                                 |
| ntp_servers       | []                                                     |
| project_id        |                                                        |
| status            | ACTIVE                                                 |
| tags              | {}                                                     |
+-------------------+--------------------------------------------------------+
```

#### 利用したリソース情報

- [ecl_network_network_v2](https://github.com/nttcom/terraform-provider-ecl/blob/master/ecl/resource_ecl_network_network_v2.go)
- [ecl_network_subbet_v2](https://github.com/nttcom/terraform-provider-ecl/blob/master/ecl/resource_ecl_network_subnet_v2.go#L57-L62)




## JSONが使えるよ・・・って明記された

細かい話ですが、

[Variable Definitions (`.tfvers`) Files](https://www.terraform.io/docs/configuration/variables.html#variable-definitions-tfvars-files)

にJSON形式についての明記がありますね。
**ただ、もともと0.11でも使えていたようですけどね。**


以上、Input Variablesについての自分的差分チェック結果でした。