Terraform resourceにおいてcount使用時の個別属性指定

備忘



Terraformで複数のインスタンスを構成するには、countが使える。
その際にそれぞれのインスタンスに異なる属性値を与えるには、listに定義しておいてそこから与える対応が可能。




## 複数のローカルファイルを作成する

### 個別に作成

```tf
resource "local_file" "file_A" {
  filename = "./file_A"
  content  = "FOO\n"
}

resource "local_file" "file_B" {
  filename = "./file_B"
  content  = "BAR\n"
}

resource "local_file" "file_C" {
  filename = "./file_C"
  content  = "BAZ\n"
}
```

それぞれにリソース名を割り振って管理
同じ様なインスタンスを沢山デプロイするような場合には、同じ様な定義をその都度行うことになり、コードが不必要に冗長となりメンテナンス性が低下してしまう。


### countを使用

countを使用することで、複数のリソース名を不要とし、冗長度をおさえられる。
ただし、少なくともnameなどキーとなる属性には異なる値を与える必要がある。
インスタンスごとに異なる属性の定義を、listとして分離しておくと、インスタンス数をそのlengthとして利用できるなどのメリットがある。



```tf
locals {
  files = [
    { filename = "./file_A", content  = "FOO\n", },
    { filename = "./file_B", content  = "BAR\n", },
    { filename = "./file_C", content  = "BAZ\n", },
  ]
}

resource "local_file" "files" {
  count    = length(local.files)

  filename = local.files[count.index].filename
  content  = local.files[count.index].content
}
```

## 操作例



### tfファイル
```
$ cat main.tf 
locals {
  files = [
    { filename = "./file_A", content  = "FOO\n", },
    { filename = "./file_B", content  = "BAR\n", },
    { filename = "./file_C", content  = "BAZ\n", },
  ]
}

resource "local_file" "files" {
  count    = length(local.files)

  filename = local.files[count.index].filename
  content  = local.files[count.index].content
}
```

### Terraform初期化

```
$ terraform init 
...
```

```
$ terraform validate
Success! The configuration is valid.
```

### ローカルファイル作成 (apply)
```
$ terraform apply --auto-approve

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # local_file.files[0] will be created
  + resource "local_file" "files" {
      + content              = <<-EOT
            FOO
        EOT
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "./file_A"
      + id                   = (known after apply)
    }

  # local_file.files[1] will be created
  + resource "local_file" "files" {
      + content              = <<-EOT
            BAR
        EOT
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "./file_B"
      + id                   = (known after apply)
    }

  # local_file.files[2] will be created
  + resource "local_file" "files" {
      + content              = <<-EOT
            BAZ
        EOT
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "./file_C"
      + id                   = (known after apply)
    }

Plan: 3 to add, 0 to change, 0 to destroy.
local_file.files[2]: Creating...
local_file.files[1]: Creating...
local_file.files[0]: Creating...
local_file.files[1]: Creation complete after 0s [id=b7e15d674814565f6ed7e5e2cdef404a4819b5a9]
local_file.files[0]: Creation complete after 0s [id=e752cf6ec8e21b2390400b3292ec6de08178fe25]
local_file.files[2]: Creation complete after 0s [id=42ac9f428da03f337ace7991cfbb364e96a7b383]

Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
```
### 作成されたファイルの確認
```
$ ls file_*
file_A  file_B  file_C
```

```
$ cat file_A
FOO
```

```
$ cat file_B
BAR
```

```
$ cat file_C
BAZ
```

### リソースはlistとして管理される

```
$ terraform state list 
local_file.files[0]
local_file.files[1]
local_file.files[2]
```

### 例えば2番目のリソースのみをdestroyするといった事も可能
[1]のリソース

```
$ terraform destroy -target=local_file.files[1] --auto-approve
local_file.files[1]: Refreshing state... [id=b7e15d674814565f6ed7e5e2cdef404a4819b5a9]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # local_file.files[1] will be destroyed
  - resource "local_file" "files" {
      - content              = <<-EOT
            BAR
        EOT -> null
      - directory_permission = "0777" -> null
      - file_permission      = "0777" -> null
      - filename             = "./file_B" -> null
      - id                   = "b7e15d674814565f6ed7e5e2cdef404a4819b5a9" -> null
    }

Plan: 0 to add, 0 to change, 1 to destroy.
local_file.files[1]: Destroying... [id=b7e15d674814565f6ed7e5e2cdef404a4819b5a9]
local_file.files[1]: Destruction complete after 0s
╷
│ Warning: Resource targeting is in effect
│ 
│ You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current configuration.
│ 
│ The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as
│ part of an error message.
╵
╷
│ Warning: Applied changes may be incomplete
│ 
│ The plan was created with the -target option in effect, so some changes requested in the configuration may have been ignored and the output values may not be fully updated. Run the
│ following command to verify that no other changes are pending:
│     terraform plan
│ 	
│ Note that the -target option is not suitable for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically
│ suggests to use it as part of an error message.
╵

Destroy complete! Resources: 1 destroyed.
```

```
$ ls file_*
file_A  file_C
```

file_Bが削除された。