[zsh]AWS CLIのコマンド入力で徹底的に楽するためのプラグインを作ってみた

こんにちは、平野です。

AWS CLIいいですよね。 AWSに限らず、私はターミナルからCUIでの操作が好きで、 最初はGUIでやっていた操作も少しずつCUIで操作できるようになっていくと、 なんかデキる人っぽい感じがしていいですよねー。(個人の感想です)

ということで、AWS CLIでコマンドを組み立てる際に ラクができるzshプラグインを作成しました。 基本的には私が個人的に使って俺TUEEEEEするためのツールですが、 ある程度体裁を整えるところまできたので、ご紹介させて頂きます。

動作例

例として、CloudWatch Logsからログの検索をして見ます。

コマンドの骨子の作成

awsのコマンドは必ず

aws <コマンド> <サブコマンド> [パラメータ...]

という書式ですよね。 なら、そこまでは一発で展開できたらラクです。 ということで、

gifアニメのように、awsとだけ入力された状態でctrl+hを押すと、 AWS CLIのコマンドが、サブコマンドレベルまで全て羅列1され、 それがfzfに送られて、検索を使って目的のコマンドを選ぶことができます。 コマンドとサブコマンドの間は/で区切っていますが、 これは単純に検索のやりやすさのためです。

そしてコマンドを選択すると、 そのコマンドの骨子となる書式がコマンドラインに展開されます。 この時、指定必須のパラメータも合わせて展開され、 引数の部分は<value>となっているので、あとはこれを埋めればOKです。

引数の選択

<value>を埋めるためにロググループをマネジメントコンソールから確認するんじゃ滑稽ですよね。 ということで、

<value>部分のどこかにカーソルがある状態でctrl+hを押すと、 ロググループの一覧がfzfで表示されます。 ここから目的のものを選べば<value>がその文字列に置きかわります。

これでコマンドが完成したので、あとは普通にエンターで実行です。

ロググループ全体を検索しないように

上記で実行と言いましたが、aws logs filter-log-eventsの場合、 フィルターする文字列を渡さないと、ログ全部返されちゃうので大変です。 また、検索対象の時刻指定もほぼ必須と言えます。 ということで、

logs/filter-log-eventsを選択するときにctrl+oを押すとオプション選択モードを移ります。 ここでオプションを選ぶと、最終的に以下のような骨子がコマンドラインに展開されます。

aws logs filter-log-events --log-group-name <value> --start-time <value> --filter-pattern <value>

あとは<value>をそれぞれ埋めればOKです。 ということで、

--start-timeの指定後に6時間前を消してるのがすごくダサいですが、 きちんと文脈を見て引数候補が選ばれているのの例ということで・・・。 この辺はもうちょっといいやり方を考え中。

リソース一覧の再読み込み

ロググループの一覧など、AWSにアクセスする必要がある一覧の取得には、 内部的にはAWS CLIコマンドを使って取得しています。 なので、初回は取得に時間がかかりますし、 MFAを設定している場合はその入力なども必要になります。

しかし一度取得したリソース一覧はローカルに保存するので、 2度目以降は瞬時に出力されるようになります。

ただ、ローカルに保存して新しく作成されたリソースが見つからないんじゃダメですよね。 ということで、

fzfでリソース一覧が表示されているときにF5を押すと一覧をリロードできます。 AWSにアクセスしに行くので少し時間がかかりますが、 これで新しいロググループが追加された場合にも対応できます。 また、すでに入力中のクエリによるフィルタリングも持続されます。

どんなコマンドに対しても使えるの?

引数候補一覧は、直前のパラメータ(--log-group-nameなど)によって操作を分けています。 ただ、どのコマンドのときにはどんな候補を出すべきか、というのは個々に対応する必要があります。 なので、究極的には全てのコマンドについて候補一覧を出す実装を書く必要があります。

しかし、さすがに一人でそんなことをやるのは大変ですし、 何より、私が使ったことのないサービスもたくさんあるので、それら全てを網羅するのは無理です。 ということで、引数候補の出力については、ごくごく限定的な数個しか実装を作っていません。

しかしパラメータ名から目的の候補一覧を出力する部分はツールの外に出しているので、 ユーザが使う必要ができたときにすぐに実装できます。 (ありていに言うと、今の所ほとんど実装してないから、 基本的には自分で実装して使ってね、ということですw)

引数候補リストの出力コマンドを作る

${FZF_AWS_HELP_RESOURCE_HOME}/commands

ディレクトリ2以下に、input_--log-group-namesなどのファイルがあり、 そこに選択肢として表示させるためのコマンドが書いてあります。 --log-group-namesであればロググループの一覧が欲しいので、中身は以下です。

aws logs describe-log-groups | jq -r '.logGroups | .[] | .logGroupName' | sort

ね、簡単でしょ?だから自分でやってね!

より具体的なものから順に見つける

input_--log-group-namesというファイルですが、今回の例だと、 input_--log-group-names_logs_filter-log-eventsという名前でもOKです。

すなわち、

aws <コマンド名> <サブコマンド> --<パラメータ名> <value>

の引数候補を得るためのコマンドは

input_--(パラメータ名)_(コマンド名)_(サブコマンド)

という名前のファイルを探しに行きます。 では、なぜinput_log-group-namesでも良いかと言うと、

1. input_--log-group-names_logs_filter-log-events
2. input_--log-group-names_logs
3. input_--log-group-names

という順番でファイルを探しに行くからです。

この仕組みによって、より具体的な引数候補を出力するコマンドを優先的に使用し、 具体的なものがない場合は、より緩いコマンドを見に行くということを行なっています。

例えば、IAMロールの一覧を表示させたいときに、 特定のサービス用にコマンドを用意すればそのサービスロールだけの一覧、 特にコマンドを準備していなければとにかくロール全部を表示、 のような対応が取れるようになっています。

中身の概要

プラグインの動作説明は以上ですので、中身を(本当に)サラッと。

このプラグインはZLEとfzfを組み合わせて作りました。

ZLE

以前の記事で紹介したZLE(Zsh Line Editor)を使っています。

Macがzshになるなら、ZLEを習得するっきゃない!

つまり、今のコマンドラインの文字列とカーソルの位置からコネコネと操作を行い、 目的の文字列にしてコマンドラインの文字列を置き換えています。

ZLEを使っているのでbashでは動かないのです、ごめんなさい。 fishは(ちゃんと使ったことないですが)ZLEと同等なことができるっぽいので、 多分ちょっと書き換えたら使えるかと思いますが、今の所非対応です。

fzf

こちらも以前紹介したブログがあるので、そちらを参照して下さい。

[ターミナル]fzfを使った自作インタラクティブアプリを作ってみよう!〜git addを快適に〜

今回特に触れてないですが、 ヘルプの内容を見ながらコマンドが選べるのは本当に強い。

fzfyml

fzfで簡単にインタラクティブなツールができるのは上の記事で紹介したのですが、 ctrl+oでのオプション選択モードや、F5でのリロードなどを実装するに当たって、 単純に一つのfzfを呼び出すだけでは実現できないので、 拙作ながらfzfymlというツールを使用しました。

fzfymlはfzfのラッパーで、 特定のコマンド入力で条件を変えて検索させるなどの拡張機能も含めて yamlファイルで設定できるようにしたものです。

こちらはまた別の機会に紹介できればと思います。

インストール

前提としているもの

以下についてはインストールされている前提です。ご了承ください。

  • Python3系
    • PyYAML
  • jq

fzfのインストール

何はなくともfzfのインストールです。 公式のGitHubからどうぞ。

配布場所

https://github.com/cm-hirano-shigetoshi/fzfyml https://github.com/cm-hirano-shigetoshi/fzf-aws-help

標準的なインストール方法

fzfymlのインストール

GitHubからクローンして、 bin/ディレクトリにパスを通すか、 bin/fzfymlのシンボリックリンクをパスの通っているディレクトリに作ったら完了です。

fzf-aws-helpのインストール

GitHubからクローンして、

source fzf-aws-help.zsh

すればOKです。 もちろん継続的に使う場合は.zshrcに書いておいて下さい。

zpluginでインストールする方法

最近zpluginというプラグインマネージャーを使い出したのですが、 これがなかなか使いやすくて良いです。 zpluginでインストールする際には以下の2行を.zshrcに書けばOKです。

zplugin ice wait'!0' as"program" pick"bin/fzfyml"; zplugin light cm-hirano-shigetoshi/fzfyml
zplugin ice wait'!0' src"fzf-aws-help.zsh"; zplugin light cm-hirano-shigetoshi/fzf-aws-help

wait'!0'を付与することでバックグラウンドでの読み込みができ、 シェルの起動速度が早くなります(多分)。

初期化

最初にawsからの展開を使おうとすると初期化プロセスが走ります。 中身は非常に単純で、aws logs helpのようなコマンドを全て実行して ローカルファイルに保存するという内容です。 コマンドの種類が多いので、この処理は数分かかります (並列化である程度短縮できるだろうけどサボってます)。

まとめ

AWS CLIが便利に使えるzshプラグインを作ってみました。

ZLEを使ってコマンドラインの文字列を編集するだけで、 コマンドの実行自体には関与しないような作りになっています。 その方が処理が独立して見通しが立てやすいのと、 コマンドの実行履歴を一箇所に集めたいので、このような形にしてみました。

リソースの引数候補については、ごくごく一部の実装しか書いていないので、 これらをきちんと整備した際にどれくらい有用になるかはまだ未知数ですが、 それを育てていく楽しみもあるかな、と思っています!

以上、もし気になった方は使ってみてください。 そして引数候補出力の実装を共有してやってもいいぜ、という方は、 プルリクエストでもなんでも送っていただけたら嬉しいです。


  1. 2019年7月時点で総数約6000個のサブコマンドがあるみたいです!が、この6000個という数字はfzfで処理するにはもってこいな数だと思っています。 
  2. FZF_AWS_HELP_RESOURCE_HOMEはこのプラグインを読み込むと設定されます。