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
こちらもおすすめ
-
使えると便利なTerraformのメタ引数と組み込み関数
2022.6.13
Special Topics
注目記事はこちら
データ分析入門
これから始めるBigQuery基礎知識
2024.02.28

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

