Ansibleのベストプラクティスなディレクトリ構成の雛形を一撃で作りたい

# やること

Ansibleのベストプラクティスなディレクトリ構成を、
毎回ゼロから作っていると面倒臭いです。（もしかして楽な方法ある...？）

せっかくなので、そのディレクトリ構成と、inventoryやymlファイルの雛形なども、
Ansibleのplaybookで作れるようにしてみようと思いました。

何かに組み込んで使うというよりも、
**「新しい環境を、Ansibleで作れるようにしようかなぁ」**というときに、
取っ掛かりとしてまず実行して雛形を作成するものです。


# 前提

たぶん後から修正したり改良したりします。

### 筆者の環境

* macOS Sierra
* Ansible 2.4.3

### 知識

* Ansibleを知っている

# 実践

## 1. 目標
ベストプラクティスなディレクトリ構成のうち、
Alternative Directory Layout を、一部省略しつつ作るようにしようと思います。

```shell:作成する構成fromAlternativeDirectoryLayout

inventories/
   production/
      hosts               # 本番用サーバのアドレス情報
   staging/
      hosts               # ステージング用サーバのアドレス情報
   develop/
      hosts               # 開発用サーバのアドレス情報

site.yml
webservers.yml
dbservers.yml

roles/
    common/
        tasks/            
            main.yml      
        handlers/         
            main.yml      
        templates/        
        files/            
        vars/             
            main.yml      
        defaults/         
            main.yml      
        meta/             
            main.yml      

```

## 2. 雛形作成playbookを作る

以下が、乱暴に作ってみた、ベストプラクティスなディレクトリ構成を作成するplaybookです。

```initializer.yml
# localhost上で、AnsibleのBestpracticeなディレクトリ構成の雛形を作成します。
# 
# 以下のように、localhost指定で作成します・
# ansible-playbook -i localhost, -c local initializer.yml
#  
 
- hosts: localhost
  vars_prompt:
    - name: "root_dir_name"
      prompt: "生成するディレクトリ名を指定してください。"
      confirm: no
      private: no
      default: "sample"
  vars:
    root_dir_path: "{{ playbook_dir }}/{{ root_dir_name }}"
    inventory_path: "{{ root_dir_path }}/inventories"
    environments: 
        - production
        - staging
        - develop
    roles_path: "{{ root_dir_path }}/roles"
    roles_subs:
        - common/tasks
        - common/handlers
        - common/templates
        - common/files
        - common/vars
        - common/defaults
        - common/meta
    roles_subs_yml:
        - common/tasks
        - common/handlers
        - common/vars
        - common/defaults
        - common/meta
    generate_marker: "## -- INITIALIZERによる挿入 --"    
    
  tasks:
    # inventories
    - name: Create environment directories
      file: 
        path: "{{ inventory_path }}/{{ item }}"
        state: directory 
        mode: 0755
      with_items: "{{ environments }}"

    - name: Create environment hosts
      blockinfile: 
        path: "{{ inventory_path }}/{{ item }}/hosts"
        create: yes
        marker: "{{ generate_marker }}"
        block: |
          [webservers]
          127.0.0.1
          
          [dbservers]
          127.0.0.1
      with_items: "{{ environments }}"

    # roles
    - name: Create role directories
      file: 
        path: "{{ roles_path }}/{{ item }}"
        state: directory 
        mode: 0755
      with_items: "{{ roles_subs }}"
 
    - name: Create role directories main.yml
      blockinfile: 
        path: "{{ roles_path }}/{{ item }}/main.yml"
        create: yes
        marker: "{{ generate_marker }}"
        block: | 
            # 担当するモジュールのみを扱うように、シンプルに保ちます。
      with_items: "{{ roles_subs_yml }}"
    

    # modules
    - name: Create module ymls
      blockinfile: 
        path: "{{ root_dir_path }}/{{ item }}.yml"
        create: yes
        marker: "{{ generate_marker }}"
        block: | 
            # 各モジュールのymlは、小分けにしたroleをincludeするだけのシンプルさを保ちます。
            - hosts: {{ item }}
              #   become_user: vagrant
              #   become: yes
              roles:
      with_items: 
        - webservers
        - dbservers

    - name: Create main yml
      blockinfile: 
        path: "{{ root_dir_path }}/site.yml"
        create: yes
        marker: "{{ generate_marker }}"
        block: | 
            # site.ymlはincludeのみでシンプルに保ちます。
            - include: webservers.yml
            - include: dbservers.yml

```


## 3. 使ってみる

以下のようにplaybookを実行して使います。
実行するとまず、出力するディレクトリ名を指定できる親切(？)設計です。
現在のディレクトリ上に指定のディレクトリを作成して、その配下に諸々を生成します。
省略すると「sample」というディレクトリで作られます。

```shell:作ったplaybookを使ってみる
$ ansible-playbook -i localhost, -c local initializer.yml
生成するディレクトリ名を指定してください。 [sample]: hoge

PLAY [localhost] ***************************************************************

TASK [Gathering Facts] *********************************************************
ok: [localhost]

TASK [Create environment directories] ******************************************
changed: [localhost] => (item=production)
changed: [localhost] => (item=staging)
changed: [localhost] => (item=develop)

TASK [Create environment hosts] ************************************************
changed: [localhost] => (item=production)
changed: [localhost] => (item=staging)
changed: [localhost] => (item=develop)

TASK [Create role directories] *************************************************
changed: [localhost] => (item=common/tasks)
changed: [localhost] => (item=common/handlers)
changed: [localhost] => (item=common/templates)
changed: [localhost] => (item=common/files)
changed: [localhost] => (item=common/vars)
changed: [localhost] => (item=common/defaults)
changed: [localhost] => (item=common/meta)

TASK [Create role directories main.yml] ****************************************
changed: [localhost] => (item=common/tasks)
changed: [localhost] => (item=common/handlers)
changed: [localhost] => (item=common/vars)
changed: [localhost] => (item=common/defaults)
changed: [localhost] => (item=common/meta)

TASK [Create module ymls] ******************************************************
changed: [localhost] => (item=webservers)
changed: [localhost] => (item=dbservers)

TASK [Create main yml] *********************************************************
changed: [localhost]

PLAY RECAP *********************************************************************
localhost                  : ok=7    changed=6    unreachable=0    failed=0   

```

以上です。

# 補足：Ansible公式のベストプラクティスに関する記述

詳しくは、公式サイトのドキュメントをご覧ください。
http://docs.ansible.com/ansible/latest/playbooks_best_practices.html