ansible

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

  • lineinfile is doing its work that is adding whatever is given in line and line is identified by your regexp. So no matter what value your setting already has, it will be overridden by your new line.

    There are two approaches that you can use :

    1. Using check_mode with failed_when.
    2. Using shell module to grep the content beforehand.

    Check_Mode (I can not get this working though but it has been recommended everywhere else):

    - name: grub - adjust
      lineinfile: 
          name: /home/vwadmin/grub-test
          regexp: '(GRUB_CMDLINE_LINUX=.*)'
          line: '\1 audit=1"'
          backrefs: yes
          state: present
       check_mode: yes
       register: presence
       failed_when: presence.changed
    

    Using grep (This one is working fine for me)

    - name: grub - adjust
      shell: grep -c 'audit' /home/vwadmin/grub-test 
      register: file
      ignore_errors: true
    
    - name: Present
      debug: msg="audit is present"
      when: file.stdout != "0"
    
    - name: Not Present
      debug: msg="audit is not present"
      when: file.stdout == "0"