How to use Ansible playbook loops to create multiple specific VMware guests on multiple free ESXi hosts using vsphere_guest module.

I am running ansible version 2.2.0.0. I have several free ESXi hosts. I would like to create multiple specific guests on each of the free ESXi hosts. I have tried to use with_dict with guests variables, hoping to loop through an arbitrary pre-defined set of ESXi hosts and guests list. But I am getting error:

fatal: [esxi1]: FAILED! => {“failed”: true, “msg”: "the field ‘args’ has an invalid value, which appears to include a variable that is undefined. The error was: ‘list object’ has no attribute ‘vmname’

Is there a way to have the playbook loop through the list of esxi hosts and guests list.

I have tried to use with_dict with guests variables, hoping to loop
through an arbitrary pre-defined set of ESXi hosts and guests list. But I
am getting error:

fatal: [esxi1]: FAILED! => {"failed": true, "msg": "the field 'args' has an
invalid value, which appears to include a variable that is undefined. The
error was: 'list object' has no attribute 'vmname'

Is there a way to have the playbook loop through the list of esxi hosts and
guests list.

Yes.

Because of your list under esxi1 and esxi2 you would need to have a loop in a loop to make it work.
To address them it's item.value.0.vmname, item.value.1.vmname, item.value.2.vmname and so on.

Loop in a loop is possible, but some what more cumbersome as it involves include:

---
- hosts: all
  connection: local

  vars:
      esxi_user: root
      esxi_password: passwordxyz
      guests:
        esxi1:
          - vmname: vm1
        esxi4:
          - vmname: vm3
          - vmname: vm4
          - vmname: vm5

  tasks:
    - vsphere_guest:
        vcenter_hostname: "{{ item.key }}"
        username: "{{ esxi_user }}"
        password: "{{ esxi_password }}"
        guest: "{{ item.value.vmname }}"
        state: powered_on
        vm_extra_config:
          vcpu.hotadd: yes
          mem.hotadd: yes
          notes: This is a test VM
        vm_disk:
          disk1:
            size_gb: 20
            type: thin
            datastore: store4
        vm_nic:
          nic1:
            type: vmxnet3
            network: VM01
            network_type: standard
        vm_hardware:
          memory_mb: 2048
          num_cpus: 2
          osid: centos64Guest
          scsi: lsi
          vm_cdrom:
            type: client
        esxi:
          datacenter: ha-datacenter
          hostname: "{{ item.key }}"
      with_dict: "{{ guests }}"

One way to do it.

Hi Kai,

Thank You so much for your help. The loop works with your suggestions except it seems to run a duplicate task and create a duplicate guest. This is with a test of 2 ESX hosts. Is there a way to work around it?

This is what I have in my inventory:

[esxi]
esxi1
esxi4

ansible-playbook --limit esxi cr_guests.yml

PLAY [all] *********************************************************************

TASK [setup] *******************************************************************
ok: [esxi4]
ok: [esxi1]

TASK [vsphere_guest] ***********************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: pysphere.resources.vi_exception.VIException: [Task Error]: Another task is already in progress.
failed: [esxi1] (item=({u’esx_host’: u’esxi1’}, u’vm1’)) => {“failed”: true, “item”: [{“esx_host”: “esxi1”}, “vm1”], “module_stderr”: “Traceback (most recent call last):\n File "/tmp/ansible_R7ozs3/ansible_module_vsphere_guest.py", line 1909, in \n main()\n File "/tmp/ansible_R7ozs3/ansible_module_vsphere_guest.py", line 1897, in main\n state=state\n File "/tmp/ansible_R7ozs3/ansible_module_vsphere_guest.py", line 1454, in create_vm\n vm.set_extra_config(vm_extra_config)\n File "/usr/lib/python2.7/site-packages/pysphere/vi_virtual_machine.py", line 1589, in set_extra_config\n FaultTypes.TASK_ERROR)\npysphere.resources.vi_exception.VIException: [Task Error]: Another task is already in progress.\n”, “module_stdout”: “”, “msg”: “MODULE FAILURE”}
changed: [esxi4] => (item=({u’esx_host’: u’esxi1’}, u’vm1’))
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: TypeError: Value of unknown type: <class ‘pysphere.resources.vi_exception.VIException’>, [Task Error]: The attempted operation cannot be performed in the current state (Powered off).
failed: [esxi4] (item=({u’esx_host’: u’esxi4’}, u’vm3’)) => {“failed”: true, “item”: [{“esx_host”: “esxi4”}, “vm3”], “module_stderr”: “Traceback (most recent call last):\n File "/tmp/ansible_lt4K1b/ansible_module_vsphere_guest.py", line 1909, in \n main()\n File "/tmp/ansible_lt4K1b/ansible_module_vsphere_guest.py", line 1815, in main\n module.exit_json(changed=state_result)\n File "/tmp/ansible_lt4K1b/ansible_modlib.zip/ansible/module_utils/basic.py", line 1799, in exit_json\n File "/tmp/ansible_lt4K1b/ansible_modlib.zip/ansible/module_utils/basic.py", line 388, in remove_values\n File "/tmp/ansible_lt4K1b/ansible_modlib.zip/ansible/module_utils/basic.py", line 388, in \n File "/tmp/ansible_lt4K1b/ansible_modlib.zip/ansible/module_utils/basic.py", line 399, in remove_values\nTypeError: Value of unknown type: <class ‘pysphere.resources.vi_exception.VIException’>, [Task Error]: The attempted operation cannot be performed in the current state (Powered off).\n”, “module_stdout”: “”, “msg”: “MODULE FAILURE”}
changed: [esxi1] => (item=({u’esx_host’: u’esxi4’}, u’vm3’))
changed: [esxi4] => (item=({u’esx_host’: u’esxi4’}, u’vm4’))
changed: [esxi1] => (item=({u’esx_host’: u’esxi4’}, u’vm4’))
changed: [esxi1] => (item=({u’esx_host’: u’esxi4’}, u’vm5’))
changed: [esxi4] => (item=({u’esx_host’: u’esxi4’}, u’vm5’))
to retry, use: --limit @/root/learn/ansible/cr_guests.retry

PLAY RECAP *********************************************************************
esxi4 : ok=1 changed=0 unreachable=0 failed=1
esxi1 : ok=1 changed=0 unreachable=0 failed=1

Thanks,
Alex

Since you inventory contain two hosts it will run the task two times, one time for each hosts.
You only wanna run it once so in your playbook set "- hosts: localhost" and remove the line "connection: local"

Hi Kai,

The playbook works perfectly now. Thanks again for all your help.

Regards,
Alex