'Ansible: lineinfile module using regexp and backrefs

I am trying to ensure that a line ends with 'audit=1"'. The before state is:

GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=vg00/lv_root rhgb quiet"

The after state should be:

GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=vg00/lv_root rhgb quiet audit=1"

Working with the Ansible lineinfile module I can add that statement if its missing, but repeated runs keep appending 'audit=1"' even if it's present. I have been playing with the regexp and negative look-ahead assertions, and just cannot get the syntax correct.

Here is example play I have:

  - name: grub - adjust
    lineinfile:
      path: /home/vwadmin/grub-test
      regexp: '(GRUB_CMDLINE_LINUX=.*)"(?!audit=1")'
      line: '\1 audit=1"'
      backrefs: yes
      state: present

Edit: Using Pacifist's suggestion I have a working solution. Confirmed to add my audit=1 statement if missing, and do nothing if present.

  - name: grub - check
    shell: grep -c 'audit' /etc/default/grub
    register: grub_file
    ignore_errors: true

  - name: grub - adjust
    lineinfile:
      path: /etc/default/grub
      regexp: '(GRUB_CMDLINE_LINUX=.*)"'
      line: '\1 audit=1"'
      backrefs: yes
      state: present
    when: grub_file.stdout == "0"

Note: I can't help but feel the reason I couldn't get it working without a pre-step, and why it doesn't work properly with check_mode, is that the negative look-ahead is not defined correctly for this case. From what I understand, the regexp match should fail when the negative look-ahead succeeds, which should cause the module to not take action. Looking at another example of this on GG I am wondering if root issue is the greedy nature of the .* wildcard in the first group match. /shrug



Solution 1:[1]

i wanted to do something similar with console kernel options and ended up with this:

- name: "Ensure console kernel options are set"
  lineinfile:
    path: /etc/default/grub
    regexp: ^GRUB_CMDLINE_LINUX=\"(?P<defaults>.*?)\s*(?P<console> console=.*)?\"$
    line: GRUB_CMDLINE_LINUX="\g<defaults> {{ kernel_console }}"
    backrefs: yes
  register: grub_changed

- name: "Rebuild grub"
  command: grub2-mkconfig –o /boot/grub2/grub.cfg >/dev/null
  when:
    - grub_changed.changed

the key part of the regexp is (?P<defaults>.*?): the last question mark - which makes the match less greedy, allows the optional console=.* to be picked up without continually appending another console to the end of the line in the line as it did with your audit. main issue is that it assumes that its always the last (set of) options in the line and i always end up with a white space if there is no console defined. but it works!

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 yee379