TerraformでAmazon WorkSpacesを簡単インポート:importブロックとfor_eachの活用法
はじめに
こんにちは、Shunです。
今回は、Amazon WorkSpacesをTerraformへ簡単にインポートする方法をご紹介します。
Terraform 1.7以降で利用可能となったimportブロック内のfor_each構文を活用して、複数のAmazon WorkSpacesを一括でインポートします。
参考: Terraform 1.7 adds test mocking and config-driven remove
importブロックの使い方については、本記事で解説をしないので、importブロックの使用方法から知りたい方は、以下の記事を先に読むことをおすすめします。
想定読者
- Terraformを使用して多数のリソースをインポートする方法に関心がある方
- Terraformのimportブロックおよびfor_each構文の使い方に興味がある方
- Amazon WorkSpacesの運用効率化に興味がある方
importブロック内でのfor_each構文の書き方
importブロック内でfor_each構文を使用することは、一般的なTerraformでのfor_eachの使用と大きな違いはありません。また、一般的なimportコマンドとの記述方法との違いもfor_eachの行が追加される程度です。
importブロック内でfor_each構文を利用する際の重要な点は、インポートするリソースのresourceブロックを同時に記述することです。
以下にfor_eachを用いたリソースの定義と、それに対応するインポートコマンドの生成例を示します。
locals {
  buckets = {
    "staging" = "bucket1"
    "uat"     = "bucket2"
    "prod"    = "bucket3"
  }
}
import {
  for_each = local.buckets
  to = aws_s3_bucket.this[each.key]
  id = each.value
}
# ここがポイント
resource "aws_s3_bucket" "this" {
  for_each = local.buckets
}
引用: Import multiple instances with for_each
resourceブロックを同時に記述する必要があるのは、importブロック内でfor_each構文を使用する際に、以下のようなコードの自動生成ができないためです。
$ terraform plan -generate-config-out=generated.tf
実施すること
前提
以下を前提としています。
- Terraform環境は構築済み
- AWS CLI環境は構築済み
- Python環境は構築済み
- Amazon WorkSpacesが既に運用されている
ゴール
本記事の目的は、以下のステップを通じて、運用中のAmazon WorkSpacesをTerraformにインポートすることです。
- AWS CLIを使用して、運用中のAmazon WorkSpacesの一覧を取得
- 取得したAmazon WorkSpaces一覧を整形
- 整形されたAmazon WorkSpacesの一覧をTerraformへ記述し、インポートを実施
最終的なインポートを実施するためのTerraformコードは、以下の通りです。
terraform {
  required_version = "~> 1.7.0"
  backend "s3" {
    bucket         = "[s3_bucket_name]"
    key            = "[s3_key_name]"
    dynamodb_table = "[dynamodb_table_name]"
    region         = "ap-northeast-1"
  }
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}
provider "aws" {
  region = "ap-northeast-1"
}
locals {
  workspaces = {
    "[User_Name1]" = {
      DirectoryId = "[DirectoryId1]"
      BundleId    = "[BundleId1]"
      WorkspaceId = "[WorkspaceId1]"
    }
    "[User_Name2]" = {
      DirectoryId = "[DirectoryId2]"
      BundleId    = "[BundleId2]"
      WorkspaceId = "[WorkspaceId2]"
    }
    "[User_Name3]" = {
      DirectoryId = "[DirectoryId3]"
      BundleId    = "[BundleId3]"
      WorkspaceId = "[WorkspaceId3]"
    }
    ...
  }
}
import {
  for_each = local.workspaces
  to       = aws_workspaces_workspace.main[each.key]
  id       = each.value.WorkspaceId
}
resource "aws_workspaces_workspace" "main" {
  for_each     = local.workspaces
  user_name    = each.key
  directory_id = each.value.DirectoryId
  bundle_id    = each.value.BundleId
  id           = each.value.WorkspaceId
}
手順
1. AWS CLIを使用して、運用中のAmazon WorkSpacesの一覧を取得
まず、Amazon WorkSpacesをTerraformへインポートするため、以下の必要情報をAWS CLIから取得します。
- UserName
- DirectoryId
- BundleId
- WorkspaceId
次のコマンドを実行して、output.jsonへAmazon WorkSpacesの情報を出力します。
aws workspaces describe-workspaces --query "Workspaces[].[UserName,DirectoryId,BundleId,WorkspaceId]" > output.json
output.jsonは、以下のようになります。
[
    [
        "[UserName1]",
        "[DirectoryId1]",
        "[BundleId1]",
        "[WorkspaceId1]"
    ],
    [
        "[UserName2]",
        "[DirectoryId2]",
        "[BundleId2]",
        "[WorkspaceId2]"
    ],
    [
        "[UserName3]",
        "[DirectoryId3]",
        "[BundleId3]",
        "[WorkspaceId3]"
    ],
...
]
2. 取得したAmazon WorkSpaces一覧を整形
(今回は、Pythonを用いて整形してみます。)
Terraformのlocalsで指定可能なmap型へ値を整形するために、Pythonを使用します。
今回は、識別がしやすいUser_Nameを基にmapを作成します。
formatted.pyという名前のPythonファイルを作成します。
import json
# output.jsonを読み込む
with open('output.json', 'r') as file:
    data = json.load(file)
formatted_data = ""
# 各レコードをmap型に変換
for record in data:
    formatted_data += f'"{record[0]}" = {{\n'
    formatted_data += f'\tDirectoryId = "{record[1]}"\n'
    formatted_data += f'\tBundleId = "{record[2]}"\n'
    formatted_data += f'\tWorkspaceId = "{record[3]}"\n'
    formatted_data += '}\n'
print(formatted_data)
権限を付与し、実行します。
$ chmod 755 formatted.py $ python3 formatted.py > formatted_output.json
formatted_output.jsonは以下のようになります。
    "[User_Name1]" = {
      DirectoryId = "[DirectoryId1]"
      BundleId    = "[BundleId1]"
      WorkspaceId = "[WorkspaceId1]"
    }
    "[User_Name2]" = {
      DirectoryId = "[DirectoryId2]"
      BundleId    = "[BundleId2]"
      WorkspaceId = "[WorkspaceId2]"
    }
    "[User_Name3]" = {
      DirectoryId = "[DirectoryId3]"
      BundleId    = "[BundleId3]"
      WorkspaceId = "[WorkspaceId3]"
    }
		...
3. 整形されたAmazon WorkSpacesの一覧をTerraformへ記述し、インポートを実施
2.で出力した内容をlocalsのworkspacesへ入れ、それを基にimportを行います。
terraform {
  required_version = "~> 1.7.0"
  backend "s3" {
    bucket         = "[s3_bucket_name]"
    key            = "[s3_key_name]"
    dynamodb_table = "[dynamodb_table_name]"
    region         = "ap-northeast-1"
  }
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}
provider "aws" {
  region = "ap-northeast-1"
}
locals {
  workspaces = {
    # ここにpythonで整形したファイルの中身を入れます
    "[User_Name1]" = {
      DirectoryId = "[DirectoryId1]"
      BundleId    = "[BundleId1]"
      WorkspaceId = "[WorkspaceId1]"
    }
    "[User_Name2]" = {
      DirectoryId = "[DirectoryId2]"
      BundleId    = "[BundleId2]"
      WorkspaceId = "[WorkspaceId2]"
    }
    "[User_Name3]" = {
      DirectoryId = "[DirectoryId3]"
      BundleId    = "[BundleId3]"
      WorkspaceId = "[WorkspaceId3]"
    }
    ...
  }
}
import {
  for_each = local.workspaces
  to       = aws_workspaces_workspace.main[each.key]
  id       = each.value.WorkspaceId
}
resource "aws_workspaces_workspace" "main" {
  for_each     = local.workspaces
  user_name    = each.key
  directory_id = each.value.DirectoryId
  bundle_id    = each.value.BundleId
  id           = each.value.WorkspaceId
}
terraform planを実行すると、以下のようなエラーが発生しますが、これは機能が実験段階であるためであり、問題ありません。
$ terraform plan ~中略~ Plan: x to import, 0 to add, 0 to change, 0 to destroy. ╷ │ Warning: Config generation is experimental │ │ Generating configuration during import is currently experimental, and the generated
このエラーは無視してterraform applyを実行します。
$ terraform apply ~中略~ Apply complete! Resources: x imported, 0 added, 0 changed, 0 destroyed.
これでインポートは完了です。
$ terraform state list aws_workspaces_workspace.main["User_Name1"] aws_workspaces_workspace.main["User_Name2"] aws_workspaces_workspace.main["User_Name3"] ...
まとめ
Terraform 1.7では、新たにimportブロック内でfor_each構文が使用できるようになりました。
この新機能のおかげで、importブロックにリソースを一つずつ記述する必要がなくなりました。これにより、コード化のプロセスがより効率的になります。
しかし、冒頭の関連記事で紹介されている、従来のimportコマンドで利用できたコード生成機能はこの新機能ではサポートされていません。
そのため、インポート自体は効率的になっても、Terraformの管理自体は煩雑になる可能性があります。
Amazon WorkSpacesの運用を考えると、以下のようなコード化が望ましい場合があります。
$ cat import.tf
import {
  to       = aws_workspaces_workspace.User_Name1
  id       = each.value.WorkspaceId
}
$ terraform plan -generate-config-out=generated.tf
$ cat generated.tf
resource "aws_workspaces_workspace" "User_Name1" {
  bundle_id                      = "BundleId1"
  directory_id                   = "DirectoryId1"
  root_volume_encryption_enabled = false
  tags                           = {}
  tags_all                       = {}
  user_name                      = "User_Name1"
  user_volume_encryption_enabled = false
  volume_encryption_key          = null
  workspace_properties {
    compute_type_name                         = ""
    root_volume_size_gib                      = 
    running_mode                              = ""
    running_mode_auto_stop_timeout_in_minutes = 
    user_volume_size_gib                      = 
  }
}
今後、様々な検証を行いながら、この新しい機能の適切な使用方法を模索していく必要があります。
最後まで読んでいただき、ありがとうございました!
テックブログ新着情報のほか、AWSやGoogle Cloudに関するお役立ち情報を配信中!
Follow @twitterGoogle Cloud Partner Top Engineer 2025、2024 AWS All Cert、ビール検定1冠
Recommends
こちらもおすすめ
- 
    AWSサービスをTerraformでコード化する:AWS Chatbot編2024.3.11 
- 
    使えると便利なTerraformのメタ引数と組み込み関数2022.6.13 
- 
    Office 365入門【2】Office 365のクラウドID管理とは?2017.10.23 
Special Topics
注目記事はこちら

データ分析入門
これから始めるBigQuery基礎知識
2024.02.28

 AWSの料金が 10 %割引になる!
『AWSの請求代行リセールサービス』
2024.07.16
 
         
      

 
      