Elastic Cloud のTerraformでのorganization メンバー管理の動作確認

# この記事の内容
Terraformのec providerのv0.12でElastic Cloudのメンバー管理ができるようになったので、動作を確認しました。

該当の製品ドキュメントはこちらです
https://registry.terraform.io/providers/elastic/ec/latest/docs/resources/organization


# 動作検証
Organization管理のためのterraformプロジェクトは、個別のDeploymentのプロジェクトとは別に作成するのが良いです。以下のファイルを新規に作成して、terraform initして初期化します。

```:terraform.tf
terraform {
  required_version = "~> 1.6"

  required_providers {
    ec = {
      source  = "elastic/ec"
      version = "0.12.0"
    }
  }
}

provider "ec" {
    apikey = var.ec-apikey
}

variable "ec-apikey" {}

resource "ec_organization" "myorg" {
}
```

```:terraform.tfvars
ec-apikey       = "<自分のAPIキー>"
```

続けて`terraform apply`すると、以下のようなエラーとなります。
```
╷
│ Error: organization already exists
│ 
│   with ec_organization.myorg,
│   on terraform.tf line 22, in resource "ec_organization" "myorg":
│   22: resource "ec_organization" "myorg" {
│ 
│ please import the organization using terraform import
╵
```

ec_organizationを使う場合、先に`terraform import ec_organization.myorg <org-id>`でimportする必要があります。`org-id`は自分のOrganization idをElastic Cloud管理画面から確認してください。結果は以下のようになります。
```
ec_organization.myorg: Importing from ID "<org-id>"...
ec_organization.myorg: Import prepared!
  Prepared ec_organization for import
ec_organization.myorg: Refreshing state... [id=<org-id>]

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

terraform.tfstateファイルを確認すると、以下のようになってます。（内容は部分的にマスクしています）
```:terraform.tfstate
{
  "version": 4,
  "terraform_version": "1.6.6",
  "serial": 7,
  "lineage": "7e265116-be43-375a-fd94-a7780d16bfb2",
  "outputs": {},
  "resources": [
    {
      "mode": "managed",
      "type": "ec_organization",
      "name": "myorg",
      "provider": "provider[\"registry.terraform.io/elastic/ec\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "id": "xxx@gmail.com",
            "members": {
              "xxx": {
                "deployment_roles": [
                  {
                    "all_deployments": true,
                    "application_roles": null,
                    "deployment_ids": null,
                    "role": "viewer"
                  }
                ],
                "email": "xxx@gmail.com",
                "invitation_pending": true,
                "organization_role": null,
                "project_elasticsearch_roles": [],
                "project_observability_roles": [],
                "project_security_roles": [],
                "user_id": ""
              },
              "yyy@xxx": {
                "deployment_roles": [
                  {
                    "all_deployments": true,
                    "application_roles": null,
                    "deployment_ids": null,
                    "role": "admin"
                  }
                ],
                "email": "yyy@xxx",
                "invitation_pending": false,
                "organization_role": "organization-admin",
                "project_elasticsearch_roles": [],
                "project_observability_roles": [],
                "project_security_roles": [],
                "user_id": "zzz"
              }
            }
          },
          "sensitive_attributes": []
        }
      ]
    }
  ],
  "check_results": null
}
```
現時点のメンバー登録と状況が一致しますね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109197/05ac715c-5e38-297d-bd63-9df4ef4092ea.png)

では、この内容を利用して、tfファイルに反映します。全てのパラメータを反映する必要はなく、今回の場合はdeployment_roleとorganization_role(設定あれば）を反映すれば良いです。

```:terraform.tf
terraform {
  required_version = "~> 1.6"

  required_providers {
    ec = {
      source  = "elastic/ec"
      version = "0.12.0"
    }
  }
}

provider "ec" {
    apikey = var.ec-apikey
}

variable "ec-apikey" {}

resource "ec_organization" "myorg" {
  members =  {
    "xxx@gmail.com": {
      "deployment_roles": [
        {
          role            = "viewer"
          all_deployments = true
        }
      ]
    },
    "yyy@xxx": {
      "deployment_roles": [
        {
          role            = "admin"
          all_deployments = true
        }
      ]
      "organization_role": "organization-admin",
    }
  }
}
```

最初のapplyでは現状の状態から変更がないので、そのまま変更なく通ります。
```:terraform applyの結果
ec_organization.myorg: Refreshing state... [id=xxx]

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.

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

では、一つ変更を行います。一人のメンバーのroleをviewer -> editorに変更します。
```:terraform.tf
terraform {
  required_version = "~> 1.6"

  required_providers {
    ec = {
      source  = "elastic/ec"
      version = "0.12.0"
    }
  }
}

provider "ec" {
    apikey = var.ec-apikey
}

variable "ec-apikey" {}

resource "ec_organization" "myorg" {
  members =  {
    "xxx@gmail.com": {
      "deployment_roles": [
        {
          role            = "editor"
          all_deployments = true
        }
      ]
    },
    "yyy@xxx": {
      "deployment_roles": [
        {
          role            = "admin"
          all_deployments = true
        }
      ]
      "organization_role": "organization-admin",
    }
  }
}
```

変更が正しく反映されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109197/fd198b6a-9442-6351-db3d-0b8a59254834.png)

次に、メンバーを一人設定から外します。
```:terraform.tf
terraform {
  required_version = "~> 1.6"

  required_providers {
    ec = {
      source  = "elastic/ec"
      version = "0.12.0"
    }
  }
}

provider "ec" {
    apikey = var.ec-apikey
}

variable "ec-apikey" {}

resource "ec_organization" "myorg" {
  members =  {
    # "xxx@gmail.com": {
    #   "deployment_roles": [
    #     {
    #       role            = "editor"
    #       all_deployments = true
    #     }
    #   ]
    # },
    "yyy@xxx": {
      "deployment_roles": [
        {
          role            = "admin"
          all_deployments = true
        }
      ]
      "organization_role": "organization-admin",
    }
  }
}
```
正しくメンバーが外されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109197/bd497d53-a174-3293-e041-bb0abe3f3dd8.png)

なお、すべてのメンバーの設定を外してapplyすると、Deploymentが存在する中ではそれはできないので、ちゃんとエラーします。
```
╷
│ Error: Removing organization member failed.
│ 
│   with ec_organization.myorg,
│   on terraform.tf line 22, in resource "ec_organization" "myorg":
│   22: resource "ec_organization" "myorg" {
│ 
│ api error: 2 errors occurred:
│       * organization.has_deployments: Organization [<org-id>] has active deployments. Please
│ terminate all deployments and pay all invoices before deleting or leaving this
│ organization.
│       * organization.has_invoices: Organization [<org-id>] has unpaid invoices. Please
│ terminate all deployments and pay all invoices before deleting or leaving this
│ organization.
```

最後、やっぱりTerraformでの管理をやめたいとなった場合のプロジェクトをdestroyしてみます。
```:terraform destroyの結果
ec_organization.myorg: Refreshing state... [id=xxx]

Terraform used the selected providers to generate the following execution plan. Resource
actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # ec_organization.myorg will be destroyed
  - resource "ec_organization" "myorg" {
      - id      = "xxx" -> null
      - members = {
          - "yyy@xxx" = {
              - deployment_roles            = [
                  - {
                      - all_deployments = true -> null
                      - role            = "admin" -> null
                    },
                ] -> null
              - email                       = "yyy@xxx" -> null
              - invitation_pending          = false -> null
              - organization_role           = "organization-admin" -> null
              - project_elasticsearch_roles = [] -> null
              - project_observability_roles = [] -> null
              - project_security_roles      = [] -> null
              - user_id                     = "xxx" -> null
            },
        } -> null
    }

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

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

ec_organization.myorg: Destroying... [id=xxx]
ec_organization.myorg: Destruction complete after 0s

Destroy complete! Resources: 1 destroyed.
```

一見、メンバーが削除されるようにも見えますが、Destroyでは変更は行われません。画面を見ると状態は維持されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109197/bd497d53-a174-3293-e041-bb0abe3f3dd8.png)


# おわり
今回のv0.12のアップデートでElastic Cloudのメンバー管理もIaCで管理できるようになりました。今回は基本的な動作の確認だけですが、使っていて問題ありませんでした。