Terraform destroyできなくて困ったとき


# 概要

* RDSがdestroyコマンドでapplyコマンド後の環境を消せない
* なんとか削除するときの手順

# 前提

* 本記事ではtfstateはremoteに存在している

# 詳細

* 以下のような内容で消せなかった
    * 具体的にはRDSのスナップショットの設定がおかしい為消せない
    * このエラーについては別途解説

```
aws_rds_cluster_dev_rds_cluster: Destroying... [id=dev-cluster]
╷
│ Error: RDS Cluster FinalSnapshotIdentifier is required when a final snapshot is required
│ 
│ 
```


```
resource "aws_rds_cluster" "dev_rds_cluster" {
  cluster_identifier      = "dev-cluster"
  engine                  = "aurora-mysql"
  engine_version          = "8.0.mysql_aurora.3.01.0"
  availability_zones      = ["ap-northeast-1a", "ap-northeast-1c"]
  db_subnet_group_name    = aws_db_subnet_group.dev_subnet_group.name
  database_name           = "hoge"
  master_username         = "admin"
  master_password         = "password"
  backup_retention_period = 0★
  skip_final_snapshot     = true★
  apply_immediately       = true★
  final_snapshot_identifier = "finalsnapshot"★
  #backup_retention_period = 1
```


* 手動でRDSを削除
* マネジメントコンソールとコマンドで確認できるリソースがあべこべに

```
$  terraform state list
```

* refreshコマンドで実態とstateを同期させる

```
$  terraform refresh      
$  terraform state list
```

* 再度destroyコマンドで削除
    * 消せる場合がある
    * 消せなければ別の方法で対応

```
$ terraform destroy
```

## 個別に消してみる

* 意外と消せるときがある

```
//terraformの管理下にあるオブジェクト一覧を出力する
$ terraform state list

//コードの内容が必要であれば以下のようにstateから出力して控えておく
$ terraform state show aws_s3_bucket.dev_s3_bucket

//ボトルネックとなっていそうな箇所を個別で削除してみる（個別削除は公式非推奨コマンドであることを留意）               
$ terraform destroy -target=aws_s3_bucket.dev_s3_bucket

//上記成功後、まとめてdestroyしてみる
$ terraform destroy 

```

* 以下エラーのときは時間がかかってタイムアウトしているだけの可能性があるのでリトライしてみること

```
Error: Failed to request discovery document: Get "https://app.terraform.io/.well-known/terraform.json": net/http: request canceled (Client.Timeout exceeded while awaiting headers)
```


# lockファイルの内容と実際に差異があって消せないとき

* initできない

```
$ terraform init

Initializing the backend...

Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
╷
│ Error: Failed to query available provider packages
│ 
│ Could not retrieve the list of available versions for provider hashicorp/aws: could not query provider registry for registry.terraform.io/hashicorp/aws: the
│ request failed after 2 attempts, please try again later: Get "https://registry.terraform.io/v1/providers/hashicorp/aws/versions": context deadline exceeded
│ (Client.Timeout exceeded while awaiting headers)
```

* 上書きapplyできない

```
$ terraform apply        
╷
│ Error: Error acquiring the state lock
│ 
│ Error message: workspace already locked (lock ID: "kaisha/kaisha-dev")
│ Lock Info:
│   ID:        2e0ac055-9074-99c7-612e-c054e0ae6b1c
│   Path:      
│   Operation: OperationTypeApply
│   Who:       yamadataro@macbookpro.local
│   Version:   1.2.0
│   Created:   2022-05-30 06:28:23.873161 +0000 UTC
│   Info:      
│ 
│ 
│ Terraform acquires a state lock to protect the state from being written
│ by multiple users at the same time. Please resolve the issue above and try
│ again. For most commands, you can disable locking with the "-lock=false"
│ flag, but this is not recommended.
╵
```

* `-lock=false `オプションを付けてロックファイル無視してapply
* tfstateは更新される
* しかしこの場合作成・削除できるが`-lock=false`オプションを使わなければ削除も生成もできない。

```
$ terraform apply -lock=false
$ terraform destroy -lock=false 
```

* .terraformディレクトリ(tfstate含む)と.terraform.lock.hclファイルをコマンドで強制削除しinitし直す

```
$ rm -fr .terraform .terraform.lock.hcl
$ terraform init
```

* initしただけの段階ではremoteのtfstateは更新されない
* applyした後反映される

```
$ terraform destroy

```

## ロックが外せない

* terraformコマンドをCtrl+Cなどで止めてしまうとSTATEファイルがおかしくなって以下のようなエラー

```
$ terraform apply                                
╷
│ Error: Error acquiring the state lock
│ 
│ Error message: workspace already locked (lock ID: "xxxxxx/xxxxxx")
│ Lock Info:
│   ID:        acef1a2e-3884-7b2f-2496-f43d5f8679f8
│   Path:      
│   Operation: OperationTypeApply
│   Who:       hoge@hogepc.local
│   Version:   1.2.0
│   Created:   2022-06-09 12:11:39.572366 +0000 UTC
│   Info:      
│ 
│ 
│ Terraform acquires a state lock to protect the state from being written
│ by multiple users at the same time. Please resolve the issue above and try
│ again. For most commands, you can disable locking with the "-lock=false"
│ flag, but this is not recommended.
╵
```
* ロックを強制的に外してから、削除等を実行

```
$ terraform force-unlock xxxxxx/xxxxxx
Do you really want to force-unlock?
  Terraform will remove the lock on the remote state.
  This will allow local Terraform commands to modify this state, even though it
  may be still be in use. Only 'yes' will be accepted to confirm.

  Enter a value: yes

Terraform state has been successfully unlocked!

The state has been unlocked, and Terraform commands should now be able to
obtain a new lock on the remote state.
```