CloudStack APIをコマンドラインから手軽に使うためのスクリプト csfind

## CloudStack APIとクライアント
 
CloudStackは比較的使いやすいGUIを備えていることが一つの特長ですがAPIでも操作することができます。

[cloudmonkey](https://cwiki.apache.org/confluence/display/CLOUDSTACK/CloudStack+cloudmonkey+CLI)や[cs](https://github.com/exoscale/cs) などのクライアントを使うことでコマンドラインからAPIを実行することができます。

CloudStackに限った話ではありませんが、コマンドラインの操作に慣れてくるとGUIよりも効率的に作業できるようになります。また、スクリプトを作成して日々の業務を自動化することもできます。

# APIを使うときに面倒なこと

APIは便利ですが面倒なこともあります。そのうちの一つが操作対象のIDを調べることです。

たとえば、仮想マシンを作成する際には、ゾーンのID、テンプレートのID、サービスオファリングのIDを取得しておく必要があります。これらのIDを取得するためには、それぞれのリソースに対応したAPIを実行し、結果をパースする必要があります。

例えば、クライアントに```cs```を使った場合は以下のようになります。
コマンドラインから実行する場合には、```jq```などを使わずに直接結果をみてコピペすることもできるので、実際に実行するコマンドはもっと短くなるかもしれませんが、目で正しいIDを探すのも結構大変です。

```bash                                                                                                                                         
zoneid=$(                                                                          
  cs listZones name=joule | jq -r ".zone[0].id"                                
)                                                                                  
templateid=$(                                                                      
  cs listTemplates \                                                               
    templatefilter=all \                                                           
    zoneid=$zoneid \                                                             
    name="CentOS 7.1 64-bit" |                                                           
  jq -r ".template[0].id"                                                          
)                                                                                  
serviceofferingid=$(                                                               
  cs listServiceOfferings name=light.S1 |                              
  jq -r ".serviceoffering[0].id"                                                   
)                                                                                  
                                                                                   
cs deployVirtualMachine \                                                          
  name=vm01 \                                                                 
  zoneid=$zoneid \                                                               
  templateid=$templateid \                                                       
  serviceofferingid=$serviceofferingid 
```

## csfind

IDを簡単に取得できれば、APIは使いやすくなりそうです。
そのために[csfind](https://github.com/atsaki/csfind)というスクリプトを書いてみました。

### インストール

```csfind```はCloudStack APIクライアントの[cs](https://github.com/exoscale/cs)と[fzf](https://github.com/junegunn/fzf)というツールを使っているので、それらをインストールしておきます。

```cs``` がCloudStack APIを実行できるように、```~/.cloudstack.ini``` などにエンドポイント、APIキー、シークレットキーを設定しておきます。

```csfind``` 自体は単なるシェルスクリプトなのでダウンロードして、```PATH``` の通ったところにおくだけで良いです。

```bash
curl -s -o /usr/local/bin/csfind https://raw.githubusercontent.com/atsaki/csfind/master/csfind && chmod +x /usr/local/bin/csfind
```

### 基本的な使い方

```csfind``` は以下のようにして動きます。

* ```cs```でリソースを取得
* ```fzf```でリソースの絞り込み
* 選択したリソースのIDの出力

例えば、ゾーンのIDを取得するには次のコマンドを実行します。

```bash
csfind zone
```

選択画面にクエリの文字列を入力することによってゾーンを絞り込んだり、カーソルで選択することができます。

IDを取得したいゾーンを選択した状態でEnterを押すとIDが出力されます。

![zone.gif](https://qiita-image-store.s3.amazonaws.com/0/15114/6f664e59-9d9f-bca5-f325-f2c8377afeb2.gif)

ゾーン名のように単純なものであれば、引数に名前を渡して選択画面を出さずにIDを出力させることもできます。（```-e```はFuzzy matchを使わない、```-1```は結果が1つの場合選択画面を出さないオプションです。）

```bash
$ csfind -e -1 zone henry
9703cdbb-aee7-41ba-ba80-4807eaa68b80
```

テンプレートのような名前が長いものについては、一部だけ入力しておくと結果を絞り込んだ状態で選択画面を開くことができます。```-x```（または```-e```） をつけると```!```を文字列の頭につけるとその文字列にマッチしない文字列だけに結果を絞り込むなどのクエリが使えるようになります。詳しい動作については[fzfのドキュメント](https://github.com/junegunn/fzf)を参照してください。

また、ゾーン名など絞りこみに必要な情報を表示しているので、それらにマッチさせて絞り込むこともできます。

```bash
csfind -x template CentOS
```

![template.gif](https://qiita-image-store.s3.amazonaws.com/0/15114/d2dc95ba-c35d-843a-5546-034d024a5c20.gif)


### csfindを使った仮想マシンのデプロイ

先にあげた```deployVirtualMachineの例は次のように書き換えることができます。
そのままではテンプレートが複数でてきてしまうためクエリの文字列を追加していますが、それでもだいぶ簡単になったと感じられるのではないでしょうか？

```bash
cs deployVirtualMachine \
  name=vm01 \
  zoneid=$( csfind -e -1 zone joule ) \
  templateid=$( csfind -e -1  tmpl 'CentOS 7.1 64-bit !Vagrant joule' ) \
  serviceofferingid=$( csfind -e -1 so light.S1 ) 
```

さらに```csfind```を使用した場合、テンプレートやサービスオファリングを事前に明確に決めていなくてもAPIを実行することができます。

例えば、次のように実行して、後から対話的に選択することができます。

```bash
cs deployVirtualMachine name=test \
  zoneid=$( csfind -e zone ) \
  templateid=$( csfind -e tmplate ) \
  serviceofferingid=$( csfind -e serviceoffering ) 
```

![deploy.gif](https://qiita-image-store.s3.amazonaws.com/0/15114/751b2ee3-cefc-e17a-8103-002c175e9feb.gif)

同じコマンドで違うゾーンに仮想マシンを作成したり、異なるテンプレートを使ったりすることもできます。

### 複数のリソースに対する操作

複数のリソースへの一括処理のしやすさはAPIを使うメリットの一つです。

```csfind``` で複数リソースを選択すると、それらのIDがまとめて出力されます。
これを利用し複数のリソースを一括して処理することができます。

例えば、削除したい仮想マシンが複数ある場合には次のようにコマンドを実行します。
（例ではhenryゾーンに削除したい仮想マシンがあったので、ゾーン名をクエリの文字列として追加しています。）

```bash
csfind vm henry | xargs -I{} cs destroyVirtualMachine id={}
```

Tabキーで選択状態をトグルし、複数の仮想マシンを選択した状態でエンターキーを押すとそれらが一括で削除されます。


![destroy.gif](https://qiita-image-store.s3.amazonaws.com/0/15114/36f97250-fc48-16f4-ca93-044f508b8475.gif)

## おわりに

記事中では```csfind```で取得したリソースを処理をするクライアントにも```cs``` を使いましたが、```cloudmonkey```や別のクライアントを使うことも可能です。ただし、```csfind```と実際に処理を行うクライアントが同じ環境を使用するように注意してください。

## 参考

* [シンプルなCloudStack CLI/ライブラリ cs - Qiita](http://qiita.com/atsaki/items/790868d05f963aa398d8)
* [おい、peco もいいけど fzf 使えよ - Qiita](http://qiita.com/b4b4r07/items/9e1bbffb1be70b6ce033)