初めてのAnsible（7章：複雑なPlaybook）


[「初めてのAnsible」](https://www.oreilly.co.jp/books/9784873117652/)を読み進めながらのメモ

前掲
[初めてのAnsible（1章：イントロダクション）](http://qiita.com/c0tt0n-candy/items/512049586f5a1f1279f3)
[初めてのAnsible（2章：Playbook:始めてみよう）](http://qiita.com/c0tt0n-candy/items/36b4eb2717447071ad21)
[初めてのAnsible（3章：インベントリ:サーバーの記述）](http://qiita.com/c0tt0n-candy/items/1b109c53d8709717a1bb)
[初めてのAnsible（4章：変数とファクト）](http://qiita.com/c0tt0n-candy/items/7144d49636a30433365c)

## [`local_action`](http://docs.ansible.com/ansible/playbooks_delegation.html#delegation)(ローカルで), [`run_once`](http://docs.ansible.com/ansible/playbooks_delegation.html#id12)(一度だけ)

`local_action`節はその名の通り、リモートホストではなくコントロールマシンで実行したいタスクを指定するもの

サーバー起動直後で完全に立ち上がっていないために、playbookの実行がエラーになってしまうような場合、

playbookの先頭で[`wait_for`モジュール](http://docs.ansible.com/ansible/wait_for_module.html#wait-for-waits-for-a-condition-before-continuing)を呼び出し、SSHサーバーが接続を受け付けられるようになってから残りの処理を行わせることができる

```
- name: wait for ssh server to be running, only once
  local_action: wait_for port=22 host="{{ inventory_hostname }}" search_regex=openSSH
  run_once: true      
```

上記の例では、`run_once`節を利用しこのタスクを一度だけ実行するようにしている

`local_action`節は複数のホストを扱っている場合 **ホストの数だけ実行される**ことになるが、一度だけ実行してくれればよい場合などには `run_once: true` としてあげる

## [`serial`](http://docs.ansible.com/ansible/playbooks_delegation.html#rolling-update-batch-size)(一度にいくつ)

Ansibleは通常、すべてのホストに並列にSSH接続し、各タスクを全ホストで同時に実行する

しかし、ロードバランサにぶら下がっているアプリケーションサーバーをアップグレードする場合など、並列に・同時に行うわけにはいかない場合,

`serial`節で一度に実行するホスト数を指定することができる

```
- name: run tasks one by one
  hosts: app
  serial: 1
  max_fail_percentage: 25
  tasks:
    :
```

上記の例で言えば、`serial; 1`で一度に1台ずつタスクを実行するようしている

また、`max_fail_percentage`節を利用して許容する失敗したホストの最大のパーセンテージを指定している

この場合、25%を超えたホストがタスクの実行に失敗した場合、全体のplayを失敗とする

```
- name: run tasks one by one
  hosts: app
  serial: "20%"
    :
```

また、上記の例のように`serial`節はパーセンテージを用いて指定することもできる


## [`faild_when`](http://docs.ansible.com/ansible/playbooks_error_handling.html)(こういう場合にはfailed)

公式に載っている例をみてみよう

```
- name: this command prints FAILED when it fails
  command: /usr/bin/example-command -x -y -z
  register: command_result
  failed_when: "'FAILED' in command_result.stderr"
```

コマンドを実行して、その出力結果を`command_result`に格納

変数`command_result`の *stderr* キーに **FAILED** が含まれていた場合には、タスクをfailedにする

いろいろ試してくださっているので参考に↓
[ansibleでの実行結果のsuccess/failedとignore_errors/failed_whenがよくわからなかったので調べてみた](http://qiita.com/sakaimo/items/67659a093f58d1922d54)

## [`changed_when`](http://docs.ansible.com/ansible/playbooks_error_handling.html#overriding-the-changed-result)(こういう場合にはchanged)

あるタスクを実行した際に、ホストの状態を変えた場合に返される changed

しかし、ホストの状態を何も変化させていないのに changed が返されるような場合もある

逆に、実際にはホストの状態を変化させているにも関わらず、changed が返されないような場合もある

使い方を公式の例でみてみよう

```
tasks:

  - shell: /usr/bin/billybass --mode="take me to the river"
    register: bass_result
    changed_when: "bass_result.rc != 2"

  # this will never report 'changed' status
  - shell: wall 'beep'
    changed_when: False
```

1つ目の`shell`では、出力結果を格納した変数`bass_result`の *rc* キーが **2** でなかった場合に changed とし、

2つ目の`shell`では常に changed にはならないように指定している


# フィルタ

* Jinja2 のテンプレートエンジンの機能
* テンプレートファイル、playbookの中でフィルタを利用可能
* 参考）[Jinja2 filters](http://docs.ansible.com/ansible/playbooks_filters.html)

## デフォルトのフィルタ

* 未定義の変数をフィルタしてデフォルト値を設定

```
{{ some_variable | default(5) }}
```

`some_variable`が定義されていればその値が、定義されていなかった場合にはデフォルト値として **5** が使われる

## 登録変数のフィルタ

* 登録変数の状態をチェックするために利用

| 名前 | 説明 |
| --- | --- |
| failed | 登録された値が、失敗したタスクだった場合に true |
| success | 登録された値が、成功したタスクだった場合に true |
| changed | 登録された値が、変化がアタタスクだった場合に true |
| skipped | 登録された値が、スキップされたタスクだった場合に true |

```
- name: run test
  command: /opt/test
  register: test_result
  ignore_errors: True

- debug: var=test_result

- debug: msg="Stop running the playbook if test failed"
  faild_when: test_result|failed
    :
```

`test_result`に格納された値が失敗したタスクのものであった場合、debugモジュールを実行してmsgを出力するようにしている

## ファイルパスのフィルタ

* コントロールマシン（ローカル）のファイルシステム上のパスが含まれている場合に役立つフィルタ群
	* Windowsの場合は `win_*` みたいなフィルタ名になってるみたい

公式では [Other Useful Filters](http://docs.ansible.com/ansible/playbooks_filters.html#other-useful-filters) にまとめられてる

# ルックアップ

* 設定データを種々のソースから読み取る機能
* playbook、テンプレート中で`{{ }}`で呼び出すことが可能
* 2つの引数を渡して`lookup`関数を呼び出して利用
	* 1つ目の引数：ルックアップ名（下記表参照）
	* 2つ目の引数：ルックアップに渡す1つ以上の引数
* 参考）[Using Lookups](http://docs.ansible.com/ansible/playbooks_lookups.html)


| 名前 | 説明 |
| --- | --- |
| file | ファイルの内容 |
| password | ランダムで生成されたパスワード |
| pipe | ローカルで実行されたコマンドの出力 |
| env | 環境変数 |
| template | 評価後のJinja2のテンプレート |
| csvfile | .csvfairuのエントリ |
| dnstxt | DNSのTXTレコード |
| redis_kv | Redisのキーのルックアップ |
| etcd | etcdのキーのルックアップ |

公式の例をみてみよう

```
- hosts: all
  vars:
     contents: "{{ lookup('file', '/etc/foo.txt') }}"

  tasks:

     - debug: msg="the value of foo.txt is {{ contents }}"
```

fileルックアップを利用し、指定したファイルの内容を変数`contents`に格納している