T-CREATOR

Ansible Jinja2 テンプレート速攻リファレンス:filters/tests/macros

Ansible Jinja2 テンプレート速攻リファレンス:filters/tests/macros

Ansible Playbook を書いていると、変数を整形したり条件判定したりする場面で Jinja2 テンプレートが欠かせません。filters で値を加工し、tests で型や状態を判定し、macros で繰り返しロジックを関数化する――この 3 つをサッと引けるリファレンスがあれば、毎回ドキュメントを検索する手間が省けますね。

本記事では、Ansible で頻繁に使う Jinja2 の filterstestsmacros を実例とともに整理し、すぐに引ける形でまとめました。初心者の方でもコピー&ペーストで試せるよう、それぞれのコードブロックは短く区切り、豊富なコメントを添えています。

早見表

filters 早見表

#カテゴリfilter 名用途記法例
1文字列upper大文字に変換{{ 'hello' | upper }}
2文字列lower小文字に変換{{ 'HELLO' | lower }}
3文字列capitalize先頭を大文字化{{ 'hello' | capitalize }}
4文字列replace文字列置換{{ 'hello' | replace('h', 'H') }}
5文字列defaultデフォルト値設定{{ my_var | default('default') }}
6文字列trim前後の空白削除{{ ' text ' | trim }}
7リストjoinリスト結合{{ ['a', 'b'] | join(', ') }}
8リストfirst最初の要素{{ my_list | first }}
9リストlast最後の要素{{ my_list | last }}
10リストunique重複除去{{ [1, 1, 2] | unique }}
11リストsortソート{{ [3, 1, 2] | sort }}
12リストlength要素数取得{{ my_list | length }}
13リストmap各要素に filter 適用{{ list | map('upper') | list }}
14リストselectattr条件で要素抽出{{ users | selectattr('age', '>', 20) }}
15辞書listキー一覧取得{{ my_dict | list }}
16辞書dict2itemsitems に変換{{ my_dict | dict2items }}
17JSON/YAMLfrom_jsonJSON パース{{ json_str | from_json }}
18JSON/YAMLto_jsonJSON 化{{ my_dict | to_json }}
19JSON/YAMLfrom_yamlYAML パース{{ yaml_str | from_yaml }}
20JSON/YAMLto_yamlYAML 化{{ my_dict | to_yaml }}
21数値abs絶対値{{ -42 | abs }}
22数値round四捨五入{{ 3.14159 | round(2) }}
23数値min最小値{{ [1, 2, 3] | min }}
24数値max最大値{{ [1, 2, 3] | max }}
25数値int整数変換{{ '42' | int }}
26Ansiblepassword_hashパスワードハッシュ{{ 'pass' | password_hash('sha512') }}
27Ansibledirnameディレクトリ名{{ '​/​etc​/​nginx.conf' | dirname }}
28Ansiblebasenameファイル名{{ '​/​etc​/​nginx.conf' | basename }}
29AnsibleipaddrIP アドレス抽出{{ '192.168.1.1​/​24' | ipaddr('address') }}

tests 早見表

#カテゴリtest 名用途記法例
1基本defined定義済みかwhen: my_var is defined
2基本undefined未定義かwhen: my_var is undefined
3基本noneNone かwhen: my_var is none
4基本trueTrue かwhen: my_var is true
5基本falseFalse かwhen: my_var is false
6型判定string文字列型かwhen: my_var is string
7型判定number数値型かwhen: my_var is number
8型判定iterableイテラブルかwhen: my_var is iterable
9型判定mapping辞書型かwhen: my_var is mapping
10数値判定even偶数かwhen: my_num is even
11数値判定odd奇数かwhen: my_num is odd
12数値判定divisibleby割り切れるかwhen: my_num is divisibleby(3)
13Ansiblechanged変更されたかwhen: result is changed
14Ansiblefailed失敗したかwhen: result is failed
15Ansibleskippedスキップされたかwhen: result is skipped
16Ansiblesuccess成功したかwhen: result is success

macros 早見表

#パターン用途記法例
1基本定義関数定義{% macro greet(name) %}Hello, {{ name }}{% endmacro %}
2呼び出しmacro 実行{{ greet('Alice') }}
3デフォルト引数省略可能な引数{% macro greet(name='Guest') %}...{% endmacro %}
4複数引数複数パラメータ{% macro user(name, age, country) %}...{% endmacro %}
5ループ繰り返し処理{% for item in items %}{{ item }}{% endfor %}
6条件分岐if/elif/else{% if level == 'admin' %}...{% endif %}
7filter 併用値の加工{{ name | upper }}
8実践例設定ファイル生成Nginx upstream、Apache VirtualHost など

早見表の使い方: この表を使って、必要な filter や test をすぐに見つけられます。記法例をコピーして Playbook に貼り付け、変数名を置き換えるだけで動作します。

背景

Jinja2 とは

Jinja2 は Python で書かれたテンプレートエンジンで、Ansible が変数展開や条件分岐、ループ処理を行う際の基盤技術です。

Playbook や Role 内のテンプレートファイル(*.j2)だけでなく、タスク定義の中でも {{ variable }}{% if ... %} といった構文を使って動的に値を組み立てられます。

なぜ filters / tests / macros が重要か

#要素役割
1filters変数を加工・整形する(例: 文字列の大文字化、リスト結合、JSON パース)
2tests変数の型や状態を判定する(例: 文字列か、定義済みか、偶数か)
3macros繰り返し使うロジックを関数として定義し、コードの重複を減らす

これらを使いこなすと、Playbook がシンプルで読みやすくなり、メンテナンス性が大きく向上します。

以下の図は、Jinja2 テンプレートが Ansible 内でどのように利用されるかを示しています。

mermaidflowchart TB
  playbook["Playbook / Role"]
  vars["変数定義<br/>(group_vars, host_vars)"]
  template["Jinja2 テンプレート<br/>(*.j2 / タスク内)"]
  filters["filters<br/>(値の加工)"]
  tests["tests<br/>(型・状態判定)"]
  macros["macros<br/>(関数定義)"]
  rendered["レンダリング結果<br/>(設定ファイル / 条件分岐)"]

  playbook --> vars
  vars --> template
  template --> filters
  template --> tests
  template --> macros
  filters --> rendered
  tests --> rendered
  macros --> rendered

図の要点: Playbook が定義した変数を Jinja2 テンプレートが受け取り、filters / tests / macros を駆使して最終的な設定ファイルや条件分岐結果を生成します。

課題

よくある悩み

Ansible で Jinja2 を使い始めると、以下のような壁にぶつかりがちです。

  1. filters の種類が多すぎて、どれを使えばよいかわからない 組み込み filters に加え、Ansible 独自の filters も多数存在し、公式ドキュメントを読んでも全体像を掴みにくい。

  2. tests の使い方が曖昧で、when 条件で失敗する 変数が定義済みか、True か、リストか――判定方法がわからず、タスクがスキップされたり意図せず実行されたりする。

  3. 繰り返しロジックをコピペしてしまい、コードが肥大化 同じ変数加工やループ処理を複数の箇所で書いてしまい、修正時に漏れが発生する。

  4. 公式ドキュメントが英語で、実例が少ない 理論はわかっても、実際の Playbook でどう書けばよいのか具体例が足りず、試行錯誤に時間がかかる。

以下の図は、Jinja2 でよく発生するエラーパターンを示しています。

mermaidflowchart LR
  task["タスク実行"]
  undefined["変数が未定義<br/>(AnsibleUndefinedVariable)"]
  typeErr["型が不一致<br/>(filter が失敗)"]
  logicErr["条件判定ミス<br/>(test が誤動作)"]
  ok["成功"]

  task --> undefined
  task --> typeErr
  task --> logicErr
  task --> ok

  style undefined fill:#f99
  style typeErr fill:#f99
  style logicErr fill:#f99
  style ok fill:#9f9

図の要点: 未定義変数や型不一致、条件判定の誤りがエラーの主な原因となります。これらを防ぐには filters と tests を正しく使う必要があります。

解決策

本記事のアプローチ

本記事では、以下の 3 ステップで Jinja2 の filters / tests / macros を体系的に理解できるようにします。

  1. カテゴリ別に整理: 文字列操作、リスト操作、辞書操作、数値操作など、用途ごとに分類
  2. 実例コード付き: すぐに試せる短いコードブロックを提供
  3. エラー回避テクニック: よくあるエラーと解決策をセットで紹介

以下の表は、filters / tests / macros の使い分け方針です。

#要素使いどころ記法例
1filters変数を整形・加工{{ my_var | upper }}
2tests変数の型・状態を判定{% if my_var is defined %}
3macros繰り返しロジックを関数化{% macro func(arg) %}...{% endmacro %}

filters / tests / macros の全体像

以下の図は、Jinja2 テンプレート内で filters / tests / macros がどのように連携するかを示しています。

mermaidflowchart LR
  input["入力変数"]
  filter1["filter で加工<br/>(例: upper, join)"]
  test1["test で判定<br/>(例: is defined)"]
  macro1["macro で関数化<br/>(例: 共通ロジック)"]
  output["出力結果"]

  input --> filter1
  filter1 --> test1
  test1 --> macro1
  macro1 --> output

図の要点: 入力変数を filters で加工し、tests で条件分岐し、macros で再利用可能なロジックにまとめることで、テンプレートがシンプルで保守しやすくなります。

具体例

filters の実例

文字列操作

大文字・小文字変換

文字列を全て大文字または小文字に変換します。

yaml- name: 文字列を大文字に変換
  debug:
    msg: "{{ 'hello world' | upper }}"
  # 出力: HELLO WORLD
yaml- name: 文字列を小文字に変換
  debug:
    msg: "{{ 'HELLO WORLD' | lower }}"
  # 出力: hello world

先頭を大文字化

文字列の先頭だけを大文字にします。

yaml- name: 先頭を大文字化
  debug:
    msg: "{{ 'hello world' | capitalize }}"
  # 出力: Hello world

文字列置換

特定の文字列を別の文字列に置き換えます。

yaml- name: 文字列置換
  debug:
    msg: "{{ 'hello world' | replace('world', 'Ansible') }}"
  # 出力: hello Ansible

デフォルト値の設定

変数が未定義または空の場合にデフォルト値を使います。

yaml- name: デフォルト値を設定
  debug:
    msg: "{{ my_var | default('デフォルト値') }}"
  # my_var が未定義なら「デフォルト値」を出力

トリム(空白除去)

文字列の前後の空白を削除します。

yaml- name: 空白を削除
  debug:
    msg: "{{ '  hello world  ' | trim }}"
  # 出力: hello world

リスト操作

リストの結合

リストの要素を指定した区切り文字で連結します。

yaml- name: リストを結合
  debug:
    msg: "{{ ['apple', 'banana', 'cherry'] | join(', ') }}"
  # 出力: apple, banana, cherry

リストの最初・最後の要素

リストの最初または最後の要素を取得します。

yaml- name: 最初の要素
  debug:
    msg: "{{ ['apple', 'banana', 'cherry'] | first }}"
  # 出力: apple
yaml- name: 最後の要素
  debug:
    msg: "{{ ['apple', 'banana', 'cherry'] | last }}"
  # 出力: cherry

リストのユニーク化

重複を除去した新しいリストを作ります。

yaml- name: 重複を除去
  debug:
    msg: '{{ [1, 2, 2, 3, 3, 3] | unique }}'
  # 出力: [1, 2, 3]

リストのソート

リストを昇順または降順でソートします。

yaml- name: リストをソート
  debug:
    msg: '{{ [3, 1, 2] | sort }}'
  # 出力: [1, 2, 3]

リストの長さ

リストの要素数を取得します。

yaml- name: リストの要素数
  debug:
    msg: "{{ ['apple', 'banana', 'cherry'] | length }}"
  # 出力: 3

辞書操作

辞書のキー一覧

辞書のキーをリストで取得します。

yaml- name: 辞書のキー一覧
  debug:
    msg: "{{ {'name': 'Alice', 'age': 30} | list }}"
  # 出力: ['name', 'age']

辞書の値一覧

辞書の値をリストで取得します。

yaml- name: 辞書の値一覧
  debug:
    msg: "{{ {'name': 'Alice', 'age': 30} | dict2items | map(attribute='value') | list }}"
  # 出力: ['Alice', 30]

辞書を items に変換

辞書をキーと値のペアのリストに変換します。

yaml- name: 辞書を items に変換
  debug:
    msg: "{{ {'name': 'Alice', 'age': 30} | dict2items }}"
  # 出力: [{'key': 'name', 'value': 'Alice'}, {'key': 'age', 'value': 30}]

JSON / YAML 操作

JSON 文字列をパース

JSON 形式の文字列を辞書やリストに変換します。

yaml- name: JSON をパース
  debug:
    msg: '{{ ''{"name": "Alice", "age": 30}'' | from_json }}'
  # 出力: {'name': 'Alice', 'age': 30}

辞書を JSON 文字列に変換

辞書やリストを JSON 形式の文字列にします。

yaml- name: 辞書を JSON に変換
  debug:
    msg: "{{ {'name': 'Alice', 'age': 30} | to_json }}"
  # 出力: {"name": "Alice", "age": 30}

YAML 文字列をパース

YAML 形式の文字列を辞書やリストに変換します。

yaml- name: YAML をパース
  debug:
    msg: "{{ 'name: Alice\nage: 30' | from_yaml }}"
  # 出力: {'name': 'Alice', 'age': 30}

辞書を YAML 文字列に変換

辞書やリストを YAML 形式の文字列にします。

yaml- name: 辞書を YAML に変換
  debug:
    msg: "{{ {'name': 'Alice', 'age': 30} | to_yaml }}"
  # 出力: (YAML 形式の文字列)

数値・日付操作

数値の絶対値

数値の絶対値を取得します。

yaml- name: 絶対値
  debug:
    msg: '{{ -42 | abs }}'
  # 出力: 42

四捨五入

数値を四捨五入します。

yaml- name: 四捨五入
  debug:
    msg: '{{ 3.14159 | round(2) }}'
  # 出力: 3.14

最小値・最大値

リストの中から最小値または最大値を取得します。

yaml- name: 最小値
  debug:
    msg: '{{ [3, 1, 4, 1, 5] | min }}'
  # 出力: 1
yaml- name: 最大値
  debug:
    msg: '{{ [3, 1, 4, 1, 5] | max }}'
  # 出力: 5

Ansible 固有 filters

IPv4 / IPv6 アドレス抽出

ネットワークアドレスから IP アドレスを抽出します。

yaml- name: IPv4 アドレス抽出
  debug:
    msg: "{{ '192.168.1.10/24' | ansible.utils.ipaddr('address') }}"
  # 出力: 192.168.1.10

パスワードハッシュ生成

平文パスワードをハッシュ化します(Linux ユーザー作成時に利用)。

yaml- name: パスワードハッシュ生成
  debug:
    msg: "{{ 'mypassword' | password_hash('sha512') }}"
  # 出力: (SHA-512 ハッシュ値)

ファイルパス操作

ファイルパスからディレクトリ名やファイル名を取得します。

yaml- name: ディレクトリ名を取得
  debug:
    msg: "{{ '/etc/nginx/nginx.conf' | dirname }}"
  # 出力: /etc/nginx
yaml- name: ファイル名を取得
  debug:
    msg: "{{ '/etc/nginx/nginx.conf' | basename }}"
  # 出力: nginx.conf

ランダム値生成

指定した長さのランダム文字列を生成します。

yaml- name: ランダム文字列生成
  debug:
    msg: '{{ 10 | random_mac }}'
  # ランダムな MAC アドレス形式の文字列を生成

tests の実例

基本的な tests

変数が定義されているか

変数が定義済みかどうかを判定します。

yaml- name: 変数が定義されているか確認
  debug:
    msg: 'my_var is defined'
  when: my_var is defined

変数が未定義か

変数が未定義かどうかを判定します。

yaml- name: 変数が未定義か確認
  debug:
    msg: 'my_var is undefined'
  when: my_var is undefined

変数が None か

変数が None(null)かどうかを判定します。

yaml- name: 変数が None か確認
  debug:
    msg: 'my_var is None'
  when: my_var is none

変数が True / False か

変数が真または偽かを判定します。

yaml- name: 変数が True か確認
  debug:
    msg: 'my_var is True'
  when: my_var is true
yaml- name: 変数が False か確認
  debug:
    msg: 'my_var is False'
  when: my_var is false

型判定 tests

文字列型か

変数が文字列型かどうかを判定します。

yaml- name: 文字列型か確認
  debug:
    msg: 'my_var is string'
  when: my_var is string

数値型か

変数が数値型かどうかを判定します。

yaml- name: 数値型か確認
  debug:
    msg: 'my_var is number'
  when: my_var is number

リスト型か

変数がリスト型かどうかを判定します。

yaml- name: リスト型か確認
  debug:
    msg: 'my_var is iterable'
  when: my_var is iterable and my_var is not string

辞書型か

変数が辞書型かどうかを判定します。

yaml- name: 辞書型か確認
  debug:
    msg: 'my_var is mapping'
  when: my_var is mapping

数値判定 tests

偶数・奇数か

数値が偶数または奇数かを判定します。

yaml- name: 偶数か確認
  debug:
    msg: 'my_num is even'
  when: my_num is even
yaml- name: 奇数か確認
  debug:
    msg: 'my_num is odd'
  when: my_num is odd

割り切れるか

数値が指定した値で割り切れるかを判定します。

yaml- name: 3 で割り切れるか確認
  debug:
    msg: 'my_num is divisible by 3'
  when: my_num is divisibleby(3)

ファイル・パス tests

ファイルが存在するか

ファイルが存在するかどうかを判定します(stat モジュールと組み合わせて使用)。

yaml- name: ファイル情報を取得
  stat:
    path: /etc/nginx/nginx.conf
  register: file_stat

- name: ファイルが存在するか確認
  debug:
    msg: 'File exists'
  when: file_stat.stat.exists

ディレクトリか

パスがディレクトリかどうかを判定します。

yaml- name: ディレクトリか確認
  debug:
    msg: 'Path is directory'
  when: file_stat.stat.isdir is defined and file_stat.stat.isdir

Ansible 固有 tests

タスクが changed か

タスクの実行結果が変更を伴ったかを判定します。

yaml- name: ファイルをコピー
  copy:
    src: /tmp/source.txt
    dest: /tmp/dest.txt
  register: copy_result

- name: 変更があったか確認
  debug:
    msg: 'File was changed'
  when: copy_result is changed

タスクが failed か

タスクが失敗したかどうかを判定します(ignore_errors と組み合わせて使用)。

yaml- name: コマンド実行
  command: /bin/false
  register: cmd_result
  ignore_errors: yes

- name: 失敗したか確認
  debug:
    msg: 'Command failed'
  when: cmd_result is failed

タスクが skipped か

タスクがスキップされたかを判定します。

yaml- name: タスクをスキップ
  debug:
    msg: 'This will be skipped'
  when: false
  register: skip_result

- name: スキップされたか確認
  debug:
    msg: 'Task was skipped'
  when: skip_result is skipped

macros の実例

基本的な macro

シンプルな関数

引数を受け取って加工した結果を返す関数を定義します。

テンプレートファイル内で以下のように記述します。

jinja2{# templates/example.j2 #}

{# macro 定義: 挨拶メッセージを生成 #}
{% macro greet(name) %}
Hello, {{ name }}!
{% endmacro %}

{# macro 呼び出し #}
{{ greet('Alice') }}
{# 出力: Hello, Alice! #}

複数引数の macro

複数の引数を受け取って処理します。

jinja2{# macro 定義: ユーザー情報を整形 #}
{% macro user_info(name, age, country) %}
Name: {{ name }}
Age: {{ age }}
Country: {{ country }}
{% endmacro %}

{# macro 呼び出し #}
{{ user_info('Bob', 25, 'Japan') }}
{# 出力:
Name: Bob
Age: 25
Country: Japan
#}

デフォルト引数付き macro

引数にデフォルト値を設定することで、省略可能にします。

jinja2{# macro 定義: デフォルト値を持つ挨拶 #}
{% macro greet_with_default(name='Guest') %}
Hello, {{ name }}!
{% endmacro %}

{# 引数なしで呼び出し #}
{{ greet_with_default() }}
{# 出力: Hello, Guest! #}

{# 引数ありで呼び出し #}
{{ greet_with_default('Charlie') }}
{# 出力: Hello, Charlie! #}

ループ処理を含む macro

リストを受け取って繰り返し処理を行います。

jinja2{# macro 定義: リストを箇条書きに整形 #}
{% macro bullet_list(items) %}
{% for item in items %}
- {{ item }}
{% endfor %}
{% endmacro %}

{# macro 呼び出し #}
{{ bullet_list(['Apple', 'Banana', 'Cherry']) }}
{# 出力:
- Apple
- Banana
- Cherry
#}

条件分岐を含む macro

引数に応じて出力を変えます。

jinja2{# macro 定義: 権限レベルに応じたメッセージ #}
{% macro permission_message(level) %}
{% if level == 'admin' %}
You have full access.
{% elif level == 'user' %}
You have limited access.
{% else %}
You have no access.
{% endif %}
{% endmacro %}

{# macro 呼び出し #}
{{ permission_message('admin') }}
{# 出力: You have full access. #}

{{ permission_message('user') }}
{# 出力: You have limited access. #}

{{ permission_message('guest') }}
{# 出力: You have no access. #}

macro と filters の組み合わせ

macro 内で filters を使って変数を加工します。

jinja2{# macro 定義: 名前を大文字化して挨拶 #}
{% macro greet_upper(name) %}
Hello, {{ name | upper }}!
{% endmacro %}

{# macro 呼び出し #}
{{ greet_upper('alice') }}
{# 出力: Hello, ALICE! #}

実践的な macro 例

Nginx の upstream 設定を生成する macro です。

jinja2{# templates/nginx_upstream.j2 #}

{# macro 定義: upstream ブロックを生成 #}
{% macro upstream_block(name, servers) %}
upstream {{ name }} {
{% for server in servers %}
    server {{ server.host }}:{{ server.port }} weight={{ server.weight | default(1) }};
{% endfor %}
}
{% endmacro %}

{# macro 呼び出し #}
{{ upstream_block('backend', [
    {'host': '192.168.1.10', 'port': 8080, 'weight': 2},
    {'host': '192.168.1.11', 'port': 8080}
]) }}

{# 出力:
upstream backend {
    server 192.168.1.10:8080 weight=2;
    server 192.168.1.11:8080 weight=1;
}
#}

この macro を使えば、複数の upstream 定義を簡潔に記述できます。

エラー回避テクニック

エラーコード: AnsibleUndefinedVariable

エラーメッセージ:

textFAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'my_var' is undefined"}

発生条件:

変数が定義されていないまま参照した場合。

解決方法:

  1. default filter でデフォルト値を設定
yaml- name: デフォルト値を使う
  debug:
    msg: "{{ my_var | default('デフォルト値') }}"
  1. is defined test で存在確認
yaml- name: 変数が定義されている場合のみ実行
  debug:
    msg: '{{ my_var }}'
  when: my_var is defined

エラーコード: AnsibleFilterError

エラーメッセージ:

textfatal: [localhost]: FAILED! => {"msg": "AnsibleFilterError: to_json requires a dictionary, list or other serializable object"}

発生条件:

filter の引数の型が不正な場合。

解決方法:

  1. 事前に型を確認
yaml- name: 型を確認してから filter を適用
  debug:
    msg: '{{ my_var | to_json }}'
  when: my_var is mapping or my_var is iterable
  1. 適切な filter を選択

文字列には to_json ではなく upperlower などを使います。

エラーコード: TypeError (test の誤用)

エラーメッセージ:

textfatal: [localhost]: FAILED! => {"msg": "Unexpected templating type error occurred on ({% if my_var is even %}): 'str' object cannot be interpreted as an integer"}

発生条件:

文字列に対して数値用の test を使った場合。

解決方法:

  1. 型変換してから test を適用
yaml- name: 文字列を数値に変換してから判定
  debug:
    msg: 'Even number'
  when: (my_var | int) is even
  1. 型を確認してから test を実行
yaml- name: 数値型の場合のみ判定
  debug:
    msg: 'Even number'
  when: my_var is number and my_var is even

実践テクニック集

複数 filters の連結

filters はパイプ(|)で繋げて連続適用できます。

yaml- name: 複数 filters を連結
  debug:
    msg: "{{ 'hello world' | upper | replace('WORLD', 'ANSIBLE') }}"
  # 出力: HELLO ANSIBLE

変数の条件付き展開

変数が定義されている場合のみ特定の値を使います。

yaml- name: 条件付き変数展開
  debug:
    msg: 'Port: {{ custom_port | default(8080) }}'
  # custom_port が未定義なら 8080 を使用

リストの要素を filter で加工

map filter を使ってリストの各要素に filter を適用します。

yaml- name: リストの全要素を大文字化
  debug:
    msg: "{{ ['apple', 'banana', 'cherry'] | map('upper') | list }}"
  # 出力: ['APPLE', 'BANANA', 'CHERRY']

辞書のキーでフィルタリング

selectattr filter で特定の条件に合う要素だけを抽出します。

yaml- name: 辞書リストから特定条件の要素を抽出
  debug:
    msg: "{{ users | selectattr('age', 'greaterthan', 20) | list }}"
  # age が 20 より大きいユーザーのみを抽出
  vars:
    users:
      - { name: 'Alice', age: 25 }
      - { name: 'Bob', age: 18 }
      - { name: 'Charlie', age: 30 }

ネストした変数の安全な参照

default と組み合わせてネストした辞書を安全に参照します。

yaml- name: ネストした変数の安全な参照
  debug:
    msg: "{{ my_dict.nested.key | default('デフォルト値') }}"
  # my_dict.nested.key が存在しなければデフォルト値を使用

環境変数の参照

Ansible では環境変数も Jinja2 で参照できます。

yaml- name: 環境変数を参照
  debug:
    msg: "Home directory: {{ lookup('env', 'HOME') }}"
  # 出力: Home directory: /home/username

図で理解する filters / tests / macros の連携

以下は、実際の Playbook で filters / tests / macros がどう連携するかを示した図です。

mermaidsequenceDiagram
  participant Playbook
  participant Jinja2
  participant Filters
  participant Tests
  participant Macros

  Playbook->>Jinja2: 変数を渡す
  Jinja2->>Filters: 値を加工
  Filters-->>Jinja2: 加工済み値
  Jinja2->>Tests: 型・状態を判定
  Tests-->>Jinja2: True / False
  Jinja2->>Macros: 関数呼び出し
  Macros-->>Jinja2: 関数の結果
  Jinja2-->>Playbook: レンダリング結果

図の要点: Playbook が Jinja2 に変数を渡し、Jinja2 が filters で加工、tests で判定、macros で関数化を行い、最終的にレンダリング結果を Playbook に返します。

まとめ

本記事では、Ansible で頻繁に使う Jinja2 の filters / tests / macros を体系的に整理しました。

#項目主なポイント
1filters文字列・リスト・辞書・数値を加工する豊富な組み込み関数群
2tests変数の型や状態を判定し、条件分岐で活用
3macros繰り返しロジックを関数化してコードの重複を削減
4エラー回避default filter や is defined test で未定義変数エラーを防ぐ
5実践テクニック複数 filters の連結、map / selectattr でリスト・辞書を効率的に操作

これらのテクニックを使いこなすことで、Playbook がシンプルかつ保守しやすくなり、チーム全体の生産性が向上するでしょう。

Jinja2 の公式ドキュメントや Ansible の公式ドキュメントも合わせて参照すると、さらに深い理解が得られます。ぜひ実際の Playbook で試してみてください。

関連リンク