- 追加された行はこの色です。
- 削除された行はこの色です。
#author("2020-03-20T17:41:39+09:00","default:haikikyou","haikikyou")
#author("2020-03-20T21:37:14+09:00","default:haikikyou","haikikyou")
[[Ansible/development]]
#contents
Lookupプラグインの作り方についてメモ。
* 独自のLookupモジュール [#s364329e]
以下のように独自のlookupプラグインを作成する。
#geshi{{{
- debug: msg={{ lookup('mylookup', 'args', key=value) }}
}}}
** プラグインのひな型 [#u3fbe262]
上記のようなlookupプラグインの実体は以下のようなクラスとなる。
#geshi(python){{{
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
# lookupプラグインのベースクラス
from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
# terms 引数
# variables ansibleで使える変数
# kwargs キーワード引数
def run(self, terms, variables, **kwargs):
print(self._templar.available_variables)
return variables
# terms プラグインの引数
# variables ansibleで使える変数が渡される
# kwargs プラグインのキーワード引数
def run(self, terms, variables, **kwargs):
"""my loopup plugin.
description
"""
return []
}}}
** プラグインのロード [#md4c1b85]
ansible.cfgで独自の場所を定義する場合は以下のようになる。
#geshi{{{
[defaults]
lookup_plugins = /path/to/plugin
}}}
&label(warn){参考};
- https://docs.ansible.com/ansible/latest/reference_appendices/config.html#default-lookup-plugin-path
* lookupが呼ばれる流れ [#wa9ff408]
独自のプラグインが呼ばれる場合のバックトレースを見てみる。~
lookupば呼ばれる流れ言っているが、実際にはjinja2でテンプレートが評価される流れである。~
jinja2テンプレートはパースされコンパイルされて実行される。
#geshi{{{
(Pdb) bt
/work/.pyenv/versions/3.8.1/bin/ansible-playbook(123)<module>()
-> exit_code = cli.run()
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/cli/playbook.py(129)run()
-> results = pbex.run()
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/executor/playbook_executor.py(172)run()
-> result = self._tqm.run(play=play)
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/executor/task_queue_manager.py(242)run()
-> play_return = strategy.run(iterator, play_context)
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/plugins/strategy/linear.py(310)run()
-> self._queue_task(host, task, task_vars, play_context)
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/plugins/strategy/__init__.py(360)_queue_task()
-> worker_prc.start()
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/executor/process/worker.py(96)start()
-> return super(WorkerProcess, self).start()
/work/.pyenv/versions/3.8.1/lib/python3.8/multiprocessing/process.py(121)start()
-> self._popen = self._Popen(self)
/work/.pyenv/versions/3.8.1/lib/python3.8/multiprocessing/context.py(276)_Popen()
-> return Popen(process_obj)
/work/.pyenv/versions/3.8.1/lib/python3.8/multiprocessing/popen_fork.py(19)__init__()
-> self._launch(process_obj)
/work/.pyenv/versions/3.8.1/lib/python3.8/multiprocessing/popen_fork.py(75)_launch()
-> code = process_obj._bootstrap(parent_sentinel=child_r)
/work/.pyenv/versions/3.8.1/lib/python3.8/multiprocessing/process.py(315)_bootstrap()
-> self.run()
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/executor/process/worker.py(130)run()
-> return self._run()
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/executor/process/worker.py(151)_run()
-> executor_result = TaskExecutor(
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/executor/task_executor.py(146)run()
-> res = self._execute()
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/executor/task_executor.py(588)_execute()
-> self._task.post_validate(templar=templar)
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/playbook/task.py(296)post_validate()
-> super(Task, self).post_validate(templar)
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/playbook/base.py(431)post_validate()
-> value = templar.template(getattr(self, name))
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/template/__init__.py(618)template()
-> d[k] = self.template(
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/template/__init__.py(572)template()
-> result = self.do_template(
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/template/__init__.py(837)do_template()
-> res = j2_concat(rf)
<template>(12)root()
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/jinja2/runtime.py(290)call()
-> return __obj(*args, **kwargs)
/work/.pyenv/versions/3.8.1/lib/python3.8/site-packages/ansible/template/__init__.py(731)_lookup()
-> ran = instance.run(loop_terms, variables=self._available_variables, **kwargs)
> /work/ansible/plugins/lookup/mylookup.py(10)run()
}}}
&label(warn){参考};
- [[ansible/template/__init__.py#L772>https://github.com/ansible/ansible/blob/stable-2.9/lib/ansible/template/__init__.py#L772]] - &size(11){&color(gray){on https://github.com/ansible/ansible/};};
- [[ansible/template/__init__.py#L719>https://github.com/ansible/ansible/blob/stable-2.9/lib/ansible/template/__init__.py#L719]] - &size(11){&color(gray){on https://github.com/ansible/ansible/};};
~
Ansibleは、モジュールパラメータに渡されたデータをjinja2のテンプレートエンジンで評価している。 ~
最終的にjinja2エンジンにcompileされて以下のように実行される。~
#geshi(python){{{
from __future__ import division, generator_stop
from jinja2.runtime import LoopContext, TemplateReference, Macro, Markup, TemplateRuntimeError, missing, concat, escape, markup_join, unicode_join, to_string, identity, TemplateNotFound, Namespace, Undefined
name = None
def root(context, missing=missing, environment=environment):
resolve = context.resolve_or_missing
undefined = environment.undefined
cond_expr_undefined = Undefined
if 0: yield None
l_0_lookup = resolve('lookup')
pass
yield to_string(environment.finalize(context.call((undefined(name='lookup') if l_0_lookup is missing else l_0_lookup), 'mylookup', hoge='foo')))
blocks = {}
debug_info = '1=12'
}}}
compile関数でバイトコードに変換され、実行コンテキストでexecで評価される。
&label(warn){参考};
- [[jinja2/environment.py#L515>https://github.com/DentonGentry/jinja2/blob/2.7-maintenance/jinja2/environment.py#L515]]
- [[ansible/template/__init__.py#L719>https://github.com/ansible/ansible/blob/stable-2.9/lib/ansible/template/__init__.py#L719]]
* 参考リンク [#ud4eab52]
- https://docs.ansible.com/ansible/latest/plugins/lookup.html