Terraform/TerrafomrerでAWS既存リソースをインポートする

## はじめに
Terraformを使ってみると`Terraformでコードを書く` よりも `既存リソースをTerraformにインポート`することが結構あります。
公式のドキュメントを読めばやり方はわかります。



ただ、少しわかりづらい箇所もあるので細かい部分も説明しながらインポート手順を説明していきます




## 前提
* AWSアカウント作成済
* AWSリソース作成済(今回は[こちらの記事](https://qiita.com/YK0214/items/59bc0e5ae89f68af74b3)で作成したlambda関数をリソースとして使用します。他のリソースでも構いません)
* terraform インストール済 (参考: https://dev.classmethod.jp/articles/beginner-terraform-install-mac/)
* terraformer インストール済 (参考: https://beyondjapan.com/blog/2020/05/terraformer-import-existing-infrastructure/)


## ディレクトリ構成

```
root
  ┣━　test
  ┃   ┣━ provider.tf
  ┃   ┣━ terraform.tfvars
  ┃   ┗━ lambda.tf
　　　　┗━ .gitignore
```
インポートするための必要最低限のファイルとを用意します
`.gitignore`はGiHub等にAWSのキーをpushしないためのファイルなのでローカルだけで作業する場合は不要です。



```tf:provider.tf
variable "aws_access_key" {}
variable "aws_secret_key" {}

provider "aws" {
  access_key = var.aws_access_key
  secret_key = var.aws_secret_key
  region     = "us-east-2"
}
```

```tf:terraform.tfvars
# AWSのアクセスキーとシークレットキーを記述
aws_access_key = "xxxxxxxxxx"
aws_secret_key = "xxxxxxxxxx"
```

```tf:lambda.tf
# ここにlambdaのリソースをインポートしていきます
```

```:.gitignore
# .tfstate files
*.tfstate
*.tfstate.*

# .tfvars files
*.tfvars

# terraformer import fils
*/generated/
```

## インポート方法
### Terraformで既存リソースをインポート
まずは `terraform リソース名` でブラウザ検索してみましょう
今回はlambdaのリソースをインポートするので `terraform lambda`で検索すると
Terraform公式のリンクが表示されます
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function
![スクリーンショット 2021-09-10 8.41.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603209/f3b05a61-cdf4-cb24-4474-e641b7acded8.png)


こちらのリンクに記載されている`Example Usage`の章を参考に最低限のリソースの雛形を書きます

```hcl:lambda.tf
# "test_lambda"の部分は任意の名前でOK
resource "aws_lambda_function" "test_lambda" {
}
```
これで雛形が完成です


次にインポートのコマンドを調べます
`Import`の章を確認しましょう
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function#import
![スクリーンショット 2021-09-10 8.43.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603209/e5b0daee-0329-bbfc-0bf7-5495e96268c0.png)

ここにインポートの際に必要なコマンドが記載されています
> $ terraform import aws_lambda_function.test_lambda my_test_lambda_function

こちらを解釈すると
> $ terraform import aws_lambda_function.(インポート先の名前) (インポートしたいlambda関数の名前)

となります。

今回は`インポート先の名前: test_lambda` 、`インポートしたいlambda関数の名前: start_stop_ec2_inatance`なのでそちらを使用してターミナル上でコマンド実行します

```
user@user test % terraform import aws_lambda_function.test_lambda start_stop_ec2_instance

aws_lambda_function.test_lambda: Importing from ID "start_stop_ec2_instance"...
aws_lambda_function.test_lambda: Import prepared!
  Prepared aws_lambda_function for import
aws_lambda_function.test_lambda: Refreshing state... [id=start_stop_ec2_instance]

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.
```

`Import successful!`のログが出れば成功です

#### インポートする際の注意点

一点注意して頂きたいのは**リソースごとにインポートコマンドの書き方が異なります。**

先ほどのlambdaの場合はコマンドの末尾に**lambda関数の名前**を入力していましたが、
例えばEC2インスタンスの場合は、以下のようにコマンドの末尾には**インスタンスのid**を入力します
> $ terraform import aws_instance.web i-12345678
参照：https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance#import


インポートのコマンドはリソースごとに調べて実行しましょう

### Terraformerでtfファイルを出力
Terraformによるインポートが終わったら、Terraformerを使ってリソースの中身を書いていきます。

GitHubに必要なコマンドとリソース名が掲載されているのでこちらを使用します
https://github.com/GoogleCloudPlatform/terraformer/blob/master/docs/aws.md
![スクリーンショット 2021-09-10 8.54.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603209/38e7bfaa-8764-9da9-cff1-6ce511c1beea.png)


基本的なコマンドは以下の通りです
>$ terraformer import aws --resources=(リソース名) --regions=(リージョン名)

まずインポートしたいリソース名をGitHub上で検索します。
検索する理由は**Terraformer上でのリソース名が一般的なリソース名を省略した形になっている場合があるからです**

例えば`security_group`をインポートしたい場合、GitHub上で　検索すると`sg`で入力してね。と書いてあります
![スクリーンショット 2021-09-10 8.57.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603209/2b5ebb91-8801-92ce-c3df-aa9938596b5f.png)


今回は`lambda`をインポートしたいのでGitHub上で調べてみると、そのまま`lambda`がリソース名として使えそうです
![スクリーンショット 2021-09-10 8.59.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603209/0b43482b-274c-1c5e-d82b-4ec4fddcc4c2.png)


リソース名がわかったらコマンドをターミナルで入力しましょう

```
user@user test % terraformer import aws --resources=lambda --regions=us-east-2

2021/09/07 09:05:11 aws importing region us-east-2
2021/09/07 09:05:14 aws importing... lambda
2021/09/07 09:05:16 aws done importing lambda
2021/09/07 09:05:16 Number of resources for service lambda: 1
2021/09/07 09:05:16 Refreshing state... aws_lambda_function.tfer--test_lambda
2021/09/07 09:05:19 Filtered number of resources for service lambda: 1
2021/09/07 09:05:19 aws Connecting.... 
2021/09/07 09:05:19 aws save lambda
2021/09/07 09:05:19 aws save tfstate for lambda
```

コマンドが成功すれば`generated`ディレクトリが生成され、その中に`lambda_function.tf`ファイルも生成されます

その中身を先ほど作成した`lambda.tf`ファイルの雛形に書き写します

```hcl:lambda.tf
resource "aws_lambda_function" "test_lambda" {
  environment {
    variables = {
      INSTANCE_ID = "i-xxxxxxxxxx"
    }
  }

  function_name                  = "start_stop_ec2_instance"
  handler                        = "lambda_function.lambda_handler"
  memory_size                    = "128"
  package_type                   = "Zip"
  reserved_concurrent_executions = "-1"
  role                           = "arn:aws:iam::xxxxxxxxxx:role/start_stop_instance_lambda"
  runtime                        = "python3.8"
  source_code_hash               = "xxxxxxxxxxxxxxxxxxxx"
  timeout                        = "3"

  tracing_config {
    mode = "PassThrough"
  }
}
```
ここで一点注意して欲しいのが`INSTANCE_ID = "i-xxxxxxxxxx"`のように[ハードコーディング](https://wa3.i-3-i.info/word12866.html)されている箇所があることです

GitHub等にpushする際は変数化してハードコーディングを回避しましょう




### インポートできたか確認

最後に既存リソースとTerraform上のリソースに差分がないか`terraform plan`を実行して確認します

```
user@user test % terraform plan

aws_lambda_function.test_lanmbda: Refreshing state... [id=start_stop_ec2_instance]

No changes. Your infrastructure matches the configuration.

Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.
```

`No changes. `と出れば差分なくインポート完了です


## 終わり
今回はlambdaを使って既存リソースのインポートを行いました
他のリソースでも同様の手順でインポートできるのでぜひやってみてください