指定が任意なオプション扱いのパラメタで、指定するパラメタが無い場合は未指定にしたいけど、ループ処理などで決まった型の辞書型変数のリストでキーが有ったり無かったりする場合の処理について。
って書いてもうまく伝わらない気もするのでサンプルコードから。
- name: create files by vars vars: files: - path: /var/tmp/ansible/var_test type: directory owner: zaki group: zaki mode: '0755' - path: /var/tmp/ansible/var_test/file1 type: touch ansible.builtin.file: state: "{{ item.type }}" path: "{{ item.path }}" mode: "{{ item.mode | default(omit) }}" owner: "{{ item.owner | default(omit) }}" group: "{{ item.group | default(omit) }}" loop: "{{ files }}"
files
変数に、path/type/pwner/group/modeを持った辞書型変数のリストを定義してるけど、1個目のディレクトリ定義は全て指定してるのに対して、2個目のファイル定義はowner/group/modeの指定無しの状態。
これをループ使って1発でansible.builtin.file
使ってファイル/ディレクトリ作成しようとしても、mode
,owner
,group
の定義は2要素目の項目に無いということで
mode: "{{ item.mode }}" owner: "{{ item.owner }}" group: "{{ item.group }}"
とplaybookに書いても、2ループ目は以下のように、変数にmode/owner/groupの定義が無いのでエラーになってしまう。
msg: |- The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'mode'
マジック変数omit
こういうときに使うのが、Ansibleのマジック変数のomitで、omit
が指定されたパラメタは無視され「パラメタ指定なし(省略)」として動作する。
omit
単体の動作は以下のコードで確認できる。
vars: data: j2_none: "{{ none }}" var_omit: "{{ omit }}" undef: undefined blank: "" tilde: ~ nullval: null tasks: - name: print debug: msg: "{{ data }}"
この内容のplaybookで実行すると、出力は以下の通り。
ok: [localhost] => msg: blank: '' j2_none: '' nullval: null tilde: null undef: undefined
omit
をセットしていたvar_omit
変数はきれいさっぱり無くなっているのを確認できる。
ついでに、Jinja2テンプレート内(というよりPythonかな?)でnone
を使ってもAnsibleで受け取るとnull
になったりせず空文字になり、YAMLのnull
,~
はAnsibleでもnull
となる。
動作はAnsible 2.9.16と2.10.7で確認。
サンプル
外部ファイル入力などで未定義を表現できないとき
上の例は「辞書で未定義の場合(keyが無い場合)はdefault
フィルタでomit
をセット」だったが、例えばAPI実行の結果を入力にしたいけどデータが無い場合は空文字になってるとか、csvファイルを入力にしたいけどカラムは固定なのでデータ無しは空文字扱い、といったパターンもある。
default
フィルタの通常動作は「フィルタの入力変数が未定義の場合は引数の変数をセット」という動作のため、変数は存在するけどセットされている変数が0(int)
やfalse(bool)
や空文字やnull
の場合は反応しない。
これらの「偽」の場合にdefault
フィルタを使って値をセットするには、引数の第2引数にtrue
をセットする。
If you want to use default with variables that evaluate to false you have to set the second parameter to true:
{{ ''|default('the string was empty', true) }}
If you want to use the default value when variables evaluate to false or an empty string you have to set the second parameter to true:
{{ lookup('env', 'MY_USER') | default('admin', true) }}
これを使えば、入力csvファイルでファイルとプロパティ一覧を以下のように作成し、
path,type,owner,group,mode /var/tmp/ansible/csv_test,directory,zaki,zaki,0755 /var/tmp/ansible/csv_test2,directory,,, /var/tmp/ansible/csv_test/file1,touch,,,
playbookではansible.builtin.read_csv
を使って
tasks: - name: read csv file ansible.builtin.read_csv: path: filelist.csv register: res_input - name: create files by csv ansible.builtin.file: state: "{{ item.type }}" path: "{{ item.path }}" mode: "{{ item.mode | default(omit, true) }}" owner: "{{ item.owner | default(omit, true) }}" group: "{{ item.group | default(omit, true) }}" loop: "{{ res_input.list }}"
みたいな実装をすることで、modeやowner指定が無い場合は省略してファイル作成ができる。
サンプル
ちなみに、file
モジュールのowner
とgroup
はnull
指定してもエラーになるが、mode
についてはnull
指定するとパラメタは無視されてデフォルト動作になるっぽい。
この辺りの動作はモジュールに依存するので動作はよく確認すること。