Ansible内联jinja模板化为列表
我不明白为什么这行不通。 我正在使用jinja动态生成我将传递给vmware_来宾模块的列表,以便我可以在主机或组变量中决定是否要添加其他磁盘。 我正在使用vmware_disk_info模块查找模板磁盘的大小,然后添加我将在组变量中定义的任何其他磁盘。 在我看来,输出的列表不是一个列表Ansible内联jinja模板化为列表,ansible,jinja2,Ansible,Jinja2,我不明白为什么这行不通。 我正在使用jinja动态生成我将传递给vmware_来宾模块的列表,以便我可以在主机或组变量中决定是否要添加其他磁盘。 我正在使用vmware_disk_info模块查找模板磁盘的大小,然后添加我将在组变量中定义的任何其他磁盘。 在我看来,输出的列表不是一个列表 --- - name: "Get facts for named template" vmware_guest_disk_info: hostname: "{{ vcenter_server }}"
---
- name: "Get facts for named template"
vmware_guest_disk_info:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
validate_certs: False
datacenter: "{{ datacenter_name }}"
name: "{{ template_name }}"
register: template_disk
delegate_to: localhost
- name: "Define new disk structure"
set_fact:
vm_disks: >-
[{% for disk in (template_disk.guest_disk_info|dictsort) %}{
'size_kb': {{ disk[1].capacity_in_kb }},
'datastore': {{ datastore_name }}},
{% endfor %}
{% for disk in additional_disks|default([]) %}{
{% if disk.size_gb is defined %}'size_gb': {{ disk.size_gb }},{% endif %}
{% if disk.size_mb is defined %}'size_mb': {{ disk.size_mb }},{% endif %}
{% if disk.size_kb is defined %}'size_kb': {{ disk.size_kb }},{% endif %}
'datastore': {{ datastore_name }}},
{% endfor %}]
delegate_to: localhost
- name: Clone the template
vmware_guest:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
validate_certs: False
name: "{{ inventory_hostname }}"
template: "{{ template_name }}"
datacenter: "{{ datacenter_name }}"
folder: "/{{ datacenter_name }}/vm/{{ folder_name }}"
cluster: "{{ cluster_name }}"
datastore: "{{ datastore_name }}"
resource_pool: "{{ resource_pool_name }}"
disk: "{{ vm_disks }}"
hardware:
memory_gb: "{{ mem_size_gb }}"
num_cpu: "{{ cpu_size }}"
networks:
- name: "{{ network_name }}"
ip: "{{ ansible_host }}"
netmask: "{{ network_mask }}"
gateway: "{{ network_gw }}"
type: static
customization:
hostname: "{{ inventory_hostname }}"
domain: "{{ domain_name }}"
dns_suffix:
- "{{ domain_name }}"
dns_servers: "{{ network_dns }}"
state: poweredon
wait_for_ip_address: yes
delegate_to: localhost
一个例子是:
additional_disks:
- size_gb: "120"
datastore: "VSAN_Datastore"
错误提示为:
fatal: [docker02 -> localhost]: FAILED! => changed=false
module_stderr: |-
Traceback (most recent call last):
File "/home/piwi/.ansible/tmp/ansible-tmp-1586075176.0007603-201082838827202/AnsiballZ_vmware_guest.py", line 102, in <module>
_ansiballz_main()
File "/home/piwi/.ansible/tmp/ansible-tmp-1586075176.0007603-201082838827202/AnsiballZ_vmware_guest.py", line 94, in _ansiballz_main
invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
File "/home/piwi/.ansible/tmp/ansible-tmp-1586075176.0007603-201082838827202/AnsiballZ_vmware_guest.py", line 40, in invoke_module
runpy.run_module(mod_name='ansible.modules.cloud.vmware.vmware_guest', init_globals=None, run_name='__main__', alter_sys=True)
File "/usr/lib/python3.6/runpy.py", line 205, in run_module
return _run_module_code(code, init_globals, run_name, mod_spec)
File "/usr/lib/python3.6/runpy.py", line 96, in _run_module_code
mod_name, mod_spec, pkg_name, script_name)
File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/tmp/ansible_vmware_guest_payload_fiddyn_z/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2834, in <module>
File "/tmp/ansible_vmware_guest_payload_fiddyn_z/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2823, in main
File "/tmp/ansible_vmware_guest_payload_fiddyn_z/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2342, in deploy_vm
File "/tmp/ansible_vmware_guest_payload_fiddyn_z/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2005, in configure_disks
AttributeError: 'str' object has no attribute 'get'
module_stdout: ''
msg: |-
MODULE FAILURE
See stdout/stderr for the exact error
rc: 1
The full traceback is:
Traceback (most recent call last):
File "/home/piwi/.ansible/tmp/ansible-tmp-1586075175.423514-45894902001082/AnsiballZ_vmware_guest.py", line 102, in <module>
_ansiballz_main()
File "/home/piwi/.ansible/tmp/ansible-tmp-1586075175.423514-45894902001082/AnsiballZ_vmware_guest.py", line 94, in _ansiballz_main
invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
File "/home/piwi/.ansible/tmp/ansible-tmp-1586075175.423514-45894902001082/AnsiballZ_vmware_guest.py", line 40, in invoke_module
runpy.run_module(mod_name='ansible.modules.cloud.vmware.vmware_guest', init_globals=None, run_name='__main__', alter_sys=True)
File "/usr/lib/python3.6/runpy.py", line 205, in run_module
return _run_module_code(code, init_globals, run_name, mod_spec)
File "/usr/lib/python3.6/runpy.py", line 96, in _run_module_code
mod_name, mod_spec, pkg_name, script_name)
File "/usr/lib/python3.6/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/tmp/ansible_vmware_guest_payload_mspbq6yr/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2834, in <module>
File "/tmp/ansible_vmware_guest_payload_mspbq6yr/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2823, in main
File "/tmp/ansible_vmware_guest_payload_mspbq6yr/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2342, in deploy_vm
File "/tmp/ansible_vmware_guest_payload_mspbq6yr/ansible_vmware_guest_payload.zip/ansible/modules/cloud/vmware/vmware_guest.py", line 2005, in configure_disks
AttributeError: 'str' object has no attribute 'get'
基于以下建议的新代码:
但是,同样的错误是:
- name: "Define new disk structure"
set_fact:
vm_disks: >-
{%- set results = [] -%}
{%- for osdisk in ( template_disk.guest_disk_info | dictsort ) -%}
{%- set od = { "size_kb": osdisk[1].capacity_in_kb } -%}
{%- set _ = od.update({ "datastore": osdisk[1].backing_datastore }) -%}
{%- set _ = results.append(od) -%}
{%- endfor -%}
{%- for disk in additional_disks|default([]) -%}
{%- set d = {"size_gb": disk.size_gb} if (disk.size_gb is defined) else {} -%}
{%- set _ = d.update({"datastore": disk.datastore_name}) -%}
{%- set _ = results.append(d) -%}
{%- endfor -%}
"{{ results }}"
var调试:
TASK [vm_clone : Debugging var] *******************************************************************************************************************
ok: [gluster01] =>
vm_disks: '"[{''size_kb'': 125829120, ''datastore'': ''VSAN_Datastore''}, {''size_gb'': ''120'', ''datastore'': ''VSAN_Datastore''}]"'
ok: [gluster02] =>
vm_disks: '"[{''size_kb'': 125829120, ''datastore'': ''VSAN_Datastore''}, {''size_gb'': ''120'', ''datastore'': ''VSAN_Datastore''}]"'
ok: [docker01] =>
vm_disks: '"[{''size_kb'': 125829120, ''datastore'': ''VSAN_Datastore''}]"'
ok: [docker02] =>
vm_disks: '"[{''size_kb'': 125829120, ''datastore'': ''VSAN_Datastore''}]"'
ok: [docker03] =>
vm_disks: '"[{''size_kb'': 125829120, ''datastore'': ''VSAN_Datastore''}]"'
ok: [docker04] =>
vm_disks: '"[{''size_kb'': 125829120, ''datastore'': ''VSAN_Datastore''}]"'
ok: [docker05] =>
vm_disks: '"[{''size_kb'': 125829120, ''datastore'': ''VSAN_Datastore''}]"'
这看起来像一个列表,为了验证这一点,我将结果传输到to_json过滤器,它错误地说,这不是一个str,而是一个列表。
因此,它肯定是一个列表。正如Uttam正确指出的,但没有提供答案,问题是您的
设置事实:
生成字符串,但磁盘必须是目录的列表,从(和)可以看出
有两个原因:第一个原因是ansible仅自动将JSON字符串强制转换为实际的pythonlist
和dict
结构,但您使用了带有单引号字符串文本和尾随逗号的python语法,这两种语法都是非法的JSON
第二,绝不能使用文本在jinja中构建丰富的数据结构:它强烈支持这些数据结构,以及来自json的精彩和|过滤器,以确保输出是合法的json和正确的转义字符
但是我知道这是一大堆单词,所以我相信你能做的最小的改变就是停止使用单引号并保护后面的逗号:
-name:“定义新磁盘结构”
设定事实:
虚拟机磁盘:>-
[
{中磁盘的%(模板_disk.guest _disk |信息| dictsort)%}
{{“if loop.first else”,“}}
{
“大小\ kb”:{{磁盘[1]。容量\单位为\ kb},
“数据存储”:“{datastore_name}”
}
{%endfor%}
{对于附加|u磁盘中的磁盘,{默认值([])%}
{{”,“如果模板\u disk.guest\u disk\u info else”“}
{
{%if disk.size_gb定义为%}“size_gb”:{{disk.size_gb},{%endif%}
{%if disk.size_-mb定义为%}“size_-mb”:{{disk.size_-mb},{%endif%}
{%if disk.size_-kb定义为%}“size_-kb”:{{disk.size_-kb},{%endif%}
“数据存储”:“{datastore_name}”
}
{%endfor%}
]
正确的代码类似于:
set\u事实:
虚拟机磁盘:>-
{%-设置结果=[]-%}
{%-对于附加磁盘中的磁盘|默认值([])-%}
{%-集合d={“数据存储”:数据存储{u name}-%}
{%-set}=d.update({“size\u-gb”:disk.size\u-gb}如果(disk.size\u-gb已定义)其他{})-%}
{%-set}=results.append(d)-%}
{%-endfor-%}
{{results}}
正如Uttam正确指出的,但没有提供答案,问题是您的设置事实:
生成字符串,但磁盘必须是目录的列表
有两个原因:第一个原因是ansible仅自动将JSON字符串强制转换为实际的pythonlist
和dict
结构,但您使用了带有单引号字符串文本和尾随逗号的python语法,这两种语法都是非法的JSON
第二,绝不能使用文本在jinja中构建丰富的数据结构:它强烈支持这些数据结构,以及来自json的精彩和|过滤器,以确保输出是合法的json和正确的转义字符
但是我知道这是一大堆单词,所以我相信你能做的最小的改变就是停止使用单引号并保护后面的逗号:
-name:“定义新磁盘结构”
设定事实:
虚拟机磁盘:>-
[
{中磁盘的%(模板_disk.guest _disk |信息| dictsort)%}
{{“if loop.first else”,“}}
{
“大小\ kb”:{{磁盘[1]。容量\单位为\ kb},
“数据存储”:“{datastore_name}”
}
{%endfor%}
{对于附加|u磁盘中的磁盘,{默认值([])%}
{{”,“如果模板\u disk.guest\u disk\u info else”“}
{
{%if disk.size_gb定义为%}“size_gb”:{{disk.size_gb},{%endif%}
{%if disk.size_-mb定义为%}“size_-mb”:{{disk.size_-mb},{%endif%}
{%if disk.size_-kb定义为%}“size_-kb”:{{disk.size_-kb},{%endif%}
“数据存储”:“{datastore_name}”
}
{%endfor%}
]
正确的代码类似于:
set\u事实:
虚拟机磁盘:>-
{%-设置结果=[]-%}
{%-对于附加磁盘中的磁盘|默认值([])-%}
{%-集合d={“数据存储”:数据存储{u name}-%}
{%-set}=d.update({“size\u-gb”:disk.size\u-gb}如果(disk.size\u-gb已定义)其他{})-%}
{%-set}=results.append(d)-%}
{%-endfor-%}
{{results}}
最终工作代码,非常感谢@mdaniel
- name: "Get facts for named template"
vmware_guest_disk_info:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
validate_certs: False
datacenter: "{{ datacenter_name }}"
name: "{{ template_name }}"
register: template_disk
delegate_to: localhost
- name: "Define new disk structure"
set_fact:
vm_disks: >-
{%- set results = [] -%}
{%- for osdisk in ( template_disk.guest_disk_info | dictsort ) -%}
{%- set od = { "size_kb": osdisk[1].capacity_in_kb } -%}
{%- set _ = od.update({ "datastore": osdisk[1].backing_datastore }) -%}
{%- set _ = results.append(od) -%}
{%- endfor -%}
{%- for disk in additional_disks|default([]) -%}
{%- if (disk.size_gb is defined) -%}
{%- set d = {"size_gb": disk.size_gb} -%}
{%- set _ = d.update({"datastore": disk.datastore_name}) -%}
{%- set _ = results.append(d) -%}
{%- endif -%}
{%- if (disk.size_mb is defined) -%}
{%- set d = {"size_mb": disk.size_mb} -%}
{%- set _ = d.update({"datastore": disk.datastore_name}) -%}
{%- set _ = results.append(d) -%}
{%- endif -%}
{%- if (disk.size_kb is defined) -%}
{%- set d = {"size_kb": disk.size_kb} -%}
{%- set _ = d.update({"datastore": disk.datastore_name}) -%}
{%- set _ = results.append(d) -%}
{%- endif -%}
{%- endfor -%}
{{ results }}
- name: Clone the template
vmware_guest:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
validate_certs: False
name: "{{ inventory_hostname }}"
template: "{{ template_name }}"
datacenter: "{{ datacenter_name }}"
folder: "/{{ datacenter_name }}/vm/{{ folder_name }}"
cluster: "{{ cluster_name }}"
datastore: "{{ datastore_name }}"
resource_pool: "{{ resource_pool_name }}"
disk: "{{ vm_disks }}"
hardware:
memory_gb: "{{ mem_size_gb }}"
num_cpu: "{{ cpu_size }}"
networks:
- name: "{{ network_name }}"
ip: "{{ ansible_host }}"
netmask: "{{ network_mask }}"
gateway: "{{ network_gw }}"
type: static
customization:
hostname: "{{ inventory_hostname }}"
domain: "{{ domain_name }}"
dns_suffix:
- "{{ domain_name }}"
dns_servers: "{{ network_dns }}"
state: poweredon
wait_for_ip_address: yes
delegate_to: localhost
并将VAR设置为如下所示,任意组合:
additional_disks:
- size_gb: "120"
datastore_name: "VSAN_Datastore"
- size_mb: "10240"
datastore_name: "VSAN_Datastore"
- size_kb: "10240000"
datastore_name: "VSAN_Datastore"
最终工作代码,非常感谢@mdaniel
- name: "Get facts for named template"
vmware_guest_disk_info:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
validate_certs: False
datacenter: "{{ datacenter_name }}"
name: "{{ template_name }}"
register: template_disk
delegate_to: localhost
- name: "Define new disk structure"
set_fact:
vm_disks: >-
{%- set results = [] -%}
{%- for osdisk in ( template_disk.guest_disk_info | dictsort ) -%}
{%- set od = { "size_kb": osdisk[1].capacity_in_kb } -%}
{%- set _ = od.update({ "datastore": osdisk[1].backing_datastore }) -%}
{%- set _ = results.append(od) -%}
{%- endfor -%}
{%- for disk in additional_disks|default([]) -%}
{%- if (disk.size_gb is defined) -%}
{%- set d = {"size_gb": disk.size_gb} -%}
{%- set _ = d.update({"datastore": disk.datastore_name}) -%}
{%- set _ = results.append(d) -%}
{%- endif -%}
{%- if (disk.size_mb is defined) -%}
{%- set d = {"size_mb": disk.size_mb} -%}
{%- set _ = d.update({"datastore": disk.datastore_name}) -%}
{%- set _ = results.append(d) -%}
{%- endif -%}
{%- if (disk.size_kb is defined) -%}
{%- set d = {"size_kb": disk.size_kb} -%}
{%- set _ = d.update({"datastore": disk.datastore_name}) -%}
{%- set _ = results.append(d) -%}
{%- endif -%}
{%- endfor -%}
{{ results }}
- name: Clone the template
vmware_guest:
hostname: "{{ vcenter_server }}"
username: "{{ vcenter_user }}"
password: "{{ vcenter_pass }}"
validate_certs: False
name: "{{ inventory_hostname }}"
template: "{{ template_name }}"
datacenter: "{{ datacenter_name }}"
folder: "/{{ datacenter_name }}/vm/{{ folder_name }}"
cluster: "{{ cluster_name }}"
datastore: "{{ datastore_name }}"
resource_pool: "{{ resource_pool_name }}"
disk: "{{ vm_disks }}"
hardware:
memory_gb: "{{ mem_size_gb }}"
num_cpu: "{{ cpu_size }}"
networks:
- name: "{{ network_name }}"
ip: "{{ ansible_host }}"
netmask: "{{ network_mask }}"
gateway: "{{ network_gw }}"
type: static
customization:
hostname: "{{ inventory_hostname }}"
domain: "{{ domain_name }}"
dns_suffix:
- "{{ domain_name }}"
dns_servers: "{{ network_dns }}"
state: poweredon
wait_for_ip_address: yes
delegate_to: localhost
并将VAR设置为如下所示,任意组合:
additional_disks:
- size_gb: "120"
datastore_name: "VSAN_Datastore"
- size_mb: "10240"
datastore_name: "VSAN_Datastore"
- size_kb: "10240000"
datastore_name: "VSAN_Datastore"
Add“-name:打印变量\n debug:\n var:additional_disks”在set_fact任务之后,验证变量是否定义正确。看一看,我添加了变量的输出您看到这个符号了吗:|-不知道这是从哪里来的好吧,这可能是一个愚蠢的解决方法,但是您是否尝试使用{{vm_disks | replace(“|-”,“”)}?等等,多行“>”就足够了吗?为什么在“>-”中使用连字符?另一个愚蠢的(也许不是)解决方法是将所有的Jinja代码