Regexp matching with replace module, but not with lineinfile

Hi,

I’m a newbie with Ansible, and I have a problem.

First, I use version 1.8.2, stock, without anything added.

Then, I want to configure /etc/network/interfaces file with Ansible, so I need to work with regexp to do what I want.

My goal is to add or rewrite some bridges configuration in that file.

I use this :

  • name: Configure /etc/network/interfaces
    lineinfile:
    dest: /etc/network/interfaces
    regexp: ‘[\r\n](# DO NOT TOUCH BEGIN[\n\r])?auto[ \t]+{{ item.if }}[ \t][\n\r](?:[ \t].[\n\r])?[ \t]bridge_maxwait[ \t]+0[ \t]([\n\r]# DO NOT TOUCH END[\n\r])?’
    line: |

DO NOT TOUCH BEGIN

auto {{ item.if }}
iface {{ item.if }} inet static
address {{ item.ip }}{{ ipconfig.stdout|trim }}
netmask 255.255.0.0
bridge_ports none
bridge_stp off
bridge_fd 0
bridge_maxwait 0

DO NOT TOUCH END

with_items: vlans
register: interface_configured

I want to add the “DO NOT TOUCH” for existing bridges too, and of course create lines for non-existing ones.

You can test regexp here : https://regex101.com/r/sK7iF0/1

We can see that for example, it matches for vmbr10.

Instead of replacing those lines, Ansible lineinfile add the line at the end of file :

DO NOT TOUCH BEGIN

auto vmbr10
iface vmbr10 inet static
address 10.111.0.2
netmask 255.255.0.0
bridge_ports none
bridge_stp off
bridge_fd 0
bridge_maxwait 0

DO NOT TOUCH END

If I change “lineinfile” and “line” with “replace” and “replace”, it works ! It replaces the matched result, but of course it does not add lines when bridge does not exists :frowning:

I see in documentation that replace module is working with “multiline” regexp, but if I force multiline mode in lineinfile adding “(?m)” at the beginning, it does not work better… :frowning:

Is someone understanding what is my problem ? And how can I do it better :slight_smile:

Thank you a lot.

Alas, not much time to help debug a regex.

It is said:

There was a man who had a problem. He tried to solve it with a regex. Now the man had two problems.

I generally like to use the “template” module whenever I can, as Ansible’s ethos is generally “keep things simple” wherever possible.

Lineinfile only really makes sense when there is no other way, and even then, sed can occasionally be an easier thing to master. I’m not a great fan of the module, to be honest. Others like it though, so it stays :slight_smile:

Hi all,

This thread has breathed some calm into me, I was about to throw a fit. I have a similar problem which I can’t seem to resolve in an idempotent way.
Long story short, I need to ensure that a stanza is in an xml file, which is generated on the fly with some variables. I need logic that says :
If the stanza is not there, add it as the variables generate it
else if the stanza is there but is different, replace it
else
DO NOTHING !

I can get Ansible to do the first case, but it keeps adding lines OR I can get Ansible to do the last case if the stanza is there, but doesn’t add it if it’s not.

Since I’ve been using Ansible for a while now and am - how you say ? in love - however, as with all great relationships there are these little things that you just wish would work how you want.

I want a “linesinfile” module that works like the logic above. The declaration “these lines should be in this file” must be kept.

I generally like to use the “template” module whenever I can, as Ansible’s ethos is generally “keep things simple” wherever possible.

In this case, I can’t use a template (easily), because I’m making checks on an xml file which is generated on the fly. For the curious, it’s the idp metadata of a shibboleth Identity Provider.
The only way I thought of was to fetch the file, turn it into a template, add the relevant lines locally and then template that to the remote file. but that seemed very contorted and too “procedural” to be idempotent.

Lineinfile only really makes sense when there is no other way, and even then, sed can occasionally be an easier thing to master. I’m not a great fan of the module, to be honest. Others like it though, so it stays :slight_smile:

I really like lineinfile, but the behaviour in this case is quite frustrating. Not that I’m recommending it change, just wanted to share my experience.

Ok, I have resolved this problem in the following way :

I’ve created a variable containing a list of the lines I want (metadata_lines)

I then do a lineinfile with a loop (with_items) on the contents of the variable.

I haven’t tested this to be idempotent even on human intervention, but it does what we need for now, that is ensure that an XML stanza is in the right file in the right place.

Thanks,
Bruce

(attachments)