Yet Another OpenStack Wrapper in Ruby - YAOのご紹介

[OpenStackアドベントカレンダー](http://www.adventar.org/calendars/968) の参加記事です。前回は [Trove のお話](http://blog.bit-isle.jp/bird/2015/12/1126) でした。

社（ペパボ）のエンジニアで開発しているOSSのRubyライブラリ、 [YAO](https://github.com/yaocloud/yao) のご紹介をします。

## YAOとは

![logo](https://raw.githubusercontent.com/yaocloud/yao/master/yao-logo.png)

`Yet Another Openstack ruby wrapper` の略です。ロゴも作ってもらいました。

実は、Ruby界隈では以下のような先行する実装がありましたが、

* fog
* ruby-openstack

fogはマルチクラウド対応前提のライブラリで依存が多い、ruby-openstackは保守がされていない、ということでどちらも微妙に痒いところに手が届かない状態でした。

ということで、自作しちゃいました。設計思想は、以下です。

* 低依存
* リソース指向の設計

## こんな感じで使います

リソース指向ということで、以下のようなリソースを表現するクラスを簡単なDSLを用いて書けます。OpenStackのAPIは綺麗なRESTfulなのでできる技だと思います。


```rb:flavor.rb
module Yao::Resources
  class Flavor < Base
    # JSONのキーのうち、属性のように使ってアクセスしたいものを列挙できる
    friendly_attributes :name, :vcpus, :disk, :swap

    # 拡張によってはキーの形式が特殊なので、それにも対応
    map_attribute_to_attribute "os-flavor-access:is_public" => :public?
    map_attribute_to_attribute "OS-FLV-DISABLED:disabled"   => :disabled?

    # 普通のメソッドは普通に定義する
    # self#[] で、元となるJSONのデータを参照できる
    def ram(unit='M')
      case unit
      when 'M'
        self["ram"]
      when 'G'
        self["ram"] / 1024.0
      end
    end
    alias memory ram

    # API として使うサービス（compute, network, identity...）を指定
    self.service        = "compute"

    # RESTful URL に出てくるリソース名を指定。複数形が自力なのは要改善...
    self.resource_name  = "flavor"
    self.resources_name = "flavors"
  end
end
```

`Yao.configure` ブロックでOpenStackに必要なパラメータを設定し、

```rb
Yao.configure do
  auth_url    "http://keystone.example.local:8080/v2.0/tokens"
  tenant_name "fooproject"
  username    "udzura"
  password    "tonk0tsu-r@men"
end
```

`list` だの `create` だのを叩くと対応するAPIを叩きます。

```rb
Yao::Flavor.list
# => [#<Yao::Resources::Flavor>, #<Yao::Resources::Flavor>, ...]

f = Yao::Flavor.get(10)
# => #<Yao::Resources::Flavor:0x007f9b159828a0 @data={... "id"=>"10"}>
f.name
# => "r1.2xlarge"
```

## こんな使い方してます

ペパボ社内のOpenStack基盤（`Nyah` と呼んでいます）の運用周りのツールを中心に、OSS（RubyGems）として出しているものはこんな感じです。なお、 [codenize.tools](http://codenize.tools/) のAWSのツール群に非常に影響を受けています :bow: 

* [kaname](https://github.com/yaocloud/kaname) ... KeyStoneのユーザ管理をコード化するツール
* [kakine](https://github.com/yaocloud/kakine) ... セキュリティグループをコード化するツール
* [pec](https://github.com/yaocloud/pec) ... インスタンスのスペックをYAMLで書いたら、その通りのインスタンスを立ち上げるツール。
* [stackspec](https://github.com/yaocloud/stackspec) ...[serverspec](https://github.com/mizzy/serverspec)や[awspec](https://github.com/k1LoW/awspec/)のように、OpenStackのリソースがちゃんと立っているか検査をしてくれるツール。WIP。

最新作であるstackspecは、少し面白くて、今のところこういうテストコードを書くと:

```rb:server_spec.rb
describe server('stackspec.example.com') do

  its(:name)            { should eq 'stackspec.example.com' }
  its(:key_name)        { should eq 'sample001' }

  its(:security_groups) { should have(4).security_groups }
  it { should have_security_group(name: "https") }

  its('flavor.id')      { should eq '8' }

end
```

こんな感じの出力をしてくれます。

```console
$ rspec spec/tenant_name/server_spec.rb
OpenStack server "stackspec.example.com"
  should have security group {:name=>"https"}
  name
    should eq "stackspec.example.com"
  key_name
    should eq "sample001"
  security_groups
    should have 4 security_groups
  flavor.id
    should eq "8"

Finished in 2.36 seconds (files took 0.2018 seconds to load)
5 examples, 0 failures
```

OpenStackテナント内で、構築がうまくいったかな？ というのを検査したり、あるべき構成を先にテストで書いてTDDしたり...と夢がありそうです。RSpecを使うのでRubyっぽさもあります。WIPなので来年頑張ります...。

## 参考

実は以前記事を書いたりしています。

* [RubyWorld Conference 2015に登壇し、OpenStackの取り組みについてお話ししました](http://tech.pepabo.com/2015/11/20/rubyworld-conference-2015/)

タイミングなど諸々で、OpenStack Summitなどでは発表していないのですが、いつかは...と思っていたりします。

----

ということで、ぜひライブラリ、ツール共々お試しいただければと思っています。

明日は tmak_tw さんです！