【发布时间】:2019-10-14 14:17:59
【问题描述】:
我已经定义了这个剧本:
---
- hosts: "{{ target }}"
tasks:
- name: buildout test
my_buildout:
cfg: "{
'/home/oerp/tmp':
{
'childs': {
'{{ custom_name }}': {
'rules': [
(
(),
('cmd', [('touch', {{ get_path('test.txt') }})])
)
]
}
}
}
}"
运行我的剧本:ansible-playbook --extra-vars "target=local_stage" --connection=local /home/oerp/src/ansible-playbooks/buildout_test.yml -v
给出这个错误:
fatal: [stage-my-odoo]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'get_path' is undefined\n\nThe error appears to be in '/home/oerp/src/ansible-playbooks/buildout_test.yml': line 4, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n tasks:\n - name: buildout test\n ^ here\n"}
现在{{ custom_name }} 是ansible 变量,其中{{ get_path('test.txt') }} 是Jinja2 表达式。
我尝试为 jinja2 表达式转义双花括号,如下所示:'{{' get_path('test.txt') '}}',但它给出了相同的输出。所以看起来它仍然将其视为 ansible 变量。我也无法删除 dict (cfg 参数类型为 dict) 的双引号包装,因为这样会忽略 ansible 变量,并且它使用文字值(如 {{ custom_name }},而不用实际值替换)
附: ansible 2.8.5.post0python version = 3.6.7 (default, Mar 29 2019, 10:38:28) [GCC 5.4.0 20160609]
更新 1
cfg 的值被 ansible 渲染并作为参数传递给模块后,预计如下所示:
{
'/home/oerp/tmp':
{
'childs': {
'my_child_dirname': {
'rules': [
(
(),
('cmd', [('touch', "{{ get_path('test.txt') }}")])
)
]
}
}
}
}
然后当模块接收到这个值时,它会被 jinja2 进一步渲染(具体是rules 部分的项目。在这种情况下,touch 命令参数`)。它看起来像这样:
{
'/home/oerp/tmp':
{
'childs': {
'my_child_dirname': {
'rules': [
(
(),
('cmd', [('touch', '/home/oerp/tmp/my_child_dirname/test.txt')])
)
]
}
}
}
}
Ansible 应该只渲染{{ custom_name }},其中{{ get_path('test.txt') }} 应该保留为稍后由我的模块处理的文字字符串。
更新 2
由于问题所在看起来令人困惑,我将尝试更清楚地说明问题所在。
在cfg 参数中,有两个变量。 custom_name 和 get_path。第一个是正常的ansible变量。它应该被视为一个,并由 ansible 替换为 value。 get_path 不是 ansible 变量。一旦my_buildout 模块接收到渲染的cfg 作为参数,它就是一个变为变量的表达式(调用方法)。
因此,{{ get_path('test.txt') }} 应该被 ansible 视为简单字符串,并且不需要转换(例如 {{ ansible_ignore_this }})。
并且说清楚,不是整个cfg 是神社表达。只有('touch', {{ get_path('test.txt') }}) 这部分由jinja 渲染(当模块接收到整个cfg 时,它会遍历该元组并尝试渲染字符串:"touch" 然后"{{ get_path('test.txt') }}"。
如果 my_buildout 模块会直接接收 cfg 参数(不使用 ansible playbook 或其他),它看起来就像 UPDATE 1 中的第一个示例中的那样,那么它就像一个魅力.
【问题讨论】:
-
根据您对我的回答的评论,我显然没有理解最终状态;你能显示你的
cfg值的前后吗?就像我所做的那样:处理可变的事物,然后将它们解决到最终状态?因为您所呈现的数据结构不能成为dict没有一些分辨率 -
@mdaniel 我更新了我的答案,解释了 ansible 渲染后预期的
cfg状态,然后在我的模块渲染它之后(使用 jinja2)。 -
等一下,在你的模块渲染它之后?这不是我要问的——我说
cfg前后应该是什么样子,而不是你的模块 对内容做了什么;你想让 ansible 渲染一些内容,然后你也调用 jinja2 来进一步渲染内容? -
另外,如果您再次调用 jinja2 是真的,那么,正如我正确指出的那样,您可以更改 您的模块 中的
variable_start_string和variable_end_string以进一步区分ansible的起始表达式和你的起始表达式 -
@mdaniel 我不是向您展示了 cfg 之前和之后的样子吗?为了更清楚,我展示了模块使用此类 cfg 后的样子。如果您不关心我的模块做什么,那么您可以忽略最后一个示例,但看起来您并不了解问题所在。您应该记下我所说的部分“(特别是规则部分的项目。在这种情况下,触摸命令参数)”。只有这部分在我的模块中呈现,其中元组的每个部分都被呈现。在这种情况下
touch和{{get_path..}}。如果不清楚,我会进一步更新我的问题。
标签: python ansible escaping jinja2