Search code examples
regexansiblejinja2

Ansible, junja2 and setting single quotes around a value with ansible.builtin.replace


I want to make sure there are single quotes around the relation_regex defined regular expression (configuring datadog postgres module with ansible).

This is what I am aiming at:

conf.yml:

instances:
-   dbname: dbname
    host: localhost
    password: password
    port: 5432
    username: datadog
    relations:
      - relation_regex: '.*'
        relkind:
        - r
        - i
        - S
        - p

This is where I am with the ansible task:


- name: Properly configure any regexp expression in a configuration file
  ansible.builtin.replace:
    path: "/etc/datadog-agent/conf.d/{{ item }}.d/conf.yaml"
    regexp: '(\s+relation_regex:)\s+(?:['']*([^'']*))'
    replace: '\g<1> ''\g<2>'''
  with_items: "{{ datadog_checks|list }}"
  notify: restart datadog-agent

Yet, this is what is produced:


.. cut ..
-      - relation_regex: .*
+      - relation_regex: '.*
.. cut ..

Ansible does not provide the ending single quote ('). Feels like a bug but perhaps there is something wrong with my lookaround regex which has odd consequences?

Versions:

ansible [core 2.11.1] 
  python version = 3.8.10 (default, Mar 15 2022, 12:22:08) [GCC 9.4.0]
  jinja version = 3.0.1
  libyaml = True

Solution

  • You omitted the next line of that "diff" output that would have been a dead giveaway of the problem:

    -    - relation_regex: .*
    +    - relation_regex: '.*
    +'
    

    which indicates that your "any character except '" needs to be more specific, saying "any character except ' or EOL characters"

    - name: Properly configure any regexp expression in a configuration file
      ansible.builtin.replace:
        path: "/etc/datadog-agent/conf.d/{{ item }}.d/conf.yaml"
        regexp: '(\s+relation_regex:)\s+(?:['']*([^''\r\n]*))'
        replace: '\g<1> ''\g<2>'''
      with_items: "{{ datadog_checks|list }}"
      notify: restart datadog-agent
    

    Also, while this isn't what you asked, you are making things harder on yourself than necessary with the single-quoted scalar containing single quoted escapes since there's (currently) nothing yaml-sensitive in those scalars that needs quoting:

    - name: Properly configure any regexp expression in a configuration file
      ansible.builtin.replace:
        path: "/etc/datadog-agent/conf.d/{{ item }}.d/conf.yaml"
        regexp: (\s+relation_regex:)\s+(?:'*([^'\r\n]*))
        replace: \g<1> '\g<2>'
      with_items: "{{ datadog_checks|list }}"
      notify: restart datadog-agent
    

    You'll also want to be cautious because as written your replace will fail to harmonize existing single quoted items, causing idempotency failures if you run that task twice

    - name: Properly configure any regexp expression in a configuration file
      ansible.builtin.replace:
        path: "/etc/datadog-agent/conf.d/{{ item }}.d/conf.yaml"
        regexp: (\s+relation_regex:)\s+(?:'*([^'\r\n]*)'*)
        replace: \g<1> '\g<2>'
      with_items: "{{ datadog_checks|list }}"
      notify: restart datadog-agent