英文:
Ansible: passing a list of objects to a python script
问题
我正在使用script
模块编写一个Ansible角色。脚本本身位于角色的files
库中。环境变量test_var
位于整个剧本的group_vars
文件夹下的YAML文件中:
---
- name: 执行脚本
script: python_script.py {{ test_var }}
args:
executable: python
如果只是一个简单的“key=value”类型的参数,这可以正常工作。但是,我不确定如何传递复杂的项目,比如列表或对象列表到Python脚本中,以便将其用作Python字典。
这方面有最佳实践吗?
上面的Ansible角色只返回列表的第一项。
YAML输入如下:
test_var:
- val:
something: 1
- other_val:
- '1'
- '2'
- '3'
Python代码如下:
import sys
i = 0
print('第一个参数:')
print(sys.argv[1])
print(' ')
tmp_string = ""
print('打印出每个参数:')
for x in sys.argv:
if i > 0:
print(x)
tmp_string += x
i += 1
print(' ')
print('将每个参数连接在一起:')
print(tmp_string)
结果如下:
changed: [localhost] => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to localhost closed.\r\n",
"stderr_lines": [
"Shared connection to localhost closed."
],
"stdout": "第一个参数:\r\n[{uval:\r\n \r\n打印出每个参数:\r\n[{uval:\r\n{usomething:\r\n1}},\r\n{uother_val:\r\n[u1,\r\nu2,\r\nu3]}]\r\n \r\n将每个参数连接在一起:\r\n[{uval:{usomething:1}},{uother_val:[u1,u2,u3]}]\r\n",
"stdout_lines": [
"第一个参数:",
"[{uval:",
" ",
"打印出每个参数:",
"[{uval:",
"{usomething:",
"1}},",
"{uother_val:",
"[u1,",
"u2,",
"u3]}]",
" ",
"将每个参数连接在一起:",
"[{uval:{usomething:1}},{uother_val:[u1,u2,u3]}]"
]
}
我不确定如何处理每行开头的u
字符。
我注意到Ansible将YAML的每一行都传递为不同的命令行参数,因此第一个参数只包含第一行。我可以使用for
循环将它们连接成一个字符串,但我不确定如何将其转换为Python可以使用的字典或其他数据结构。
英文:
I'm writing an Ansible role using the script
module. The script itself is located within the role's files
library. The environment variable test_var
is located within a YAML file under the group_vars
folder of the whole playbook:
---
- name: execute script
script: python_script.py {{ test_var }}
args:
executable: python
This works fine and well if it's only one simple "key=value" kind of parameter, however I'm not sure how should I pass complex items like lists or list of objects to the python script to use it as a python dictionary.
Is there a best practice for this?
The Ansible role above only returns the first item of the list.
The yaml input:
test_var:
- val:
something: 1
- other_val:
- '1'
- '2'
- '3'
The python code:
import sys
i = 0
print('The first argument: ')
print sys.argv[1]
print(' ')
tmp_string = ""
print('Every argument printed out:')
for x in sys.argv:
if i > 0:
print x
tmp_string += x
i += 1
print(' ')
print('Concatenating together each argument:')
print tmp_string
Results:
changed: [localhost] => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to localhost closed.\r\n",
"stderr_lines": [
"Shared connection to localhost closed."
],
"stdout": "The first argument: \r\n[{uval:\r\n \r\nEvery argument printed out:\r\n[{uval:\r\n{usomething:\r\n1}},\r\n{uother_val:\r\n[u1,\r\nu2,\r\nu3]}]\r\n \r\nConcatenateing together each argument:\r\n[{uval:{usomething:1}},{uother_val:[u1,u2,u3]}]\r\n",
"stdout_lines": [
"The first argument: ",
"[{uval:",
" ",
"Every argument printed out:",
"[{uval:",
"{usomething:",
"1}},",
"{uother_val:",
"[u1,",
"u2,",
"u3]}]",
" ",
"Concatenateing together each argument:",
"[{uval:{usomething:1}},{uother_val:[u1,u2,u3]}]"
]
}
I'm not sure what to do whit the u
s at the beginning of every line.
As I see Ansible passes every line of the yaml as a different command line argument, so the first one only contains the first line. I could concatenate these into a single string with a for
loop, but I'm not sure how to convert that into a dictionary or something python can use.
答案1
得分: 1
Ansible 并没有提供一个很好的机制来将复杂数据传递给 script
模块。可能更简单的方法是编写自己的 Ansible 模块,然后像其他模块一样将数据传递给它:
---
- name: 运行我的模块
mymodule:
someparameter: "{{ test_var }}"
你的模块可以是一个带有一些现有代码顶部的 Python 脚本。以下是一个非常简单的模板,支持上面的示例:
#!/usr/bin/python
from __future__ import absolute_import, division, print_function # NOQA
from ansible.module_utils.basic import AnsibleModule
def main():
argument_spec = {
'someparameter': dict(type='list', required=True),
}
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
result = {'changed': False}
data = module.params['someparameter']
# ...在这里处理你的数据...
module.exit_json(**result)
if __name__ == '__main__':
main()
将你的模块放入你的角色的 library
目录中,然后你就可以使用了。
你可以在文档中找到更多信息:
- https://docs.ansible.com/ansible/2.3/dev_guide/developing_modules_general.html
- https://docs.ansible.com/ansible/latest/dev_guide/developing_program_flow_modules.html
英文:
Ansible doesn't really provide a great mechanism for passing complex data to the script
module. It might be simpler to write your own Ansible module, and then pass your data to it like any other module:
---
- name: run my module
mymodule:
someparameter: "{{ test_var }}"
Your module can be a Python script with only a little boilerplate on top of your existing code. Here's a very simple template that would support the above example:
#!/usr/bin/python
from __future__ import absolute_import, division, print_function # NOQA
from ansible.module_utils.basic import AnsibleModule
def main():
argument_spec = {
'someparameter': dict(type='list', required=True),
}
module = AnsibleModule(argument_spec=argument_spec,
supports_check_mode=True)
result = {'changed': False}
data = module.params['someparameter']
# ...do something with your data here...
module.exit_json(**result)
if __name__ == '__main__':
main()
Drop your module into the library
directory of your role and you're all set.
You can find more information in the docs:
答案2
得分: 0
可能需要对变量应用一个过滤器。请尝试以下内容:
---
- name: 执行脚本
script: python_script.py {{ test_var | to_yaml }}
args:
executable: python
英文:
Probably, you need to apply a filter to the variable. Try this:
---
- name: execute script
script: python_script.py {{ test_var | to_yaml }}
args:
executable: python
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论