はじめに
この記事はAnsibleのタグを付けていますが、Ansible特有の話は無くてJinja2のmacroの話です。
Ansibleのplaybookを書いていて、テンプレートファイルが大きくなってくると共通部分を別ファイルにして読み込むようにしたくなってきます。複数箇所で読み込む際にパラメータを渡してテンプレート内の変数を違う値に展開したいと思いました。
Jinja2のincludeにはパラメータを渡せない
Ansibleのtemplateモジュールのドキュメントからリンクされている
Jinja2のTemplate Designer Documentationを見てみました。
Includeといういかにもな名前のステートメントがあるので使い方を見てみました。が、下記の例のように変数コンテキストを引き継ぐという指定はできますが、パラメータを渡すことは出来ないようです。
{% include "sidebar.html" ignore missing with context %}
Jinja2のユーザ定義マクロならパラメータを渡せる
さらに見ていくとImportというステートメントがありました。
以下の例のようにマクロを定義します。
{% macro input(name, value='', type='text') -%}
<input type="{{ type }}" value="{{ value|e }}" name="{{ name }}">
{%- endmacro %}
使う側はImport Context Behaviorの説明にあるように、from ファイル名 import マクロ名 with context
として読み込みます。
{% from 'forms.j2' import input with context %}
後は使いたい箇所で以下のようにパラメータを渡して呼び出せばOKです。
{{ input('username', value='John') }}
あるいは
{% import 'forms.j2' as forms with context %}
としてインポートして
{{ forms.input('username', value='John') }}
のように呼び出すことも可能です。Pythonのimportと同じですね。
with context無しだとエラーになった
with context
を付けずに試してみると、以下の様なエラーが出ました。
fatal: [cent65] => {'msg': "AttributeError: 'NoneType' object has no attribute 'add_locals'", 'failed': True}
よくわかっていませんが、with context
は必要なようです。
まとめ
ということで、Ansibleでテンプレートファイルを分割する場合は、Jinja2のマクロ機能を使うのがお勧めです。