Ansible 変数の優先順位と書き方をまとめてみた

Ansibleは変数を色々な場所に書くことができるが、どんな書き方をすれば良いのかまとまった資料が僕の力では見つけられなかったので自分でまとめちゃえの会。  
変数の優先順位については[Variable precedence: Where should I put a variable?](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#variable-precedence-where-should-i-put-a-variable)に記載されているので、これを上から実際に書いてみる。
一応オーバーライドされることの確認もしながらやります。

> command line values (eg “-u user”)
> role defaults
> inventory file or script group vars
> inventory group_vars/all
> playbook group_vars/all
> inventory group_vars/*
> playbook group_vars/*
> inventory file or script host vars
> inventory host_vars/*
> playbook host_vars/*
> host facts / cached set_facts
> play vars
> play vars_prompt
> play vars_files
> role vars (defined in role/vars/main.yml)
> block vars (only for tasks in block)
> task vars (only for the task)
> include_vars
> set_facts / registered vars
> role (and include_role) params
> include params
> extra vars (always win precedence)


# はじめに
| environment  | version |
|:-------------|:--------|
| MacOS Mojave | 10.14.6 |
| Python       | 3.7.4   |
| Ansible      | 2.8.3   |
- Playbookはローカルに対して実行します  
- この記事で書いたコードは一応以下で公開しています  
  https://github.com/answer-d/ansible_var_pecedence_test
- 間違っているところや補足事項があったらコメント頂ければ幸いです


# 01. command line values (eg “-u user”)
~~playbook実行コマンドの引数に与える値であり、こっちで定義するものではないはず、割愛~~

(2019/08/19追記)
認識がちょっと間違っていたので訂正、説明だけでコードは書きません!(スマン)

playbookの実行時、例えば`-u user`というオプションを与えるとAnsible実行ユーザを変更できるが、そのユーザ名は内部的には`ansible_user`という変数に格納される
そのため、インベントリファイルで以下のように変数を定義することで、実行対象ホストごとにAnsible実行ユーザを変更することができたりする
(↑の話は[Working with Inventory - Hosts and non-standard ports](https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html#hosts-and-non-standard-ports)にも書かれてます)

```ini
[targets]
localhost
other1.example.com ansible_user=answer_d
other2.example.com ansible_user=tekitou_user
```

この時、playbook実行時に指定している引数(`-u user`みたいなやつ)は実は一番弱くて、`02. role defaults`に負けるんだよ！という話っぽい
※ 実際にdefaultsで`ansible_user`をオーバーライドするケースは無いと思うけど、書いて実行してみたらそうなります


# 02. role defaults
ここからが本題

`roles/*/defaults/main.yml`に記載される変数
`01. command line values`を除くと最も優先順位が低く、これ以降で実装する全ての変数定義でオーバーライドされる

```text:ディレクトリ構成
.
├── inventory
├── roles
│   └── test_role
│       ├── defaults
│       │   └── main.yml
│       └── tasks
│           └── main.yml
└── site.yml
```

```ini:inventory
[local]
localhost
```

```yaml:roles/test_role/defaults/main.yml
---
var_test02: "This is 'role defaults'"
```

```yaml:roles/test_role/tasks/main.yml
---
- name: "test02 - role defaults"
  debug: var=var_test02
```

```yaml:site.yml
---
- name: "test ansible var precedence"
  hosts: all
  roles:
    - test_role
```

```terminal:Playbook実行
# ansible-playbook -i inventory site.yml

PLAY [test ansible var precedence] *********************************************************************************

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

TASK [test_role : test02 - role defaults] **************************************************************************
ok: [localhost] => {
    "var_test02": "This is 'role defaults'"
}

PLAY RECAP *********************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```


# 03. inventory file or script group vars
inventoryファイルに書く変数のうち、グループに対して与えるやつのこと

```ini:inventory
[local]
localhost

# allは「全てのホスト」を意味するビルトインのグループ
[all:vars]
var_test03_1="This is 'inventory file or script group vars (all)'"
var_test03_2="This is 'inventory file or script group vars (all)'"

# 定義しているグループで指定、もちろんallより強くなる
[local:vars]
var_test03_2="This is 'inventory file or script group vars (local)'"
```

```yaml:roles/test_role/defaults/main.yml
---
var_test02: "This is 'role defaults'"
var_test03_1: "This is 'role defaults'"
var_test03_2: "This is 'role defaults'"
```

```yaml:roles/test_role/tasks/main.yml
---
- name: "test02 - role defaults"
  debug: var=var_test02

- name: "test03 - inventory file or script group vars"
  debug: var=var_test03_{{ item }}
  with_items: [1, 2]
```

`var_test03_1`にはdefaultsがオーバーライドされて「`inventory file or script group vars (all)`」が
`var_test03_2`には↑がさらにオーバーライドされて「`inventory file or script group vars (local)`」が入るはず

```terminal:Playbook実行
# ansible-playbook -i inventory site.yml

PLAY [test ansible var precedence] *********************************************************************************

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

TASK [test_role : test02 - role defaults] **************************************************************************
ok: [localhost] => {
    "var_test02": "This is 'role defaults'"
}

TASK [test_role : test03 - inventory file or script group vars] ****************************************************
ok: [localhost] => (item=1) => {
    "ansible_loop_var": "item",
    "item": 1,
    "var_test03_1": "This is 'inventory file or script group vars (all)'"
}
ok: [localhost] => (item=2) => {
    "ansible_loop_var": "item",
    "item": 2,
    "var_test03_2": "This is 'inventory file or script group vars (local)'"
}

PLAY RECAP *********************************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```


# ちょっと待った
ここでファイル構造の都合が悪いことがわかったのでちょっと構成を変更
`inventory`フォルダを作って、その中にインベントリファイルを置く、ついでに名前をhostsに
ファイルの内容は今までの`inventory`と一緒

```console:ディレクトリ構成
.
├── inventory
│   └── hosts
├── roles
│   └── test_role
│       ├── defaults
│       │   └── main.yml
│       └── tasks
│           └── main.yml
└── site.yml
```

一応動作確認(Playbook実行コマンドは変わる)

```terminal:Playbook実行
# ansible-playbook -i inventory/hosts site.yml

PLAY [test ansible var precedence] *********************************************************************************

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

TASK [test_role : test02 - role defaults] **************************************************************************
ok: [localhost] => {
    "var_test02": "This is 'role defaults'"
}

TASK [test_role : test03 - inventory file or script group vars] ****************************************************
ok: [localhost] => (item=1) => {
    "ansible_loop_var": "item",
    "item": 1,
    "var_test03_1": "This is 'inventory file or script group vars (all)'"
}
ok: [localhost] => (item=2) => {
    "ansible_loop_var": "item",
    "item": 2,
    "var_test03_2": "This is 'inventory file or script group vars (local)'"
}

PLAY RECAP *********************************************************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

# 04. inventory group_vars/all
`<インベントリファイルが置いてあるパス>/group_vars/all.yml`に書いてあるやつ(もしくは`all`フォルダの中の任意のyamlファイルでも良いっぽい)

```console:ディレクトリ構成
.
├── inventory
│   ├── group_vars
│   │   └── all.yml
│   └── hosts
├── roles
│   └── test_role
│       ├── defaults
│       │   └── main.yml
│       └── tasks
│           └── main.yml
└── site.yml
```

```ini:inventory/hosts
[local]
localhost

# allは「全てのホスト」を意味するビルトインのグループ
[all:vars]
var_test03_1="This is 'inventory file or script group vars (all)'"
var_test03_2="This is 'inventory file or script group vars (all)'"
var_test04_1="This is 'inventory file or script group vars (all)'"

# 定義しているグループで指定、もちろんallより強くなる
[local:vars]
var_test03_2="This is 'inventory file or script group vars (local)'"
var_test04_2="This is 'inventory file or script group vars (all)'"
```

```yaml:inventory/group_vars/all.yml
---
var_test04_1: "This is 'inventory group_vars/all'"
var_test04_2: "This is 'inventory group_vars/all'"
```

```yaml:roles/test_role/tasks/main.yml(長くなってしまうので差分のみ)
- name: "test04 - inventory group_vars/all"
  debug: var=var_test04_{{ item }}
  with_items: [1, 2]
```

公式ドキュメントの順位によれば、`var_test04_1`と`var_test04_2`はともに、`inventory/group_vars/all.yml`に書いてある値になるはず

```terminal:Playbook実行(長くなってしまうので一部のみ)
TASK [test_role : test04 - inventory group_vars/all] ***************************************************************
ok: [localhost] => (item=1) => {
    "ansible_loop_var": "item",
    "item": 1,
    "var_test04_1": "This is 'inventory group_vars/all'"
}
ok: [localhost] => (item=2) => {
    "ansible_loop_var": "item",
    "item": 2,
    "var_test04_2": "This is 'inventory group_vars/all'"
}
```

なりました


# 05. playbook group_vars/all
`inventory group_vars/all`と似たような感じで、`<Playbookが置いてあるパス>/group_vars/all.yml`に書くってことかな？

```console:ディレクトリ構成
.
├── group_vars
│   └── all.yml
├── inventory
│   ├── group_vars
│   │   └── all.yml
│   └── hosts
├── roles
│   └── test_role
│       ├── defaults
│       │   └── main.yml
│       └── tasks
│           └── main.yml
└── site.yml
```

```yaml:inventory/group_vars/all.yml
---
var_test04_1: "This is 'inventory group_vars/all'"
var_test04_2: "This is 'inventory group_vars/all'"
var_test05: "This is 'inventory group_vars/all'"
```

```yaml:group_vars/all.yml
---
var_test05: "This is 'playbook group_vars/all'"
```

```yaml:roles/test_role/tasks/main.yml(差分のみ)
- name: "test05 - playbook group_vars/all"
  debug: var=var_test05
```

```terminal:Playbook実行(一部のみ)
TASK [test_role : test05 - playbook group_vars/all] ****************************************************************
ok: [localhost] => {
    "var_test05": "This is 'playbook group_vars/all'"
}
```

へぇーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー(初めて知ったマン)


# 06. inventory group_vars/*
# 07. playbook group_vars/*
group_varsを`all.yml`じゃなくて`local.yml`に書くだけ、似てるので2つまとめてやる

```console:ディレクトリ構成
.
├── group_vars
│   ├── all.yml
│   └── local.yml
├── inventory
│   ├── group_vars
│   │   ├── all.yml
│   │   └── local.yml
│   └── hosts
├── roles
│   └── test_role
│       ├── defaults
│       │   └── main.yml
│       └── tasks
│           └── main.yml
└── site.yml
```

```yaml:group_vars/all.yml
---
var_test05: "This is 'playbook group_vars/all'"
var_test06: "This is 'playbook group_vars/all'"
```

```yaml:inventory/group_vars/local.yml
---
var_test06: "This is 'inventory group_vars/*'"
var_test07: "This is 'inventory group_vars/*'"
```

```yaml:group_vars/local.yml
---
var_test07: "This is 'playbook group_vars/*'"
```

```yaml:roles/test_role/tasks/main.yml(差分のみ)
- name: "test06 - inventory group_vars/*"
  debug: var=var_test06

- name: "test07 - playbook group_vars/*"
  debug: var=var_test07
```

```terminal:Playbook実行(一部のみ)
TASK [test_role : test06 - inventory group_vars/*] *****************************************************************
ok: [localhost] => {
    "var_test06": "This is 'inventory group_vars/*'"
}

TASK [test_role : test07 - playbook group_vars/*] ******************************************************************
ok: [localhost] => {
    "var_test07": "This is 'playbook group_vars/*'"
}
```

この辺知らないでinventory group_varsもplaybook group_varsも使ってるとハマりそうだなーとか思ったりした

```text:まとめ：group_varsの優先順位
inventory group_vars/all
    < playbook group_vars/all
        < inventory group_vars/*
            < playbook group_vars/*
```


# 08. inventory file or script host vars
`03. inventory file or script group vars`のホストver
iniファイル形式の場合host_varsはホスト名の後ろに書くみたい。インベントリファイルもyamlの方が書きやすそうだ

```ini:inventory/hosts
[local]
localhost var_test08="This is 'inventory file or script host vars'"

# allは「全てのホスト」を意味するビルトインのグループ
[all:vars]
var_test03_1="This is 'inventory file or script group vars (all)'"
var_test03_2="This is 'inventory file or script group vars (all)'"
var_test04_1="This is 'inventory file or script group vars (all)'"

# 定義しているグループで指定、もちろんallより強くなる
[local:vars]
var_test03_2="This is 'inventory file or script group vars (local)'"
var_test04_2="This is 'inventory file or script group vars (all)'"
```

```yaml:inventory/group_vars/local.yml
---
var_test06: "This is 'inventory group_vars/*'"
var_test07: "This is 'inventory group_vars/*'"
var_test08: "This is 'inventory group_vars/*'"
```

```yaml:roles/test_role/tasks/main.yml(差分のみ)
- name: "test08 - inventory file or script host vars"
  debug: var=var_test08
```

```terminal:Playbook実行(一部のみ)
TASK [test_role : test08 - inventory file or script host vars] *****************************************************
ok: [localhost] => {
    "var_test08": "This is 'inventory file or script host vars'"
}
```


# 09. inventory host_vars/*
# 10. playbook host_vars/*
`06. inventory group_vars/*`、`07. playbook group_vars/*`のホストver
host_varsに「all」はないようである

```console:ディレクトリ構成
.
├── group_vars
│   ├── all.yml
│   └── local.yml
├── host_vars
│   └── localhost.yml
├── inventory
│   ├── group_vars
│   │   ├── all.yml
│   │   └── local.yml
│   ├── host_vars
│   │   └── localhost.yml
│   └── hosts
├── roles
│   └── test_role
│       ├── defaults
│       │   └── main.yml
│       └── tasks
│           └── main.yml
└── site.yml
```

にわかに「これがAnsibleディレクトリ構成のベストプラクティスだよワッショイショイ！！」みたいなドキュメントで見る形になってきた

```ini:inventory/hosts
[local]
localhost var_test08="This is 'inventory file or script host vars'" var_test09="This is 'inventory host_vars/*'"

# allは「全てのホスト」を意味するビルトインのグループ
[all:vars]
var_test03_1="This is 'inventory file or script group vars (all)'"
var_test03_2="This is 'inventory file or script group vars (all)'"
var_test04_1="This is 'inventory file or script group vars (all)'"

# 定義しているグループで指定、もちろんallより強くなる
[local:vars]
var_test03_2="This is 'inventory file or script group vars (local)'"
var_test04_2="This is 'inventory file or script group vars (all)'"
```

```yaml:inventory/host_vars/localhost.yml
---
var_test09: "This is 'inventory host_vars/*'"
var_test10: "This is 'inventory host_vars/*'"
```

```yaml:host_vars/localhost.yml
---
var_test10: "This is 'playbook host_vars/*''"
```

```yaml:roles/test_role/tasks/main.yml(差分のみ)
- name: "test09 - inventory host_vars/*"
  debug: var=var_test09

- name: "test10 - inventory host_vars/*"
  debug: var=var_test10
```

```terminal:Playbook実行(一部のみ)
TASK [test_role : test09 - inventory host_vars/*] ******************************************************************
ok: [localhost] => {
    "var_test09": "This is 'inventory host_vars/*'"
}

TASK [test_role : test10 - inventory host_vars/*] ******************************************************************
ok: [localhost] => {
    "var_test10": "This is 'playbook host_vars/*''"
}
```

# 11. host facts / cached set_facts
host factsは[Local facts (facts.d)](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#local-facts-facts-d)のことかな？
`/etc/ansible/facts.d/*.fact`なファイルを参照して設定されるfactのことで、こんな感じのところに読み込まれる
  
```jinja
{{ ansible_local['preferences']['general']['asdf'] }}
```

また、cached set_factsについては[Caching Facts](https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#caching-facts)に書かれている
「とってきたfactはオプションをオンにしておくとキャッシュすることができて、それをPlaybook実行時に使えるから強い」みたいなことが書いてある(適当)

> With a very large infrastructure with thousands of hosts, fact caching could be configured to run nightly. Configuration of a small set of servers could run ad-hoc or periodically throughout the day. With fact caching enabled, it would not be necessary to “hit” all servers to reference variables and information about them.

> With fact caching enabled, it is possible for machine in one group to reference variables about machines in the other group, despite the fact that they have not been communicated with in the current execution of /usr/bin/ansible-playbook.

こんな感じのところに読み込まれる

```jinja
{{ hostvars['asdf.example.com']['ansible_facts']['os_family'] }}
```

格納される場所を見る感じ、これらは他の変数定義で上書きするようなモノではなさそうである、割愛


# 12. play vars
PLAYに対して指定するvars

```yaml:host_vars/localhost.yml
---
var_test10: "This is 'playbook host_vars/*''"
var_test12: "This is 'playbook host_vars/*''"
```

```yaml:site.yml
---
- name: "test ansible var precedence"
  hosts: all
  vars:
    - var_test12: "This is 'play vars'"
  roles:
    - test_role
```

```yaml:roles/test_role/tasks/main.yml(差分のみ)
- name: "test12 - play vars"
  debug: var=var_test12
```

```terminal:Playbook実行(一部のみ)
TASK [test_role : test12 - play vars] ******************************************************************************
ok: [localhost] => {
    "var_test12": "This is 'play vars'"
}
```


# 13. play vars_prompt
vars_promptはPlaybook実行時に変数の入力をさせる機能、詳細は[Prompts](https://docs.ansible.com/ansible/latest/user_guide/playbooks_prompts.html#prompts)参照

```yaml:site.yml
---
- name: "test ansible var precedence"
  hosts: all
  vars:
    - var_test12: "This is 'play vars'"
    - var_test13: "This is 'play vars'"
  vars_prompt:
    - name: var_test13
      prompt: "input var_test13"
      private: no
  roles:
    - test_role
```

```yaml:roles/test_role/tasks/main.yml(差分のみ)
- name: "test13 - play vars_prompt"
  debug: var=var_test13
```

```terminal:Playbook実行(一部のみ)
# ansible-playbook -i inventory/hosts site.yml
input var_test13: This is 'play vars_prompt'
```

Playbook実行時にプロンプトが出てきて変数に格納される

```terminal
TASK [test_role : test13 - play vars_prompt] ***********************************************************************
ok: [localhost] => {
    "var_test13": "This is 'play vars_prompt'"
}
```

これよりも強い変数があるってことは、上書きされる可能性があるということか…入力させといて上書きされたら結構ショックかもしれないな(´・ω・｀)


# 14. play vars_files
vars_filesディレクティブで明示的にインポートする変数。vars_promptより強いのは意識しておかないとハマるかも？

```console:ディレクトリ構成
.
├── group_vars
│   ├── all.yml
│   └── local.yml
├── host_vars
│   └── localhost.yml
├── inventory
│   ├── group_vars
│   │   ├── all.yml
│   │   └── local.yml
│   ├── host_vars
│   │   └── localhost.yml
│   └── hosts
├── roles
│   └── test_role
│       ├── defaults
│       │   └── main.yml
│       └── tasks
│           └── main.yml
├── site.yml
└── vars_files_test.yml
```

```yaml:vars_files_test.yml
---
var_test14: "This is 'play vars_files'"
```

```yaml:site.yml
---
- name: "test ansible var precedence"
  hosts: all
  vars:
    - var_test12: "This is 'play vars'"
    - var_test13: "This is 'play vars'"
  vars_prompt:
    - name: var_test13
      prompt: "input var_test13"
      private: no
    - name: var_test14
      prompt: "input var_test14"
      private: no
  vars_files:
    - vars_files_test.yml
  roles:
    - test_role
```

```yaml:roles/test_role/tasks/main.yml(差分のみ)
- name: "test14 - play vars_files"
  debug: var=var_test14
```

```terminal:Playbook実行(一部のみ)
# ansible-playbook -i inventory/hosts site.yml
input var_test13: This is 'play vars_prompt'
input var_test14: This is 'play vars_prompt'
```
```terminal
TASK [test_role : test14 - play vars_files] ************************************************************************
ok: [localhost] => {
    "var_test14": "This is 'play vars_files'"
}
```


# 15. role vars (defined in role/vars/main.yml)
もはや説明不要な変数記載場所、キミ実は結構強めの位置なんだね！

```console:ディレクトリ構成
.
├── group_vars
│   ├── all.yml
│   └── local.yml
├── host_vars
│   └── localhost.yml
├── inventory
│   ├── group_vars
│   │   ├── all.yml
│   │   └── local.yml
│   ├── host_vars
│   │   └── localhost.yml
│   └── hosts
├── roles
│   └── test_role
│       ├── defaults
│       │   └── main.yml
│       ├── tasks
│       │   └── main.yml
│       └── vars
│           └── main.yml
├── site.yml
└── vars_files_test.yml
```

```yaml:roles/test_role/vars/main.yml
---
var_test15: "This is 'role vars'"
```

```yaml:vars_files_test.yml
---
var_test14: "This is 'play vars_files'"
var_test15: "This is 'play vars_files'"
```

```yaml:roles/test_role/tasks/main.yml(差分のみ)
- name: "test15 - role vars"
  debug: var=var_test15
```

```terminal:Playbook実行(一部のみ)
TASK [test_role : test15 - role vars] ******************************************************************************
ok: [localhost] => {
    "var_test15": "This is 'role vars'"
}
```


# 16. block vars (only for tasks in block)
# 17. task vars (only for the task)
`BLOCK < TASK`の順に強くなる、まぁそりゃそうだよね

```yaml:roles/test_role/vars/main.yml
---
var_test15: "This is 'role vars'"
var_test16: "This is 'role vars'"
```

```yaml:roles/test_role/tasks/main.yml(差分のみ)
- block:
  - name: "test16 - block vars"
    debug: var=var_test16
  - name: "test17 - task vars"
    debug: var=var_test17
    vars:
      - var_test17: "This is 'task vars'"
  vars:
    - var_test16: "This is 'block vars'"
    - var_test17: "This is 'block vars'"
```

```terminal:Playbook実行(一部のみ)
TASK [test_role : test16 - block vars] *****************************************************************************
ok: [localhost] => {
    "var_test16": "This is 'block vars'"
}

TASK [test_role : test17 - task vars] ******************************************************************************
ok: [localhost] => {
    "var_test17": "This is 'task vars'"
}
```

単純に`PLAY < BLOCK < TASK`じゃなくて`PLAY < role vars < BLOCK < TASK`なのはちょっと違和感あるかもな？


# 18. include_vars
[include_vars – Load variables from files, dynamically within a task](https://docs.ansible.com/ansible/latest/modules/include_vars_module.html#include-vars-load-variables-from-files-dynamically-within-a-task)で読み込む変数
↑見るとわかるけど、読み込みの仕方が実は色々あるみたい、知らなかった！
今回は一番シンプルなやつで

```console:ディレクトリ構成
.
├── group_vars
│   ├── all.yml
│   └── local.yml
├── host_vars
│   └── localhost.yml
├── include_vars_test.yml
├── inventory
│   ├── group_vars
│   │   ├── all.yml
│   │   └── local.yml
│   ├── host_vars
│   │   └── localhost.yml
│   └── hosts
├── roles
│   └── test_role
│       ├── defaults
│       │   └── main.yml
│       ├── tasks
│       │   └── main.yml
│       └── vars
│           └── main.yml
├── site.yml
└── vars_files_test.yml
```

```yaml:include_vars_test.yml
---
var_test18: "This is 'include_vars'"
```

```yaml:roles/test_role/tasks/main.yml(差分のみ)
- name: "include_vars"
  include_vars: include_vars_test.yml

- name: "test18 - include_vars"
  debug: var=var_test18
  vars:
    - var_test18: "This is 'task vars'"
```

```terminal:Playbook実行(一部のみ)
TASK [test_role : include_vars] ************************************************************************************
ok: [localhost]

TASK [test_role : test18 - include_vars] ***************************************************************************
ok: [localhost] => {
    "var_test18": "This is 'include_vars'"
}
```


# 19. set_facts / registered vars
前者は[set_fact – Set host facts from a task](https://docs.ansible.com/ansible/latest/modules/set_fact_module.html?highlight=set_facts#set-fact-set-host-facts-from-a-task)で設定する変数
factなのでfact_cacheが効いたり、グローバル変数っぽい感じになったりする

後者は[Register Variables](https://docs.ansible.com/ansible/latest/user_guide/playbooks_conditionals.html?highlight=register#register-variables)参照
これで他変数を上書きするケースってあんまり無いような気がする

ということでset_factだけやるます

```yaml:include_vars_test.yml
---
var_test18: "This is 'include_vars'"
var_test19: "This is 'include_vars'"
```

```yaml:roles/test_role/tasks/main.yml(差分のみ)
- name: "set_facts"
  set_fact:
    var_test19: "This is 'set_facts'"

- name: "test19 - set_facts"
  debug: var=var_test19
```

```terminal:Playbook実行(一部のみ)
TASK [test_role : set_facts] ***************************************************************************************
ok: [localhost]

TASK [test_role : test19 - set_facts] ******************************************************************************
ok: [localhost] => {
    "var_test19": "This is 'set_facts'"
}
```


# 20. role (and include_role) params
role実行時にパラメータ渡しができるらしい → [Role Duplication and Execution](https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html#role-duplication-and-execution)

```yaml:site.yml
---
- name: "test ansible var precedence"
  hosts: all
  vars:
    - var_test12: "This is 'play vars'"
    - var_test13: "This is 'play vars'"
  vars_prompt:
    - name: var_test13
      prompt: "input var_test13"
      private: no
    - name: var_test14
      prompt: "input var_test14"
      private: no
  vars_files:
    - vars_files_test.yml
  roles:
    - role: test_role
      var_test20: "This is 'role (and include_role) params'"
```

```yaml:roles/test_role/tasks/main.yml(差分のみ)
- name: "set_facts"
  set_fact:
    var_test19: "This is 'set_facts'"
    var_test20: "This is 'set_facts'"

- name: "test19 - set_facts"
  debug: var=var_test19

- name: "test20 - role (and include_role) params"
  debug: var=var_test20

```

```terminal:Playbook実行(一部のみ)
TASK [test_role : test20 - role (and include_role) params] *********************************************************
ok: [localhost] => {
    "var_test20": "This is 'role (and include_role) params'"
}
```


# 21. include params
情報がなかなか見つけられなくて苦労した…
[include – Include a play or task list](https://docs.ansible.com/ansible/latest/modules/include_module.html?highlight=include#include-include-a-play-or-task-list)と同時に変数指定するパターンのことだと思う

```console:ディレクトリ構成
.
├── group_vars
│   ├── all.yml
│   └── local.yml
├── host_vars
│   └── localhost.yml
├── include_vars_test.yml
├── inventory
│   ├── group_vars
│   │   ├── all.yml
│   │   └── local.yml
│   ├── host_vars
│   │   └── localhost.yml
│   └── hosts
├── roles
│   └── test_role
│       ├── defaults
│       │   └── main.yml
│       ├── tasks
│       │   ├── main.yml
│       │   └── test21.yml
│       └── vars
│           └── main.yml
├── site.yml
└── vars_files_test.yml
```

```yaml:site.yml
---
- name: "test ansible var precedence"
  hosts: all
  vars:
    - var_test12: "This is 'play vars'"
    - var_test13: "This is 'play vars'"
  vars_prompt:
    - name: var_test13
      prompt: "input var_test13"
      private: no
    - name: var_test14
      prompt: "input var_test14"
      private: no
  vars_files:
    - vars_files_test.yml
  roles:
    - role: test_role
      var_test20: "This is 'role (and include_role) params'"
      var_test21: "This is 'role (and include_role) params'"
```

```yaml:roles/test_role/tasks/test21.yml
---
- name: "test21 - include params"
  debug: var=var_test21
```

```yaml:roles/test_role/tasks/main.yml(差分のみ)
- name: "include test21"
  include: test21.yml
  var_test21: "This is 'include params'"
```

```terminal:Playbook実行(一部のみ)
TASK [test_role : test21 - include params] *************************************************************************
ok: [localhost] => {
    "var_test21": "This is 'include params'"
}
```

なお、このPlaybookの実行時は以下のWARNINGが出たので、この方式で変数を書くのはやめておいた方が良さそう

```
[DEPRECATION WARNING]: Specifying include variables at the top-level of the task is deprecated. Please see:
https://docs.ansible.com/ansible/playbooks_roles.html#task-include-files-and-encouraging-reuse   for currently
supported syntax regarding included files and variables. This feature will be removed in version 2.12. Deprecation
warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
```

ちなみに、`include_tasks`で以下のように書いてもsyntax errorになるので注意

```yaml
- name: "include test21"
  include_tasks: test21.yml
  var_test21: "This is 'include_tasks params'"
```

```terminal
ERROR! 'var_test21' is not a valid attribute for a TaskInclude

The error appears to be in '/Users/answer_d/work/ansible_var_pecedence_test/roles/test_role/tasks/main.yml': line 78, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
```

(2019/08/23追記)
これなら`include_tasks`でもいけました

```yaml
- name: "include test21"
  include_tasks: test21.yml
  vars:
    var_test21: "This is 'include params'"
```

```terminal
TASK [test_role : test21 - include params] ******************************************************************************
ok: [localhost] => {
    "var_test21": "This is 'include params'"
}
```

書き方は`task vars`と一緒っぽいけど、`role (and include_role) params`をしっかり上書きしているので優先度が違っているのがわかる
こっちだとDEPRECATION WARNINGは出ないので今後使うならこれ

# 22. extra vars (always win precedence)
Playbook実行時に`-e`をつけて変数を書くやり方、こいつが最強

```yaml:roles/test_role/tasks/test21.yml
---
- name: "test21 - include params"
  debug: var=var_test21

- name: "test22 - extra vars"
  debug: var=var_test22
```

```yaml:roles/test_role/tasks/main.yml(差分のみ)
- name: "include test21"
  include: test21.yml
  var_test21: "This is 'include params'"
  var_test22: "This is 'include params'"
```

```terminal:Playbook実行(一部のみ)
# ansible-playbook -i inventory/hosts site.yml -e '{"var_test22":"This is \'extra vars\'"}'
```
```terminal
TASK [test_role : test22 - extra vars] *****************************************************************************
ok: [localhost] => {
    "var_test22": "This is 'extra vars'"
}
```