はじめに
Ansible の変数では様々な型が扱えますが、基本的にゆるめなため、型をチェックしたいことがあるかもしれません。
いままでは、assert
モジュールと、type_debug
フィルターを組みわせるチェックする方法しか思いつかなかったのが、こちらを拝見したら is string
のような書き方もできることを知りました。
せっかくなので、両方のやり方をまとめます。
- 動作確認環境
- Ansible 2.9.6
- Python 3.6.7
[目次]
■ 方法1: type_debug
フィルターを利用する
type_debug
フィルターは、変数の方を表示するフィルターです。
"{{ 'hello' | type_debug }}"
であれば、 str
と表示されます。この性質を利用した型チェックです。
検証 Playbook
いくつか型の種類を用意した変数のリストを assert します。ここでは str
(文字列)であることをチェックします。
assert
では、デバッグ的に success_msg
、fail_msg
を利用します。
- hosts: localhost gather_facts: no connection: local vars: targets: # チェック対象 - hello - 100 - "100" - -100 - 0.9 - [1, 2, 3] - {name: hoge} tasks: - name: assert: that: - (item | type_debug) == "str" # ポイント success_msg: "{{ item }} type is {{ item | type_debug }}" fail_msg: "{{ item }} type is {{ item | type_debug }}, NOT str" loop: "{{ targets }}"
検証結果
結果です。targets
で定義した値のうち、hello
と "100"
のみ ok
となりました。
$ ansible-playbook -i localhost, assert.yml PLAY [localhost] ************************************************************************************************* TASK [assert type] *********************************************************************************************** ok: [localhost] => (item=hello) => { "ansible_loop_var": "item", "changed": false, "item": "hello", "msg": "hello type is str" // hello は ok } failed: [localhost] (item=100) => { "ansible_loop_var": "item", "assertion": "(item | type_debug) == \"str\"", "changed": false, "evaluated_to": false, "item": 100, "msg": "100 type is int, NOT str" } ok: [localhost] => (item=100) => { "ansible_loop_var": "item", "changed": false, "item": "100", "msg": "100 type is str" // "100" は ok } failed: [localhost] (item=-100) => { "ansible_loop_var": "item", "assertion": "(item | type_debug) == \"str\"", "changed": false, "evaluated_to": false, "item": -100, "msg": "-100 type is int, NOT str" } failed: [localhost] (item=0.9) => { "ansible_loop_var": "item", "assertion": "(item | type_debug) == \"str\"", "changed": false, "evaluated_to": false, "item": 0.9, "msg": "0.9 type is float, NOT str" } failed: [localhost] (item=[1, 2, 3]) => { "ansible_loop_var": "item", "assertion": "(item | type_debug) == \"str\"", "changed": false, "evaluated_to": false, "item": [ 1, 2, 3 ], "msg": "[1, 2, 3] type is list, NOT str" } failed: [localhost] (item={'name': 'hoge'}) => { "ansible_loop_var": "item", "assertion": "(item | type_debug) == \"str\"", "changed": false, "evaluated_to": false, "item": { "name": "hoge" }, "msg": "{'name': 'hoge'} type is dict, NOT str" } PLAY RECAP ******************************************************************************************************* localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
2個目の値 100
も、3個目 "100"
も、メッセージ上は 100
と表示され、
"msg": "100 type is int, NOT str"
とか
"msg": "100 type is str"
とかになるのが少しややこしいですね。
■ 方法2: is [型名]
を利用する
次に、こちらで知った方法です。
検証 Playbook
チェック対象の変数は同じです。
assert
で、item is string
のように指定します。 str
ではなく string
です。
- hosts: localhost gather_facts: no connection: local vars: targets: - hello - 100 - "100" - -100 - 0.9 - [1, 2, 3] - {name: hoge} tasks: - name: assert type assert: that: - item is string # ポイント success_msg: "{{ item }} type is {{ item | type_debug }}" fail_msg: "{{ item }} type is {{ item | type_debug }}, NOT str" loop: "{{ targets }}"
検証結果
結果です。hello
と "100"
のみ ok
となりました。
$ ansible-playbook -i localhost, assert.yml PLAY [localhost] **************************************************************************************************** TASK [assert type] ************************************************************************************************** ok: [localhost] => (item=hello) => { "ansible_loop_var": "item", "changed": false, "item": "hello", "msg": "All assertions passed" // hello は ok } failed: [localhost] (item=100) => { "ansible_loop_var": "item", "assertion": "item is string", "changed": false, "evaluated_to": false, "item": 100, "msg": "Assertion failed" } ok: [localhost] => (item=100) => { "ansible_loop_var": "item", "changed": false, "item": "100", "msg": "All assertions passed" // "100" は ok } failed: [localhost] (item=-100) => { "ansible_loop_var": "item", "assertion": "item is string", "changed": false, "evaluated_to": false, "item": -100, "msg": "Assertion failed" } failed: [localhost] (item=0.9) => { "ansible_loop_var": "item", "assertion": "item is string", "changed": false, "evaluated_to": false, "item": 0.9, "msg": "Assertion failed" } failed: [localhost] (item=[1, 2, 3]) => { "ansible_loop_var": "item", "assertion": "item is string", "changed": false, "evaluated_to": false, "item": [ 1, 2, 3 ], "msg": "Assertion failed" } failed: [localhost] (item={'name': 'hoge'}) => { "ansible_loop_var": "item", "assertion": "item is string", "changed": false, "evaluated_to": false, "item": { "name": "hoge" }, "msg": "Assertion failed" } PLAY RECAP ********************************************************************************************************** localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
■ 型の名前のまとめ
各値の type_debug
フィルター適用後の値と、is [型名]
で ok
となる型名をまとめます。
値 | type debug 結果 |
is [型名] |
---|---|---|
hello |
str |
string |
100 |
int |
number |
"100" |
str |
string |
-100 |
int |
number |
0.9 |
float |
number |
[1, 2, 3] |
list |
sequence |
{name: hoge} |
dict |
sequence / mapping |
試した限り、{name: hoge}
については、 is sequence
でも is mapping
でも assert
が ok
となったのが意外でした。
is [型名]
の方は、Jinja2 の List of Builtin Tests によるもののようです。@satoru_satoh さん、情報ありがとうございます!
また、Jinja2 2.11 では number
以外にも、float
や integer
も利用できるようです。
おわりに
型をあまり意識しなくていいことがメリットなこともありますが、つまずくこともあるかもしれません。
型のチェックが必要な時に、参考になれば幸いです。