search a string in ansible when condition over loop

Viewed 1854

Team, I want to loop on sda devices only excluding loop devices so I am trying to compare a part of string if it exists in key that is from ansible_devices item variable and stuck at syntax error.

I want to print msg only on WHEN condition Is met. basically, I want to only msg print when there is substring loop in the key.

I have below sample output and I am able to retrieve it but now I want to compare it with some string but failing, as marked #fails in task

values.yml

loop_device: "loop"

task.yaml

  debug:
    msg: "{{ ansible_hostname }} {{ item }} {{ ansible_devices[item]['partitions'] }}"
  when:
    - "not ansible_devices[item] is search('loop')" #fails
    - ansible_devices[item]['partitions'] is mapping #works
    - ansible_devices[item]['partitions'] | length == 0 #works
  with_items: "{{ ansible_devices }}"

output error:

 TASK [local_volume_mount : Print device partitions that are defined using mapping] ***
17:14:23  Tuesday 27 April 2021  
17:14:23  fatal: [node1]: FAILED! => {"msg": "The conditional check 'not ansible_devices[item] is search('loop')' failed. The error was: Unexpected templating type error occurred on ({% if not ansible_devices[item] is search('loop') %} True {% else %} False {% endif %}): expected string or bytes-like object\n\nThe error appears to be in '/ansible-managed/jenkins-slave/slave0/workspace/run_ansible_playbook/k8s/baremetal/roles/local_volume_mount/tasks/main.yml': line 24, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Print device partitions that are defined using mapping\n  ^ here\n"}

sample ansible_Devices is below

ok: [node1] => {
       "ansible_devices": {
           "loop0": {
               "holders": [],
               "host": "",
               "links": {
                   "ids": [],
                   "labels": [],
                   "masters": [],
                   "uuids": []
               },
               "model": null,
               "partitions": {},
               "removable": "0",
               "rotational": "1",
               "sas_address": null,
               "sas_device_handle": null,
               "scheduler_mode": "none",
               "sectors": "0",
               "sectorsize": "512",
               "size": "0.00 Bytes",
               "support_discard": "0",
               "vendor": null,
               "virtual": 1
           },
          "sda2": {
               "holders": [],
               "host": "",
               "links": {
                   "ids": [],
                   "labels": [],
                   "masters": [],
                   "uuids": []
               },
               "model": null,
               "partitions": {},
               "removable": "0",
               "rotational": "1",
               "sas_address": null,
               "sas_device_handle": null,
               "scheduler_mode": "none",
               "sectors": "0",
               "sectorsize": "512",
               "size": "0.00 Bytes",
               "support_discard": "0",
               "vendor": null,
               "virtual": 1
           },


output is still printing loop device

  ok: [node1] => (item=loop0) => {
      "msg": "node1 loop0 {}"
  }
  ok: [node1] => (item=loop0) => {
      "msg": "node1 sda2 {}"
  }

I even tried below combos

    - '"loop" not in ansible_devices[item]'
    - ansible_devices[item] is not match("loop")
    - ansible_devices[item] is not search("loop")

tried answer 1 below

- debug: after entering loop efficient
    msg: "{{ ansible_hostname }} {{ item.key }} {{ item.value.partitions }}"
  when:
    - item.key is not search('loop')
    - item.value.partitions is mapping
    - item.value.partitions | length == 0
  loop: "{{ ansible_devices | dict2items }}"
  with_dict: "{{ ansible_devices }}"

error output for Answer1 with dict2items

 ERROR! Syntax Error while loading YAML.
    mapping values are not allowed here
  
  The error appears to be in '/ansible-managed/jenkins-slave/slave0/workspace/run_ansible_playbook/k8s/baremetal/roles/local_volume_mount/tasks/main.yml': line 25, column 8, but may
  be elsewhere in the file depending on the exact syntax problem.
  
  The offending line appears to be:
  
  - debug: after entering loop efficient
      msg: "{{ ansible_hostname }} {{ item.key }} {{ item.value.partitions }}"
         ^ here
  We could be wrong, but this one looks like it might be an issue with
  missing quotes. Always quote template expression brackets when they
  start a value. For instance:
  
      with_items:
        - {{ foo }}
  
  Should be written as:
  
      with_items:
        - "{{ foo }}"
2 Answers

Quick fix => item is not search('loop')

Since you use with_items on a dict, only the list of its keys is returned in the loop. Thus item is the key you want to search on.

Meanwhile, there is a much more efficient way to loop over your dictionaries which will return an element containing both the key and the value.

  • Historical syntax: with_dict: "{{ ansible_devices }}"
  • New syntax: loop: "{{ ansible_devices | dict2items }}"

See: https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html

in your case this would give:

- debug:
    msg: "{{ ansible_hostname }} {{ item.key }} {{ item.value.partitions }}"
  when:
    - item.key is not search('loop')
    - item.value.partitions is mapping
    - item.value.partitions | length == 0
  loop: "{{ ansible_devices | dict2items }}"

We can actually go a step further and filter out most of the elements from the dict before we even start to loop. We still need to check the length in a when clause as this can't be calculated easily during filtering

- debug:
    msg: "{{ ansible_hostname }} {{ item.key }} {{ item.value.partitions }}"
  when: item.value.partitions | length == 0
  loop: >-
    {{
      ansible_devices
      | dict2items
      | rejectattr('key', 'search', 'loop')
      | selectattr('value.partition', 'mapping')
      | list
    }}

figured it out after several combinations.

- '"loop" not in item' or

define in values.yml

loop_device_substring: "loop"

task.yaml

- '"{{ loop_device_substring }}" not in item'

below is complete task with one option commented.

- name: "Print device partitions that are Null and not a loop device"
  debug:
    msg: "{{ ansible_hostname }} {{ item }} {{ ansible_devices[item]['partitions'] }}"    
  when:
    - ansible_devices[item]['partitions'] | length == 0
    - ansible_devices[item]['partitions'] is mapping
    - '"loop" not in item'
    #- '"{{ loop_device_substring }}" not in item'
  with_items: "{{ ansible_devices }}"

output

  skipping: [node1] => (item=loop0) 
 ok: [node1] => (item=sda2) => {
      "msg": "node1 sda2 {}"
  }
Related