Need help parsing output from VMware collection

I’m trying to use the community.vmware collection to automate the creation of a number of VMs (fine with that bit), where I am coming unstuck is parsing the output of community.vmware.vmware_datastore_info

“datastores”: [
{
“name”: “datastore1”,
“summary”: {
“_vimtype”: “vim.Datastore.Summary”,
“accessible”: true,
“capacity”: 119990648832,
“datastore”: “vim.Datastore:656bd379-a008a098-6ed8-d05099c155c9”,
“freeSpace”: 84916830208,
“maintenanceMode”: null,
“multipleHostAccess”: null,
“name”: “datastore1”,
“type”: “VMFS”,
“uncommitted”: 3793282394,
“url”: “/vmfs/volumes/656bd379-a008a098-6ed8-d05099c155c9”
}
},
{
“name”: “datastore2”,
“summary”: {
“_vimtype”: “vim.Datastore.Summary”,
“accessible”: true,
“capacity”: 239981297664,
“datastore”: “vim.Datastore:656bd392-48951fa8-1f7f-d05099c155c9”,
“freeSpace”: 238469251072,
“maintenanceMode”: null,
“multipleHostAccess”: null,
“name”: “datastore2”,
“type”: “VMFS”,
“uncommitted”: 0,
“url”: “/vmfs/volumes/656bd392-48951fa8-1f7f-d05099c155c9”
}
}
]

---
# find free space on cluster datastores
- name: Retrieve information on free space in each datastore
  community.vmware.vmware_datastore_info:
    hostname: "{{ '<host>>' }}"
    username: "{{ 'root' }}"
    password: "{{ '<password>>' }}"
    validate_certs: False
    schema: vsphere
    properties:
      - name
      - summary
  delegate_to: localhost
  register: info

- name: datastore info output
  ansible.builtin.debug:
    msg="{{ info }}"
#    msg="{{ info | type_debug}}"

So the output is of type “dict” but I can’t seem identify the correct syntax to extract the fields i want from the output. I want to extract the datastore name and the available free space to evaluate whether I have enough free space to deploy on that datastore (make sense?).

Can someone who knows what their doing point me the in the right direction, or offer some example code?

I tried using map to pull the relevant fields but I can’t make this work, there is a gap in my understanding…

Like this:

$ cat newbie01.yml
---
# newbie01.yml
- name: Result stuff
  hosts: localhost
  gather_facts: false
  vars:
    info:
      "datastores": [
        {
        "name": "datastore1",
        "summary": {
        "_vimtype": "vim.Datastore.Summary",
        "accessible": true,
        "capacity": 119990648832,
        "datastore": "vim.Datastore:656bd379-a008a098-6ed8-d05099c155c9",
        "freeSpace": 84916830208,
        "maintenanceMode": null,
        "multipleHostAccess": null,
        "name": "datastore1",
        "type": "VMFS",
        "uncommitted": 3793282394,
        "url": "/vmfs/volumes/656bd379-a008a098-6ed8-d05099c155c9"
        }
        },
        {
        "name": "datastore2",
        "summary": {
        "_vimtype": "vim.Datastore.Summary",
        "accessible": true,
        "capacity": 239981297664,
        "datastore": "vim.Datastore:656bd392-48951fa8-1f7f-d05099c155c9",
        "freeSpace": 238469251072,
        "maintenanceMode": null,
        "multipleHostAccess": null,
        "name": "datastore2",
        "type": "VMFS",
        "uncommitted": 0,
        "url": "/vmfs/volumes/656bd392-48951fa8-1f7f-d05099c155c9"
        }
        }
        ]
  tasks:
    - name: Show names, freeSpace
      ansible.builtin.debug:
        msg: '{{ item }}'
      loop:
        - '{{ info.datastores | map(attribute="name") |
           zip(info.datastores | map(attribute="summary.freeSpace")) }}'

$ ansible-playbook newbie01.yml
PLAY [Result stuff] ********************************************************************************************

TASK [Show names, freeSpace] ********************************************************************************************
ok: [localhost] => (item=[['datastore1', 84916830208], ['datastore2', 238469251072]]) => {
    "msg": [
        [
            "datastore1",
            84916830208
        ],
        [
            "datastore2",
            238469251072
        ]
    ]
}

PLAY RECAP **********************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Or another way to say it is:

if info.datastores[0].summary.freeSpace > lower_limit:
    deploy_on(info.datastores[0].name)

That’s pseudo-code, but the expression is right.

1 Like

Thank you Sir! You’ve been a big help to me, much appreciated!

2 Likes

Next stupid question, how do I loop through every value in the dictionary “index”

e.g. info.datastores[0].name
info.datastores[0].summary.freeSpace

until:
info.datastores[n].name
info.datastores[n].summary.freeSpace

where n is the final integer in the index ?

I want to be able to examine every datastore for free space and also only deploy on a select set of datastores whose name corresponds to a particular pattern…

i.e.

How do I translate this example in the ansible documentation to my particular use case:

  • name: Count our fruit
    ansible.builtin.debug:
    msg: “{{ item }} with index {{ my_idx }}”
    loop:
    • apple
    • banana
    • pear
      loop_control:
      index_var: my_idx

I’d do something like this maybe:

    - name: Conditional deploy on datastore
      ansible.builtin.include_tasks:
        file: deploy_on_datastore.yml
      vars:
        min_free_space: 4916830208
      when:
        - datastore.summary.freeSpace > min_free_space
        - datastore['summary']['type'] == 'VMFS'      # another way to address "summary"
        - datastore.name is regex("^data.*[13579]$")  # odd-numbered datastore#
        - datastore.name is regex("a.t.*e")           # another arbitrary conditon
      loop: '{{ info.datastores }}'
      loop_control:
        loop_var: datastore

I’m having the same problem need help with zos JCL output trying to do a fine on the sis out

Please be more specific. Show the data, and perhaps what you’ve tried so far.

This should be able to be done with filters
required_space being how much you need

"{{ info.datastores | selectattr('summary.freeSpace', 'gt' , required_space) | map(attribute='name') | first }}"

That should select the first one it finds that is large enough.
You could also throw in a sort to get the datastore with the most available space.

"{{ info.datastores | sort(attribute='summary.freeSpace', reverse=true) | selectattr('summary.freeSpace', 'gt' , required_space) | map(attribute='name') | first }}"

I ran a test against one of our datacenters:

- name: Name
  hosts: thathost
  gather_facts: false
  tasks:
    - name: Retrieve information on free space in each datastore
      environment: "{{ vcenter_env }}"
      community.vmware.vmware_datastore_info:
        schema: vsphere
        properties:
          - name
          - summary
      delegate_to: localhost
      register: info

    - name: show total length
      ansible.builtin.debug:
        var: info.datastores | length
      
    - name: unsorted first
      ansible.builtin.debug:
        var: output
      vars:
        output:
          candidates: "{{ info.datastores | selectattr('summary.freeSpace', 'gt', 9999999999999 ) | map(attribute='summary.freeSpace') }}"
          first_num: "{{ info.datastores | selectattr('summary.freeSpace', 'gt', 9999999999999 ) | map(attribute='summary.freeSpace') | first  }}"
          first_name: "{{ info.datastores | selectattr('summary.freeSpace', 'gt', 9999999999999 ) | map(attribute='name') | first }}"
    
    - name: sorted first
      ansible.builtin.debug:
        var: output
      vars:
        output:
          candidates: "{{ info.datastores | selectattr('summary.freeSpace', 'gt', 9999999999999 ) | sort(attribute='summary.freeSpace', reverse=true) | map(attribute='summary.freeSpace') }}"
          first_num: "{{ info.datastores | selectattr('summary.freeSpace', 'gt', 9999999999999 ) | sort(attribute='summary.freeSpace', reverse=true) | map(attribute='summary.freeSpace') | first }}"
          first_name: "{{ info.datastores | selectattr('summary.freeSpace', 'gt', 9999999999999 ) | sort(attribute='summary.freeSpace', reverse=true) | map(attribute='name') | first }}"

And output:

PLAY [Name] *********************************************************************************************************************************************************************************************************************************************
Saturday 25 May 2024  11:51:14 -0400 (0:00:00.019)       0:00:00.019 ********** 

TASK [Retrieve information on free space in each datastore] *********************************************************************************************************************************************************************************************
ok: [thathost -> localhost]
Saturday 25 May 2024  11:51:22 -0400 (0:00:07.445)       0:00:07.465 ********** 

TASK [show total length] ********************************************************************************************************************************************************************************************************************************
ok: [thathost] => 
  info.datastores | length: '56'
Saturday 25 May 2024  11:51:22 -0400 (0:00:00.108)       0:00:07.573 ********** 

TASK [unsorted first] 
ok: [thathost] => 
  **output:
    candidates:
    - 28662707519488
    - 18981516738560
    - 31680767197184
    - 15031020290048
    - 10736076062720
    - 57689932562432
    first_name: AKT_500_UGN_DR_MMM
    first_num: '28662707519488'
**
Saturday 25 May 2024  11:51:22 -0400 (0:00:00.342)       0:00:07.915 ********** 

TASK [sorted first] 
ok: [thathost] => 
  **output:
    candidates:
    - 57689932562432
    - 31680767197184
    - 28662707519488
    - 18981516738560
    - 15031020290048
    - 10736076062720
    first_name: KTR_DR_FGND
    first_num: '57689932562432'
**

PLAY RECAP 
thathost        : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

Playbook run took 0 days, 0 hours, 0 minutes, 8 seconds
Saturday 25 May 2024  11:51:22 -0400 (0:00:00.229)       0:00:08.145 ********** 
===============================================================================

You can see that it filtered out 50 of our datastores based on size (I hope I never deploy any one thing that big). And you can see the differences between sorting.

That should allow you to just specify the parameter for deployment rather than looping.

1 Like