ansibleのロールを直接実行できる、ansible-artというツールを作った。

## 制作背景
ansibleでロールを対象サーバに適用する際、次の手順を踏む必要があります。

1. ロールの開発
2. ロールを実行するplaybookの開発
3. インベントリの作成や、host_varsなどの変数の作成
4. 2. のplaybookの実行

ここで私が常々感じていたのは、ロールを対象サーバに適用したいだけなのに、2. でわざわざロールを適用するためのplaybookを開発しないといけないのは無駄だということです。ロール名と3. で作成した情報さえあれば、ロールは適用できるはずです。  
そこで、ロール名と3. で作成した情報を引数に与えれば、対象サーバにロールを適用できる、ansible-artというツールを作ろう！ と思い至りました。

## インストール
インストールはpipさえあれば、次のコマンドで一発です。

```shell-session
# pip install ansible-art
```

インストール後、ロールが配置されているディレクトリを設定します。次のコマンドを実行します。

```shell-session
$ ansible-art config
```

すると、ansible.cfgの内容がviで開くので、roles_pathの値にロールが配置されているディレクトリを絶対パスで指定します。

```
roles_path = <ロールが配置されているディレクトリの絶対パス>
```

以上でインストールおよび設定は完了です。

## 使い方
ansible-artは次のようなコマンド体系を持っています。

```
ansible-art [-h] [-V]
ansible-art role list
ansible-art role params <ロール名>
ansible-art config
ansible-art apply <ロール名> <インベントリファイル> [-p <dir>] [-g <dir>] [-a <args>]
```

順に一つずつ解説していきます。

* `ansible-art [-h] [-V]`
`-h`オプションでヘルプを表示します。`-V`オプションでバージョンを表示します。

* `ansible-art role list`
ansible-artが認識している全ロールを表示します。

* `ansible-art role params <ロール名>`
`<ロール名>`に指定したロールで定義されている変数を表示します。
内部的にはdefaults/main.ymlの内容を表示しているだけです。
このような実装になっているのは、実際にユーザがhost_varsやgroup_varsを用いて定義できる変数はdefaults/main.ymlに記載されているものに限られる、というポリシーがあるからです。

* `ansible-art config`
ansible-artが参照するansible.cfgファイルを編集します。
ansible-artがロールを適用する際、内部的にはansible-playbookコマンドが呼び出されます。このansible-playbookコマンドが参照するansible.cfgは、ansible-art専用の物として独立に存在します。このansible.cfgを編集するコマンドが`ansible-art config`です。

* `ansible-art apply <ロール名> <インベントリファイル> [-p <dir>] [-g <dir>] [-a <args>]`
`<ロール名>`に指定したロールを対象サーバに適用します。内部的にはansible-playbookコマンドを実行しています。
対象サーバはデフォルトで`all`グループになります。つまり、インベントリファイルに記載されている全サーバが対象です。
`-p <dir>`オプションを使用すると、`<dir>`に指定したディレクトリをhost_varsディレクトリとして認識させることができます。もしこのオプションを指定しなかった場合、ansible-artはコマンドを実行したディレクトリから`host_vars`という名称のディレクトリを探して、host_varsディレクトリとして扱います。さらに`host_vars`という名称のディレクトリが無かった場合、host_varsディレクトリは無いものとしてansible-artはロールを適用します。
`-g <dir>`オプションはgroup_varsディレクトリに関して、`-p <dir>`オプションと同様の振る舞いをします。
`-a <args>`オプションを使用すると、`<args>`に指定された引数を内部的に実行されているansible-playbookコマンドに渡すことができます。これにより、ansible-playbookコマンドによって実現できることはansible-artでも実現可能になっています。使い方の例としては「ロール適用サーバの限定」があります。`-a "-l <グループ名>"`オプションを使用することで、ロールの適用対象サーバを`<グループ名>`に指定したグループに限定することができます。

## 実行例

### 環境
以下のようなディレクトリ構成下で、ansible-artを試しに使ってみようと思います。
なお、`ansible-art config`コマンドで`roles_path`は`/root/ansible/roles`に設定済みとします。

```
/root/ansible(カレントディレクトリ)
├── host_vars_dirs
│   ├── host_vars_01
│   │   └── 192.168.100.10.yml
│   └── host_vars_02
│       └── 192.168.100.10.yml
├── inventory
└── roles
    └── hello
        ├── defaults
        │   └── main.yml
        └── tasks
            └── main.yml
```

各々のファイルの内容を見ていきます。

* インベントリ

```ini:/root/ansible/inventory
192.168.100.12

[group01]
192.168.100.11
192.168.100.10
```

* ロール`hello`

```yml:/root/ansible/roles/hello/tasks/main.yml
---
- name: greeting
  shell: echo "Hello, {{ greeting }}"
  register: ret

- name: return_greeting
  debug: msg="{{ ret.stdout }}"
```

```yml:/root/ansible/roles/hello/defaults/main.yml
---
greeting: "World!!"
```

* host_vars

```yml:/root/ansible/host_vars_dirs/host_vars_01/192.168.100.10.yml
---
greeting: "I am {{ inventory_hostname }}"
```

```yml:/root/ansible/host_vars_dirs/host_vars_02/192.168.100.10.yml
---
greeting: "I like Ansible!!"
```

### `ansible-art apply`の実行
ではansible-artコマンドを実行していきましょう！

* `ansible-art apply hello inventory`  
まずはオプションを何も指定しないところから。ロール名とインベントリファイルの指定だけで、ロールが適用されていることがわかります。また`-p <dir>`オプションを指定していないので、host_varsは無いものとして扱われていることもわかります。
 
```bash
code-controller01:~/ansible # ansible-art apply hello inventory

PLAY [apply role *** hello ***] ************************************************

TASK [setup] *******************************************************************
ok: [192.168.100.12]
ok: [192.168.100.11]
ok: [192.168.100.10]

TASK [hello : greeting] ********************************************************
changed: [192.168.100.12]
changed: [192.168.100.11]
changed: [192.168.100.10]

TASK [hello : return_greeting] *************************************************
ok: [192.168.100.12] => {
    "msg": "Hello, World!!"
}
ok: [192.168.100.10] => {
    "msg": "Hello, World!!"
}
ok: [192.168.100.11] => {
    "msg": "Hello, World!!"
}

PLAY RECAP *********************************************************************
192.168.100.10             : ok=3    changed=1    unreachable=0    failed=0   
192.168.100.11             : ok=3    changed=1    unreachable=0    failed=0   
192.168.100.12             : ok=3    changed=1    unreachable=0    failed=0   

```

* `ansible-art apply hello inventory -p host_vars_dirs/host_vars_01`  
今度は`-p <dir>`オプションを指定して、host_varsとして扱うディレクトリを指定してみます。ホスト`192.168.100.10`の実行結果が変わり、host_varsの内容が反映されていることがわかります。

```bash
code-controller01:~/ansible # ansible-art apply hello inventory -p host_vars_dirs/host_vars_01

PLAY [apply role *** hello ***] ************************************************

TASK [setup] *******************************************************************
ok: [192.168.100.12]
ok: [192.168.100.11]
ok: [192.168.100.10]

TASK [hello : greeting] ********************************************************
changed: [192.168.100.12]
changed: [192.168.100.10]
changed: [192.168.100.11]

TASK [hello : return_greeting] *************************************************
ok: [192.168.100.12] => {
    "msg": "Hello, World!!"
}
ok: [192.168.100.11] => {
    "msg": "Hello, World!!"
}
ok: [192.168.100.10] => {
    "msg": "Hello, I am 192.168.100.10"
}

PLAY RECAP *********************************************************************
192.168.100.10             : ok=3    changed=1    unreachable=0    failed=0   
192.168.100.11             : ok=3    changed=1    unreachable=0    failed=0   
192.168.100.12             : ok=3    changed=1    unreachable=0    failed=0 
```

* `ansible-art apply hello inventory -p host_vars_dirs/host_vars_02`  
次はhost_varsとして指定するディレクトリを変更してみます。  
こんな風にネイティブなansibleと異なり、host_vars、group_varsディレクトリを簡単に切り換えられるのもansible-artのメリットです。

```bash
code-controller01:~/ansible # ansible-art apply hello inventory -p host_vars_dirs/host_vars_02

PLAY [apply role *** hello ***] ************************************************

TASK [setup] *******************************************************************
ok: [192.168.100.12]
ok: [192.168.100.10]
ok: [192.168.100.11]

TASK [hello : greeting] ********************************************************
changed: [192.168.100.12]
changed: [192.168.100.11]
changed: [192.168.100.10]

TASK [hello : return_greeting] *************************************************
ok: [192.168.100.12] => {
    "msg": "Hello, World!!"
}
ok: [192.168.100.11] => {
    "msg": "Hello, World!!"
}
ok: [192.168.100.10] => {
    "msg": "Hello, I like Ansible!!"
}

PLAY RECAP *********************************************************************
192.168.100.10             : ok=3    changed=1    unreachable=0    failed=0   
192.168.100.11             : ok=3    changed=1    unreachable=0    failed=0   
192.168.100.12             : ok=3    changed=1    unreachable=0    failed=0 
```

* `ansible-art apply hello inventory -a "-l group01"`  
お次は`-a <args>`オプションを使ってみましょう。`ansible-playbook`コマンドの`-l`オプションを使って、ロールの適用対象サーバを`group01`グループに絞ります。

```bash
code-controller01:~/ansible # ansible-art apply hello inventory -a "-l group01"

PLAY [apply role *** hello ***] ************************************************

TASK [setup] *******************************************************************
ok: [192.168.100.10]
ok: [192.168.100.11]

TASK [hello : greeting] ********************************************************
changed: [192.168.100.11]
changed: [192.168.100.10]

TASK [hello : return_greeting] *************************************************
ok: [192.168.100.11] => {
    "msg": "Hello, World!!"
}
ok: [192.168.100.10] => {
    "msg": "Hello, World!!"
}

PLAY RECAP *********************************************************************
192.168.100.10             : ok=3    changed=1    unreachable=0    failed=0   
192.168.100.11             : ok=3    changed=1    unreachable=0    failed=0   
```

* `ansible-art apply hello inventory -a "-v"`  
最後によくplaybookのデバッグに使われる、`ansible-playbook`コマンドの`-v`オプションを使ってみます。もちろん`-vvvvv`オプションも同様に指定可能です。


```bash
code-controller01:~/ansible # ansible-art apply hello inventory -a "-v"
Using /root/.ansible-art/ansible.cfg as config file

PLAY [apply role *** hello ***] ************************************************

TASK [setup] *******************************************************************
ok: [192.168.100.12]
ok: [192.168.100.10]
ok: [192.168.100.11]

TASK [hello : greeting] ********************************************************
changed: [192.168.100.12] => {"changed": true, "cmd": "echo \"Hello, World!!\"", "delta": "0:00:00.001743", "end": "2016-11-26 03:58:06.506200", "rc": 0, "start": "2016-11-26 03:58:06.504457", "stderr": "", "stdout": "Hello, World!!", "stdout_lines": ["Hello, World!!"], "warnings": []}
changed: [192.168.100.10] => {"changed": true, "cmd": "echo \"Hello, World!!\"", "delta": "0:00:00.002103", "end": "2016-11-26 03:58:06.624735", "rc": 0, "start": "2016-11-26 03:58:06.622632", "stderr": "", "stdout": "Hello, World!!", "stdout_lines": ["Hello, World!!"], "warnings": []}
changed: [192.168.100.11] => {"changed": true, "cmd": "echo \"Hello, World!!\"", "delta": "0:00:00.001968", "end": "2016-11-26 03:58:06.923400", "rc": 0, "start": "2016-11-26 03:58:06.921432", "stderr": "", "stdout": "Hello, World!!", "stdout_lines": ["Hello, World!!"], "warnings": []}

TASK [hello : return_greeting] *************************************************
ok: [192.168.100.12] => {
    "msg": "Hello, World!!"
}
ok: [192.168.100.11] => {
    "msg": "Hello, World!!"
}
ok: [192.168.100.10] => {
    "msg": "Hello, World!!"
}

PLAY RECAP *********************************************************************
192.168.100.10             : ok=3    changed=1    unreachable=0    failed=0   
192.168.100.11             : ok=3    changed=1    unreachable=0    failed=0   
192.168.100.12             : ok=3    changed=1    unreachable=0    failed=0  
```

## 最後に
いかがでしたでしょうか？
ansible-artを使うと、ロール毎に実行用のplaybookを管理する必要がなくなってスッキリするかと思います。またhost_vars、group_varsディレクトリを容易に切り換えられるようになることもメリットです。
是非使ってみて下さい！

以下、ansible-artのGitHubレポジトリです。
GitHub: https://github.com/bbrfkr/ansible-art