loopsansible

Ansible change variable in when condition


I would like to know if it's possible with Ansible to test 2 values in a when condition that are changed in the loop.

disksizefromjson is a variable that I extracted from a json file (and this value is being correctly changed when I remove the when condition).

item['Size'] is the variable that I extracted from a previous task with a powershell command.

---
- name: get disk info on windows vm 
  ansible.windows.win_powershell:
    script: |
      Get-ciminstance win32_volume -Filter DriveType=3 | where-object{$_.Label -notlike "*Reserved*" -and $_.SystemVolume -ne $true} | Select-Object Name, Label, FileSystem, BlockSize, @{'Name'='Size'; 'Expression'={[math]::Ceiling($_.Capacity / 1GB)}}, @{'Name'='Freespace'; 'Expression'={[math]::Ceiling($_.Freespace / 1GB)}}, @{'Name'='Free'; 'Expression'={[math]::Ceiling(($_.Freespace * 100)/$_.Capacity)}} | Sort-Object Name
  register: diskNewVm

- name: test disk size
  set_fact:
    disksizefromjson: "{{ diskinfosfromjson | from_json | selectattr('Name', 'equalto',  item['Name']) | map(attribute='Size') | first | default(10) }}"
  when: item['Size'] > disksizefromjson
  loop: "{{ diskNewVm.output }}"

This results in the following error:

The conditional check 'item['Size'] > disksizefromjson' failed. The error was: error while evaluating conditional (item['Size'] > disksizefromjson): 'disksizefromjson' is undefined

When I remove the when condition, disksizefromjson is defined well...

So, is it possible to have 2 variables in when condition?


Solution

  • So, is it possible to have 2 variables in when condition?

    Sure, you can use any number of variables there. But the error that Ansible gives you is absolutely expected because during the first iteration of your loop the disksizefromjson variable (by the way, Ansible is Python-based, so it's recommended to use the snake case notation) doesn't exist yet.

    If you know a safe default value for your case, you can simply define it using the default filter (note I used a trimmed multiline YAML string without newline preservation for a better readability of a long chain of Jinja2 filters):

    - name: test disk size
      set_fact:
        disksizefromjson: >-
          {{
            diskinfosfromjson
            | from_json
            | selectattr('Name', 'equalto',  item['Name'])
            | map(attribute='Size')
            | first
            | default(10)
          }}
      when: item['Size'] > disksizefromjson | default(10)
      loop: "{{ diskNewVm.output }}"
    

    Speaking of which, it seems like you tried to do that because you used a | default(10) inside the variable definition itself. There is another problem with your template: the default filter, as any other, doesn't work exactly as a try-catch construct, it refers to the previous value. So, in your case, it will only work if the first item of your map(attribute='Size') is undefined.