lineinfile task that spans multiple lines

I’m trying to make my lineinfile command that uses multiple lines idempotent:

  • lineinfile: >
    dest=/etc/example.conf
    regexp=‘^[test(.*)’
    line=‘[test]{{ ‘\n’ }}secondline’

I’ve tried this, and the following regexp variations:

regexp=‘’/^[test(.*)/s’ # trying to get it to work multiline
regexp=‘^[test]{{ ‘\n’ }}secondline’ # trying to use same pattern in ‘line’

I’ve also tried a bunch of other variations, with no luck, as well as adding ‘insertafter=EOF’. In all cases, I ended up getting another block of text each time I ran ansible-playbook.

How can I do a lineinfile with multiple lines with idempotence?

(Also, I can’t get the line to work without wrapping newlines, tab characters, etc. in a variable reference ({{ }}), though I’ve seen other examples online where those whitespace characters must be working correctly.

The one way i know of is either just use shell/command and use sed, or break this into tasks, the first counts and registers the line needs to be replaced again using shell/cmd “grep”, and the second does the lineinfile per item using “with_sequence” and remember to add +1 to the number counted as sequence does not accept 0 count

This was mentioned before in the list

Is there any way to make lineinfile work with Python’s multiline regex (like /pattern/s)? lineinfile makes the idempotence a bit easier than grep/sed. But I’ll go that route if need be. Usually, I just use a template file anyways, but for this particular file, there are just three lines that need replacing, and the config file is pretty long.

Another option that would work for ini-style files:

  • ini_file:
    dest=/etc/example.conf
    section=test
    option=example
    value=value

Just add one option/value pair for each required option. Unfortunately, in my case, the config file in question isn’t actually an ini-style file, so ini_file doesn’t work.

sed/grep will not affect your file, they will just get how many lines you would like to change

Hello, although this is an older thread, I came across it today while searching for a solution to also use lineinfile to edit multiple lines after a designated regex.
Apologies if this is not the right way to do it, (and if its a bad way, would love to see the “right” way to do it). But hey, I just needed to get it done and this one was a bit of a challenge.

Note the syntax to get around the YAML gotcha with the command below. Here’s is what worked for me although disclaimer YMMV.

idempotent using with multiline regex with register

  • name: “Test for subjectAltName = IP in /etc/pki/tls/openssl.cnf”
    command: ‘grep “^subjectAltName = IP: {{ (ansible_eth0 | default(ansible_lo)).ipv4.address }}” /etc/pki/tls/openssl.cnf’
    register: test_grep
    failed_when: “‘PLACEHOLDERHACK’ in test_grep.stderr”
    #ignore_errors: yes

  • name: “modify SSL cert configuration add subjectAltName = IP to /etc/pki/tls/openssl.cnf”
    lineinfile: ‘dest=/etc/pki/tls/openssl.cnf regexp=“^[ v3_ca ]” state=present insertafter=“^[ v3_ca ]” line=“[ v3_ca ]\nsubjectAltName = IP: {{ (ansible_eth0 | default(ansible_lo)).ipv4.address }}” backup=yes’
    when: test_grep.stdout == “”

Idempotent result in edited file Where the nodes IP is ‘192.168.xx.xx’:

Original target file was just the section:
[ v3_ca ]

Idempotent result (post multiple iterations) in edited target file then included section and the desired IP:

[ v3_ca ]
subjectAltName = IP: 192.168.xx.xx

Note that I actually had to modify the above code for our handling of virtual hosts running CentOS-7 as I was getting “ansible_eth0.ipv4.address is undefined” errors.
Were still running ansible 1.9.4, but I also tried upgrading to latest ansible version (as of 2016-02-35) version 2.x and still saw the problem.
Let me know if seeing the other workaround for handling dynamically named (and specific) network interfaces on CentOS-7 might be useful.