Ansibleでtemplateから複数のconfファイルをコピーしてサービスを再起動するRole


#はじめに
Ansibleを使って構成管理していると、よくあるパターンとして、「templatesモジュールでconfファイルを配置して更新があればrestartする」というのがあります。

Playbookとしては似たようなパターンなのにconfファイルごとにいちいち書き分けるのは非効率です。

下記のようにvarsとwith_dictを使うことで、一つのRoleで複数のミドルウェア、複数のconfファイルの管理に対応できます。

##メリット
ループするのなら`with_items`でもできますが、`with_dict`にするのには理由があります。
それは、別のvarsで特定の設定ファイルのパラメータを上書きしたい時に便利だからです。

`with_items`だと、親要素単位で上書きされてしまうため、差分のない箇所も重複して定義する必要があります。

例えば、本記事のように`config_file`について`with_items`でループさせた場合、`middleware_conf2`にだけ差分がある場合でも`middleware_conf`も再度定義する必要があります。これは親要素の`config_file`単位で上書きされてしまうためです。

`with_dict`を使うと、`config_file`配下の`middleware_conf`、`middleware_conf2`単位での上書きが可能になります。

本番環境とステージング環境で特定の設定ファイルのパラメータだけ違う、というような場合に差分だけ上書きできるので効率よくパラメータ管理ができます。

##前提
ansible.cfgに下記が設定されていること

```Bash:ansible.cfg
[defaults]
hash_behaviour = merge
```

##sample

###ディレクトリ構成

```bash:ディレクトリ構成
site.yml
roles/
|--put_conf_and_restart/
|  |--handlers/
|  |  |--main.yml
|  |--tasks/
|  |  |--main.yml
|  |--templates/
|  |  |--middleware.conf.j2
|  |  |--middleware.conf2.j2
group_vars/
|--targetgroup.yml
host_vars/
|--targethost.yml
```

###vars
varsの記載箇所は環境に合わせてください。まずはgroup_varsで定義します。

```yaml:group_vars/targetgroup.yml
---
my_vars:
  middlewares:
    middleware:
      service:
        name: middleware
      configs:
        config_file:
          middleware_conf:
            template: middleware.conf.j2
            owner: user
            group: group
            mode: '0644'
            path: /path/to/middleware.conf
            params:
              parameter: PARAMETER
          middleware_conf2:
            template: middleware.conf2.j2
            owner: user
            group: group
            mode: '0644'
            path: /path/to/middleware2.conf
            params:
              parameter2: PARAMETER2
```

###Role
with_dictでmy_vars.middlewares.middleware.configs.config_file以下でループさせています。配置したいconfファイルが複数ある場合でも、ここに複数定義することで対応できます。
テンプレートファイルはそれぞれ用意する必要があります。
なお、owner, group, modeについてはデフォルト値を用意しておくと、varsに定義がない場合デフォルト値が採用されるので便利です。

```yaml:put_conf_and_restart/tasks/main.yml
---
- name: put Middleware config files
  template:
    src: "{{ item.value.template }}"
    dest: "{{ item.value.path }}"
    owner: "{{ item.value.owner | default('root') }}"
    group: "{{ item.value.group | default('root') }}"
    mode: "{{ item.value.mode | default('0644') }}"
  with_dict: "{{ my_vars.middlewares.middleware.configs.config_file }}"
  notify:
    - restart service
```
###template
テンプレートについては、冒頭でmy_vars配下のそれぞれのconfファイルごとに定義したparamsの値が変数paramsにセットされます。
デフォルト値を用意しておくことで、my_varsに定義していないパラメータについてはデフォルト値が採用されます。

```put_conf_and_restart/temlpates/middleware.conf.j2
{% set params = item.value.params %}

{% if params.parameter is defined %}
parameter            = {{ params.parameter }}
{% else %}
parameter            = default value
{% endif %}
```
```put_conf_and_restart/temlpates/middleware.conf2.j2
{% set params = item.value.params %}

{% if params.parameter2 is defined %}
parameter2            = {{ params.parameter2 }}
{% else %}
parameter2            = default value
{% endif %}
```
###handlers
handlersについては、定義したservice.nameに基づいてrestartをかけます。

```yaml:put_conf_and_restart/handlers/main.yml
---
- name: restart service
  service:
    name: "{{ my_vars.middlewares.middleware.service.name }}"
    state: restarted
  when: not ansible_check_mode
```

###site.yml

```bash:site.yml
---
- hosts: targethost
  roles:
    - role: put_conf_and_restart
```

##差分をhost_varsに定義してgroup_varsを上書きする
ここでgroup_varsで定義した変数をhost_varsで上書きする例を見てみましょう。

Ansibleでは、varsの記載箇所によって採用される優先度が変わります。

参考：[公式ドキュメント](http://docs.ansible.com/ansible/playbooks_variables.html)

group_varsよりhost_varsの方が優先度が高いので、同じ項目が両方に定義されていた場合、host_varsの値に「上書き」されます。

例えばmiddleware_conf2のみに差分がある場合、host_varsに下記のように定義すればOKです。
（ここではparameter2の値が異なる）


```yaml:host_vars/targethost.yml
---
my_vars:
  middlewares:
    middleware:
      configs:
        config_file:
          middleware_conf2:
            template: middleware.conf2.j2
            owner: user
            group: group
            mode: '0644'
            path: /path/to/middleware2.conf
            params:
              parameter2: PARAMETER2_HOST
```
こうすることで、共通するmiddleware.confのパラメータはgroup_varsの値を採用しつつ、差分であるmiddleware_conf2のパラメータのみを上書きすることができます。