3

I have a task that creates multiple files, if they not exists. It works, until a filename is used as item that contains a pair of square brackets. I've tried to escape with backslashes and {% raw %} tags, but it does not work.

Test playbook:

---
- name: Test playbook
  hosts: localhost
  gather_facts: no

  tasks:
  - name: Testfile
    ansible.builtin.command:
      cmd: 'touch ~/{{ item }}'
    args:
      creates: "~/{{ item }}"
    with_items:
      - 'test1.txt' # works
      - 'tes[t2.txt' # works
      - 'test3].txt' # works
      - 'tes[t4].txt' # DOESNT WORK

First run:

changed: [localhost] => (item=test1.txt)
changed: [localhost] => (item=tes[t2.txt)
changed: [localhost] => (item=test3].txt)
changed: [localhost] => (item=tes[t4].txt)

Consecutive runs:

ok: [localhost] => (item=test1.txt)
ok: [localhost] => (item=tes[t2.txt)
ok: [localhost] => (item=test3].txt)
changed: [localhost] => (item=tes[t4].txt)

Folder content:

ls ~/tes*
'/home/user/tes[t2.txt'  '/home/user/tes[t4].txt'   /home/user/test1.txt   /home/user/test3].txt

Environment:

  • Ubuntu 20 (via WSL2)
  • ansible [core 2.12.1]

Is this a bug, or is there any way to escape the characters so that the task is fully idempotent?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
jan-di
  • 755
  • 7
  • 16
  • 2
    Kindof a "feature." In 2.0, `glob` was added to the `creates`. – Jack Dec 19 '21 at 02:56
  • @Jack you're right I think it's due to the `glob` *feature* of `creates`, see [my answer](https://stackoverflow.com/a/70410125/4413446) – Romain Dec 19 '21 at 09:23

1 Answers1

4

The problem is due to the fact that creates can handle glob syntax (highlighted by @Jack). In glob syntax [ has a special meaning and need to be escaped. I did manage to do it only manually by escaping the [ through this Jinja2 filter {{ item|replace('[', '[[]') }}. I did not found an equivalent convenient filter equivalent to Python glob.escape. However it works!

- name: Test playbook
  hosts: localhost
  gather_facts: no

  tasks:
  - name: Testfile
    ansible.builtin.command:
      cmd: "touch ~/{{ item }}"
    args:
      creates: "~/{{ item|replace('[', '[[]') }}"
    with_items:
      - 'test1.txt' # works
      - 'tes[t2.txt' # works
      - 'test3].txt' # works
      - 'tes[t4].txt' # DOESNT WORK

Further reading on glob escaping -> glob and bracket characters ('[]').

Romain
  • 19,910
  • 6
  • 56
  • 65