【Ansible】varsファイルをOSディストリビューションごとに切り替える

# はじめに
同じパッケージであるにも関わらず、ディストリビューションで名称が違う場合があります。またインストールパス／設定ファイルのパスが微妙に違う場合があります。

たとえばApache2.4のパッケージ名は、CentOS7の場合は「httpd」ですが、Amazon Linuxの場合は「httpd24」となります。タスクごとにwhen句で指定しても良いのですが、同じ値を複数個所で使う場合はPlaybookが煩雑になります。

このような場合、ディストリビューション／OS環境ごとに変数をあらかじめ定義し、切り替えられたら便利です。またこの制御をグローバルに行う（≒Role呼び出し元のPlaybookで制御する）のではなく、Roleに閉じた範囲で制御できた方が見通しが良くなります。

このようなケースの解決策を以下にまとめます。

# TL;DR
- vars（roles/????/vars/main.yml）の中ではwhen句で切り替えられない
- 各Roleのタスク（roles/????/tasks/main.yml）で、include_varsを使う
- include_varsと併せてwhen句を使う

# 試してみる
## 環境
CentOS7とAmazon Linuxで動作を確認しました。
いずれもVirtual BoxとVagrantでローカルにVMを作った環境となります。

必要な設定ファイル、Playbookは下記に公開しています。
https://github.com/tmiki/server-config

### CentOS7
OS: CentOS Linux release 7.5.1804 (Core)
Python: 2.7.5
Ansible: 2.7.0

### Amazon Linux
OS: Amazon Linux AMI 2017.03
Python: 2.7.12
Ansible: 2.6.4


## Ansible Playbookディレクトリ構成
Ansible Playbookのディレクトリ構成は下記であるとします。

```bash
/path/to/ansible-playbooks/
  - ansible.cfg
  - ssh_config
  - sys_local.yml  ### ローカルホスト用のPlaybook。この中で各種Roleを読み込む。
  - hosts/  ### 環境ごとのホスト、変数の定義。今回は省略。
  - roles/  ### 各種Roleを格納しているディレクトリ
    - common/
    - common_httpd/  ### 今回はこのRoleの中の話になります。
    - common_supervisor/
    - :
    - :

```

## Playbookの定義
まず、OSディストリビューションごとに変数定義ファイルを用意します。名前は、vars-CentOS7.ymlとvars-AmazonLinux.ymlとします。
これらのvarsファイルの中で、「httpd_package_name」変数を定義します。

```yaml:roles/common_httpd/vars/vars-CentOS7.yml
---
httpd_package_name: httpd
```

```yaml:roles/common_httpd/vars/vars-AmazonLinux.yml
---
httpd_package_name: httpd24

```

タスクから下記のように指定します。when句でOSディストリビューションごとに読み込むvarsファイルを切り替えています。
実際にApacheをインストールするyumモジュールの「name」パラメータに、上記で定義した「httpd_package_name」変数を渡しています。

```yaml:roles/common_httpd/tasks/main.yml
---
- name: Configure packages' name for AmazonLinux
  include_vars: vars-AmazonLinux.yml
  when: (ansible_distribution == "Amazon")

- name: Configure packages' name for CentOS7
  include_vars: vars-CentOS7.yml
  when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "7")

- name: Install Apache2.4
  yum: name="{{httpd_package_name}}" state=present update_cache=yes
```

## 解説・補足
### 想定していないOSディストリビューションで実行する
このPlaybookを、CentOS7／AmazonLinux以外のディストリビューションで実行するとエラーとなります。「httpd_package_name」変数が未定義状態になるので。

### include_varsに変数を指定する。
「include_vars」を指定している個所は通常のPlaybookのタスクファイルであるため、任意の変数が利用できます。
したがって、下記のような指定も可能です。

```yaml:roles/common_httpd/tasks/main.yml
- name: Configure packages' name for each distributions
  include_vars: vars-{{ansible_distribution}}{{ansible_distribution_major_version}}.yml

```

CentOSやUbuntuでは「ansible_distribution_major_version」が正しく設定されるので上記で問題なく動きます。
Amazon Linuxは「ansible_distribution_major_version」が「NA」になりますので、注意が必要です。
\# 恐らくAmazon Linux 2は当該値が2になるのではないかと思いますが、未検証

とはいえこの場合、「NA」は単なる文字列なので、「vars-AmazonNA.yml」というファイルを置いておけば事足ります。

ちなみに、「ansible -m setup localhost」の結果はそれぞれ下記のようになります。

```bash:CentOS7
$ ansible -m setup localhost
### ※途中省略
        "ansible_distribution": "CentOS",
        "ansible_distribution_file_parsed": true,
        "ansible_distribution_file_path": "/etc/redhat-release",
        "ansible_distribution_file_variety": "RedHat",
        "ansible_distribution_major_version": "7",
        "ansible_distribution_release": "Core",
        "ansible_distribution_version": "7.5.1804",
### ※途中省略
```


```bash:AmazonLinux
$ ansible -m setup localhost
### ※途中省略
        "ansible_distribution": "Amazon",
        "ansible_distribution_file_parsed": true,
        "ansible_distribution_file_path": "/etc/system-release",
        "ansible_distribution_file_variety": "Amazon",
        "ansible_distribution_major_version": "NA",
        "ansible_distribution_release": "NA",
        "ansible_distribution_version": "2017.03",
### ※途中省略
```