これは Ansible 2 Advent Calendar 2019 の3日目の記事です。
■ はじめに
assert
モジュールの that
オプションで >=
や <=
などを利用することで、数値の範囲をチェックできます。
この記事では、簡単なサンプルをもとに説明します。
■ 【要件1】 1〜1000 であることをチェックする (int も float も ok)
まずは、1〜1000 の数値( int も float も ok)であることをチェックする方法です。
数値 x
のをチェックしたい場合、assert
モジュールの that
には以下のように指定します。
- name: range check assert: that: - 1 <= x - x <= 1000
1 <= item <= 1000
のように書きたくなるかもしれませんが、残念ながらできません。その代わり、複数の AND 条件として指定します。
x
の各値と assert
の結果は以下のようになります。
x の値 |
assert の判定 |
備考 |
---|---|---|
1 |
ok |
|
1.0 |
ok |
float |
999.9 |
ok |
float |
1000 |
ok |
|
1_000 |
ok |
桁区切りリテラル |
1000.0 |
ok |
|
0b1111101000 |
ok |
1000 の 2進数表記 |
01750 |
ok |
1000 の 8進数表記 |
0x3E8 |
ok |
1000 の 16進数表記 |
-1 |
failed |
|
0 |
failed |
|
0.9 |
failed |
float |
1000.1 |
failed |
float |
1001 |
failed |
float |
0b1111101001 |
failed |
1001 の 2進数表記 |
01751 |
failed |
1001 の 8進数表記 |
0x3E9 |
failed |
1001 の 16進数表記 |
検証
実態に試してみます。
Playbook
以下の Playbook を利用します。
数値のパターンをいろい試すため、ok
になる想定の値と、failed
になる想定の値をそれぞれリストにして、それぞれ loop
でチェックします。
- hosts: localhost gather_facts: no vars: ok_patterns: - 1 - 1.0 - 999.9 - 1000 - 1_000 - 1000.0 - 0b1111101000 # 1000 - 01750 # 1000 - 0x3E8 # 1000 failed_patterns: - -1 - 0 - 0.9 - 1000.1 - 1001 - 0b1111101001 # 1001 - 01751 # 1001 - 0x3E9 # 1001 tasks: - name: ok pattern assert: that: - 1 <= item - item <= 1000 loop: "{{ ok_patterns }}" - name: failed patterns assert: that: - 1 <= item - item <= 1000 loop: "{{ failed_patterns }}"
実行結果
Playbook を実行します。failed
時は、どの条件に引っかかったか表示されます。
$ ansible-playbook -i localhost, validate/range1.yml PLAY [localhost] ******************************************************************************************************** TASK [ok pattern] ******************************************************************************************************* ok: [localhost] => (item=1) => { "ansible_loop_var": "item", "changed": false, "item": 1, "msg": "All assertions passed" } ok: [localhost] => (item=1.0) => { "ansible_loop_var": "item", "changed": false, "item": 1.0, "msg": "All assertions passed" } ok: [localhost] => (item=999.9) => { "ansible_loop_var": "item", "changed": false, "item": 999.9, "msg": "All assertions passed" } ok: [localhost] => (item=1000) => { "ansible_loop_var": "item", "changed": false, "item": 1000, "msg": "All assertions passed" } ok: [localhost] => (item=1000) => { "ansible_loop_var": "item", "changed": false, "item": 1000, "msg": "All assertions passed" } ok: [localhost] => (item=1000.0) => { "ansible_loop_var": "item", "changed": false, "item": 1000.0, "msg": "All assertions passed" } ok: [localhost] => (item=1000) => { "ansible_loop_var": "item", "changed": false, "item": 1000, "msg": "All assertions passed" } ok: [localhost] => (item=1000) => { "ansible_loop_var": "item", "changed": false, "item": 1000, "msg": "All assertions passed" } ok: [localhost] => (item=1000) => { "ansible_loop_var": "item", "changed": false, "item": 1000, "msg": "All assertions passed" } TASK [failed patterns] ************************************************************************************************** failed: [localhost] (item=-1) => { "ansible_loop_var": "item", "assertion": "1 <= item", "changed": false, "evaluated_to": false, "item": -1, "msg": "Assertion failed" // failed } failed: [localhost] (item=0) => { "ansible_loop_var": "item", "assertion": "1 <= item", "changed": false, "evaluated_to": false, "item": 0, "msg": "Assertion failed" // failed } failed: [localhost] (item=0.9) => { "ansible_loop_var": "item", "assertion": "1 <= item", "changed": false, "evaluated_to": false, "item": 0.9, "msg": "Assertion failed" // failed } failed: [localhost] (item=1000.1) => { "ansible_loop_var": "item", "assertion": "item <= 1000", "changed": false, "evaluated_to": false, "item": 1000.1, "msg": "Assertion failed" // failed } failed: [localhost] (item=1001) => { "ansible_loop_var": "item", "assertion": "item <= 1000", "changed": false, "evaluated_to": false, "item": 1001, "msg": "Assertion failed" // failed } failed: [localhost] (item=1001) => { "ansible_loop_var": "item", "assertion": "item <= 1000", "changed": false, "evaluated_to": false, "item": 1001, "msg": "Assertion failed" // failed } failed: [localhost] (item=1001) => { "ansible_loop_var": "item", "assertion": "item <= 1000", "changed": false, "evaluated_to": false, "item": 1001, "msg": "Assertion failed" // failed } failed: [localhost] (item=1001) => { "ansible_loop_var": "item", "assertion": "item <= 1000", "changed": false, "evaluated_to": false, "item": 1001, "msg": "Assertion failed" // failed } PLAY RECAP ************************************************************************************************************** localhost : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
1〜1000 の数値( float も ok)であることをチェックできました。
■ 【要件2】 1〜1000 の int であることをチェックする
次の要件は、数値の範囲に加えて、int
であることのチェックもします。
assert
の書き方としては、要件1の条件に加えて、type_debug
フィルターを利用して型チェックをします。
- name: range check assert: that: - (item | type_debug ) == "int" # 型チェック - 1 <= x - x <= 1000
これにより、要件1 のときは異なり、数値的には範囲内だが int
でない 1.0
のような値は failed
になります。
x
の各値と assert
の結果は以下のようになります。
x の値 |
assert の判定 |
備考 |
---|---|---|
1 |
ok |
|
1000 |
ok |
|
1_000 |
ok |
桁区切りリテラル |
0b1111101000 |
ok |
1000 の 2進数表記 |
01750 |
ok |
1000 の 8進数表記 |
0x3E8 |
ok |
1000 の 16進数表記 |
-1 |
failed |
|
0 |
failed |
|
0.9 |
failed |
float |
1.0 |
failed |
float 、範囲内だが型が違う |
999.9 |
failed |
float 、範囲内だが型が違う |
1000.0 |
failed |
範囲内だが型が違う |
1000.1 |
failed |
float |
1001 |
failed |
float |
0b1111101001 |
failed |
1001 の 2進数表記 |
01751 |
failed |
1001 の 8進数表記 |
0x3E9 |
failed |
1001 の 16進数表記 |
検証
実態に試してみます。
Playbook
以下の Playbook を利用します。要件1のときと似たような方式です。
ok_patterns
、failed_patterns
の内容が異なる点と、assert
の that
オプションに、型チェックの条件を加えてます。
- hosts: localhost gather_facts: no vars: ok_patterns: - 1 - 1000 - 1_000 - 0b1111101000 # 1000 - 01750 # 1000 - 0x3E8 # 1000 failed_patterns: - -1 - 0 - 0.9 - 1.0 - 999.9 - 1000.0 - 1000.1 - 1001 - 0b1111101001 # 1001 - 01751 # 1001 - 0x3E9 # 1001 tasks: - name: ok pattern assert: that: - (item | type_debug) == "int" # 型チェック - 1 <= item - item <= 1000 loop: "{{ ok_patterns }}" - name: failed pattern assert: that: - (item | type_debug) == "int" # 型チェック - 1 <= item - item <= 1000 loop: "{{ failed_patterns }}"
実行結果
Playbook を実行します。
$ ansible-playbook -i localhost, validate/range2.yml PLAY [localhost] ******************************************************************************************************** TASK [ok pattern] ******************************************************************************************************* ok: [localhost] => (item=1) => { "ansible_loop_var": "item", "changed": false, "item": 1, "msg": "All assertions passed" } ok: [localhost] => (item=1000) => { "ansible_loop_var": "item", "changed": false, "item": 1000, "msg": "All assertions passed" } ok: [localhost] => (item=1000) => { "ansible_loop_var": "item", "changed": false, "item": 1000, "msg": "All assertions passed" } ok: [localhost] => (item=1000) => { "ansible_loop_var": "item", "changed": false, "item": 1000, "msg": "All assertions passed" } ok: [localhost] => (item=1000) => { "ansible_loop_var": "item", "changed": false, "item": 1000, "msg": "All assertions passed" } ok: [localhost] => (item=1000) => { "ansible_loop_var": "item", "changed": false, "item": 1000, "msg": "All assertions passed" } TASK [failed pattern] *************************************************************************************************** failed: [localhost] (item=-1) => { "ansible_loop_var": "item", "assertion": "1 <= item", "changed": false, "evaluated_to": false, "item": -1, "msg": "Assertion failed" // failed } failed: [localhost] (item=0) => { "ansible_loop_var": "item", "assertion": "1 <= item", "changed": false, "evaluated_to": false, "item": 0, "msg": "Assertion failed" // failed } failed: [localhost] (item=0.9) => { "ansible_loop_var": "item", "assertion": "(item | type_debug ) == \"int\"", "changed": false, "evaluated_to": false, "item": 0.9, "msg": "Assertion failed" // failed } failed: [localhost] (item=1.0) => { "ansible_loop_var": "item", "assertion": "(item | type_debug ) == \"int\"", "changed": false, "evaluated_to": false, "item": 1.0, "msg": "Assertion failed" // failed } failed: [localhost] (item=999.9) => { "ansible_loop_var": "item", "assertion": "(item | type_debug ) == \"int\"", "changed": false, "evaluated_to": false, "item": 999.9, "msg": "Assertion failed" // failed } failed: [localhost] (item=1000.0) => { "ansible_loop_var": "item", "assertion": "(item | type_debug ) == \"int\"", "changed": false, "evaluated_to": false, "item": 1000.0, "msg": "Assertion failed" // failed } failed: [localhost] (item=1000.1) => { "ansible_loop_var": "item", "assertion": "(item | type_debug ) == \"int\"", "changed": false, "evaluated_to": false, "item": 1000.1, "msg": "Assertion failed" } failed: [localhost] (item=1001) => { "ansible_loop_var": "item", "assertion": "item <= 1000", "changed": false, "evaluated_to": false, "item": 1001, "msg": "Assertion failed" // failed } failed: [localhost] (item=1001) => { "ansible_loop_var": "item", "assertion": "item <= 1000", "changed": false, "evaluated_to": false, "item": 1001, "msg": "Assertion failed" // failed } failed: [localhost] (item=1001) => { "ansible_loop_var": "item", "assertion": "item <= 1000", "changed": false, "evaluated_to": false, "item": 1001, "msg": "Assertion failed" // failed } failed: [localhost] (item=1001) => { "ansible_loop_var": "item", "assertion": "item <= 1000", "changed": false, "evaluated_to": false, "item": 1001, "msg": "Assertion failed" // failed } PLAY RECAP ************************************************************************************************************** localhost : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
1〜1000 の数値( int のみ ok)であることをチェックできました。
■ まとめ
数値の範囲を assert モジュールでチェックする方法を確認しました。
assert
モジュールのthat
オプションに複数の条件を指定して、範囲を表現する- 型チェックも加える場合は、
type_debug
フィルターを利用する