Ansible встроенный шаблон дзиндзя в список - PullRequest
1 голос
/ 05 апреля 2020

Я не могу понять, почему это не сработает. Я использую jinja для динамического генерирования списка, который я передам модулю vmware_guest, чтобы я мог принять решение в параметрах хоста или группы, если я хотел бы добавить дополнительные диски. Я использую модуль vmware_disk_info, чтобы найти размер диска шаблона, а затем добавить все дополнительные диски, которые я бы определил в группе var. Мне кажется, что выведенный список просто не является списком ????

---
- 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

, и пример var будет:

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'

пример вывода 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},
     ]

Новый код, основанный на предложении ниже: Однако та же ошибка:

- 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, это список. Так что это определенно список.

Ответы [ 2 ]

0 голосов
/ 07 апреля 2020

окончательный рабочий код, Большое спасибо @ 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

и настройте свои переменные так, как вам нужно, в любой комбинации:

additional_disks:
  - size_gb: "120"
    datastore_name: "VSAN_Datastore"
  - size_mb: "10240"
    datastore_name: "VSAN_Datastore"
  - size_kb: "10240000"
    datastore_name: "VSAN_Datastore"
0 голосов
/ 05 апреля 2020

Как правильно указал Уттам, но не дал ответа, проблема в том, что ваш set_fact: создает строку , но disks должен быть list из dict, как видно из прекрасного руководства код )

Есть две причины: во-первых, ansible только авто-принуждения JSON - просмотр строк в реальных структурах python list и dict, но вы использовали синтаксис python со строковыми литералами в одинарных кавычках и запятыми, оба из которых недопустимы: JSON

во-вторых, никогда не следует создавать богатую структуру данных в jinja , используя текст : он имеет сильную поддержку этих структур данных, а также замечательную | to_json Фильтры и |from_json, обеспечивающие правильность вывода JSON и правильно экранированные символы

Но я знаю, что это много слов, поэтому я считаю, что самое маленькое изменение, которое вы можете сделать, чтобы вызвать ситуацию работа состоит в том, чтобы прекратить использовать одинарные кавычки и охранять конечная запятая:

- name: "Define new disk structure"
  set_fact:
    vm_disks: >-
      [
      {% for disk in (template_disk.guest_disk_info|dictsort) %}
      {{ "" if loop.first else "," }}
      {
        "size_kb": {{ disk[1].capacity_in_kb }},
        "datastore": "{{ datastore_name }}"
      }
      {% endfor %}
      {% for disk in additional_disks|default([]) %}
      {{ "," if template_disk.guest_disk_info else "" }}
      {
        {% 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 %}
      ]

Код правильный будет похож на

set_fact:
  vm_disks: >-
     {%- set results = [] -%}
     {%- for disk in additional_disks|default([]) -%}
     {%-   set d = {"datastore": datastore_name} -%}
     {%-   set _ = d.update({"size_gb": disk.size_gb} if (disk.size_gb is defined) else {}) -%}
     {%-   set _ = results.append(d) -%}
     {%- endfor -%}
     {{ results }}
...