Replacing line using lineinfile results in multiple insertions even when line isn't present

Hello,

I am working on a playbook that would automatically add a bridge network device to /etc/network/interfaces (on Debian-based distributions); this new interface should replace the existing config for the specified ethX port (e.g. eth0).

Before playbook:

The loopback network interface

auto lo
iface lo inet loopback

auto eth0

iface eth0 inet dhcp

After playbook:

The loopback network interface

auto lo
iface lo inet loopback

bridge interface for kvm

auto br0
iface br0 inet dhcp
bridge_ports eth0
bridge_stp on
bridge_fd 0

I have a variable, interface_num, defined to specify which eth device entry to modify, e.g. this example would replace settings for eth0 with br0:

interface_comment: ‘# bridge interface for kvm’
interface_num: 0

Ideally I’d just match the two eth0 lines above and replace them with the 5 br0 lines using a single task, however added \n to the task appeared to make it no longer match. I did get it working using the following tasks, which first replaces the “auto eth0” line with a comment, then deletes the “iface eth0 inet dhcp” line, and finally uses the inserted comment as an anchor to insert each br0 line:

  • name: remove existing ethX in /etc/network/interfaces (part 1)
    tag: networking
    lineinfile: dest=/etc/network/interfaces
    backup=yes
    regexp=“^auto eth${interface_num}$”
    line=‘${interface_comment}’
    state=present

  • name: remove existing ethX in /etc/network/interfaces (part 2)
    tag: networking
    lineinfile: dest=/etc/network/interfaces
    backup=no
    regexp=‘^iface eth${interface_num} inet [a-z]+$’
    state=absent

  • name: add bridge interface to /etc/network/interfaces
    tag: networking
    lineinfile: dest=/etc/network/interfaces
    backup=no
    regexp=‘${item}’
    line=‘${item}’
    insertafter=‘${interface_comment}’
    state=present

insert the new bridge interface; the following lines must be in reverse order

with_items:

  • ’ bridge_fd 0’
  • ’ bridge_stp on’
  • ’ bridge_ports eth${interface_num}’
  • ‘iface br${interface_num} inet dhcp’
  • ‘auto br${interface_num}’
    notify: restart networking

This works, however if I run the playbook multiple times on the system, each time after the initial play the “remove existing ethX in /etc/network/interfaces (part 1)” task adds a new comment at the end of the file. Thus, running it 4 times would result in the following file:

The loopback network interface

auto lo
iface lo inet loopback

bridge interface for kvm

auto br0
iface br0 inet dhcp
bridge_ports eth0
bridge_stp on
bridge_fd 0

bridge interface for kvm

bridge interface for kvm

bridge interface for kvm

Can someone help me determine why this task seems to be matching, even when “auto eth0” does not exist in the file, or do you have a suggestion about a better way to do this? I don’t want to use a template in this case because I don’t know if there will be other interfaces present in the file and prefer to just replace the lines associated with the desired interface.

Thanks,

Andrew Martin

Any ideas on why this is occurring?

Thanks!

Andrew

Because, related to the first task that’s the way lineinfile works.
If no match found but state=present the ‘line’ will be added

to avoid this just add

backrefs=yes

to the first task.

HTH

Phil.