Ansible Jinja2 テンプレート速攻リファレンス:filters/tests/macros
Ansible Playbook を書いていると、変数を整形したり条件判定したりする場面で Jinja2 テンプレートが欠かせません。filters で値を加工し、tests で型や状態を判定し、macros で繰り返しロジックを関数化する――この 3 つをサッと引けるリファレンスがあれば、毎回ドキュメントを検索する手間が省けますね。
本記事では、Ansible で頻繁に使う Jinja2 の filters、tests、macros を実例とともに整理し、すぐに引ける形でまとめました。初心者の方でもコピー&ペーストで試せるよう、それぞれのコードブロックは短く区切り、豊富なコメントを添えています。
早見表
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 | 辞書 | dict2items | items に変換 | {{ my_dict | dict2items }} |
| 17 | JSON/YAML | from_json | JSON パース | {{ json_str | from_json }} |
| 18 | JSON/YAML | to_json | JSON 化 | {{ my_dict | to_json }} |
| 19 | JSON/YAML | from_yaml | YAML パース | {{ yaml_str | from_yaml }} |
| 20 | JSON/YAML | to_yaml | YAML 化 | {{ 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 }} |
| 26 | Ansible | password_hash | パスワードハッシュ | {{ 'pass' | password_hash('sha512') }} |
| 27 | Ansible | dirname | ディレクトリ名 | {{ '/etc/nginx.conf' | dirname }} |
| 28 | Ansible | basename | ファイル名 | {{ '/etc/nginx.conf' | basename }} |
| 29 | Ansible | ipaddr | IP アドレス抽出 | {{ '192.168.1.1/24' | ipaddr('address') }} |
tests 早見表
| # | カテゴリ | test 名 | 用途 | 記法例 |
|---|---|---|---|---|
| 1 | 基本 | defined | 定義済みか | when: my_var is defined |
| 2 | 基本 | undefined | 未定義か | when: my_var is undefined |
| 3 | 基本 | none | None か | when: my_var is none |
| 4 | 基本 | true | True か | when: my_var is true |
| 5 | 基本 | false | False か | 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) |
| 13 | Ansible | changed | 変更されたか | when: result is changed |
| 14 | Ansible | failed | 失敗したか | when: result is failed |
| 15 | Ansible | skipped | スキップされたか | when: result is skipped |
| 16 | Ansible | success | 成功したか | 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 %} |
| 7 | filter 併用 | 値の加工 | {{ name | upper }} |
| 8 | 実践例 | 設定ファイル生成 | Nginx upstream、Apache VirtualHost など |
早見表の使い方: この表を使って、必要な filter や test をすぐに見つけられます。記法例をコピーして Playbook に貼り付け、変数名を置き換えるだけで動作します。
背景
Jinja2 とは
Jinja2 は Python で書かれたテンプレートエンジンで、Ansible が変数展開や条件分岐、ループ処理を行う際の基盤技術です。
Playbook や Role 内のテンプレートファイル(*.j2)だけでなく、タスク定義の中でも {{ variable }} や {% if ... %} といった構文を使って動的に値を組み立てられます。
なぜ filters / tests / macros が重要か
| # | 要素 | 役割 |
|---|---|---|
| 1 | filters | 変数を加工・整形する(例: 文字列の大文字化、リスト結合、JSON パース) |
| 2 | tests | 変数の型や状態を判定する(例: 文字列か、定義済みか、偶数か) |
| 3 | macros | 繰り返し使うロジックを関数として定義し、コードの重複を減らす |
これらを使いこなすと、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 を使い始めると、以下のような壁にぶつかりがちです。
-
filters の種類が多すぎて、どれを使えばよいかわからない 組み込み filters に加え、Ansible 独自の filters も多数存在し、公式ドキュメントを読んでも全体像を掴みにくい。
-
tests の使い方が曖昧で、
when条件で失敗する 変数が定義済みか、True か、リストか――判定方法がわからず、タスクがスキップされたり意図せず実行されたりする。 -
繰り返しロジックをコピペしてしまい、コードが肥大化 同じ変数加工やループ処理を複数の箇所で書いてしまい、修正時に漏れが発生する。
-
公式ドキュメントが英語で、実例が少ない 理論はわかっても、実際の 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 を体系的に理解できるようにします。
- カテゴリ別に整理: 文字列操作、リスト操作、辞書操作、数値操作など、用途ごとに分類
- 実例コード付き: すぐに試せる短いコードブロックを提供
- エラー回避テクニック: よくあるエラーと解決策をセットで紹介
以下の表は、filters / tests / macros の使い分け方針です。
| # | 要素 | 使いどころ | 記法例 |
|---|---|---|---|
| 1 | filters | 変数を整形・加工 | {{ my_var | upper }} |
| 2 | tests | 変数の型・状態を判定 | {% if my_var is defined %} |
| 3 | macros | 繰り返しロジックを関数化 | {% 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"}
発生条件:
変数が定義されていないまま参照した場合。
解決方法:
defaultfilter でデフォルト値を設定
yaml- name: デフォルト値を使う
debug:
msg: "{{ my_var | default('デフォルト値') }}"
is definedtest で存在確認
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 の引数の型が不正な場合。
解決方法:
- 事前に型を確認
yaml- name: 型を確認してから filter を適用
debug:
msg: '{{ my_var | to_json }}'
when: my_var is mapping or my_var is iterable
- 適切な filter を選択
文字列には to_json ではなく upper や lower などを使います。
エラーコード: 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 を使った場合。
解決方法:
- 型変換してから test を適用
yaml- name: 文字列を数値に変換してから判定
debug:
msg: 'Even number'
when: (my_var | int) is even
- 型を確認してから 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 を体系的に整理しました。
| # | 項目 | 主なポイント |
|---|---|---|
| 1 | filters | 文字列・リスト・辞書・数値を加工する豊富な組み込み関数群 |
| 2 | tests | 変数の型や状態を判定し、条件分岐で活用 |
| 3 | macros | 繰り返しロジックを関数化してコードの重複を削減 |
| 4 | エラー回避 | default filter や is defined test で未定義変数エラーを防ぐ |
| 5 | 実践テクニック | 複数 filters の連結、map / selectattr でリスト・辞書を効率的に操作 |
これらのテクニックを使いこなすことで、Playbook がシンプルかつ保守しやすくなり、チーム全体の生産性が向上するでしょう。
Jinja2 の公式ドキュメントや Ansible の公式ドキュメントも合わせて参照すると、さらに深い理解が得られます。ぜひ実際の Playbook で試してみてください。
関連リンク
articleAnsible Jinja2 テンプレート速攻リファレンス:filters/tests/macros
articleAnsible Inventory 初期構築:静的/動的の基本とベストプラクティス
articleAnsible Push vs Pull を検証:大規模環境での配布・制御モデル
articleAnsible SSH/WinRM 接続エラー完全攻略:認証・ポート・プロキシの落とし穴
articleAnsible CI/CD 運用:GitHub Actions で lint/test/デプロイを自動化
articleAnsible 役割設計:Roles/Collections でスケーラブルに分割する指針
articleReact でデータ取得を最適化:TanStack Query 基礎からキャッシュ戦略まで実装
articleAnsible Jinja2 テンプレート速攻リファレンス:filters/tests/macros
articlePython Dev Containers 完全レシピ:再現可能な開発箱を VS Code で作る
articleStorybook で Zustand をモックする:Controls 連動とシナリオ駆動 UI
articlePrisma を Monorepo で使い倒す:パス解決・generate の共有・依存戦略
articleプラグイン競合の特定術:WordPress で原因切り分けを高速化する手順
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来