TerraformのバックエンドにTerraform Cloudを利用しているときに リソースインポートでエラーが発生して困っていた。 これについて調べていたら、リソースインポート時の変数参照についていろいろわかったのでそのまとめ。
Terraform 0.15.5で検証。
発生したエラー
再現手順
まずは発生したエラーについて。 特定の条件でリソースのインポートを行うとエラーが発生するというもので、再現手順は以下の通り。
- サンプルリポジトリの通りリソースを構築(terraform apply)する
- リソースをstateファイルから削除する
- Terraformをリモート実行モードに切り替える
- Terraform Cloud上で未定義の変数(例:
undefined_variable = "test"
)を設定する - Terraformをローカル実行モードに切り替える
- 2で削除したリソースをインポートする
以上の手順で実行したとき、リソースが正常通りインポートされることを期待するが、 実際には以下の通りエラーになる。
$ terraform import aws_s3_bucket.sample sample-import-tf Acquiring state lock. This may take a few moments... ╷ │ Error: Value for undeclared variable │ │ A variable named "undefined_variable" was assigned a value, but the root module does not declare a variable of that name. To use this value, add a "variable" block to │ the configuration. ╵
エラー原因
当然ながら、原因は手順4で未定義変数に値を設定しようとしたこと。 リソースインポート時に未定義変数への値の割り当てが実行できずにエラーとなった。
未定義変数への値の代入があると、terraform plan
でも警告はあるがエラーにはならないので
インポート時はエラー扱いになるという挙動の違いに混乱した。
$ terraform plan ... ╷ │ Warning: Value for undeclared variable │ │ The root module does not declare a variable named "undefined_variable" but a value was found in file "terraform.tfvars". If you meant to use this value, add a │ "variable" block to the configuration. │ │ To silence these warnings, use TF_VAR_... environment variables to provide certain "global" settings to all configurations in your organization. To reduce the │ verbosity of these warnings, use the -compact-warnings option.
また、一番驚いたのはローカル実行モードなのにTerraform Cloud上の変数を参照したところ。 ローカル実行モードでは変数のタブも参照できなくなるので、利用されないだけでなく、利用できないという認識だった。 ドキュメントを確認したが、インポートの章でもremoteの章でも変数を参照するという記載は見付からなかった。 リソースインポート作業が発生する場合は、過去に設定した変数はもう使わないからと放置せず、予め削除しておいた方がよさそう。
追加検証
この挙動について理解するために、以下のような追加検証を行った。
ローカル変数定義ファイルの参照
Terraform Cloud上の変数定義で、未定義変数に値を設定しているとエラーになることはわかった。
ではローカルの変数定義ファイル(terraform.tfvars
)で未定義変数に値を設定しているとどうなるか検証した。
手順は以下の通り
- サンプルリポジトリの通りリソースを構築(terraform apply)する
- リソースをstateファイルから削除する
- ローカルのterraform変数定義ファイル(terraform.tfvars)に未定義変数(例:
undefined_variable = "value"
)を設定する - 2で削除したリソースをインポートする
以上の検証の結果、リソースインポートはエラーにはならず警告だけ出力してインポートに成功した。 ローカルの変数定義ファイルも参照はされるものの、Terraform Cloud上の変数定義とは異なりエラー扱いにならないというのは挙動の違いに驚かされる。
$ terraform import aws_s3_bucket.sample sample-import-tf Acquiring state lock. This may take a few moments... Import successful! The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform. ╷ │ Warning: Value for undeclared variable │ │ The root module does not declare a variable named "undefined_variable" but a value was found in file "terraform.tfvars". If you meant to use this value, add a │ "variable" block to the configuration. │ │ To silence these warnings, use TF_VAR_... environment variables to provide certain "global" settings to all configurations in your organization. To reduce the │ verbosity of these warnings, use the -compact-warnings option. ╵
ローカルとリモート両方での未定義変数設定
リソースインポート時にローカルとリモート両方の変数定義が参照されていることがわかった。 では、ローカルとリモート両方で変数定義が行われているときの挙動を確認した。
手順は以下の通り。
- サンプルリポジトリの通りリソースを構築(terraform apply)する
- リソースをstateファイルから削除する
- Terraformをリモート実行モードに切り替える
- Terraform Cloud上で未定義の変数(例:
undefined_variable = "test"
)を設定する - ローカルのterraform変数定義ファイル(terraform.tfvars)に、4とは別の未定義変数(例:
another_undefined_variable = "value"
)を設定する - Terraformをローカル実行モードに切り替える
- 2で削除したリソースをインポートする
以上の検証の結果、2つの未定義変数の設定で警告とエラーが出力されることを確認した。 このため、どちらかで変数定義を行っていればもう1方の変数定義が無視されるということはなく、両方の変数定義が参照される様子。
$ terraform import aws_s3_bucket.sample sample-import-tf Acquiring state lock. This may take a few moments... Releasing state lock. This may take a few moments... ╷ │ Warning: Value for undeclared variable │ │ The root module does not declare a variable named "another_undefined_variable" but a value was found in file "terraform.tfvars". If you meant to use this value, add a │ "variable" block to the configuration. │ │ To silence these warnings, use TF_VAR_... environment variables to provide certain "global" settings to all configurations in your organization. To reduce the │ verbosity of these warnings, use the -compact-warnings option. ╵ ╷ │ Error: Value for undeclared variable │ │ A variable named "undefined_variable" was assigned a value, but the root module does not declare a variable of that name. To use this value, add a "variable" block to │ the configuration. ╵
リソース削除時の挙動
リソースインポート時にエラーは発生することは理解したが、 逆にリソースをstateから除外するときにどうなるか検証した。
手順は以下の通り
- サンプルリポジトリの通りリソースを構築(terraform apply)する
- Terraformをリモート実行モードに切り替える
- Terraform Cloud上で未定義の変数(例:
undefined_variable = "test"
)を設定する - ローカルのterraform変数(terraform.tfvars)に、3とは別の未定義変数(例:
undef = "value"
)を設定する - Terraformをローカル実行モードに切り替える
- リソースをstateファイルから削除する
結果は以下の通り、警告もエラーも生じずにリソースを除外することができた。 state操作において変数を参照するのはインポート時だけの挙動の様子。
$ terraform state rm aws_s3_bucket.sample Acquiring state lock. This may take a few moments... Removed aws_s3_bucket.sample Successfully removed 1 resource instance(s).
まとめ
Terraform Cloud利用時におけるリソースインポート時には ローカル実行モードであってもTerraform Cloudおよびローカルで設定した変数定義が参照される。 特にローカルでは警告止まりだった未定義変数の警告が、Terraform Cloudだとエラー扱いになる。 ローカル実行モードで利用する場合はTerraform Cloud上の変数定義はすべて削除しておいた方がよい。