出力を入力へ

プログラミングに関する自分が考えた事を中心にまとめます

Terraform Cloudでリソースインポート時の変数参照

TerraformのバックエンドにTerraform Cloudを利用しているときに リソースインポートでエラーが発生して困っていた。 これについて調べていたら、リソースインポート時の変数参照についていろいろわかったのでそのまとめ。

Terraform 0.15.5で検証。

発生したエラー

再現手順

まずは発生したエラーについて。 特定の条件でリソースのインポートを行うとエラーが発生するというもので、再現手順は以下の通り。

  1. サンプルリポジトリの通りリソースを構築(terraform apply)する
  2. リソースをstateファイルから削除する
  3. Terraformをリモート実行モードに切り替える
  4. Terraform Cloud上で未定義の変数(例: undefined_variable = "test")を設定する
  5. Terraformをローカル実行モードに切り替える
  6. 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)で未定義変数に値を設定しているとどうなるか検証した。

手順は以下の通り

  1. サンプルリポジトリの通りリソースを構築(terraform apply)する
  2. リソースをstateファイルから削除する
  3. ローカルのterraform変数定義ファイル(terraform.tfvars)に未定義変数(例: undefined_variable = "value")を設定する
  4. 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.
╵

ローカルとリモート両方での未定義変数設定

リソースインポート時にローカルとリモート両方の変数定義が参照されていることがわかった。 では、ローカルとリモート両方で変数定義が行われているときの挙動を確認した。

手順は以下の通り。

  1. サンプルリポジトリの通りリソースを構築(terraform apply)する
  2. リソースをstateファイルから削除する
  3. Terraformをリモート実行モードに切り替える
  4. Terraform Cloud上で未定義の変数(例: undefined_variable = "test")を設定する
  5. ローカルのterraform変数定義ファイル(terraform.tfvars)に、4とは別の未定義変数(例: another_undefined_variable = "value")を設定する
  6. Terraformをローカル実行モードに切り替える
  7. 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から除外するときにどうなるか検証した。

手順は以下の通り

  1. サンプルリポジトリの通りリソースを構築(terraform apply)する
  2. Terraformをリモート実行モードに切り替える
  3. Terraform Cloud上で未定義の変数(例: undefined_variable = "test")を設定する
  4. ローカルのterraform変数(terraform.tfvars)に、3とは別の未定義変数(例: undef = "value")を設定する
  5. Terraformをローカル実行モードに切り替える
  6. リソースを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上の変数定義はすべて削除しておいた方がよい。