Ansibleのroleの依存関係を可視化する

前回、[Ansibleのインベントリとvarsの可視化](http://qiita.com/unchemist/items/4cc0202a8d60a811ed29)を行いました。
が、おそらく(私の経験上)「Ansible」「依存関係」ときて分かりにくいものといえば、roleの依存関係ではないでしょうか？

# TL;DR

以下の方に便利です。

* 既にAnsibleを最大限活用しており、たくさんのロールが作られている
* ロールのmetaにはちゃんと`dependencies`を記載して、ロール間の依存関係を定義している
* 正直、ロールが多すぎてロール間の関連を把握しきれない

上記の方に対して、ansigenomeというツールによって、複数のroleに対して以下の情報が得られるようになります。

* roleの統計を一覧化できる
* role間の依存関係を可視化できる

大体以下のようなイメージになります。

![ansigenome_export.png](https://qiita-image-store.s3.amazonaws.com/0/16458/49acf3d7-40ba-f753-099e-1a36780daa74.png)


# ロールの依存関係を明記する

可視化…の前に、そもそもの話。

Ansibleのロール(role)には、依存関係を記載することができます。

[Playbook Roles and Include Statements — Ansible Documentation | Playbook Roles and Include Statements | Role Dependencies](http://docs.ansible.com/ansible/playbooks_roles.html#role-dependencies)

例えば、role-elasticsearchとrole-jdkという2つのロールがあったときに、role-elasticsearchを動かすためには、事前にrole-jdkを動かす必要がある、といったような使い方をします。この例では、ElasticsearchはそもそもJDKがインストールされていないと動かないので、そうしたソフトウェアの動作上の依存関係(制約)を定義するときに活用します。

上記リンクの通り、依存関係は `meta/main.yml` の中に、 `dependencies:`と明記することができます。

```yml:role-elasticsearch/meta/main.yml
dependencies:
  - role-jdk
```

また、システムとして扱う際には、「どのイメージでも前提として入れなければならない基本パッケージ」というものもあるかもしれません。いわゆる、「common」や「base」といわれるroleのことです。
[AnsibleのBest Practices](http://docs.ansible.com/ansible/playbooks_best_practices.html#directory-layout)でも、同様のディレクトリ構成が示されています。

## ロールの依存関係を明記するメリット

依存関係を定義することによって、以下のようなメリットがあります。

### ロールを小分けにすることで、再利用が行いやすくなる

例えばJDKやruby、pythonなど、「前提としてインストールされるべきもの」を別ロールにすることで、他のロールでも利用しやすくできます。

### ロール(得てしてミドルウェア)の記載が簡潔かつ最小限になる

playbookファイルには、上記の例でいう「子」のロールしか記載する必要がありません。
従って、いちいち前提のロールを把握してplaybookに書く必要がなく、自然と「動かしたいものだけ」書けばよいことになります。

## ロールの依存関係を明記するデメリット

### ほぼAnsible-Galaxyを動かすことが前提になる

デメリット…と言うほどまであるかは分かりませんが、上記のように依存関係を書いてしまうと、そのロールだけ準備しても動かなくなります。
上記の例でいう、role-elasticsearchというロールだけ準備しても動きません。なぜなら、role-jdkが手元にないからです。

また、role-jdkを活用しようとすると、そのロール単体でGitリポジトリに配置するしかありません。従って、[Ansible-Galaxy](https://galaxy.ansible.com/)の利用がほぼ暗黙的な前提となります。

### ロールの依存関係を俯瞰で把握するのが難しい

playbookが1つしかない場合は、複数のroleもplaybook内に含めてしまう、いわば「全部入り」の構成にすればそれほど問題にはならないのですが、playbookを複数で運用し始めると、途端にカオスになっていきます。roleを分割していったことにより、果たしてこのroleはどんな依存関係があるのか？直接の依存関係は見ればよいものの、その先は？というのがどんどん複雑化してきます。

このエントリは、この「把握」を行いやすくするために`ansigenome`というツールを紹介するものです。

# ansigenomeでロールの情報を可視化する

Chefでは、berkshelfが`berks viz` コマンドでcookbookの依存関係を可視化できるのに対し、 同様のことをAnsibleでは`ansigenome`によって実現してくれます。

https://github.com/nickjj/ansigenome

## インストール

上記のREADMEの通りですが、`pip`コマンドで一発です。

```bash:ansigenomeのインストール
$ sudo pip install ansigenome
```

これから行うことは、皆さんが作ったロールを1つのディレクトリに集めた上で行ってください。
大体以下のようなイメージです。

```
role_dir/
├ role_a
├ role_b
├ role_c
└ role_d
```

## ロールの統計情報を見る

`ansigenome scan` コマンドで、ロールの統計の一覧を見ることができます。
ただ、初回実行時はコンフィグのセットアップになるので、適当にEnterを連打してください。
表示にある通り、`$HOME/.ansigenome.conf`というファイルが作られるようになります。

```
$ ansigenome scan <ロールのディレクトリ>

    Welcome to ansigenome, you are seeing this message because there
    were no available config files to load.

    Answering the questions below will setup a global config, you
    only need to do this once. You can also exit with CTRL+D.

    This config file will be placed in $HOME/.ansigenome.conf for now.


What's your name? []:
Which company do you belong to? []:
What's your website? []:
What's your e-mail address? []:
What's your twitter name without the @? []:

Which source control are you using? [git]:
Which host are you using for SCM? [https://github.com]:
What's your user name on the above host? [someone]:
How are your roles prefixed in the url? [ansible-]:

Pick a license type by choosing a number:

  1. MIT
  2. GPLv2
  3. GPLv3
  4. AGPLv3
  5. LGPL
  6. Apache-2.0
  7. BSDv2
  8. BSDv3
  9. Other

 []: 1
```

初回セットアップが終わったら、再度同じコマンドを実行してみてください。
すると、以下のような表示が見られます。

<img width="635" alt="ansigenome_scan.png" src="https://qiita-image-store.s3.amazonaws.com/0/16458/b6bf0661-ab48-5bfb-cd25-4525601a7453.png">


* ロールの一覧
  * defaultsで設定しているvarの数
  * factを設定している数
  * ファイル数
  * 行数
* ロール全体のチェック
  * READMEが書かれていないロール数
  * meta情報が存在していないロール数

しかも、色付きで分かりますね。どのロールがどのような状態で、どのような問題があるのかが分かります。

## ロール間の依存関係を可視化する

さて、いよいよロール間の依存関係を図にします。`ansigenome export`コマンドによって、graphviz用のファイルを生成することができます。

```bash
$ ansigenome export <ロールのディレクトリ> -f dot -o <dotファイルの出力先パス(例: /tmp/hoge.dot)>
```

例えば以下のようなイメージです。

```bash
$ ansigenome export roles/ -f dot -o /tmp/test.dot
```

本当は、`-f png` によって直接pngファイルへ出力できるはずなのですが、エラーで出力できず…。
dotファイルを出力した後は、`dot`コマンドによってpngに変換します。
`dot`コマンドはgraphvizをインストールすることで利用できるようになります。インストールは[前回の記事](http://qiita.com/unchemist/items/4cc0202a8d60a811ed29)もご覧ください。

```bash
$ dot -Tpng -o <出力先のpngファイルのパス(例: /tmp/hoge.png)> <読み込むdotファイル>
```

例えば以下のようなイメージです。

```bash
$ dot -Tpng -o /tmp/test.png /tmp/test.dot
```

その後、出力されたpngファイルは、以下のようなイメージになります。

![ansigenome_export.png](https://qiita-image-store.s3.amazonaws.com/0/16458/49acf3d7-40ba-f753-099e-1a36780daa74.png)

どうでしょう？非常に分かりやすくないでしょうか？

# ansigenomeの他のオプション

```bash
$ ansigenome --help
Usage: ansigenome [config|scan|gendoc|genmeta|export|init|run] [--help] [options]


ansigenome config --help
create a necessary config file to make ansigenome work

ansigenome scan --help
scan a path containing Ansible roles and report back useful stats

ansigenome gendoc --help
generate a README from the meta file for each role

ansigenome genmeta --help
augment existing meta files to be compatible with Ansigenome

ansigenome export --help
export roles to a dependency graph, requirements file and more

ansigenome init --help
init new roles with a custom meta file and tests

ansigenome run --help
run shell commands inside of each role's directory


Options:
  --version   show program's version number and exit
  -h, --help  show this help message and exit

ansigenome command --help for more info on a command
```

このように、READMEやmeta情報を解析した内容から出力することができるようです。
ただ、`gendoc`だけ試してみましたが、問答無用で既存のREADMEを上書きしてしまったので、ちゃんと書いている人には無用かもしれません…。

# どんな風に使うべきか

Ansibleを利用している会社・プロジェクト・システムなどで、一体自分たちのロールがどのような状況にあるかを把握するには、非常にわかりやすいツールだと思います。この画像を設計資料に載せておくだけで、全体的なイメージは湧きやすくなるのではないでしょうか？

ただ、単純に可視化するだけでもニヤニヤできるかもしれません。それだけでも楽しくないですか？