【Ansible】かゆいところに手が届く12のTips　その１

Ansibleを使っていて、個人的にハマって調べたことをTipとしてまとめていきたいと思います。Tipsが溜まったらその2もやります！

[その２はこちら](http://qiita.com/Gin/items/58df302714f9a28048c5)

# 今回紹介するTips

1. shellモジュールで状態確認コマンドを実行した際にchangedを出さない
2. 変数が未定義の時の判定
3. 配列が空の場合にエラーを出さない
4. 多重配列をループさせたい
5. 現在時刻を取得したい
6. ローカルに作業前のバックアップ領域を作成したい
7. handlerを即座に実行したい
8. Ansibleの変数の優先順位
9. 変数のスコープについて
10. Jinja2のtemplateはとても便利
11. 仮想マシン作り直したらAnsibleが届かなくなった
12. User用のパスワードの生成

## shell moduleでの状態確認にchangedは出したくない

**changed_when: false**をつける

```yaml:task
shell: systemctl get-default
changed_when: false
```

## 変数が未定義の時の判定

**is defined**を使う

```:tasks
- copy:
    src: "{{ host }}"
    dest: /etc/hosts

  when: host is defined
```

## 配列が空の場合にエラーを出さない

**default([])**を使う

```:tasks
- sysctl:
    name: "{{ item.name }}"
    value: "{{ item.value }}"

  with_items:
    - "{{ KERNELPARAMETER_LIST | default([]) }}"
```

## 多重配列をループさせたい

**with_subelements**を使う

```:var
userlist:
  - name: user1
    uid: 100
    groups:
      - user1
      - wheel
```

```:task

user:
  name: "{{ item.0.name }}"
  uid: "{{ item.0.uid }}"
  group: "{{ item.1 }}"

with_subelements:
  - "{{ userlist }}"
  - groups
```

## 現在時刻を取得したい

**lookup**を使う

```:var
date: "{{ lookup('pipe','date +%Y%m%d%H%M') }}"
```

## ローカルに作業前のバックアップ領域を作成したい

```:tasks
- file:
    path: "/tmp/{{ lookup('pipe','date +%Y%m%d%H%M') }}"
    state: directory
    mode: 0777
    owner: root
    group: root
  connection: local
  run_once: True
  changed_when: False
```
## handlerを即座に実行したい

**meta: flush_handlers**を使う。

notifyを利用してhandlerを呼び出した場合、handlerが実行されるのは、いずれかです。

* pre_task/tasks/post_taskセクションの終了時
* roleを呼び出したtasksセクションの終了時

即座に実行させるためには、以下のようにします。

```:task
tasks:
   - shell: some tasks go here
   - meta: flush_handlers
   - shell: some other tasks
```

## Ansibleの変数の優先順位

↑弱い

```:var
- role defaults [1]
- inventory vars [2]
- inventory group_vars
- inventory host_vars
- playbook group_vars
- playbook host_vars
- host facts
- registered vars
- set_facts
- play vars
- play vars_prompt
- play vars_files
- role and include vars
- block vars (only for tasks in block)
- task vars (only for the task)
- extra vars (always win precedence)
```
↓強い

## 変数のスコープについて

Ansibleの変数のスコープは以下の３つです。

|種類|内容|
|:-------|:--|
|Global|コンフィグや環境変数やコマンドラインでセットされたもの
|Play|それぞれのPlaybookごとに設定された値やinclude_varsの値|
|Host|実行されたホストごとの変数、gather_factsで収集した値や、registerで登録した値などそれぞれ独立しています|

そのため、role内で定義した変数も別のroleに引き継がれます。変数は被らないように注意しましょう。

## Jinja2のtemplateはとても便利

template内で**if**や**for**が使え、自由度の高い記載が行えます。
ここを参考にすると良いです。
[Template Designer Documentation](http://jinja.pocoo.org/docs/dev/templates/)


```:hosts.j2
{% for item in HOST_LIST %}
{{ item }}
{% endfor %}
```

```:ntp.conf.j2
・・・
{% for hostname in NTP_LIST %}
{% if loop.first %}
server {{ hostname }} iburst minpoll 4 maxpoll 5 prefer
{% else %}
server {{ hostname }} iburst minpoll 4 maxpoll 5
{% endif %}
{% endfor %}
・・・
```


## 仮想マシン作り直したらAnsibleが届かなくなった

SSHコマンドは通るのになぜー？

```
rhel7 | UNREACHABLE! => {
    "changed": false,
    "msg": "ERROR! SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh",
    "unreachable": true
}
```

```:/var/log/secure
Mar 14 17:41:42 localhost sshd[5796]: Connection closed by x.x.x.x [preauth]
```

以下のいずれかを実施しましょう。

- `known_hosts`に前のデータが残っている場合があるので削除
- `ansible.cfg`内の`ANSIBLE_HOST_KEY_CHECKING=False`のコメントを外す


## User用のパスワードの生成

```bash
python -c 'import crypt; print crypt.crypt("パスワード", "$1$SomeSalt$")'
```

参考:[AnsibleのUserモジュールでpasswordを設定する時の注意](http://longkey1.net/blog/2014/01/22/ansible-add-user-password/)


[その２はこちら](http://qiita.com/Gin/items/58df302714f9a28048c5)