TerraformにTROCCOの既存ユーザーとチームをインポートしてみる

## はじめに
前回、Terraformを使ってTROCCOのチームを作ったところ既存のものと重複してしまいました。

https://qiita.com/khpkymgc/items/e879b00c94b4efdcdc9a

今更ですが、既存環境の設定をインポートして既存の設定を含めてTerraformで管理できるようにしていこうと思います。

## やりたいこと
 - TROCCOに登録済みのユーザーをTerraformで管理できるようにする
 - TROCCOに登録済みのチームをTerraformで管理できるようにする

## Terraformのimportの使い方を調べる
詳しく知りたい方は弊社Dさんの公開している下記を参考ください

https://qiita.com/SoySoySoyB/items/4f64e6dfcf028fae9140#import%E3%83%96%E3%83%AD%E3%83%83%E3%82%AF%E3%81%AE%E6%89%8B%E9%A0%86

上記は私には難しかったので、もっと基礎の下記の記事を参考にしました

https://dev.classmethod.jp/articles/terraform-import-command-and-import-block/

まとめると下記の設定をすればインポートできそうです。

 - importブロックを設定する
 - インポートするユーザーやチームのリソースを作成する

## TROCCOに登録済みのユーザーをインポートする
まず、**importブロック** を設定します。
ややこしくなりそうなので新しい.tfファイルを作成しました。

```import_user.tf
import {
  to = trocco_user.import # trocco_user.import はインポートするユーザーのリソースと名前です
  id = XXXX # インポートしたいユーザーのidを指定します
}

# リソースの名前は既存と重複しないものを設定する必要があります
resource "trocco_user" "import" {
# 必須項目のみ記載しています
  email                           = "import_user@example.com"
  role                            = "member"
}
```

::: note info
importブロックで使用したidはTROCCO APIで取得しました
https://documents.trocco.io/apidocs/get-users
:::

terraform plan するとこのようにimportが1件発生するのがわかります
指定していない値はTROCCOの現在の値に合わせて設定されました。

```
>terraform plan
trocco_user.import: Preparing import... [id=XXXX]
trocco_user.import: Refreshing state...

Terraform will perform the following actions:

  # trocco_user.import will be imported
    resource "trocco_user" "import" {
        can_use_audit_log               = true
        email                           = "import_user@example.com"
        id                              = XXXX
        is_restricted_connection_modify = false
        password                        = (sensitive value)
        role                            = "admin"
    }

Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.
```

terraform apply を実行して反映すると、.tfstateにインポートしたユーザーが反映されました！

```.tfstate
    {
      "mode": "managed",
      "type": "trocco_user",
      "name": "import",
      "provider": "provider[\"registry.terraform.io/trocco-io/trocco\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "can_use_audit_log": true,
            "email": "import_user@example.com",
            "id": XXXX,
            "is_restricted_connection_modify": false,
            "password": "",
            "role": "admin"
          },
          "sensitive_attributes": [
            [
              {
                "type": "get_attr",
                "value": "password"
              }
            ]
          ]
        }
      ]
    },
```

この時点では、インポートしたユーザーはTerraform上で管理している部署に紐づけられていないいないのでそのあたりも設定しておきます。

まず、部署は **var.department** で指定しているのでインポートしたユーザーを追記します。

```var.department
variable "departments" {
  type = map(list(string))
  default = {
    "sales" = [
      "sales01",
      "sales02",
      "import_user"
    ]
    ~~~
        ]
  }
}
```

この時点でterraform plan をしてみると、既存の設定(trocco_user.users)に引っかかり **import_user** が新しいユーザーとして作成されそうになります。

```
>terraform plan

  # trocco_user.users["import_user@example.com"] will be created
  + resource "trocco_user" "users" {
      + can_use_audit_log               = true
      + email                           = "import_user@example.com"
      + id                              = (known after apply)
      + is_restricted_connection_modify = false
      + password                        = (sensitive value)
      + role                            = "admin"
    }

Plan: 1 to add, 0 to change, 0 to destroy.
```
::: note info
既存でどんな設定をしているかは下記をご参考ください
https://qiita.com/khpkymgc/items/011880d16186129560b7
:::

別のリソースで作成すると同アドレスのユーザーが存在していても認識できないようです
既存のリソースに対して除外条件を設定することも考えましたが、管理が手間になるので他の方法を探します

## import_userの所属するリソースを変更する 
調べたところ、.tfstateを書き換えて **import_user** を **trocco_user.users**リソース 配下へ移し替え、 **trocco_user.import**リソースを削除すれば良いようです。
trocco_user.usersリソースを見ると、trocco_user.importリソースにはなかった **"index_key"** が存在したので、これを追加して**trocco_user.users**リソース配下に書き換えます。

```.tfstate
{
      "mode": "managed",
      "type": "trocco_user",
      "name": "users",
      "provider": "provider[\"registry.terraform.io/trocco-io/trocco\"]",
      "instances": [
        {
 ~~~~~~~~~
      {
        "index_key": "import_user@example.com", # 手入力で追加しました
          "schema_version": 0,
          "attributes": {
            "can_use_audit_log": true,
            "email": "import_user@example.com",
            "id": XXXX,
            "is_restricted_connection_modify": false,
            "password": "",
            "role": "admin"
          },
          "sensitive_attributes": [
            [
              {
                "type": "get_attr",
                "value": "password"
              }
            ]
          ]
        }
      ]
    },
```

 **trocco_user.import**リソースを削除(importブロックも削除しました)して terraform plan を実行すると、うまくいったようです！

## TROCCOに登録済みのチームをTerraformで管理できるようにする
ユーザーのインポートができたので、チームもインポートしていきます。
同じように、importブロックと作成したいリソースを記載します

```team_import.tf
import {
  to = trocco_team.import_sample
  id = XXXX
}

# サンプルチーム
resource "trocco_team" "import_sample" {
  name        = "サンプル"
  description = "チームの例"

  members = flatten([
    for department, members in var.departments : [
      for member in members : {
        user_id = local.user_email_ids[local.local_part_to_email[member]],
        role    = lower(department) == "test" ? "team_member" : "team_admin"
      }
      if lower(department) == "admin" || lower(department) == "test"
    ]
  ])
}
```

::: note info
チームのidを取得するAPIはこちら
https://documents.trocco.io/apidocs/get-teams
:::

::: note info
チーム作成時の処理については前回の記事もご参考ください
https://qiita.com/khpkymgc/items/e879b00c94b4efdcdc9a#trocco_team-%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B%E6%BA%96%E5%82%99%E3%82%92%E3%81%99%E3%82%8B
:::

terraform plan を実行すると問題なくインポートされそうです

```
>terraform plan

Plan: 1 to import, 0 to add, 0 to change, 0 to destroy.
```

terraform apply を実行し、インポートが完了しました！

```
>terraform apply

Apply complete! Resources: 1 imported, 0 added, 0 changed, 0 destroyed.
```

チームでは、リソースの移動が不要なのでimportブロックの削除などは行わなくても問題ありません。
ただ、もう使わない&管理上スッキリさせたいので削除しても問題ありません

## インポート完了後、terraform planを行うと何故かchangeが発生する
チームのインポートが完了した後、設定を変更せずterraform planを実行してみました。
すると、何故かchangeが発生してしまいました

```
 # trocco_team.import_sample will be updated in-place
  ~ resource "trocco_team" "import_sample" {
        id          = XXXX
      ~ members     = [
          ~ {
              ~ user_id = ○○○○ -> △△△△
                # (1 unchanged attribute hidden)
            },
          ~ {
              ~ user_id = △△△△ -> ○○○○
                # (1 unchanged attribute hidden)
            },

        ]
        name        = "サンプル"
        # (1 unchanged attribute hidden)
    }
```

チームに所属するユーザーの登録順が変わることでchangeが発生するようです
確認したところ、Terraform Provider for TROCCOの古いバージョンで発生していた不具合のようです。
Providerのバージョンを0.3.0から最新の0.7.0へアップデートしてみます。

下記のサイトを参考に、.tfファイルへバージョン情報を追記し、```terraform init -upgrade```を実行しました。

https://dev.classmethod.jp/articles/upgrade-terraform-registry-module-version/

再度terraform planを行うと、No changeとなり問題ないことが確認できました

```
>terraform plan

No changes. Your infrastructure matches the configuration.
```

お疲れ様でした！

## おわりに
今回はインポートするリソースが少なかったので、APIで手動で情報を取得してimportブロックを手入力してと人力作業でどうにかなりましたが、数が多いと大変そうだなと感じました。
冒頭で紹介したDさんの記事ではそのあたりをPythonを使ってうまいこと実施されていたので実運用を考えるとTerraform以外の言語の知識も勉強しないといけないなと思いました。

また、記事の最後に書いた  **インポート完了後、terraform planを行うとchangeが発生する** 問題について、最初自分で調べたところ「flattenを使うと処理順は考慮されない(毎回バラバラの順番になる)」という情報があり、ここまで試してきた内容が全部駄目になるかとすごく焦りました。
Providerのバージョンアップで済んで本当に良かったです。
やりたいことに対して、実装方法の選択肢をいくつか持っておいて対応できるようにすることって重要だなとひしひしと感じました。

terraform importが無事に使えたことでTerraformの基本的な内容は一旦履修できた気でいますが、これからも色々試して良いやり方を学んでいきたいと思います！