Search code examples
ansiblejinja2

How escape : in a when conditional


I'm trying to loop a list and using a when, but if the when has : the Lint fails.

For example:

---
- name: Check variable starts with substring
  hosts: all
  tasks:
    - name: Verify variable
      ansible.builtin.debug:
        msg: "{{ item }}"
      when: item.startswith('Model : ')
      with_items:
        - "Model : Server 1"
        - "Other Item"
        - "Model : Server 2"

returns this error because of the ::

user@server~$ ansible-lint test.yml
syntax-check: Ansible syntax check failed.
test.yml:1 ERROR! We were unable to read either as JSON nor YAML, these are the errors we got from each:
JSON: Expecting value: line 1 column 1 (char 0)

Syntax Error while loading YAML.
  mapping values are not allowed in this context

The error appears to be in '/home/user/test.yml': line 8, column 36, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

        msg: "{{ item }}"
      when: item.startswith('Model : ')
                                   ^ here



Finished with 1 failure(s), 0 warning(s) on 1 files.
user@server~$

If I include the global when as variable:

---
- name: Check variable starts with substring
  hosts: all
  tasks:
    - name: Verify variable
      ansible.builtin.debug:
        msg: "{{ item }}"
      when: "{{ item.startswith('Model : ') }}"
      with_items:
        - "Model : Server 1"
        - "Other Item"
        - "Model : Server 2"

The Lint doesn't validate it either:

user@server~$ ansible-lint test.yml
no-jinja-when: No Jinja2 in when.
test.yml:5 Task/Handler: Verify variable

You can skip specific rules or tags by adding them to your configuration file:
# .config/ansible-lint.yml
warn_list:  # or 'skip_list' to silence them completely
  - no-jinja-when  # No Jinja2 in when.

Finished with 1 failure(s), 0 warning(s) on 1 files.
user@server~$

How could I scape that :?


Solution

  • Put the pattern into a variable. For example,

        - debug:
            msg: "{{ item }}"
          when: item.startswith(pattern)
          with_items:
            - 'Model : Server 1'
            - 'Other Item'
            - 'Model : Server 2'
          vars:
            pattern: 'Model :'
    

    gives

    ok: [test_01] => (item=Model : Server 1) => 
      msg: 'Model : Server 1'
    skipping: [test_01] => (item=Other Item) 
    ok: [test_01] => (item=Model : Server 2) => 
      msg: 'Model : Server 2'
    

    Optionally, use match instead of startswith and select items. Quoting:

    match succeeds if it finds the pattern at the beginning of the string

        - debug:
            msg: "{{ item }}"
          loop: "{{ data|select('match', pattern) }}"
          vars:
            pattern: 'Model :'
            data:
              - 'Model : Server 1'
              - 'Other Item'
              - 'Model : Server 2'
    

    gives

    ok: [test_01] => (item=Model : Server 1) => 
      msg: 'Model : Server 1'
    ok: [test_01] => (item=Model : Server 2) => 
      msg: 'Model : Server 2'
    

    Example of a complete playbook for testing

    - hosts: all
    
      tasks:
    
        - debug:
            msg: "{{ item }}"
          when: item.startswith(pattern)
          with_items:
            - 'Model : Server 1'
            - 'Other Item'
            - 'Model : Server 2'
          vars:
            pattern: 'Model :'
    
        - debug:
            msg: "{{ item }}"
          loop: "{{ data|select('match', pattern) }}"
          vars:
            pattern: 'Model :'
            data:
              - 'Model : Server 1'
              - 'Other Item'
              - 'Model : Server 2'