ansible-playbook実行中にFactsを再取得する方法

# あらまし
先日docker-engineを`1.8.3`から`1.9.0`にverupしたところ
アプリケーションが軒並み動かなくなり、調べたところ
Network Interfaceの`docker0`が
**`172.17.42.1` から `172.17.0.1`に仕様変更**されており
設定ファイルに直接`172.17.42.1`と記載していた部分を
総置き換えすることになった。
(Release noteちゃんと読めよって話ではある。)

最初は
「ansible-playbookで指定している`172.17.42.1`を
`ansible_docker0.ipv4.address`に置き換えるだけっしょ？ちょろいっしょ。」
とか言ってたんだけど、ansible-palybookで
`ansible_docker0.ipv4.address`の値を取得できずエラーとなり、ハマった。

```shell-session
fatal: [IP_ADDR] => One or more undefined variables: 'ansible_docker0' is undefined
```

要するに全然ちょろくなかったので、自戒を込めて方法を記載しておく。

# なぜハマったのか
ansible-playbookでdocker-engineをinstallした後
ansibleのFactsが更新されておらず
追加されたdocker0の情報が取得できなかった。

# Factsの再取得方法
結論を先に書いておくと`setup`でOK。
通常`:`の後に諸々書くのだが、そんなことはしなくていいらしい。

*ex) docker-engine install後にFacts再取得。*

```yaml:facts-setup.yml
- hosts: all
  become: true
  tasks:
    - apt: name=docker-engine
    - setup:
```

# Factsって？
ansible-playbook実行後に出てくるアレ。

```console
GATHERING FACTS ***************************************************************
ok: [IP_ADDR]
```

なにやってるかっていうと、対象HostのHW情報やらなんやら取得している。
取得内容は以下のようなansibleコマンドで確認可能。

*ex) inventory `hosts` の `all` groupsのHost情報を取得*

```sh
$ ansible -i hosts all -m setup
```

公式はこちら。
[Ansible >> Docs >> Variables](http://docs.ansible.com/ansible/playbooks_variables.html#information-discovered-from-systems-facts)


# 動作検証
GCEのVMで動作検証を実施しています。
- OS:Debian Wheezy (3.16.7-ckt11-1+deb8u4~bpo70+1)
- MachineType:n1-standard-1

## 評価するplaybook
このplaybookでは簡略化の為
docker-engineをinstallする為の前準備は
済ませているものとしています。
簡略化した手順とは [Installation on Debian](https://docs.docker.com/engine/installation/debian/#debian-wheezy-stable-7-x-64-bit) の 
`Add an entry for your Debian operating system.` 
までの手順となります。

```yaml:docker-test.yml
- hosts: all
  become: true
  tasks:
    # ipコマンドでdocker0のinterface情報取得
    # (docker-engine install前)
    - command: bash -c "ip addr show dev docker0"
      register: docker0_info
      changed_when: false
      ignore_errors: true
      always_run: yes
    - debug: var=docker0_info.stdout

    # Install Docker.
    - apt: name=docker-engine=1.9.0-0~wheezy

    # ipコマンドでdocker0のinterface情報取得
    # (docker-engine install後)
    - command: bash -c "ip addr show dev docker0"
      register: docker0_info
      changed_when: false
      ignore_errors: true
      always_run: yes
    - debug: var=docker0_info.stdout

    # Facts再取得前のinterfase情報確認
    - debug: var=ansible_interfaces
    - debug: var=ansible_docker0

    # docker0 interface 起動まで待機
    - wait_for: path=/proc/sys/net/ipv4/conf/docker0 state=present
    # Facts再取得
    - setup:

    # Facts再取得後のinterfase情報確認
    - debug: var=ansible_interfaces
    - debug: var=ansible_docker0
```
## docker-engine Install前
docker-engineのinstall前は`docker0`は作成されていないので
情報は取得できない。
(ipコマンドはエラーとなっているが、`ignore-errors: true`をつけることにより
playbook終了を回避している。)

```shell-session
TASK: [command bash -c "ip addr show dev docker0"] ****************************
failed: [IP_ADDR] => {"changed": true, "cmd": ["bash", "-c", "ip addr show dev docker0"], "delta": "0:00:00.002841", "end": "2015-11-14 14:59:57.483245", "rc": 1, "start": "2015-11-14 14:59:57.480404", "warnings": []}
stderr: Device "docker0" does not exist.
...ignoring

TASK: [debug var=docker0_info.stdout] *****************************************
ok: [IP_ADDR] => {
    "var": {
        "docker0_info.stdout": ""
    }
}
```

## Factsを再取得してない場合
docker-engineはinstallされて、実際にOS上には`docker0`のIFは起動しているのに
ansible上には情報はない。
このまま`docker0.ipv4.address`を取得しようものならplaybookがエラーとなる。

```shell-session
TASK: [debug var=docker0_info.stdout] *****************************************
ok: [IP_ADDR] => {
    "var": {
        "docker0_info.stdout": "3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN \n    link/ether 02:42:29:0c:98:f0 brd ff:ff:ff:ff:ff:ff\n    inet 172.17.0.1/16 scope global docker0\n       valid_lft forever preferred_lft forever"
    }
}

TASK: [debug var=ansible_interfaces] ******************************************
ok: [IP_ADDR] => {
    "var": {
        "ansible_interfaces": [
            "lo",
            "eth0"
        ]
    }
}

TASK: [debug var=ansible_docker0] *********************************************
ok: [IP_ADDR] => {
    "var": {
        "ansible_docker0": "ansible_docker0"
    }
}
```

## Factsを再取得した場合
`docker0`の情報が確認できる。やったね。

```shell-session
TASK: [setup ] ****************************************************************
ok: [IP_ADDR]

TASK: [debug var=ansible_interfaces] ******************************************
ok: [IP_ADDR] => {
    "var": {
        "ansible_interfaces": [
            "lo",
            "docker0",
            "eth0"
        ]
    }
}

TASK: [debug var=ansible_docker0] *********************************************
ok: [IP_ADDR] => {
    "var": {
        "ansible_docker0": {
            "active": false,
            "device": "docker0",
            "id": "8000.0242290c98f0",
            "interfaces": [],
            "ipv4": {
                "address": "172.17.0.1",
                "netmask": "255.255.0.0",
                "network": "172.17.0.0"
            },
            "macaddress": "02:42:29:0c:98:f0",
            "mtu": 1500,
            "promisc": false,
            "stp": false,
            "type": "bridge"
        }
    }
}
```