Terraform v1.5 から実験的機能として generate-config-out が追加されています。
Import - Generating Configuration | Terraform | HashiCorp Developer
既存リソースの HCL を出力する機能で、個人的には待望の機能です。
import 自体の利用頻度は低いのですが、頻度が少ない故煩雑になりがちな作業が無くなるので大変喜ばしいです。
検証環境
今回は Terraform v1.6.1 と aws provider で試しています。
% terraform version
Terraform v1.6.1
on darwin_arm64
+ provider registry.terraform.io/hashicorp/aws v5.21.0
以下の S3 バケットがAWS上に作成されている状態です。
これらを -generate-config-out
オプションで取り込みます。
example-tf-generate-config-root-123456789012
example-tf-generate-config-mod1-123456789012
example-tf-generate-config-mod2-123456789012
example-tf-generate-config-mod3-123456789012
example-tf-generate-config-prefix-20231014024553631000000001
基本
import ブロックを記述します。
import {
id = "example-tf-generate-config-root-123456789012"
to = aws_s3_bucket.this
}
aws provider では既にドキュメントにも import ブロックが記載されています。
例: s3_bucket#import
この状態で terraform plan -generate-config-out=generated.tf
を実行します。
% terraform plan -generate-config-out=generated.tf
aws_s3_bucket.this: Preparing import... [id=example-tf-generate-config-root-123456789012]
aws_s3_bucket.this: Refreshing state... [id=example-tf-generate-config-root-123456789012]
Terraform will perform the following actions:
# aws_s3_bucket.this will be imported
# (config will be generated)
resource "aws_s3_bucket" "this" {
... (略)
Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.
╷
│ Warning: Config generation is experimental
│
│ Generating configuration during import is currently experimental, and the generated
│ configuration format may change in future versions.
╵
────────────────────────────────────────────────────────────────────────────────────────────
Terraform has generated configuration and written it to generated.tf. Please review the
configuration and edit it as necessary before adding it to version control.
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take
exactly these actions if you run "terraform apply" now.
指定したファイル名で tf ファイルが生成されます。
% cat generated.tf
# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.
# __generated__ by Terraform from "example-tf-generate-config-root-123456789012"
resource "aws_s3_bucket" "this" {
bucket = "example-tf-generate-config-root-123456789012"
bucket_prefix = null
force_destroy = null
object_lock_enabled = false
tags = {}
tags_all = {}
}
生成された tf ファイルを使用し、apply で state へ取り込みます。
% terraform apply
aws_s3_bucket.this: Preparing import... [id=example-tf-generate-config-root-123456789012]
aws_s3_bucket.this: Refreshing state... [id=example-tf-generate-config-root-123456789012]
Terraform will perform the following actions:
# aws_s3_bucket.this will be imported
resource "aws_s3_bucket" "this" {
arn = "arn:aws:s3:::example-tf-generate-config-root-123456789012"
...(略)
Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_s3_bucket.this: Importing... [id=example-tf-generate-config-root-123456789012]
aws_s3_bucket.this: Import complete [id=example-tf-generate-config-root-123456789012]
Apply complete! Resources: 1 imported, 0 added, 0 changed, 0 destroyed.
オプションが長いので覚えられない
そんな私に
import ブロックを記述した状態で、単純に terraform plan
を実行するとオプションを付与したコマンドを出力してくれます。
╷
│ Error: Import block target does not exist
│
│ on imports.tf line 1:
│ 1: import {
│
│ The target for the given import block does not exist. If you wish to automatically
│ generate config for this resource, use the -generate-config-out option within terraform
│ plan. Otherwise, make sure the target resource exists within your configuration. For
│ example:
│
│ terraform plan -generate-config-out=generated.tf
ファイルを上書きしてしまいそうで怖い
そんな私に
指定したtfファイルが既に存在する状態で実行するとエラー出力してくれます。
│ Error: Target generated file already exists
│
│ Terraform can only write generated config into a new file. Either choose a different
│ target location or move all existing configuration out of the target file, delete it and
│ try again.
書く場所がわからない
そんな私に
module 内に記述すると直下に書いてねとエラー出力してくれます。
╷
│ Error: Invalid import configuration
│
│ on _modules/mod1/mod1.tf line 9:
│ 9: import {
│
│ An import block was detected in "module.mod1". Import blocks are only allowed
│ in the root module.
module へ import する場合
既に module 内にリソース定義があるので、 -generate-config-out オプションを付けても、ファイルへの出力は無いです。
オプションの話からは外れますが、import ブロックでは module への import も可能です。
二点制約があります。
- module 内にリソース定義されている必要がある
- terraform init 後、つまり、state に含まれている状態である必要がある
- import ブロックは module 内ではなく root (直下) に記述する必要がある
ネストしたmoduleにも対応しています。
to の指定は以下の様に、 module.{module名}
を連ねていくだけです。
# module への import
import {
id = "example-tf-generate-config-mod1-123456789012"
to = module.mod1.aws_s3_bucket.this
}
# mod1のmodule mod2 への import
import {
id = "example-tf-generate-config-mod2-123456789012"
to = module.mod1.module.mod2.aws_s3_bucket.this
}
# mod1のmodule mod2のmodule mod3 への import
import {
id = "example-tf-generate-config-mod3-123456789012"
to = module.mod1.module.mod2.module.mod3.aws_s3_bucket.this
}
制限事項
公式ドキュメントにも記載があります。
現時点の制限事項として、競合する属性を持つ場合に出力されたファイルをそのまま利用できない事が発生します。
今回例として使用している aws_s3_bucket では、 bucket_prefix を使用して作成したリソースを取り込もうとした所、発生しました。
% terraform plan -generate-config-out=generated.tf
aws_s3_bucket.this: Preparing import... [id=example-tf-generate-config-prefix-20231014024553631000000001]
aws_s3_bucket.this: Refreshing state... [id=example-tf-generate-config-prefix-20231014024553631000000001]
Planning failed. Terraform encountered an error while generating this plan.
╷
│ Warning: Config generation is experimental
│
│ Generating configuration during import is currently experimental, and the generated
│ configuration format may change in future versions.
╵
╷
│ Error: Conflicting configuration arguments
│
│ with aws_s3_bucket.this,
│ on generated.tf line 1:
│ (source code not available)
│
│ "bucket": conflicts with bucket_prefix
╵
╷
│ Error: Conflicting configuration arguments
│
│ with aws_s3_bucket.this,
│ on generated.tf line 2:
│ (source code not available)
│
│ "bucket_prefix": conflicts with bucket
出力されたファイルを見ると、 conflict の制限がある bucket
と bucket_prefix
の両方が指定されています。
この様な状態となった場合は、いずれかの属性を削除する事で取り込みできるようになります。
% cat generated.tf
# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.
# __generated__ by Terraform
resource "aws_s3_bucket" "this" {
bucket = "example-tf-generate-config-prefix-20231014024553631000000001"
bucket_prefix = "example-tf-generate-config-prefix-"
force_destroy = null
object_lock_enabled = false
tags = {}
tags_all = {}
}
まとめ
これまでimportする際にリソース定義の記述を試行錯誤していた所、terraform 単体で完結できるのは素晴らしいです。
既にあるリソースと同じ定義で新たに作成したいといった場合にも活躍しそうです。