lineinfile task that spans multiple lines

2,335 views
Skip to first unread message

Jeff Geerling

unread,
Feb 6, 2014, 3:02:58 PM2/6/14
to ansible...@googlegroups.com
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.

Walid

unread,
Feb 6, 2014, 10:57:27 PM2/6/14
to ansible...@googlegroups.com
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


--
You received this message because you are subscribed to the Google Groups "Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ansible-proje...@googlegroups.com.
To post to this group, send email to ansible...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Jeff Geerling

unread,
Feb 8, 2014, 4:17:18 PM2/8/14
to ansible...@googlegroups.com
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.

Jeff Geerling

unread,
Feb 10, 2014, 10:20:12 AM2/10/14
to ansible...@googlegroups.com
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.

Walid

unread,
Feb 10, 2014, 12:06:56 PM2/10/14
to ansible...@googlegroups.com
sed/grep will not affect your file, they will just get how many lines you would like to change

Chris McConnell

unread,
Feb 26, 2016, 9:52:50 AM2/26/16
to Ansible Project
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.
Reply all
Reply to author
Forward
0 new messages