2

Goal: Automate code to be ovf agnostic as possible. Build a playbook that will allow for any OVF template with any custom ovf properties and network interface names to be deployed without changing YAML playbook.

Enviornment: ansible 2.8.7 python version = 3.6.8

Code Example:

  **Dicts: cust-ovf-answer.yml**

       custovfnetworkanswers: 
            Management: "vmportgroup"

       custovfanswers: 
            fqdn: "s0u1tst.dmn.local"
            dns1: "10.100.0.14"
            dns2: "10.100.0.17"
            ntp1: "ntp1.dmn.local"
            ntp2: "ntp2.dmn.local"
            ipv4.how: "Manual"
            ipv4.addr: "10.100.0.135"
            ipv4.mask: "255.255.255.224"
            ipv4.gw: "10.100.0.158"


**Playbook: Deploy_OVF_to_System.yml**

    ... MAGIC STUFF GOING ON UP HERE ...

    - name: Get Unqiue OVF Answers
      include_vars:
         file: ".../cust-ovf-answers.yml"

    - name: Deploy Appliance OVF
      vmware_deploy_ovf:  
      hostname: "{{ inventory_hostname }}"
      username: "{{ vcenter_username }}"
      password: "{{ vcenter_password }}"
      validate_certs: no
      name: "r{{ custVMName }}"  
      datacenter: "TEST"
      folder: "/test/vm/aas"
      datastore: "{{ targetDatastore }}"
      allow_duplicates: no
      disk_provisioning: "thick" 
      networks:
        args: "{{ custovfnetworkanswers | to_json }}"
        # "Management": "{{ vmportgroup }}"
      power_on: no 
      wait: no
      ovf: "{{ custOvfFile.files[0].path }}"
      fail_on_spec_warnings: no
      inject_ovf_env: yes
      properties: 
        args: "{{ custovfanswers | to_json }}"
        # fqdn: "{{ item.value.fdqn }}" 
        # dns1: "{{ item.value.dns1 }}"
        # dns2: "{{ item.value.dns2 }}"
        # ntp1: "ntp1.dmn.local"
        # ntp2: "ntp2.dmn.local"
        # ipv4.how: "Manual"
        # ipv4.addr: "10.100.0.135"
        # ipv4.mask: "255.255.255.224"
        # ipv4.gw: "10.100.0.158"
  delegate_to: localhost
  when: 
    #- custovfanswers is defined
    #- custovfnetworkanswers is defined

**Output 1: **

Errors when networks: & properties: is defined with args: "{{ custom_dict| to_json }}".

{
    "hosts": {
        "vCenter Host": {
            "_ansible_no_log": false,
            "action": "set_fact",
            "ansible_facts": {
                "buildvmCustomConfigFileLoc": ".../cust-ovf-answer.yml"
            },
            "changed": false
        }
    },
    "task": {
        "duration": {
            "end": "2019-11-22T18:05:50.616891Z",
            "start": "2019-11-22T18:05:50.544148Z"
        },
        "id": "005056a7-5f58-135f-6306-000000000a39",
        "name": "set_fact"
    }
},
{
    "hosts": {
        "vCenter Host": {
            "_ansible_no_log": false,
            "action": "include_vars",
            "ansible_facts": {
                "custovfanswers": {
                    "dns1": "10.100.0.14",
                    "dns2": "10.100.0.17",
                    "fqdn": "s0u1tst.dmn.local",
                    "ipv4.addr": "10.100.0.135",
                    "ipv4.gw": "10.100.0.158",
                    "ipv4.how": "Manual",
                    "ipv4.mask": "255.255.255.224",
                    "ntp1": "ntp1.dmn.local",
                    "ntp2": "ntp2.dmn.local",
                },
                "custovfnetworkanswers": {
                    "Management": "VMTraffic_test"
                }
            },
            "ansible_included_var_files": [
                ".../cust-ovf-answer.yml"
            ],
            "changed": false
        }
    },
    "task": {
        "duration": {
            "end": "2019-11-22T18:05:50.741706Z",
            "start": "2019-11-22T18:05:50.653958Z"
        },
        "id": "005056a7-5f58-135f-6306-000000000a3a",
        "name": "Get Unqiue OVF Answers"
    }
},
{
    "hosts": {
        "vCenter Host": {
            "_ansible_delegated_vars": {
                "ansible_host": "localhost"
            },
            "_ansible_no_log": false,
            "action": "vmware_deploy_ovf",
            "changed": false,
            "exception": "Traceback (most recent call last):\n  File \"/home/swelsch/.ansible/tmp/ansible-tmp-1574445950.872407-14317549312709/AnsiballZ_vmware_deploy_ovf.py\", line 114, in <module>\n    _ansiballz_main()\n  File \"/home/swelsch/.ansible/tmp/ansible-tmp-1574445950.872407-14317549312709/AnsiballZ_vmware_deploy_ovf.py\", line 106, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/swelsch/.ansible/tmp/ansible-tmp-1574445950.872407-14317549312709/AnsiballZ_vmware_deploy_ovf.py\", line 49, in invoke_module\n    imp.load_module('__main__', mod, module, MOD_DESC)\n  File \"/usr/lib/python3.6/imp.py\", line 235, in load_module\n    return load_source(name, filename, file)\n  File \"/usr/lib/python3.6/imp.py\", line 170, in load_source\n    module = _exec(spec, sys.modules[name])\n  File \"<frozen importlib._bootstrap>\", line 618, in _exec\n  File \"<frozen importlib._bootstrap_external>\", line 678, in exec_module\n  File \"<frozen importlib._bootstrap>\", line 219, in _call_with_frames_removed\n  File \"/tmp/ansible_vmware_deploy_ovf_payload_9pywu9rd/__main__.py\", line 685, in <module>\n  File \"/tmp/ansible_vmware_deploy_ovf_payload_9pywu9rd/__main__.py\", line 677, in main\n  File \"/tmp/ansible_vmware_deploy_ovf_payload_9pywu9rd/__main__.py\", line 465, in upload\n  File \"/tmp/ansible_vmware_deploy_ovf_payload_9pywu9rd/__main__.py\", line 372, in get_lease\n  File \"/tmp/ansible_vmware_deploy_ovf_payload_9pywu9rd/__main__.py\", line 344, in get_objects\nKeyError: 'network'\n",
            "failed": true,
            "module_stderr": "Traceback (most recent call last):\n  File \"/home/swelsch/.ansible/tmp/ansible-tmp-1574445950.872407-14317549312709/AnsiballZ_vmware_deploy_ovf.py\", line 114, in <module>\n    _ansiballz_main()\n  File \"/home/swelsch/.ansible/tmp/ansible-tmp-1574445950.872407-14317549312709/AnsiballZ_vmware_deploy_ovf.py\", line 106, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/swelsch/.ansible/tmp/ansible-tmp-1574445950.872407-14317549312709/AnsiballZ_vmware_deploy_ovf.py\", line 49, in invoke_module\n    imp.load_module('__main__', mod, module, MOD_DESC)\n  File \"/usr/lib/python3.6/imp.py\", line 235, in load_module\n    return load_source(name, filename, file)\n  File \"/usr/lib/python3.6/imp.py\", line 170, in load_source\n    module = _exec(spec, sys.modules[name])\n  File \"<frozen importlib._bootstrap>\", line 618, in _exec\n  File \"<frozen importlib._bootstrap_external>\", line 678, in exec_module\n  File \"<frozen importlib._bootstrap>\", line 219, in _call_with_frames_removed\n  File \"/tmp/ansible_vmware_deploy_ovf_payload_9pywu9rd/__main__.py\", line 685, in <module>\n  File \"/tmp/ansible_vmware_deploy_ovf_payload_9pywu9rd/__main__.py\", line 677, in main\n  File \"/tmp/ansible_vmware_deploy_ovf_payload_9pywu9rd/__main__.py\", line 465, in upload\n  File \"/tmp/ansible_vmware_deploy_ovf_payload_9pywu9rd/__main__.py\", line 372, in get_lease\n  File \"/tmp/ansible_vmware_deploy_ovf_payload_9pywu9rd/__main__.py\", line 344, in get_objects\nKeyError: 'network'\n",
            "module_stdout": "",
            "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error",
            "rc": 1
        }
    },
    "task": {
        "duration": {
            "end": "2019-11-22T18:05:53.288639Z",
            "start": "2019-11-22T18:05:50.791547Z"
        },
        "id": "005056a7-5f58-135f-6306-000000000a3b",
        "name": "Deploy Appliance OVF"
    }
}

**Output 2: ** Errors when properties: is defined with args: "{{ custom_dict| to_json }}". Networks: is defined by hard coding it in.

{
    "hosts": {
        "vCenter Host": {
            "_ansible_no_log": false,
            "action": "include_vars",
            "ansible_facts": {
                "custovfanswers": {
                    "dns1": "10.100.0.14",
                    "dns2": "10.100.0.17",
                    "fqdn": "s0u1tst.dmn.local",
                    "ipv4.addr": "10.100.0.135",
                    "ipv4.gw": "10.100.0.158",
                    "ipv4.how": "Manual",
                    "ipv4.mask": "255.255.255.224",
                    "ntp1": "ntp1.dmn.local",
                    "ntp2": "ntp2.dmn.local",
                },
                "custovfnetworkanswers": {
                    "Management": "vmportgroup"
                }
            },
            "ansible_included_var_files": [
                ".../cust-ovf-answer.yml"
            ],
            "changed": false
        }
    },
    "task": {
        "duration": {
            "end": "2019-11-22T18:42:33.098663Z",
            "start": "2019-11-22T18:42:33.001653Z"
        },
        "id": "005056a7-5f58-c3eb-25e1-000000000a3a",
        "name": "Get Unqiue OVF Answers"
    }
    },
    {
    "hosts": {
        "vCenter Host": {
            "_ansible_delegated_vars": {
                "ansible_host": "localhost"
            },
            "_ansible_no_log": false,
            "action": "vmware_deploy_ovf",
            "changed": true,
            "instance": {
                "annotation": "xxxx",
                "current_snapshot": null,
                "customvalues": {},
                "guest_consolidation_needed": false,
                "guest_question": null,
                "guest_tools_status": "guestToolsNotRunning",
                "guest_tools_version": "0",
                "hw_cluster": null,
                "hw_cores_per_socket": 1,
                "hw_datastores": [
                    "s0u1aas-nlsas"
                ],
                "hw_esxi_host": "s0u1aas.dmn.local",
                "hw_eth0": {
                    "addresstype": "assigned",
                    "ipaddresses": null,
                    "label": "Network adapter 1",
                    "macaddress": "00:50:56:a7:ae:20",
                    "macaddress_dash": "00-50-56-a7-ae-20",
                    "portgroup_key": null,
                    "portgroup_portkey": null,
                    "summary": "vmportgroup"
                },
                "hw_files": [
                    "[s0u1aas-nlsas] r10s0u1tst/r10s0u1tst.vmx",
                    "[s0u1aas-nlsas] r10s0u1tst/r10s0u1tst.vmsd",
                    "[s0u1aas-nlsas] r10s0u1tst/r10s0u1tst.vmdk"
                ],
                "hw_folder": "/test/vm/AAS",
                "hw_guest_full_name": null,
                "hw_guest_ha_state": null,
                "hw_guest_id": null,
                "hw_interfaces": [
                    "eth0"
                ],
                "hw_is_template": false,
                "hw_memtotal_mb": 32768,
                "hw_name": "r10s0u1tst",
                "hw_power_status": "poweredOff",
                "hw_processor_count": 4,
                "hw_product_uuid": "4227ef4b-0d98-e254-f9e7-b798bbee43fc",
                "hw_version": "vmx-13",
                "instance_uuid": "50271468-256d-9c69-7154-cfbdd26fc900",
                "ipv4": null,
                "ipv6": null,
                "module_hw": true,
                "snapshots": [],
                "vnc": {}
            },
            "invocation": {
                "module_args": {
                    "allow_duplicates": false,
                    "cluster": null,
                    "datacenter": "TEST",
                    "datastore": "s0u1aas-nlsas",
                    "deployment_option": null,
                    "disk_provisioning": "thin",
                    "fail_on_spec_warnings": false,
                    "folder": "/test/vm/aas",
                    "hostname": "vCenter Host",
                    "inject_ovf_env": true,
                    "name": "r10s0u1tst",
                    "networks": {
                        "Management": "vmportgroup "
                    },
                    "ovf": "xxx.ovf",
                    "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
                    "port": 443,
                    "power_on": false,
                    "properties": {
                        "args": "{\"fqdn\": \"s0u1tst.dmn.local\", \"dns1\": \"10.100.0.14\", \"dns2\": \"10.100.0.17\", \"ntp1\": \"ntp1.dmn.local\", \"ntp2\": \"ntp2.dmn.local\", \"ipv4.how\": \"Manual\", \"ipv4.addr\": \"10.100.0.135\", \"ipv4.mask\": \"255.255.255.224\", \"ipv4.gw\": \"10.100.0.158\"}"
                    },
                    "resource_pool": "Resources",
                    "username": "xxxx",
                    "validate_certs": false,
                    "wait": false,
                    "wait_for_ip_address": false
                }
            }
        }
    },
    "task": {
        "duration": {
            "end": "2019-11-22T18:43:35.923602Z",
            "start": "2019-11-22T18:42:33.148318Z"
        },
        "id": "005056a7-5f58-c3eb-25e1-000000000a3b",
        "name": "Deploy Appliance OVF"
    }

If I hard code it all, everything imports as intended.

Stephen W
  • 21
  • 1

1 Answers1

0

I think that your issue is the args:. You can directly inject your dict variables. BTW, you don't need to use the to_json convert filter as Ansible will deal with it.

  […]
      disk_provisioning: "thick" 
      networks: "{{ custovfnetworkanswers }}"
      power_on: no 
  […]
      inject_ovf_env: yes
      properties: "{{ custovfanswers }}"
  delegate_to: localhost
  […]

Bonus

In some cases the keys of what you have to provide needs to be dynamic (unpredictive key names or list lenght). To solve that you can forge the variable as a json string with jinja2.

Dynamic list of dict sample:

vars:
  custom_networks: >
    [ {% for nic in nics %}
        { 'name':'{{ nic.id }}',
          'mac':'{{ nic.mac }}',
          'ip': '{{ nic.ip }}'
        }{% if not loop.last %},{% endif %}
      {% endfor %}
    ]

Dynamic key name:

vars:
  custom_ovf_input: "{ '{{ network_name }}': '{{ network_address }}' }"

Then you can use that forged variable directly (no need to use any filter to translate it to yaml Ansible will deal with it).

Dharman
  • 30,962
  • 25
  • 85
  • 135
xenlo
  • 761
  • 1
  • 7
  • 21