question on lineinfile module

Hi everyone,

I have one play that does not do what I want it to:

- name: set kernel multiversions
  lineinfile:
    dest: /etc/zypp/zypp.conf
    line: "multiversion.kernels = latest,oldest,running"
    regexp: "multiversion.kernels = latest,latest-1,running"
    state: present

I expect
-> the module scans for a line matching "regex"
-> if this is found, the found line is replaced with "line"
-> if "regex" has no matches, nothing is done

The module instead scans the file, and on the first run it behaves as I
expect, the line in the file is modified. On subsequent runs, one line
(per run) is added to the file (before EOF), so that I have multiple
lines containing "line".

Is this behaviour expected? How can I make a replacement only when
"regex" matches?

When using a registered variable, this variable is shown as:

ok: [hostname] => {
    "myrole_var1": {
        "backup": "",
        "changed": true,
        "diff": [
            {
                "after": "",
                "after_header": "/etc/zypp/zypp.conf (content)",
                "before": "",
                "before_header": "/etc/zypp/zypp.conf (content)"
            },
            {
                "after_header": "/etc/zypp/zypp.conf (file attributes)",
                "before_header": "/etc/zypp/zypp.conf (file attributes)"
            }
        ],
        "msg": "line added"
    }
}

So nothing I could use "when" on.

I use the blockinfile module to add a line in this file, but I do not
see how to use this module to replace one line. This module runs only
once, on subsequent runs it says "OK" instead of "Changed".

Regards,
Werner

No, and you are not alone
https://github.com/ansible/ansible-modules-core/issues/3975

Hi Werner,

You would want to use the backrefs feature of the lineinfile module. Here is an example that I use for deleting root password hashes from the /etc/shadow file. I use regex numbered groups (with parens and \1, etc) to capture and replay existing parts of lines as needed:

  • name: delete root password
    lineinfile: ‘dest=/etc/shadow
    backup=yes
    backrefs=yes
    regexp=“^(root):.?:(.)$”
    line=“\1:*:\2”’

And another example (two tasks) that update an ntp config with a new IP address:

The following two tasks will replace existing ntp config from .135 to .133

  • name: Fix ntp.conf
    lineinfile: dest=/etc/ntp.conf
    backup=yes
    state=present
    backrefs=yes
    regexp=‘^(.server.) 192.168.1.135’
    line=‘\1 192.168.1.133’
  • lineinfile: dest=/etc/ntp.conf
    state=present
    backup=yes
    backrefs=yes
    regexp=‘^(.restrict.) 192.168.1.135’
    line=‘\1 192.168.1.133’

Kai Stian Olstad [29.06.2016 15:21]:

The module instead scans the file, and on the first run it behaves as I
expect, the line in the file is modified. On subsequent runs, one line
(per run) is added to the file (before EOF), so that I have multiple
lines containing "line".

Is this behaviour expected? How can I make a replacement only when
"regex" matches?

No, and you are not alone
https://github.com/ansible/ansible-modules-core/issues/3975

Yes, that's exactly what happens here. Thank you for pointing me there.

I already thought of using an "absent" and a "present" task, but now I
use the replace module, and it seems to work:

- name: replace kernel multiversions
  replace:
    dest: /etc/zypp/zypp.conf
    regexp: "^multiversion.kernels = latest,latest-1,running"
    replace: "multiversion.kernels = latest,oldest,running"

BTW, I'm running ansible version 2.1.0.0, and it's the first time I use
the lineinfile module (since I'm quite new to ansible).

Regards,
Werner

Hi Joanna,

so using lineinfile with regexp, but without backrefs will duplicate a
line and lineinfile with regexp and backrefs will not? Indeed, it seems
to be like that.

- name: another replacement attempt
  lineinfile:
    dest: /etc/zypp/zypp.conf
    backrefs: yes
    regexp: '^(multiversion.kernels = latest),(latest-1),(running)$'
    line: '\1,oldest,\3'
    state: present

works as expected and does not create a duplicate line if regexp is not
found. The registered variable shows '"changed": false'.

I added that to the bug report...

This behaviour is not documented on
<http://docs.ansible.com/ansible/lineinfile_module.html&gt;, so I consider
this as an error.

Werner

Joanna Delaporte [29.06.2016 20:59]: