regexreplaceansibletoml

Ansible lineinfile and replace modules, attempting to configure toml txt file


I have been trying to update configuration settings in a pi-hole.toml file.

After attempting lineinfile, it landed me on the replace module as the more appropriate to use. But I haven't had any luck with getting either to work.

Here's what I have so far in my replace module call. If the toml file is set to the default value of domain = "pi.hole"(leading whitespace intentional), it seems to think it's ok, and makes no changes. I would expect it to ensure the regexp match also matches the replace.;

- name: Configure pihole.toml settings.
  ansible.builtin.replace:
    path: /etc/pihole/pihole.toml
    regexp: "{{ item.regexp }}"
    replace: "{{ item.replace }}"
    after: "{{ item.after }}"
    before: "{{ item.before }}"
  loop:
    - { 
        regexp: '^  domain =.*$',
        replace: '  domain = "{{ pi_hole_domain }}" ### CHANGED, default = "pi.hole"',
        after: '^\[webserver\]$',
        before: '^  \[webserver.session\]'
      }

I have also tried this, having it specifically look for the default value of domain = "pi.hole", assuming if found, it would force a replace. But I get the same behavior. Ansible thinks it's ok, and makes no changes;

- name: Configure pihole.toml settings.
  ansible.builtin.replace:
    path: /etc/pihole/pihole.toml
    regexp: "{{ item.regexp }}"
    replace: "{{ item.replace }}"
    after: "{{ item.after }}"
    before: "{{ item.before }}"
  loop:
    - { 
        regexp: '^  domain = "pi\.hole".*$',
        replace: '  domain = "{{ pi_hole_domain }}" ### CHANGED, default = "pi.hole"',
        after: '^\[webserver\]$',
        before: '^  \[webserver.session\]'
      }

Here's the default pihole.toml file for reference: https://github.com/pi-hole/FTL/blob/master/test/pihole.toml, and the relevant part I want changed would be:

# Some other sections and configurations here

[webserver]
  # On which domain is the web interface served?
  #
  # Possible values are:
  #     <valid domain>
  domain = "pi.hole"

  # Some other configurations here

  [webserver.session]
 
  # Some other configurations here

I've been reading over other Questions/Answers, tried numerous other solutions, and checked with a couple AIs, but nothing I'm finding seems to line up with the behavior I'm seeing in my attempts. Thinking I'm overlooking something really simple, and just not seeing it :)

SOLUTION: Based on the multiline mode snag, here's the solution that ended up working best for me:

- name: Configure pihole.toml settings.
  ansible.builtin.replace:
    path: /etc/pihole/pihole.toml
    regexp: "{{ item.regexp }}"
    replace: "{{ item.replace }}"
    after: "{{ item.after }}"
    before: "{{ item.before }}"
  loop:
    - { 
        regexp: '^  domain = "pi\.hole".*$',
        replace: '  domain = "{{ pi_hole_domain }}" ### CHANGED, default = "pi.hole"',
        after: '(?m)^\[webserver\]$',
        before: '  \[webserver.session\]'
      }

The regex parameter does support multiline mode by default. And through some trial and error, it seems you can enable multiline mode for the after parameter by using the multiline mode flag (?m), but the before parameter does not appear to support the multiline mode flag.


Solution

  • As pointed out in the manual of the replace module neither after nor before is using multiline. So ^ and $ does not represent the beginning or end of the line but of the whole file.

    Does not use MULTILINE, so ^ and $ will only match the beginning and end of the file.

    Reference: in both after and before parameters descriptions.


    So, here would be the task achieving what you are looking for:

    - name: Configure pihole.toml settings.
      ansible.builtin.replace:
        path: /etc/pihole/pihole.toml
        regexp: "{{ item.regexp }}"
        replace: "{{ item.replace }}"
        after: "{{ item.after }}"
        before: "{{ item.before }}"
      loop:
        - regexp: '^  domain =.*$'
          replace: '  domain = "{{ pi_hole_domain }}" ### CHANGED, default = "pi.hole"'
          after: '\[webserver\]'
          before: '  \[webserver.session]'