英文:
Lookup method interpreting result
问题
I am using a lookup method which returns a password (using cyberark.. but that is not relevant for this issue description)
当密码中包含花括号并且第二个查找参数中有变量时,结果会被Jinja解释。
Here is a simplified example.
在清单变量中,我有以下值:
existing_var: 'just a string' ansible_password: '{{ lookup("mylookup", "{{ existing_var }}") }}'
其中mylookup是一个测试查找方法,它始终返回一个单个字符串"x{g{%Y}",如下所示。 (这必须存储在ansible配置文件中指定的查找文件夹中,名称为"mylookup.py"。)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.errors import AnsibleError
from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
#we return always the same string without taking account of any parameter.
return ["x{g{%Y"]
我不希望查找结果被解释。
但实际上是被解释了。
这导致了一个ansible解释错误:"遇到未知标签'Y'.. 字符串:{%Y"。
当查找的第二个参数中没有花括号时,我注意到这种情况不会发生。
ansible_password: '{{ lookup("mylookup", "simple string without curly braces.")}}'
如何避免这种解释?
为了解决这个问题,我尝试增加日志详细程度并启用调试。没有有用的日志,ansible一旦调用查找方法就会失败。我已经将复杂的密码查找方法存根化,以简化问题并在这里展示。我尝试使用过滤器"safe"和"string",但都没有效果。我已经删除了第二个参数,并观察到在这种情况下,返回的字符串不会被解释。
英文:
I am using a lookup method which returns a password (using cyberark.. but that is not relevant for this issue description)
When the password happens to contain a curly brace and there is a variable in second lookup parameter, the result is interpreted by jinja.
Here is a simplified example.
Among the inventory variables I have the following values:
existing_var: 'just a string'
ansible_password: '{{ lookup("mylookup", "{{ existing_var }}") }}'
Where mylookup is a test lookup method, that returns always a single string "x{g{%Y" such as below.
(this has to be stored in the lookup folder specified in the ansible config files, with name "mylookup.py".)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.errors import AnsibleError
from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
#we return always the same string without taking account of any parameter.
return ["x{g{%Y"]
I don't expect the lookup result to be interpreted.
But it is.
This lead to an ansible interpretation error : "encountered unknown tag 'Y'.. string: {%Y".
Of course being a password in my real world case, the result is not meant to be interpreted.
I have noticed that this does not occur when there is no curly brace in the lookup second parameter.
ansible_password: '{{ lookup("mylookup", "simple string without curly braces.")}}'
How to avoid this interpretation?
To solve this issue, I have tried to increase log verbosity, and activated debug. There was no useful log, ansible fails as soon as the lookup method is called.
I have stubbed the complex password lookup method to simplify the issue and present it here.
I have tried to use the filters "safe" and "string", to no avail.
I have removed the second parameter, and observed that in this case, the returned string is not interpreted.
答案1
得分: 1
A: 问题不是由lookup插件引起的。Ansible不会对查找进行模板化。请参阅不安全或原始字符串:
> "处理查找插件返回的值时,Ansible使用一种称为不安全的数据类型来阻止模板化。"
为测试创建一个minimal reproducible example (mre)项目
shell> tree .
.
├── ansible.cfg
├── hosts
├── pb.yml
└── plugins
└── lookup
└── mylookup.py
2 directories, 4 files
配置自定义查找插件的路径DEFAULT_LOOKUP_PLUGIN_PATH
shell> cat ansible.cfg
[defaults]
gathering = explicit
collections_path = $HOME/.local/lib/python3.9/site-packages/
inventory = $PWD/hosts
lookup_plugins = $PWD/plugins/lookup
retry_files_enabled = false
stdout_callback = yaml
创建自定义查找插件
shell> cat plugins/lookup/mylookup.py
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
return ["x{g{%Y"]
,简单的清单
shell> cat hosts
localhost
,以及一个playbook
shell> cat pb.yml
- hosts: localhost
vars:
test_passwd1: "{{ lookup('mylookup') }}"
test_passwd2: "{{ lookup('mylookup', 'simple string without curly braces') }}"
test_passwd3: "{{ lookup('mylookup', existing_var) }}"
tasks:
- debug:
var: test_passwd1
- debug:
var: test_passwd2
- debug:
var: test_passwd3
vars:
existing_var: !unsafe x{g{%Y
- debug:
var: test_passwd3
vars:
existing_var: x{g{%Y
结果:
- Ansible不会对查找进行模板化
test_passwd1: "{{ lookup('mylookup') }}"
给出的结果是
test_passwd1: x{g{%Y
- 如果添加了一个字面参数,没有任何区别。自定义查找插件mylookup不需要参数。我们在这里添加它是为了展示额外参数的扩展可能会引起问题
test_passwd2: "{{ lookup('mylookup',
'simple string without curly braces') }}"
得到相同的结果
test_passwd2: x{g{%Y
- 如果要展开包含特殊字符如*
{
或%
的变量,必须标记为**!unsafe***
existing_var: !unsafe x{g{%Y
test_passwd3: "{{ lookup('mylookup', existing_var) }}"
可以正常工作
test_passwd3: x{g{%Y
- 如果省略***!unsafe***
existing_var: x{g{%Y
test_passwd3: "{{ lookup('mylookup', existing_var) }}"
展开失败:
> msg: 'An unhandled exception occurred while templating ''{{ lookup(''mylookup'', existing_var) }}''. Error was a <class ''ansible.errors.AnsibleError''>, original message: template error while templating string: Encountered unknown tag ''Y''.. String: x{g{%Y. Encountered unknown tag ''Y''.'
<hr>
<sup>
注意:测试***!unsafe***。给定以下文件
shell> cat test_passwd.txt
x{g{%Y
下面的play按预期工作,因为Ansible阻止了查找插件输出的模板化
shell> cat pb.yml
- hosts: localhost
vars:
test_passwd: "{{ lookup('file', 'test_passwd.txt') }}"
tasks:
- debug:
var: test_passwd
shell> ansible-playbook pb.yml
PLAY [localhost] ******************************************************************************
TASK [debug] ************************************************************************************
ok: [localhost] =>
test_passwd: x{g{%Y
PLAY RECAP **************************************************************************************
localhost: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- 当你声明一个变量为***!unsafe***时,也不会出现问题。例如,
- debug:
var: test_passwd
vars:
test_passwd: !unsafe x{g{%Y
给出
test_passwd: x{g{%Y
- 当省略***!unsafe***时,任务将失败
- debug:
var: test_passwd
vars:
test_passwd: x{g{%Y
失败的消息是
> msg: 'An unhandled exception occurred while templating ''x{g{%Y''''. Error was a <class ''ansible.errors.AnsibleError''>, original message: template error while templating string: Encountered unknown tag ''Y''.. String: x{g{%Y. Encountered unknown tag ''Y''.'
</sup>
英文:
Q: "How to avoid this interpretation?" (of the lookup plugin)
A: The problem is not caused by the lookup plugin. Ansible does not template lookups. See Unsafe or raw strings:
> "When handling values returned by lookup plugins, Ansible uses a data type called unsafe to block templating."
Create a mre project for testing
shell> tree .
.
├── ansible.cfg
├── hosts
├── pb.yml
└── plugins
└── lookup
└── mylookup.py
2 directories, 4 files
Configure the path to your custom lookup plugin DEFAULT_LOOKUP_PLUGIN_PATH
shell> cat ansible.cfg
[defaults]
gathering = explicit
collections_path = $HOME/.local/lib/python3.9/site-packages/
inventory = $PWD/hosts
lookup_plugins = $PWD/plugins/lookup
retry_files_enabled = false
stdout_callback = yaml
Create the custom lookup plugin
shell> cat plugins/lookup/mylookup.py
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
from ansible.plugins.lookup import LookupBase
class LookupModule(LookupBase):
def run(self, terms, variables=None, **kwargs):
return ["x{g{%Y"]
, simple inventory
shell> cat hosts
localhost
, and a playbook
shell> cat pb.yml
- hosts: localhost
vars:
test_passwd1: "{{ lookup('mylookup') }}"
test_passwd2: "{{ lookup('mylookup', 'simple string without curly braces') }}"
test_passwd3: "{{ lookup('mylookup', existing_var) }}"
tasks:
- debug:
var: test_passwd1
- debug:
var: test_passwd2
- debug:
var: test_passwd3
vars:
existing_var: !unsafe x{g{%Y
- debug:
var: test_passwd3
vars:
existing_var: x{g{%Y
Results:
- Ansible does not template lookups
test_passwd1: "{{ lookup('mylookup') }}"
gives
test_passwd1: x{g{%Y
- There is no difference if you ad a literal parameter. The custom lookup plugin mylookup doesn't require a parameter. We add it here to show the expansion of this additional parameter may cause the problem
test_passwd2: "{{ lookup('mylookup',
'simple string without curly braces') }}"
gives the same result
test_passwd2: x{g{%Y
- You have to mark !unsafe a variable that comprises special characters like
{
or%
if you want to expand it
existing_var: !unsafe x{g{%Y
test_passwd3: "{{ lookup('mylookup', existing_var) }}"
works fine
test_passwd3: x{g{%Y
- If you omit !unsafe
existing_var: x{g{%Y
test_passwd3: "{{ lookup('mylookup', existing_var) }}"
the expansion fails:
> msg: 'An unhandled exception occurred while templating ''{{ lookup(''mylookup'', existing_var) }}''. Error was a <class ''ansible.errors.AnsibleError''>, original message: An unhandled exception occurred while templating ''x{g{%Y''. Error was a <class ''ansible.errors.AnsibleError''>, original message: template error while templating string: Encountered unknown tag ''Y''.. String: x{g{%Y. Encountered unknown tag ''Y''.'
<hr>
<sup>
Note: Test !unsafe. Given the file
shell> cat test_passwd.txt
x{g{%Y
- The play below works as expected because Ansible blocks the templating of the lookup plugins' output
shell> cat pb.yml
- hosts: localhost
vars:
test_passwd: "{{ lookup('file', 'test_passwd.txt') }}"
tasks:
- debug:
var: test_passwd
shell> ansible-playbook pb.yml
PLAY [localhost] ******************************************************************************
TASK [debug] **********************************************************************************
ok: [localhost] =>
test_passwd: x{g{%Y
PLAY RECAP ************************************************************************************
localhost: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- The problem also does not appear when you declare a variable is !unsafe. For example,
- debug:
var: test_passwd
vars:
test_passwd: !unsafe x{g{%Y
gives
test_passwd: x{g{%Y
- The task will fail when you omit !unsafe
- debug:
var: test_passwd
vars:
test_passwd: x{g{%Y
fails
> msg: 'An unhandled exception occurred while templating ''x{g{%Y''. Error was a <class ''ansible.errors.AnsibleError''>, original message: template error while templating string: Encountered unknown tag ''Y''.. String: x{g{%Y. Encountered unknown tag ''Y''.'
</sup>
答案2
得分: -2
你正在遇到的问题是因为mylookup查找方法返回的密码中包含花括号,Jinja会将其解释为模板标签,导致错误。
为了避免这种解释并确保密码字符串被视为文字,你可以使用Jinja提供的quote过滤器。quote过滤器会转义字符串中的字符,以防止它们被解释为模板标签。
以下是如何修改你的代码以使用quote过滤器的示例:
ansible_password: '{{ lookup("mylookup", existing_var | quote) }}'
英文:
The issue you're experiencing occurs because when the password returned by the mylookup lookup method contains curly braces, Jinja interprets it as a template tag, leading to errors.
To avoid this interpretation and ensure that the password string is treated as a literal, you can use the quote filter provided by Jinja. The quote filter escapes characters in a string to prevent them from being interpreted as template tags.
Here's an example of how you can modify your code to use the quote filter:
ansible_password: '{{ lookup("mylookup", existing_var | quote) }}'
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论