3

I spent a bit of time today trying to write some Ansible plays to only run commands if the corresponding lines weren't present in the relevant command output. After a bit of trial & error I've got something that works for me, but I'm not clear as to why my initial comparison with an empty string doesn't work.

Here is a playbook demonstrating my problem:

- name: test
  hosts: localhost
  tasks:
  - shell: "cat /tmp/cmdoutput"
    register: cmdoutput

  - debug: var=filtered_output
    vars:
      filtered_output: "{{ cmdoutput.stdout | regex_search(item) }}"
    with_items:
      - "aa .* xx"
      - "bb .* yy"

  - debug: msg="do action that inserts {{ item }}"
    with_items:
      - "aa .* xx"
      - "bb .* yy"
    when: cmdoutput.stdout | regex_search(item) == ""

  - debug: msg="do action that inserts {{ item }}"
    with_items:
      - "aa .* xx"
      - "bb .* yy"
    when: not cmdoutput.stdout | regex_search(item)
cat /tmp/cmdoutput
aa b c d xx
aa f g h yy
bb i j k xx

This results in the following output:

$ ansible-playbook test.yml 
 [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'


PLAY [test] **********************************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************************
ok: [localhost]

TASK [shell] *********************************************************************************************************************
changed: [localhost]

TASK [debug] *********************************************************************************************************************
ok: [localhost] => (item=None) => {
    "filtered_output": "aa b c d xx"
}
ok: [localhost] => (item=None) => {
    "filtered_output": ""
}

TASK [debug] *********************************************************************************************************************
skipping: [localhost] => (item=None) 
skipping: [localhost] => (item=None) 

TASK [debug] *********************************************************************************************************************
skipping: [localhost] => (item=None) 
ok: [localhost] => (item=None) => {
    "msg": "do action that inserts bb .* yy"
}

PLAY RECAP ***********************************************************************************************************************
localhost                  : ok=4    changed=1    unreachable=0    failed=0   

i.e. "filtered_output": "", but the following when comparison doesn't match.

So my questions are:

  • why doesn't the second debug when condition match ""?
  • what type of object is the output of the regex_search? - a string or an array or something else?
  • is there any, or where could I find more info on the regex_search filter? - (at this point in time AFAICT) it's not in the jinja doco and only appears in the filters section of the official docs as brief examples

My Ansible version: 2.5.1

Thanks

lambfrier
  • 625
  • 8
  • 13

1 Answers1

3

To answer your question

why doesn't the second debug when condition match ""?

When there is no regex match object of type 'NoneType' is returned. This type has no length. Instead of testing empty string ( off-topic see E602)

when: cmdoutput.stdout|regex_search(item) == ""

use (you already have it in your example).

when: not cmdoutput.stdout|regex_search(item)
Vladimir Botka
  • 39,879
  • 4
  • 23
  • 43
  • So I guess one of the problems was my interpretation of the "filtered_output": "" debug line above. The output is an empty string because it's cast to a String due to the quotes. I had seen a [bug report for E602](https://github.com/ansible/ansible-lint/issues/457) but my quick read was that empty string comparison was needed in some cases, which was not quite the point. I had also tried piping to length, but got 'condition object of type 'NoneType' has no len()' errors. Your answer clarifies why - thanks. I guess part of my question was how to easily see this NoneType object. – lambfrier Mar 22 '19 at 01:56