てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] 「つまずき Ansible 【Part18】boolean と仲良くなりたい」ふりかえり

はじめに

2020/10/10 に、YouTube Live で「つまずき Ansible 【Part18】boolean と仲良くなりたい」という配信をしました。

実際に作業しながらエラーと戦って進めるシリーズです。

tekunabe.connpass.com

今回は、when や assert などで特にする boolean 値 についていろいろ試します。 Ansible 2.10 で変わった挙動も扱います。

やったことや、わかったことをふりかえります。

  • 環境
    • ansible 2.9.14
      • デフォルトからの設定変更 HOST_KEY_CHECKING のみ
    • 一部明示した箇所のみ ansible 2.10.0

動画

www.youtube.com


■ やったこと

おためし

以下のように、when にさまざまな値を与えて、そのタスクが実行されれば True、skip されれば False 扱いだと理解しながらひとつずつ試しました。

その結果をコメントとして付記します。一部は 変数未定義の undefined となりました。

---
- hosts: localhost
  gather_facts: false
  connection: local

  tasks:
    - name: 
      debug:
        msg: mathed!!!
      when:
        - "'None'"      # True
        - "None"        # False
        - "'Null'"      # True
        - "Null"        # undefined
        - Null          # True
        - "'NaN'"       # True
        - "NaN"         # undefined
        - NaN           # undefined
        - "'False'"     # True
        - 'False'       # False
        - -1            # True
        - ''            # True   * python の bool() とは違う 
        - ""            # True   * python の bool() とは違う 
        - "''"          # False
        - "'hogehoge'"  # True
        - "hogehoge"    # undefined
        - 'hogehoge'    # undefined
        - True          # True
        - TRUE          # True
        - true          # True
        - 0             # False
        - 1             # True

概ね、最終的な評価は Pythonbool() に渡した結果と同じと言えると思います。

ただ、最終的に文字列として評価されるのかどうかは意識する必要があります。たとえば、'False' という指定は文字列ではなく、"'False'" は文字列として評価されます。

2.10 との比較

Ansible 2.10 で、CONDITIONAL_BARE_VARS という設定項目のデフォルトが True から、False に変更されました(2.9のドキュメント2.10のドキュメント)。

これにより、最悪 2.9 と 2.10 とで判定が反転するケースがあります。

以下の Playbook を CONDITIONAL_BARE_VARS はデフォルトのまま、 2.9.14 と 2.10.0 で実行してためしました。結果をコメントで付記します。

---
- hosts: localhost
  gather_facts: false
  connection: local

  tasks:
    - name: 1-1
      debug:
        msg: "matched!!"
      when:
        - item
      loop:
        - 0           # 同じ(False)
        - 1           # 同じ(True
        - "0"         # 2.9 False、2.10 True
        - "1"         # 同じ(True)
        - '0'         # 2.9 False、2.10 True
        - '1'         # 同じ(True)
        - "'0'"       # 同じ(True)
        - "'1'"       # 同じ(True)

    - name: 1-2
      debug:
        msg: "matched!!"
      when:
        - item
      loop:
        - True        # 同じ(True)
        - False       # 同じ(False)
        - "True"      # 同じ(True)
        - "False"     # 2.9 False、2.10 True
        - 'True'      # 同じ(True)
        - 'False'     # 2.9 False、2.10 True
        - "'True'"    # 同じ(True)
        - "'False'"   # 同じ(True)

    - name: debug 1-3
      debug:
        msg: matched!
      when: 
        - condition  # 2.9 False、2.10 True
      vars:
        condition: "1 == 0"

どういうことか

やや推測も入りますが、こういうことかなと思います。たとえば、

      when:
        - condition

condition の中身が "1 == 0" だったとき CONDITIONAL_BARE_VARS がデフォルトで True な 2.9 では、

      when:
        - "1 == 0"

という解釈になり、結果的に False

一方で、 CONDITIONAL_BARE_VARS がデフォルトで False な 2.10 では、

      when:
        - "'1 == 0'"

という解釈になり、結果的に True。(1文字以上の文字列は True

bare vars が厳密に何を指すのかは詳細はわからないのですが、前述のように、評価式に変数名だだけが与えられることを指すようです。 このような状態のときは警告が表示されます。この警告は 2.9 でも表示されます。もし表示されたら 2.10 への移行時は特に注意したほうが良さそうです。

[DEPRECATION WARNING]: evaluating 'item' as a bare variable, this behaviour will go away and you might need to add |bool to
 the expression in the future. Also see CONDITIONAL_BARE_VARS configuration toggle. This feature will be removed in version 
2.12. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.

もちろん CONDITIONAL_BARE_VARS の設定は、 ansible.cfg などで変更できます。

参考: 2.9.14 の結果(クリックして開く)

PLAY [localhost] *****************************************************************

TASK [1-1] ***********************************************************************
skipping: [localhost] => (item=0) 
ok: [localhost] => (item=1) => {
    "msg": "matched!!"
}
skipping: [localhost] => (item=0) 
ok: [localhost] => (item=1) => {
    "msg": "matched!!"
}
skipping: [localhost] => (item=0) 
ok: [localhost] => (item=1) => {
    "msg": "matched!!"
}
ok: [localhost] => (item='0') => {
    "msg": "matched!!"
}
ok: [localhost] => (item='1') => {
    "msg": "matched!!"
}

TASK [1-2] ***********************************************************************
ok: [localhost] => (item=True) => {
    "msg": "matched!!"
}
skipping: [localhost] => (item=False) 
ok: [localhost] => (item=True) => {
    "msg": "matched!!"
}
skipping: [localhost] => (item=False) 
ok: [localhost] => (item=True) => {
    "msg": "matched!!"
}
skipping: [localhost] => (item=False) 
ok: [localhost] => (item='True') => {
    "msg": "matched!!"
}
ok: [localhost] => (item='False') => {
    "msg": "matched!!"
}

TASK [debug 1-3] *****************************************************************
skipping: [localhost]

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

参考: 2.10.0 の結果(クリックして開く)

PLAY [localhost] ***************************************************************

TASK [1-1] *********************************************************************
skipping: [localhost] => (item=0) 
ok: [localhost] => (item=1) => {
    "msg": "matched!!"
}
ok: [localhost] => (item=0) => {
    "msg": "matched!!"
}
ok: [localhost] => (item=1) => {
    "msg": "matched!!"
}
ok: [localhost] => (item=0) => {
    "msg": "matched!!"
}
ok: [localhost] => (item=1) => {
    "msg": "matched!!"
}
ok: [localhost] => (item='0') => {
    "msg": "matched!!"
}
ok: [localhost] => (item='1') => {
    "msg": "matched!!"
}

TASK [1-2] *********************************************************************
ok: [localhost] => (item=True) => {
    "msg": "matched!!"
}
skipping: [localhost] => (item=False) 
ok: [localhost] => (item=True) => {
    "msg": "matched!!"
}
ok: [localhost] => (item=False) => {
    "msg": "matched!!"
}
ok: [localhost] => (item=True) => {
    "msg": "matched!!"
}
ok: [localhost] => (item=False) => {
    "msg": "matched!!"
}
ok: [localhost] => (item='True') => {
    "msg": "matched!!"
}
ok: [localhost] => (item='False') => {
    "msg": "matched!!"
}

TASK [debug 1-3] ***************************************************************
ok: [localhost] => {
    "msg": "matched!"
}

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


Part19 にむけて

以下のネタを検討中です。気が向いたものをやります。

  • Ansible 2.10 関連ほかにも
  • connection: local ななにか
  • Ansible Toewr / AWX をコマンドがら操作する
  • ansible.cfg
  • Jinja2、フィルター
  • Windows
  • ESXi で VM作成
  • parsee_cli モジュール(Part15 の続き)