AnsibleWorks Galaxyにroleを登録してみる

投稿内容を考えあぐねていたところにちょうど[AnsibleWorks Galaxy](https://galaxy.ansibleworks.com/ "AnsibleWorks Galaxy")がβリリースされたので、ここぞとばかりに利用してみようと思います。

## AnsibleWorks Galaxyとは何か
AnsibleWorks Galaxy(以下、Galaxyと呼びます)にアクセスしてみると、

> "your hub for finding, reusing, and sharing the best Ansible content."

とあります。端的に言えば、Ansibleの処理単位として用いられるroleの共有サービスのようです。以前から要望としてはちらほら目にしていましたが、満を持してという感じでしょうか。

ただ、roleを実際に日常的に書いていると実感しますが、不特定多数と共有できるほど汎用的に書くのはなかなか難しいところもあるので、そのまま用いるというよりはショーケースとして皆で持ち寄るぐらいのつもりで気軽に登録するのがよさそうかなと感じています。

## Galaxyの利用準備
Ansible本体がバージョンアップしてansible-galaxyというCLIが追加されているので、何はなくともアップデートしておきます。私はAnsibleをpipでインストールしているので、

```
$ sudo pip install -U ansible
```

で最新のものにアップデートしました。

説明の先取りですが、Galaxyに登録するためにはrole単体でGithubにリポジトリが存在している必要があるので、今回登録するroleとして、実際に使っているものの中でもまだ汎用的に使えなくもなさそうな[fluentd(というかtd-agent)のセットアップを行うrole](https://github.com/xica/ansible-role-td-agent "ansible-role-td-agent")を切り出してみました。roleの実装に甘いところが多々あるのはご容赦下さい。

個人的には、Python製のプロダクトであるところのAnsibleなのでBitbucketに対応して欲しいところですね。あと、READMEもrstが使えたらなと。

## roleの作成
準備ができたので、実際にGalaxyに登録するroleを作成してみます。[こちら](https://galaxy.ansibleworks.com/intro)を見てみると、ansible-galaxy initというCLIでscaffoldできるようなのでやってみましょう。--init-path(デフォルトは".")で指定したディレクトリに、引数の名前のディレクトリが作成されます。

ドキュメントでは作成したリポジトリをgit cloneしてからそのリポジトリのディレクトリに入ってansible-galaxy initを実行するように説明しているように見えるのですが、それだと二重にディレクトリが作られてしまうので、ちょっとこの辺はドキュメントのバグなのかよく分からないところです。逆に、

```
$ git clone https://github.com/xica/ansible-role-td-agent.git
$ ansible-galaxy init ansible-role-td-agent
The directory %s already exists.

You can use --force to re-initialize this directory,
however it will reset any main.yml files that may have
been modified there already.
```

のように既にあるディレクトリに対して実行しようとすると怒られます。メッセージに不具合があるのは早速pull requestしておきました。

ansible-galaxy initが何をするのか気になるので適当な名前で試してみたところ、role以下ディレクトリに空のymlを、それとmeta/main.ymlのテンプレートを作成してくれるようです。

```
$ ansible-galaxy init galaxy-init-test
galaxy-init-test was created successfully
$ ls galaxy-init-test
defaults files handlers meta tasks templates vars
```

meta/main.ymlを見てみると、Galaxyへの登録に必要な情報のテンプレートが記述されているので、記入したりコメントアウトを外したりして適切なものに修正します。ただ、末尾の"dependencies"にこのような不吉なことが書いてあります。

```yaml:galaxy-init-test/meta/main.yml
dependencies:
  # List your role dependencies here, one per line. Only
  # dependencies available via galaxy should be listed here.
```

何故不吉かというと、ansible-role-td-agentではOS毎に処理を分岐させるために以下の様なdependenciesを既に書いているからです。

```yaml:ansible-role-td-agent/meta/main.yml
dependencies:
  - { role: succhiello.td_agent/RedHat, when: "ansible_os_family == 'RedHat'" }
  - { role: succhiello.td_agent/Ubuntu, when: "ansible_distribution == 'Ubuntu' and ansible_distribution_release in ['lucid', 'precise', 'raring']" }
```

ひとまず置いておいて、とにかく先に進めてみます。

meta/main.ymlをGalaxy用に修正する以外は、roleの作成としては普段通り普通にroleを作成すれば問題ないはずです。今回は既にroleの内容を作成してあるので、リポジトリをpushして登録してみます。READMEはとりあえずスルー。

余談ですが、Ansibleのユーザーは大体自分なりのansible-galaxy initと同じようなことをするユーティリティを実装していることと思います。私もroleを作成するyeoman generatorを実装してみたのですが、今回のアップデートで完全に無用の長物となりました。

## roleの登録
roleの登録は、冒頭でも示した[Galaxyのサイト](https://galaxy.ansibleworks.com/ "AnsibleWorks Galaxy")で行います。ユーザー登録が必要ですが、私はGithub連携でやってしまいました。登録してサインインしたら、ヘッダーの"Add a Role"から入力していきます。

私はリポジトリ名をAnsible roleであることが明確なものにしたかったので、リポジトリ名がそのまま登録名に使われるデフォルトの振る舞いではなく明示的に設定する方法をとってみました。dependenciesに既に書いてある通り、succhiello.td_agentという名前で登録されることを期待して入力しています。

![galaxyAddRole.png](https://qiita-image-store.s3.amazonaws.com/0/30899/aa102b61-e00e-b3f3-b234-ca666e873438.png)

結果、無事失敗しました…Galaxyの紹介としては、エラーケースが出せたのは寧ろ良いことなので怪我の功名と思うことにします。

![galaxyFailed.png](https://qiita-image-store.s3.amazonaws.com/0/30899/cd77079d-e49b-e45d-ac2b-df66c251e234.png)

エラーメッセージを見ると、meta/main.ymlに何か間違いがあるようです。読み込み時にある程度検証していることが分かります。エラーが出るということは、元々ちゃんと動いていたroleの中身を切り出すに辺り、ついでにちょっと修正したままテストせずに登録しようとしたことがバレバレなのですが、それはさておきmeta/main.ymlの冒頭の方を見てみると、

```yaml:ansible-role-td-agent/meta/main.yml
---
galaxy_info:
  author: "EBIHARA Satoshi"
  description: 
  company: xica
  license: BSD
  min_ansible_version: 1.4
```

とりあえずdescriptionが空なまま横着をしたのはよくなさそうです。ここは、出力するテンプレートの時点で不正でないように、""を指定しておいて欲しいような気もします。

description自体を削除してしまい、他にもしょうもない間違いがたくさんあったので修正した上でpushし直し、先の"My Roles"で"Re-import"してみました。私の環境では、"Import Status"が"Running"のまま変化しなかったのですが、リロードしたら無事"ok"に切り替わりました。

## roleのインストール
登録したroleが実際にインストールできるかどうか試してみます。まず以下のような環境を用意しておきます。inventories/hostsの内容は適宜読み替えて下さい。

```
$ tree
.
├── inventories
│   └── hosts
├── roles
└── site.yml
```

```yaml:site.yml
- hosts: test_hosts
  connection: ssh
  sudo: yes
  roles:
    - succhiello.td_agent
```

```ini:inventories/hosts
[test_hosts]
# ********************
```

先に触れたdependenciesの問題が気になりますが、ひとまず素直にansible-galaxy installを実行してみます。"--roles-path"がないとansible.cfgで設定されたパスか/etc/ansible/rolesにインストールするようなので、明示的に指定しておきます。

```
$ ansible-galaxy install --roles-path ./roles succhiello.td_agent
no version specified, installing master
 - downloading role from https://github.com/xica/ansible-role-td-agent/archive/master.tar.gz
 - extracting succhiello.td_agent to roles/succhiello.td_agent
succhiello.td_agent was installed successfully
```

無事インストールできたようです。roles以下を見ると、確かにsucchiello.td_agentができています。dependenciesを見て「succhiello.td_agent/RedHatなどというroleは登録されていない」のようなエラーが出ないか心配だったのですが、杞憂だったようです。

ansible-galaxyに手を入れてGalaxyのweb APIから取得できるroleのメタデータも眺めてみましたが、dependenciesが空になっていたので、ある程度はmeta/main.ymlの記述を見てふさわしくないもの({ role:***, when: *** }のようなもの)は飛ばしてくれているのかも知れません。

試しに[DigitalOcean](https://www.digitalocean.com "DigitalOcean")の自分の環境に対して実際にansible-playbookを実行してみました。

```
$ ansible-playbook -K -i inventories/hosts site.yml
```

出力は割愛しますが、問題なく動作しました！

本当はroleのバージョン付けなどについても試してみたかったのですが、もう大分長くなってしまいましたし20日も大分佳境に入りつつあるので、今回はこんなところにしておきたいと思います。READMEをきちんと書くとか、role自体もまだ汎用的にできるところがあるので、後でアップデートしておきたいところです。

皆さんも、他のユーザーに共有できそうであったり参考になりそうなroleを実装したら是非Galaxyに登録してみて下さい！