# Loop through List

**URL:** <https://forum.ansible.com/t/loop-through-list/37210>\
**Category:** Ansible Project\
**Tags:** vmware\
**Created:** [October 12, 2022, 1:33pm UTC](https://forum.ansible.com/t/loop-through-list/37210 "2022-10-12T13:33:57Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Rai\_Ner](https://avatars.discourse-cdn.com/v4/letter/r/35a633/32.png) [@Rai\_Ner](https://forum.ansible.com/u/Rai_Ner)\
**Post date:** [October 12, 2022, 1:33pm UTC](https://forum.ansible.com/t/loop-through-list/37210/1 "2022-10-12T13:33:57Z")

</div>

Hi,

I would like to add a VM with vmware guest. I would like to keep it flexibel, some VMs will have one disk, some two disks. Currently I am using 2 tasks with a when: 1disk or 2 condition but that is no nice solution.

Example Task:

- name: Create a VM with multiple disks of different disk controller types  
community.vmware.vmware\_guest:  
hostname: “{{ vcenter\_hostname }}”  
username: “{{ vcenter\_username }}”  
…  
datastore: datastore1  
disk:
- size\_gb: “{{ disks[0].size\_gb }}” #30  
unit\_number: 0
- size\_gb: “{{ disks[1].size\_gb }}” #10  
unit\_number: 1  
networks:
- name: VM Network  
device\_type: vmxnet3  
delegate\_to: localhost  
register: deploy\_vm

host A vars file:

disks:

- size\_gb: 30
- size\_gb: 10

host B vars file:

disks:

- size\_gb: 30

Any ideas how to achieve this in a nicer way ? I tried also using loops but without success. Leaving the 2nd “size\_gb:” empty does not work.

Many thanks  
Rainer

---

<div class="post-metadata">

**Author:** ![Walter\_Rowe](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/walter_rowe/32/4506_2.png) [@Walter\_Rowe](https://forum.ansible.com/u/Walter_Rowe)\
**Post date:** [October 12, 2022, 2:13pm UTC](https://forum.ansible.com/t/loop-through-list/37210/2 "2022-10-12T14:13:17Z")

</div>

We created a JSON list that specifies a number of things for different server types. One JSON list provides Linux disk specs. One JSON list provides Windows disk specs.

fs\_spec: [

# linux apache web server servers

{ profile: apache , name: system , device: a, size: 75, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 0, owner: root, group: root, perms: 0755 }, # /  
{ profile: apache , name: sites , device: b, size: 32, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 0, owner: root, group: root, perms: 0755 }, # /sites

# linux commvault media servers

{ profile: commvault , name: system , device: a, size: 75, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 0, owner: root, group: root, perms: 0755 }, # /  
{ profile: commvault , name: ddb , device: b, size: 512, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 0, owner: root, group: root, perms: 0755 }, # /ddb  
{ profile: commvault , name: index , device: c, size: 512, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 1, owner: root, group: root, perms: 0755 }, # /index

# linux docker container servers

{ profile: docker , name: system , device: a, size: 75, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 0, owner: root, group: root, perms: 0755 }, # /  
{ profile: docker , name: containers , device: b, size: 100, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 0, owner: root, group: root, perms: 0755 }, # /containers

# linux general purpose servers

{ profile: general , name: system , device: a, size: 75, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 0, owner: root, group: root, perms: 0755 }, # /

# linux CBS INFO servers

{ profile: cbsinfo , name: system , device: a, size: 80, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 0, owner: root, group: root, perms: 0755 }, # /  
{ profile: cbsinfo , name: apps , device: b, size: 64, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 0, owner: oranist, group: dba, perms: 0755 }, # /apps  
{ profile: cbsinfo , name: ftp , device: c, size: 64, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 1, owner: ftp, group: ftp, perms: 0750 }, # /ftp

# linux MySQL database servers

{ profile: mysql , name: system , device: a, size: 75, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 0, owner: root, group: root, perms: 0755 }, # /  
{ profile: mysql , name: tmp , device: b, size: 100, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 1, owner: root, group: root, perms: 0755 }, # /tmp  
{ profile: mysql , name: apps , device: c, size: 512, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 0, owner: oranist, group: dba, perms: 0755 }, # /apps  
{ profile: mysql , name: archive , device: d, size: 512, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 1, owner: oranist, group: dba, perms: 0755 }, # /archive  
{ profile: mysql , name: mydata , device: e, size: 512, type: thin, ctrl\_type: paravirtual, ctrl: 2, unit: 0, owner: mysql, group: dba, perms: 0755 }, # /mydata  
{ profile: mysql , name: mybackups , device: f, size: 1024, type: thin, ctrl\_type: paravirtual, ctrl: 2, unit: 1, owner: mysql, group: dba, perms: 0755 }, # /mybackups

# linux nginx web server servers

{ profile: nginx , name: system , device: a, size: 75, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 0, owner: root, group: root, perms: 0755 }, # /  
{ profile: nginx , name: sites , device: b, size: 32, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 0, owner: root, group: root, perms: 0755 }, # /sites

# linux Oracle database servers

{ profile: oracle , name: system , device: a, size: 80, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 0, owner: root, group: root, perms: 0755 }, # /  
{ profile: oracle , name: swap , device: b, size: 64, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 1, owner: root, group: root, perms: 0755 }, # swap  
{ profile: oracle , name: tmp , device: c, size: 64, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 2, owner: root, group: root, perms: 0755 }, # /tmp  
{ profile: oracle , name: apps , device: d, size: 192, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 0, owner: oranist, group: dba, perms: 0755 }, # /apps  
{ profile: oracle , name: external , device: e, size: 32, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 1, owner: oranist, group: dba, perms: 0755 }, # /external  
{ profile: oracle , name: archive , device: f, size: 128, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 2, owner: oranist, group: dba, perms: 0755 }, # /archive  
{ profile: oracle , name: oradata , device: g, size: 1024, type: thin, ctrl\_type: paravirtual, ctrl: 2, unit: 0, owner: oranist, group: dba, perms: 0750 }, # /oradata  
{ profile: oracle , name: orafra , device: h, size: 1024, type: thin, ctrl\_type: paravirtual, ctrl: 2, unit: 1, owner: oranist, group: dba, perms: 0750 }, # /orafra

# linux Oracle + MySQL database servers

{ profile: oracle\_mysql , name: system , device: a, size: 75, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 0, owner: root, group: root, perms: 0755 }, # /  
{ profile: oracle\_mysql , name: swap , device: b, size: 64, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 1, owner: root, group: root, perms: 0755 }, # swap  
{ profile: oracle\_mysql , name: tmp , device: c, size: 64, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 2, owner: root, group: root, perms: 0755 }, # /tmp  
{ profile: oracle\_mysql , name: apps , device: d, size: 192, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 0, owner: oranist, group: dba, perms: 0755 }, # /apps  
{ profile: oracle\_mysql , name: external , device: e, size: 50, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 1, owner: oranist, group: dba, perms: 0755 }, # /external  
{ profile: oracle\_mysql , name: archive , device: d, size: 512, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 2, owner: oranist, group: dba, perms: 0755 }, # /archive  
{ profile: oracle\_mysql , name: oradata , device: f, size: 768, type: thin, ctrl\_type: paravirtual, ctrl: 2, unit: 0, owner: oranist, group: dba, perms: 0750 }, # /oradata  
{ profile: oracle\_mysql , name: orafra , device: g, size: 1024, type: thin, ctrl\_type: paravirtual, ctrl: 2, unit: 1, owner: oranist, group: dba, perms: 0750 }, # /orafra  
{ profile: oracle\_mysql , name: mydata , device: h, size: 640, type: thin, ctrl\_type: paravirtual, ctrl: 3, unit: 0, owner: mysql, group: dba, perms: 0755 }, # /mydata  
{ profile: oracle\_mysql , name: mybackups , device: i, size: 960, type: thin, ctrl\_type: paravirtual, ctrl: 3, unit: 1, owner: mysql, group: dba, perms: 0755 }, # /mybackups

# linux tomcat application servers

{ profile: tomcat , name: system , device: a, size: 75, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 0, owner: root, group: root, perms: 0755 }, # /  
{ profile: tomcat , name: sites , device: b, size: 32, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 0, owner: root, group: root, perms: 0755 }, # /sites

# linux ASD tomcat/weblogic application servers

{ profile: tomweb , name: system , device: a, size: 75, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 0, owner: root, group: root, perms: 0755 }, # /  
{ profile: tomweb , name: u01 , device: b, size: 100, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 0, owner: root, group: root, perms: 0755 }, # /u01  
{ profile: tomweb , name: data , device: c, size: 100, type: thin, ctrl\_type: paravirtual, ctrl: 2, unit: 0, owner: root, group: root, perms: 0755 }, # /data

# linux ASD APPNODE (tomcat/weblogic) application servers

{ profile: appnode , name: system , device: a, size: 75, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 0, owner: root, group: root, perms: 0755 }, # /  
{ profile: appnode , name: u01 , device: b, size: 100, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 0, owner: root, group: root, perms: 0755 }, # /u01  
{ profile: appnode , name: data , device: c, size: 100, type: thin, ctrl\_type: paravirtual, ctrl: 2, unit: 0, owner: root, group: root, perms: 0755 }, # /data  
{ profile: appnode , name: apps , device: d, size: 100, type: thin, ctrl\_type: paravirtual, ctrl: 3, unit: 0, owner: root, group: root, perms: 0755 }, # /apps

# linux ASD subversion/jira

{ profile: subversion , name: system , device: a, size: 75, type: thin, ctrl\_type: paravirtual, ctrl: 0, unit: 0, owner: root, group: root, perms: 0755 }, # /  
{ profile: subversion , name: u01 , device: b, size: 20, type: thin, ctrl\_type: paravirtual, ctrl: 1, unit: 0, owner: root, group: root, perms: 0755 }, # /u01  
{ profile: subversion , name: data , device: c, size: 200, type: thin, ctrl\_type: paravirtual, ctrl: 2, unit: 0, owner: root, group: root, perms: 0755 }, # /data

# all preceding lines must end with a comma - makes it easier to copy sections above to create new server roles - json\_query ignores this

{ the: end }  
]

# use [0:-1] to drop off the last line “{ the: end }”

valid\_linux\_types: “{{ fs\_spec[0:-1] | map(attribute=‘profile’) | sort | unique }}”

fs\_spec\_windows: [

# Windows commvault media servers

{ profile: commvault , disk\_number: 0 , name: system , device: c, size: 100, type: thin, ctrl\_type: lsilogicsas, ctrl: 0, unit: 0, block: 4096 }, # OS/Sys  
{ profile: commvault , disk\_number: 1 , name: Index , device: e, size: 100, type: thin, ctrl\_type: lsilogicsas, ctrl: 1, unit: 0, block: 4096 }, # Index  
{ profile: commvault , disk\_number: 2 , name: DDB , device: f, size: 100, type: thin, ctrl\_type: lsilogicsas, ctrl: 2, unit: 0, block: 4096 }, # DDB

# Windows general purpose servers

{ profile: general , disk\_number: 0 , name: system , device: c, size: 100, type: thin, ctrl\_type: lsilogicsas, ctrl: 0, unit: 0, block: 4096 }, # OS/Sys  
{ profile: general , disk\_number: 1 , name: Data1 , device: e, size: 100, type: thin, ctrl\_type: lsilogicsas, ctrl: 1, unit: 0, block: 4096 }, # Data1

# Windows IIS web servers

{ profile: iis , disk\_number: 0 , name: system , device: c, size: 100, type: thin, ctrl\_type: lsilogicsas, ctrl: 0, unit: 0, block: 4096 }, # OS/Sys  
{ profile: iis , disk\_number: 1 , name: Data1 , device: e, size: 300, type: thin, ctrl\_type: lsilogicsas, ctrl: 1, unit: 0, block: 4096 }, # Data1

# Windows MS SQL servers

{ profile: mssql , disk\_number: 0 , name: system , device: c, size: 100, type: thin, ctrl\_type: lsilogicsas, ctrl: 0, unit: 0, block: 4096 }, # OS/Sys  
{ profile: mssql , disk\_number: 1 , name: Data1 , device: e, size: 100, type: thin, ctrl\_type: lsilogicsas, ctrl: 0, unit: 1, block: 65536 }, # Data1  
{ profile: mssql , disk\_number: 2 , name: Data2 , device: f, size: 100, type: thin, ctrl\_type: lsilogicsas, ctrl: 0, unit: 2, block: 65536 }, # Data2  
{ profile: mssql , disk\_number: 3 , name: Backup , device: g, size: 100, type: thin, ctrl\_type: lsilogicsas, ctrl: 1, unit: 0, block: 4096 }, # Backup  
{ profile: mssql , disk\_number: 4 , name: Index , device: i, size: 5, type: thin, ctrl\_type: lsilogicsas, ctrl: 1, unit: 1, block: 65536 }, # Index  
{ profile: mssql , disk\_number: 5 , name: Log , device: l, size: 50, type: thin, ctrl\_type: lsilogicsas, ctrl: 2, unit: 0, block: 65536 }, # Log  
{ profile: mssql , disk\_number: 6 , name: SQL , device: p, size: 75, type: thin, ctrl\_type: lsilogicsas, ctrl: 2, unit: 1, block: 4096 }, # SQL Program  
{ profile: mssql , disk\_number: 7 , name: TempDB , device: t, size: 50, type: thin, ctrl\_type: lsilogicsas, ctrl: 3, unit: 0, block: 65536 }, # TempDB

# all preceding lines must end with a comma - makes it easier to copy sections above to create new server roles - json\_query ignores this

{ the: end }

]

# use [0:-1] to drop off the last line “{ the: end }”

valid\_windows\_types: “{{ fs\_spec\_windows[0:-1] | map(attribute=‘profile’) | sort | unique }}”

We build our VMs from templates that all have a single system disk. Note the template param references an os\_type var. We have templates for windows2016, windows2019, redhat7, redhat8, redhat9, ubuntu20, ubuntu22, etc. Our service portal lets the user choose which OS they want and that sends is one of these names as the template to source for the new VM.

NOTE that we create the VM “poweredoff”. We don’t power it on until we have added the disks it will need. We do that so that the first boot from the template already has all the raw storage attached to it.

- name: create the guest vm using template  
community.vmware.vmware\_guest:  
validate\_certs: no  
hostname: “{{ vcenter[location|lower].vc }}”  
datacenter: “{{ vcenter[location|lower].dc }}”  
cluster: “{{ vcenter[location|lower].cl }}”  
name: “{{ vm\_guest\_name | lower }}”  
state: poweredoff  
template: “{{ os\_type }}”  
folder: “{{ esx\_folder }}”  
datastore: “{{ vcenter[location|lower].ds }}”  
hardware:  
hotadd\_cpu: yes  
hotadd\_memory: yes  
memory\_mb: “{{ vm\_spec[vm\_size].ram }}”  
num\_cpus: “{{ vm\_spec[vm\_size].cpu }}”  
networks:
- name: “VLAN\_{{ vlan }}”  
type: dhcp  
start\_connected: yes  
connected: yes  
wait\_for\_ip\_address: no  
delegate\_to: localhost  
register: newvm

We use a json\_query filter to extract the specific items from the list that we need for a given server type. This task sets fs\_list to just the list of disks associated with a given server type. Note the start of the jinja template selects which JSON list to source. We get a param from our service portal for fs\_type that we use to filter the JSON list via json\_query.

- name: collect disk list for {{ fs\_type }} machine  
set\_fact:  
fs\_list: “{{ (fs\_spec if my\_family != ‘windows’ else fs\_spec\_windows) | json\_query(‘[?profile==`'+fs_type+'`]’) }}”

We then take our fs\_list and eliminate the system disk (since that comes with the template). We also create an empty disk list that will hold the final disk list we want to add.

- name: Initialize disk lists  
set\_fact:  
type\_list: “{{ (fs\_spec if my\_family != ‘windows’ else fs\_spec\_windows) | json\_query(‘[?profile==`'+fs_type+'` && name!=`system`]’) }}”  
disk\_list: 

We then massage a “additional disks” list into a disk param we can send to VMware.

- name: Build vmware\_guest\_disk list from filesystem list  
set\_fact:  
disk\_list: “{{ disk\_list + this\_list }}”  
loop: “{{ type\_list }}”  
vars:  
this\_list: [{ size\_gb: “{{ item.size }}”, type: “{{ item.type }}”, datastore: “{{ vcenter[location|lower].ds }}”, scsi\_type: “{{ item.ctrl\_type }}”, scsi\_controller: “{{ item.ctrl }}”, unit\_number: “{{ item.unit }}” } ]

We then call vmware\_guest\_disk to add the disks (on the **condition the system has more than one** ).

- name: Add disk(s) to {{ vm\_guest\_name | lower }}  
community.vmware.vmware\_guest\_disk:  
datacenter: “{{ vcenter[location|lower].dc }}”  
hostname: “{{ vcenter[location|lower].vc }}”  
name: “{{ vm\_guest\_name | lower }}”  
validate\_certs: no  
disk: “{{ disk\_list }}”  
**when: (disk\_list|length) \> 0**

Lastly we power on the new VM. When the VM boots for the first time and does its device discovery it will find all the raw disks needed for the type of server we are standing up.

- name: Power Up New Machine ({{ vm\_guest\_name | lower }})  
community.vmware.vmware\_guest:  
hostname: “{{ vcenter[location|lower].vc }}”  
datacenter: “{{ vcenter[location|lower].dc }}”  
cluster: “{{ vcenter[location|lower].cl }}”  
validate\_certs: no  
name: “{{ vm\_guest\_name | lower }}”  
state: poweredon  
delegate\_to: localhost

Every server we stand up on VMware goes through these tasks. We have more tasks that add tags, etc, but this is the basic framework.

The disk spec JSON lists are in a vars file. We easily can add more disk configurations by expanding the JSON lists. The ‘profile’ is the key in the JSON lists that we match to ‘os\_type’ we receive from our service portal. If we want to create a new server type with a different disk layout then we offer a new os\_type value in the service portal and defined a new disk list with a new profile key in the JSON list. We do this for resource settings too (CPU, RAM), and all the other parameters we use in our vmware\_guest task.

Our philosophy is to make absolutely everything parameter driven. This means the tasks never have to change. The source dictionaries and JSON lists that we source for our parameters are what we change, along with the corresponding values we offer in our service portal. We let users choose the VLAN, CPU/RAM, OS, server purpose, location (VMware instance), and backup strategy.

Walter

---

<div class="post-metadata">

**Author:** ![Rai\_Ner](https://avatars.discourse-cdn.com/v4/letter/r/35a633/32.png) [@Rai\_Ner](https://forum.ansible.com/u/Rai_Ner)\
**Post date:** [October 13, 2022, 6:46am UTC](https://forum.ansible.com/t/loop-through-list/37210/3 "2022-10-13T06:46:43Z")

</div>

Hi, Walter Rowe,  
thanks for your provided solution. For sure I will have a closer look at it.  
Rainer

---

<div class="post-metadata">

**Author:** ![Walter\_Rowe](https://sea1.discourse-cdn.com/ansible/user_avatar/forum.ansible.com/walter_rowe/32/4506_2.png) [@Walter\_Rowe](https://forum.ansible.com/u/Walter_Rowe)\
**Post date:** [October 13, 2022, 12:56pm UTC](https://forum.ansible.com/t/loop-through-list/37210/4 "2022-10-13T12:56:35Z")

</div>

Your other option is to look up a properly described disk list in a dictionary before you run vmware\_guest and use that disk list in vmware\_guest as you create the new machine. You need to specify all the attributes required.

Walter Rowe
