OSによって処理を変えるPlaybookディレクトリの作成


以前にansibleでvim,zshの設定を自動化する記事(http://qiita.com/nl0_blu/items/428656c1147775faefd1)
を書いたが、これはvagrantの仮想マシンなど様々な場面で利用できた。

しかし、CentOS7とUbuntu16.04など環境が違う場合に、パッケージをインストールするコマンドが異なるためplaybookの中身を変更する必要があった。

そのため本記事では、その改善案としてPlaybookのディレクトリ構造やYAMLの中身などを変えることで、上記の手間をなくしたい。

##OSをどう判別するか

setup_moduleの結果で得られる変数はplaybookに利用できることから、これを利用する。

```
$ ansible -m setup 192.168.12.183
　：
　：
　かなり長い出力です。
```

この中の

* ディストリビューションを示す：　"ansible_distribution"
* ディストリビュションのバージョンを示す：　"ansible_distribution_major_version"

をplaybook内で利用する。

## 完成したディレクトリ

```shell-session

├Vagrantfile     
└provisioning/　　　　　　　
　├ hosts                 #Inventoryファイル(対象サーバーのIP等)
　├ site.yml              #マスタープレイブック
　├ centos6.yml           #centos6用のロールをまとめたプレイブック
　├ centos7.yml           #centos7用のロールをまとめたプレイブック
　├ ubuntu16.yml          #ubuntu16用のロールをまとめたプレイブック
　├ files                 #テンプレートとなるファイルなど
　　└ .vimrc              
　　└ .zshrc               
　└ roles
  　  　├ vim_centos      #centos用のvim設定ロール
    　　　└ tasks
    　　　　└ main.yml
    　　├ zsh_centos      #centos用のzsh設定ロール
    　　　└ tasks
    　　　　└ main.yml
    　　├ vim_ubuntu      #ubuntu用のvim設定ロール
    　　　└ tasks
    　　　　└ main.yml
    　　├ zsh_ubuntu      #ubuntu用のzsh設定ロール
    　　　└ tasks
    　　　　└ main.yml
```

## Inventoryファイル、YAMLの中身の例

Inventoryファイル(hosts)

```hosts
[hostname]
192.168.33.12

# 対象がcentos6であると想定
# centos6 only group
[centos6:children]
hostname

#以下は今回は利用しないのでコメントアウト
#centos7 only group
#[centos7:children]
#hostname

#ubuntu16 only group
#[ubuntu16:children]
#hostname

#all group
#[all:children]
#hostname
```

site.ymlでは、先ほどの方法でOSを判定してincludeするプレイブックを決める

```site.yml
---

# centos6 specific tasks
- include: centos6.yml
  when:
   - ansible_distribution == "CentOS"
   - ansible_distribution_major_version == "6"

# centos7 specific tasks
- include: centos7.yml
  when:
   - ansible_distribution == "CentOS"
   - ansible_distribution_major_version == "7"

#Ubuntu specific tasks
- include: ubuntu16.yml
  when:
   - ansible_distribution == "Ubuntu"
   - ansible_distribution_major_version == "16"
```

centos6と判定されたら、vim_centosとzsh_centosのロールを実行することをcentos6.ymlに記述する(centos7.ymlも同様)

```centos6.yml
---

- hosts: centos6
  user: vagrant
  sudo: yes
  roles:
  - vim_centos
  - zsh_centos
```

ubuntu16と判定されたら、vim_ubuntuとzsh_ubuntuのロールを実行することをubuntu16.ymlに記述する

以下は各タスクの中身、centosとubuntuでコマンドが違うことがポイント。
コードは突っ込みどころありです。

```roles/vim_centos/tasks/main.yml
---
- name: vim requires install by yum
  yum: name={{ item }} state=latest
  with_items:
    - gcc
    - git
    - mercurial
    - ncurses-devel
    - lua
    - lua-devel
    - perl
    - perl-devel
    - perl-ExtUtils-Embed
    - python
    - python-devel
    - libselinux-python

- name: install vim by yum
  yum: name=vim state=present

- name: copy .vimrc file to dest home
  copy: src="../../../files/.vimrc" dest="~vagrant/.vimrc" owner=vagrant group=vagrant mode="u=rw,g=r,o=r"
```

```roles/zsh_centos/tasks/main.yml
---
- name: install zsh by yum
  yum: name=zsh state=present

- name: set zsh as default shell for root
  command: chsh -s '/bin/zsh' root

- name: copy .zshrc file to dest home
  copy: src="../../../files/.zshrc" dest="~vagrant/.zshrc" owner=vagrant group=vagrant mode="u=rw,g=r,o=r"
```

```roles/vim_ubuntu/tasks/main.yml
---
- name: vim requires install by apt
  apt: name={{ item }} state=latest update_cache=yes
  with_items:
    - gcc
    - git
    - mercurial
    - perl
    - python

- name: Install vim by apt
  apt: name=vim state=present

- name: copy .vimrc file to dest home
  copy: src="../../../files/.vimrc" dest="~vagrant/.vimrc" owner=vagrant group=vagrant mode="u=rw,g=r,o=r"
```

```roles/zsh_ubuntu/tasks/main.yml
---
- name: install zsh by apt
  apt: name=zsh state=present

- name: set zsh as default shell for vagrant
  command: chsh -s '/bin/zsh' vagrant

- name: copy .zshrc file to dest home
  copy: src="../../../files/.zshrc" dest="~vagrant/.zshrc" owner=vagrant group=vagrant mode="u=rw,g=r,o=r"
```

##まとめ

簡単にテストしたところ、大丈夫そうだった。(バグあったら修正します)

```
$ ansible-playbook site.yml -i hosts -u vagrant --check
```

また、今回はAnsibleの本格的なイメージの理解として、ansibleのベストプラクティスを参考にした。
http://docs.ansible.com/ansible/playbooks_best_practices.html


この構造にすることで、OSにより処理が異なる設定(例えばDockerのインストール)に対しても、roleを書いて各OSのPlaybookに含ませることで対処できる。