HubotからDigitalOceanAPIを叩いてみる


Hubot-scriptは、hubot経由で外部APIを叩く機能も多いですね。（本来それが目的のような気もします）

さて、最近１時間１円で話題のクラウドホスティングの[DigitalOcean](http://digitalocean.com)は、APIもシンプルでhubotから管理しやすそうなので、ちょっと試してみました。

##準備
１．DigitalOceanのアカウントを取得します。[参考URL](http://blog.cloudninja.asia/?p=304)
２．DigitalOceanにログインして、APIのページからClient IDとAPI Keyを取得します。
３．とりあえず１つサーバを立ち上げてみます。（DigitalOcean上のサーバ１つの単位をdropletと呼んでいるようです）

##今回叩くAPI
DigitalOceanの[APIページ](https://developers.digitalocean.com/)を参考にします。

DigitaiOceanのAPIだけで、dropletを作って、電源OFFして、スナップショット取って、破棄するのができてしまうので、気づくとお金をちゃりんちゃりん払う事にもなります。

といっても最低構成のdropletだと、１時間１セント（最低金額が0.007$なのですが請求時に１セント未満は繰り上げられて0.01$になります）なので、そうそうたいしたことにはならないと思います。

でも最初ですので、プログラムがバグってて悪影響が出ても大丈夫なように、閲覧系のAPIだけ叩いてみましょう。

/droplets - Show All Active Droplets
/images - All Images
の２つのAPIを叩きます。

ちなみに、「APIを叩く」という表現は単純にDigitalOceanのAPIにアクセスするというだけのことです。


##サンプルプログラム

モジュールを２つ使います。
APIを叩くのに、scoped-http-clientを利用しています。
また、APIを連続で叩く際に、ネストが深くならないように、async.jsを利用しています。
coffeescriptだと、インデントでcallback配列の制御ができるので楽でいいですね。

```digitalocean.coffee
HttpClient     = require 'scoped-http-client'
async = require 'async'

CLIENT_ID = '__YOUR_CLIENT_ID__'
API_KEY = '__YOUR_API__KEY__'

class DigitalOcean
  constructor: (debug = false) ->

  get : (path, params, callback) ->
    params.client_id=CLIENT_ID
    params.api_key=API_KEY
    url = "https://api.digitalocean.com/#{path}/?"+("#{k}=#{v}" for k,v of params).join('&')
    console.log(url) if debug
    HttpClient.create(url)
      .header("User-Agent", "Hubot/#{@version}")
        .get() (err,res,body) =>
          try
            callback(JSON.parse(body))
          catch e
            console.log(e)
            console.log("can't load")

  check_api_status : (json) ->
    json.status == 'OK'

  show_droplets : (droplets) ->
    ("#{droplet.name}(#{droplet.id})" for droplet in droplets).join('\n')

  show_images : (images) ->
    ("#{image.name}(#{image.id})" for image in images).join('\n')

module.exports = (robot) ->
  api = new DigitalOcean(debug=false)

  robot.respond /digitalocean\s*(リスト|list)/i, (msg) ->
    async.waterfall [
      (callback)->
        api.get("droplets", {}, (json) ->
          if api.check_api_status(json)
            if (json.droplets.length > 0)
              msg.reply '今動いているdropletはこれだけありますー。\n' + api.show_droplets(json.droplets)
            else
              msg.reply '今はdropletは一つも立ち上がってないですー。'
            callback null
          else
            msg.reply "digitaloceanのdroplets_apiが正常に動いていないようですー。"
        )
      (callback)->
        api.get("images", {filter:"my_images"}, (json)->
          if api.check_api_status(json)
            if (json.images.length > 0)
              msg.reply '今動いている自前管理のimageはこれだけありますー。\n' + api.show_images(json.images)
            else
              msg.reply '今は自前管理のimageは一つもないですー。'
            callback null
          else
            msg.reply "digitaloceanのimages_apiが正常に動いていないようですー。"
        )
    ], (err) ->
```

package.jsonのdependenciesにも忘れず追加してください。

```package.json
        :
        :  
  "dependencies": {
        :
    "scoped-http-client": "0.9.8",
    "async": "0.2.9",
        :
  },
```
##動かし方

hubotの名前が、@hubotだとして、
「@hubot digitalocean リスト」と話しかけましょう。

hubotがAPIを叩いて調べにいってくれます。名前とIDでdropletとsnapshotイメージについて教えてくれます。

##こんな人にどうぞ

いちいちDigitalOceanのWEBページにログインして、リンククリックして…というのが面倒な人はぜひどうぞ。