'before and after regex in replace block - caret isn't working as expected

Very difficult to understand ansible behavior. I'm trying to edit my /etc/postfix/master.cf file to turn on the submission block.

I copied the file to /tmp as I'm working on it, so my simple Ansible playbook should be:

- name: Edit the master.cf file
  replace:
    path: /tmp/master.cf
    after: '^#tlsproxy'
    before: '^#smtps'
    regexp: '^#(.*)$'
    replace: '\1'

But this doesn't work. It does work if I make one change, which is taking out the caret ^ in the before and after fields. This makes ... no sense to me at all. What makes even less sense, if I use:

after: '^#'

amazingly, it will do what I expect and uncomment all the lines after the first commented line.

But:

after: '^#t'

suddenly stops matching anything. I've read the Python page on regex and yet I'm baffled by this.

Any ideas? The playbook will work fine without the carets but I want to do this really correctly and match exactly what I want to match.

Thanks!



Solution 1:[1]

Ansible's replace module: uses DOTALL, which means the . special character can match newlines.

When you specify after: '^#tlsproxy', that caret is really saying: 'from the beginning of the search string, immediately followed by #tlsproxy', where the caret effectively means from the beginning of the file.

Ansible tries to match this:

"Pattern for before/after params did not match the given file: ^#tlsproxy(?P<subsection>.*?)^#smtps"

With re.DOTALL, if you want to match the patterns from the beginning of a line, use a newline character instead:

- name: Edit the master.cf file
  replace:
    path: master.cf
    after: '\n#tlsproxy'
    before: '\n#smtps'
    regexp: '^#(.*)$'
    replace: '\1'

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 jeroenflvr