Terraform職人の @minamijoyo です。
クラウドワークスではAWSのインフラ構成管理にHashiCorpの Terraform を利用しており、 日々Terraformの設定ファイルを書いてるわけですが、 コード書いてると、リソースタイプの名前がうろ覚えとか、属性値の名前のスペルに自信がないとか、この属性値って必須項目だっけ? とか、なんだかんだで公式ドキュメントを見ながらコードを書いてることが多いです。
Vimのプラグインで補完してくれるやつがあるのは知ってるんだけど、 あらかじめリストファイルを持っているアプローチだと、バージョンに合わせてリストファイルの更新しないといけなくて、仕組み上の限界があるし、サポートされてない自作プロバイダとかだとそもそも使えない。
なんかもっといいかんじにできないかなぁと思って、趣味でTerraformのソースコードを読んでたら、最近入ったGetSchema APIというのを見つけて、欲しかったのはこれだよ感で早速試してみたらバグってるし。まじかよ。で、バグ報告や修正に協力したり、AWSプロバイダにも修正を取り込んでもらったり、なんやかんやあって、結果的にTerraformプロバイダから動的に型定義情報を取得するtfschemaという俺得ツールができたので、テラフォーマーズの皆さんの役に立つかなーと思って紹介します。
特徴
- Terraformのコアと同じgo-pluginプロトコルを使ってTerraformプロバイダから動的に型定義情報を取得できます。
- リソースタイプの一覧が取得できます。
- このリソースタイプの一覧を使ってbash/zshでコマンド引数の補完も可能。
- なので、このリソースタイプの一覧補完を使ってシュッと公式ドキュメントを開くこともできる。
TerraformプロバイダとはAWS/GCP/AzureなどのTerraformのプラグインのことです。 Terraformのコアと同じ方法でTerraformプロバイダのバイナリと実際に通信しているのがポイントで、 あらかじめリストファイルを作成しておくわけでもないので、最新版のリストファイルがまだ更新されていないみたいな問題は原理的にありません。
とりあえずまぁデモを見てくれ。
tfschemaはCLIツールで、最終的にはLanguage Server Protocolとか実装してエディタにインテグレーションしたいなーと妄想してるんだけど、CLIツール単体としても十分有用なので、ここらで使い方を説明しておきます。
本稿執筆時点のtfschemaのバージョンは最新版のv0.1.1です。最新の状況についてはREADMEをご確認下さい。
インストール
いくつか方法があるんだけど、Macユーザの場合はHomebrewのtapを用意してあるので、これを使うのが一番簡単かなと思います。
$ brew install minamijoyo/tfschema/tfschema
あとツール自体はGoで書いてるので、Goの開発環境があればgo getでもビルド&インストールできます。
$ go get -u github.com/minamijoyo/tfschema
その他ビルド済のバイナリをGitHubのリリースページに置いてあるので、ダウンロードして展開して適当にパスが通ってるところに置いて下さい。
https://github.com/minamijoyo/tfschema/releases
Windowsは手元に開発環境がなく稼働確認できてないですが、もし需要があってデバッグ手伝ってくれる人がいればIssueを立てて頂ければなんとかします。
サポートしてるTerraformプロバイダのバージョン
AWS/GCP/Azureのメジャーどころのプロバイダは以下のバージョン以降が必要です。
- terraform-provider-aws >= v1.11.0
- terraform-provider-google >= v1.5.0
- terraform-provider-azurerm >= v1.3.0
その他のプロバイダについては、動くかもしれないし、動かないかもしれません。 というのもtfschemaが内部的に使用しているGetSchema APIというのがわりと最近入ったTerraformの機能で、プロバイダが最新のTerraformのAPIをサポートしていないと動きません。
具体的にはプロバイダをビルドするのに依存しているライブラリに以下のバージョンが必要です。
- hashicorp/terraform >= v0.10.8
- zclconf/go-cty >= 14e23b14828dd12cc7ae0956813c7e91a196e68f (2018/01/06)
基本的な使い方
terraform init
でインストールされたプラグインのバイナリはデフォルトで .terraform/plugins/<OS>_<ARCH>
配下に保存されています。(Macの場合 <OS>_<ARCH>
は darwin_amd64
です)
tfschemaはこのバイナリを利用することができるので、terraformコマンドを実行するのと同じディレクトリで実行できます。
ここでは例としてterraform init
でAWSプロバイダをインストールします。
$ echo 'provider "aws" {}' > main.tf $ terraform init Initializing provider plugins... - Checking for available provider plugins on https://releases.hashicorp.com... - Downloading plugin for provider "aws" (1.11.0)... The following providers do not have any version constraints in configuration, so the latest version was installed. To prevent automatic upgrades to new major versions that may contain breaking changes, it is recommended to add version = "..." constraints to the corresponding provider blocks in configuration, with the constraint strings suggested below. * provider.aws: version = "~> 1.11" Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.
この状態で、 tfschema resource show aws_security_group
を実行すると、aws_security_groupの型定義が取得できます。
$ tfschema resource show aws_security_group +------------------------+-------------+----------+----------+----------+-----------+ | ATTRIBUTE | TYPE | REQUIRED | OPTIONAL | COMPUTED | SENSITIVE | +------------------------+-------------+----------+----------+----------+-----------+ | description | String | false | true | false | false | | name | String | false | true | true | false | | name_prefix | String | false | true | false | false | | owner_id | String | false | false | true | false | | revoke_rules_on_delete | Bool | false | true | false | false | | tags | Map(String) | false | true | false | false | | vpc_id | String | false | true | true | false | +------------------------+-------------+----------+----------+----------+-----------+ block_type: egress, nesting: NestingSet, min_items: 0, max_items: 0 +------------------+--------------+----------+----------+----------+-----------+ | ATTRIBUTE | TYPE | REQUIRED | OPTIONAL | COMPUTED | SENSITIVE | +------------------+--------------+----------+----------+----------+-----------+ | cidr_blocks | List(String) | false | true | false | false | | description | String | false | true | false | false | | from_port | Number | true | false | false | false | | ipv6_cidr_blocks | List(String) | false | true | false | false | | prefix_list_ids | List(String) | false | true | false | false | | protocol | String | true | false | false | false | | security_groups | Set(String) | false | true | false | false | | self | Bool | false | true | false | false | | to_port | Number | true | false | false | false | +------------------+--------------+----------+----------+----------+-----------+ block_type: ingress, nesting: NestingSet, min_items: 0, max_items: 0 +------------------+--------------+----------+----------+----------+-----------+ | ATTRIBUTE | TYPE | REQUIRED | OPTIONAL | COMPUTED | SENSITIVE | +------------------+--------------+----------+----------+----------+-----------+ | cidr_blocks | List(String) | false | true | false | false | | description | String | false | true | false | false | | from_port | Number | true | false | false | false | | ipv6_cidr_blocks | List(String) | false | true | false | false | | protocol | String | true | false | false | false | | security_groups | Set(String) | false | true | false | false | | self | Bool | false | true | false | false | | to_port | Number | true | false | false | false | +------------------+--------------+----------+----------+----------+-----------+
ただみんなが使ってるTerraformのコードベースがtfschemaがサポートしていない古いバージョンのプラグインを使用している場合は、別の場所に置いたプラグインのバイナリを読み込むことも可能です。
tfschemaは以下のパスからプロバイダのバイナリを探します。
※これはterraformがプロバイダのバイナリを探すルールとおおよそ同じですが、厳密には若干異なります。詳細は長くなるので割愛。
- カレントディレクトリ
tfschema
のバイナリと同じディレクトリ- ユーザベンダディレクトリ ( terraform.d/plugins/
<OS>_<ARCH>
) - 自動インストールディレクトリ ( .terraform/plugins/
<OS>_<ARCH>
) - グローバルプラグインディレクトリ ( $HOME/.terraform.d/plugins )
- グローバルプラグインディレクトリ(OS/ARCH) ( $HOME/.terraform.d/plugins/
<OS>_<ARCH>
) - GOPATH ( $GOPATH/bin )
tfschema自体にはプラグインのインストール機能はないので、terraformが使っているのと異なるバージョンのプラグインをtfschemaで使いたい場合は、terraform init
で取得したバイナリを適宜tfschemaで見えるディレクトリに移動して下さい。
コマンド補完
bash/zshでコマンドの引数の補完を有効にするには以下のコマンドを実行して下さい。
$ tfschema -install-autocomplete
このコマンドを実行すると ~/.bashrc
と ~/.zshrc
に以下の行が追加されます。
.bashrc
complete -C </path/to/tfschema> tfschema
.zshrc
autoload -U +X bashcompinit && bashcompinit complete -o nospace -C </path/to/tfschema> tfschema
bash/zshをリロードするとタブでサブコマンドやリソースタイプの補完が有効になるはずです。 ちなみにこの補完機能も動的にリソースタイプ一覧を取得しているので、プロバイダのバージョンが上がっても補完を再インストールする必要はありません。
コマンドの使い方もうちょっと補足
tfschemaには現状provider, resource, dataのサブコマンドがあり、それぞれTerraformのprovider, resource, dataブロックに対応します。
$ tfschema --help Usage: tfschema [--version] [--help] <command> [<args>] Available commands are: data provider resource
resourceの下にはlist, show, browseのサブコマンドがあります。 listはリソースタイプの一覧の取得、showはリソースの型定義の取得、browseは公式ドキュメントをシステムのWebブラウザで開きます。 パラメータの意味調べるのに結局公式ドキュメント見るんかいって言われそうだけどw
$ tfschema resource --help This command is accessed by using one of the subcommands below. Subcommands: browse Browse a documentation of resource list List resource types show Show a type definition of resource
$ tfschema resource list aws | grep aws_security aws_security_group aws_security_group_rule
resource show はリソースの型定義を取得し、デフォルトで人が読みやすいようにテーブル形式で出力しますが
、プログラムでパースできるように -format=json
を指定するとJSONで出力もできるようにしてあります。
$ tfschema resource show --help Usage: tfschema resource show [options] RESOURCE_TYPE Options: -format=type Set output format to table or json (default: table)
既知の問題
既知の問題として一部のリソースで以下のような無効なスキーマエラーが出ることがあります。
$ tfschema resource show aws_glue_catalog_database Failed to get schema from provider: unexpected EOF The child panicked: panic: invalid Schema.Elem 4; need *Schema or *Resource
これはTerraformの既知のバグで、コアとプロバイダ側でバリデーションの条件が矛盾していることに起因します。Terraformのコア側のバグ修正は、Terraform v0.11.4で既にマージされており、Terraformプロバイダ側のバグ修正もそのうちマージされる予定です。
現時点で以下のリソースでこの不具合が確認されています。
terraform-provider-aws
- data/aws_ecs_container_definition
- data/aws_vpc_peering_connection
- resource/aws_api_gateway_deployment
- resource/aws_api_gateway_gateway_response
- resource/aws_api_gateway_integration
- resource/aws_api_gateway_integration_response
- resource/aws_api_gateway_method
- resource/aws_api_gateway_method_response
- resource/aws_batch_job_definition
- resource/aws_glue_catalog_database
- resource/aws_lambda_function
これで治る見込み。
terraform-provider-google
- data/source_storage_object_signed_url
- resource/bigquery_dataset
- resource/bigquery_table
- resource/compute_instance
- resource/compute_project_metadata
- resource/dataproc_cluster
- resource/pubsub_subscription
一旦修正されたけど、リバートされた。Terraformコア側の修正がマージされたのでそのうちリトライされるはず。
おわりに
Terraformプロバイダから動的に型定義情報を取得するtfschemaというツールを作ったので紹介しました。
まだとりあえず自分が欲しいものを作ったというかんじなので、使ってみて動いたーとか、エラーが出て動かないとか、なにがしかフィードバックもらえるとうれしいです。GitHubにスターをもらえると喜びます。
GitHubのIssueを立てたりするのに抵抗あれば、雑にTwitterで @minamijoyo にフィードバックいただければと思います。
あと クラウドソーシングのクラウドワークス ではTerraform大好きっ子を募集しています。