シンプルなCloudStack CLI/ライブラリ cs

CloudStackは各種操作を実行するための[APIを提供](https://cloudstack.apache.org/docs/api/)しています。

今回は[cs](https://github.com/exoscale/cs)という[exoscale](https://www.exoscale.ch)により開発されているシンプルなCLI/Pythonライブラリについて紹介します。

# 特徴

* 1ファイル約240行のシンプルな実装
* Python2/3対応
* POSTメソッドのサポート
* 非同期コマンドの同期・非同期実行可能
* AnsibleのCloudStackモジュール(Extra)での採用
  * [Cloud Modules — Ansible Documentation](http://docs.ansible.com/list_of_cloud_modules.html)

# インストール

pipを使ってインストールすることができます。

```bash
$ pip install cs
```

# 使い方

csはCLI、Pythonライブラリとして使用することができます。

## CLIとして使用する

### 設定

まず認証情報等の設定を行います。
設定は環境変数または設定ファイルを用いて行います。

環境変数で設定を行う場合は、以下の環境変数を使用します。

```bash
$ export CLOUDSTACK_ENDPOINT=YOUR_ENDPOINT
$ export CLOUDSTACK_KEY=YOUR_API_KEY
$ export CLOUDSTACK_SECRET=YOUR_SECRET_KEY
```

設定ファイルはエンドポイント、APIキー、シークレットキーを記述したiniファイルです。

```ini
[cloudstack]
endpoint = YOUR_ENDPOINT
key = YOUR_API_KEY
secret = YOUR_SECRET_KEY
```

上記の内容のファイルを以下の何れかに保存してください。
（上の方が優先順位が高いです。）

1. 環境変数```CLOUD_CONFIG```で使用されたiniファイル
2. カレントディレクトリの```cloudstack.ini```
3. ホームディレクトリの```.cloudstack.ini```

### コマンドの実行

コマンド名とオプションを与えることで実行する事ができます。
出力フォーマットはJSONです。出力先がttyの場合にはシンタックスハイライトされます。

```--post```でPOSTで実行、```--async``` でポーリングの無効化が可能です。

```bash
$ cs listZones name=tesla
{
  "count": 1, 
  "zone": [
    {
      "allocationstate": "Enabled", 
      "dhcpprovider": "VirtualRouter", 
      "id": "a117e75f-d02e-4074-806d-889c61261394", 
      "localstorageenabled": true, 
      "name": "tesla", 
      "networktype": "Advanced", 
      "securitygroupsenabled": false, 
      "tags": [], 
      "zonetoken": "bbbd8944-a3c5-3538-8a2a-71d93a788ab5"
    }
  ]
}
```

## ライブラリとして使用する

CloudStackオブジェクトを使用してAPIを実行します。
read_configを使う事で設定ファイルを探索・読み込むことができます。

```py
from cs import read_config, CloudStack

config = read_config()

# cs = CloudStack(**config) や cs = CloudStack(**read_config())でも可
cs = CloudStack(
    endpoint=config["endpoint"],
    key=config["key"],
    secret=config["secret"]
)

print cs.listZones(name="tesla")
```

## IPythonから使用する

[60 Recipes for Apache CloudStack: Using the CloudStack Ecosystem](http://www.amazon.co.jp/60-Recipes-Apache-CloudStack-Ecosystem-ebook/dp/B00O5HOOUG) （PDFも公開されています）ではlibcloudをIPythonから使用する方法が紹介されています。

書籍では```InteractiveShellEmbed```を使う方法が書いてありますが、ここではipython起動時に自動でインポートするよう設定します。

```~/.ipython/profile_default/startup``` に以下のようなファイルを置いておくとipython起動時に自動で実行してくれます(ここでは```cs_ipython.py```という名前にしました。)
。

```py:cs_ipython.py
from cs import read_config, CloudStack
cs = CloudStack(**read_config())
```

IPythonからcsを使って簡単にCloudStackを対話的に操作することができます。

```pycon
>>> zones = cs.listZones()

>>> [zone["name"] for zone in zones["zone"]]
[u'tesla', u'henry', u'pascal']
```

# 他のライブラリ・ツールとの比較

他のCloudStack APIを使用するライブラリ・ツールとして同じPythonで書かれているcloudmonkey, libcloudと比較してみます。

## cloudmonkey

CloudStackのCLIといえば[cloudmonkey](https://cwiki.apache.org/confluence/display/CLOUDSTACK/CloudStack+cloudmonkey+CLI)が有名です。

cloudmonkeyはコマンド・パラメータの補完、シンタックスハイライト、出力形式の変更、プロファイルによる認証情報の管理など便利な機能を多く実装しています。

cloudmonkeyはライブラリではなくCLIなので、ライブラリとしてPythonプログラムから呼び出すといった用途には向いていません。また、設定変更時に設定ファイルを書き換えてしまうのでシェルスクリプト等から使う場合にも想定した設定を使用しているか注意する必要があります（```set profile```で複数プロファイルを切り替えて使用している場合は特に）。

csはライブラリとして使用する事が想定されているため容易にプログラムから使用することができます。

## libcloud

[libcloud](https://libcloud.apache.org/)は、各種クラウドに対応したPythonのライブラリで、CloudStackにも対応しています。

libcloudは各種クラウドの操作を同じAPIで実行することができるよう、独自のAPIを提供しています（例えば、どのプロバイダでも仮想マシンの作成は```create_node```です）。また、各メソッドはJSON等を生で返すのではなく、オブジェクトを返すため結果のパースやフォーマットに頭を悩ませる必要がありません。

一方で、libcloudのメソッドとCloudStackAPIの対応関係を把握する必要がある、libcloudから使用できるAPI・パラメータは限られてしまうという問題があります。

csは出力としてJSON（をパースしたdict）が返ってくるため、後処理が面倒な事がありますが、CloudStackの全てのAPIをそのままの名前で使用する事が可能であるためメソッドの対応関係を覚える必要がなく、ライブラリが対応しておらず困るといったこともありません。

# まとめ

Ansible等のPython製のツールでCloudStackを操作しようとしたときライブラリとして何を使うか迷っていたのですが、あまり良い選択肢がなく悩んでいました。csはシンプルで動作も把握しやすいので今後使っていきたいと思います。