Terraformの Error: Provider configuration not present を解決する

この記事は **[リンクバルアドベントカレンダー2022](https://qiita.com/advent-calendar/2022/linkbal)** の最終日の記事です。

## はじめに
Terraformが0.12系という化石バージョンのリポジトリで作業することがありました。バージョンアップをしてみると `Error: Provider configuration not present` にぶち当たり、このエラーを解決する日本語の記事はすぐ見つからなかったので、私が解決できた方法を書きます。

## 環境
- OS: macOS Ventura Version 13.0.1
- terraform:
    - before version: 0.12.0
    - after version: 0.13.7
    - provider: aws 4.39.0

:::note warn
注意
エラーの原因が私と同じでない場合は、解決方法が変わるはずです
:::

「さっさと結論を教えて」というあなたは、[解決手順のまとめ](#解決手順のまとめ)に飛んでください！


## エラー内容
0.12系では使えない `for_each` を使いたかったので `terraform 0.13upgrade` して `terraform init --reconfigure` して `terafform plan` をすると、こんなエラーが、、、

```
$ terraform 0.13upgrade
...


$ terraform init --reconfigure
...

$ terafform plan

Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan,
but will not be persisted to local or remote state storage.


Error: Provider configuration not present

To work with data.aws_iam_policy_document.xxxxx 
its original provider configuration at  
provider["registry.terraform.io/-/aws"] is required, 
but it has been removed.
This occurs when a provider configuration is removed 
while objects created by that provider still exist in the state.
Re-add the provider configuration to destroy 
data.aws_iam_policy_document.xxxxx,
after which you can remove the provider configuration again.
```

うん、TOEICで375点を叩き出した僕は、素直にGoogle翻訳に頼ります。

> provider["registry.terraform.io/-/aws"] での元のプロバイダー構成が必要ですが、削除されました。
> これは、そのプロバイダーによって作成されたオブジェクトがまだ状態に存在しているときに、プロバイダー構成が削除された場合に発生します。
> プロバイダー構成を再度追加して、data.aws_iam_policy_document.xxxxx を破棄します。その後、プロバイダー構成を再度削除できます。

・・・よくわからないので、エラー内容でググると、以下の記事が私のブラウザでは検索結果のTOPに表示されました。

https://discuss.hashicorp.com/t/source-of-providers-might-caused-an-error-provider-configuration-not-present/14409

記事の内容を今回の私のケースに当てはめると、 `["registry.terraform.io/-/aws"]` を抹消すればいけそうな気がします。

## やってみる
実際に試した内容をそのまま記載します。

コメントに簡単な説明をしています。

```sh
# providerを確認する
$ terraform providers

Providers required by configuration:
.
└── provider[registry.terraform.io/hashicorp/aws]

Providers required by state:

    provider[registry.terraform.io/-/aws]

# 念の為リモートのstateをローカルに保存しておく
$ terraform state pull > terraform.tfstate.manualbackup20221225

# providerをリプレイスしてみる
$ terraform state replace-provider 'registry.terraform.io/-/aws' 'registry.terraform.io/hashicorp/aws'
Terraform will perform the following actions:

  ~ Updating provider:
    - registry.terraform.io/-/aws
    + registry.terraform.io/hashicorp/aws

Changing 11 resources:

  aws_wafv2_regex_pattern_set.xxx
  data.aws_iam_policy_document.xxxxx
  aws_iam_role_policy_attachment.xxx
  aws_wafv2_web_acl.xxx
  aws_backup_plan.xxx
  aws_instance.xxx
  aws_sqs_queue.xxx
  aws_sqs_queue.xxx_xxx
  aws_backup_selection.xxx
  aws_backup_vault.xxx
  aws_iam_policy.xxx

Do you want to make these changes?
Only 'yes' will be accepted to continue.

# yes入力
Enter a value: yes

# 改めてplanしても変わらずエラー...
$ terafform plan
# 出力は割愛

# ファイルを確認してみる
$tree -a
.
├── .terraform
│   ├── plugins
│   │   ├── darwin_amd64
│   │   │   ├── lock.json
│   │   │   └── terraform-provider-aws_v3.37.0_x5
│   │   ├── registry.terraform.io
│   │   │   ├── - # こいつはなんなんだ
│   │   │   │   └── aws
│   │   │   │       └── 4.41.0
│   │   │   │           └── darwin_amd64
│   │   │   │               └── terraform-provider-aws_v4.41.0_x5
│   │   │   └── hashicorp
│   │   │       └── aws
│   │   │           └── 4.41.0
│   │   │               └── darwin_amd64
│   │   │                   └── terraform-provider-aws_v4.41.0_x5
│   │   └── selections.json
│   ├── terraform.tfstate
│   └── terraform.tfstate.manualbackup20221201-1506
├── .terraform-version
├── README.md
├── backup.tf
├── ...

# .terraform/registry.terraform.io/-/ が原因っぽい
# 削除前に念の為どこかにコピーしておく
$ cp -r .terraform/registry.terraform.io/-/ ~/

# registry.terraform.io/- を削除する
$ rm -rf .terraform/registry.terraform.io/-/

# 再度providerを確認すると [registry.terraform.io/-/aws] は消えている
$ terraform providers

Providers required by configuration:
.
└── provider[registry.terraform.io/hashicorp/aws]

Providers required by state:

    provider[registry.terraform.io/hashicorp/aws]

# 再度planをすると別のエラーが出る
$ terraform plan

Error: Could not load plugin


Plugin reinitialization required. Please run "terraform init".

Plugins are external binaries that Terraform uses to access and manipulate resources.
The configuration provided requires plugins which can't be located,
don't satisfy the version constraints, or are otherwise incompatible.

Terraform automatically discovers provider requirements from your configuration,
including providers used in child modules. To see the
requirements and constraints, run "terraform providers".

Failed to instantiate provider "registry.terraform.io/hashicorp/aws" to obtain
schema: unknown provider "registry.terraform.io/hashicorp/aws"

# Please run "terraform init". と言われたとおり、initする
$ terraform init
Initializing the backend...

Initializing provider plugins...
- Using previously-installed hashicorp/aws v4.41.0

The following providers do not have any version constraints in configuration,
so the latest version was installed.

To prevent automatic upgrades to new major versions that may contain breaking
changes, we recommend adding version constraints in a required_providers block
in your configuration, with the constraint strings suggested below.

* hashicorp/aws: version = "~> 4.41.0"

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.

$ terraform plan
# 成功！
```

## 解決手順のまとめ
1. エラーに記載されている `-` が付いているprovidersファイルを削除
    - 例 `rm -rf .terraform/registry.terraform.io/-/`
1. `terraform init`


## `-`  が付いているディレクトリはなんなのか
ぶっちゃけ私はわかっていません。
わかっていることは、 `terraform 0.13upgrade` を実行することで生まれたことです。

以下、私の雑な仮説です。

`terraform 0.13upgrade` 実行後に、以下の内容の `terraform/versions.tf` が自動で生成されます。

```terraform:terraform/versions.tf
terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
    }
  }
  required_version = ">= 0.13"
}
```

`hashicorp/aws` が既存のディレクトリとバッティングして、既存のディレクトリ名が `-` に変更されてしまった？

`terraform 0.13upgrade` 実行前の状態を確認していなかったので、わからずです...

## おわりに
よいクリスマスをお過ごしください！