Ansible lineinfile multiple lines - Replace multiple Lines | Devops Junction

In this post, we are going to see how to use Ansible lineinfile module to replace multiple Lines at the same time. How to use Multiple Regular Expressions or Regex at the same time. How to Match Multiple lines.

For this example, we are going to take apache httpd.conf file as our base file and we are going to Replace all the WebSite related configuration in the file to make it as new WebSite.

Simply put, we are going to migrate our Existing website/virtualhost to the new website/virtualhost

Before any modification, A Quick Ad Hoc Command to Check What is the Current Configuration Values

 

Quick Command to Check What is the Current Configuration

$ ansible web -m shell -a 'egrep -in "^ServerName|^ServerAdmin|^LogLevel|^DocumentRoot" /etc/httpd/conf/httpd.conf' -i ansible_hosts 
mwiweb02 | CHANGED | rc=0 >> 
88:ServerAdmin [email protected] 
99:ServerName www.middlewareinventory.com:80 
123:DocumentRoot "/var/www/html" 
193:LogLevel warn

 

With a help of ansible, ad hoc command and grep we were able to get the Current Configuration values on the remote server httpd.conf file.

Now let us write a Playbook to Change these values all at once in a Multiple Search and Replace manner.

 

Ansible Lineinfile Playbook to Replace Multiple Lines

Here is the playbook to replace multiple lines using lineinfile module. We have used with_items iteration/loop statement to pass multiple values to the regex and line  parameters at the same time.

In lineinfile module, regex parameter used to hold the String that we are searching for and line is to hold the line which we want to replace with.

Having said that. Now look at the Playbook

---
  - name: Examples of lineinfile
    hosts: web
    tasks:
      - name: "Ansible Lineinfile Multiple Lines"
        become: yes
        become_user: root
        lineinfile:
          path: /etc/httpd/conf/httpd.conf
          # Line to Search/Match against
          regexp: '{{item.From}}'
          # Line to Replace with
          line: '{{item.To}}'
          state: present  
          # To validate the Changes Before Committing/Saving
          validate: "httpd -t -f %s"
        with_items:
         - { From: 'ServerName www.middlewareinventory.com:80', To: 'ServerName www.devopsjunction.com:80'}
         - { From: 'ServerAdmin [email protected]', To: 'ServerAdmin [email protected]'}
         - { From: '^LogLevel .*', To: 'LogLevel debug'}
         - { From: '^DocumentRoot .*', To: 'DocumentRoot "/var/www/devopsjunction"'}

 

In with_items, Each Item is having two values  From and To.

Here,

From would be referred as {{item.From}} in the regexp parameter and the

To would be referred as {{item.To}} in the line parameter

 

Validate the Configuration using AD HOC command

$ ansible web -m shell -a 'egrep -in "^ServerName|^ServerAdmin|^LogLevel|^DocumentRoot" /etc/httpd/conf/httpd.conf' -i ansible_hosts 
mwiweb02 | CHANGED | rc=0 >> 
88:ServerAdmin [email protected] 
99:ServerName www.devopsjunction.com:80 
123:DocumentRoot "/var/www/devopsjunction" 
193:LogLevel debug

 

You can see Our Requirement is Completed. We have successfully migrated the Virtual Host/Website from one domain to another Domain. Thanks to Ansible lineinfile.

 

A Quick Caveat I would like to give here is that Ansible lineinfile would consider only the last matching line,

when there are more than one entries you want to replace of the same string/keyword. You should use replace module

Here is the quick example.

 

Replace multiple lines and entires with Replace module

Sometimes you would want to replace multiple entries of some string or word.  Additionally you would have a list of strings to be replaced.

for example let us suppose you want to replace multiple strings and their multiple entries. You cannot use line in file module as mentioned earlier.

Let us consider the traditional Fox and Grape story saved into a file named story

A Fox one day spied a beautiful bunch of ripe grapes hanging from a vine trained along the branches of a tree. The grapes seemed ready to burst with juice, and the Fox's mouth watered as he gazed longingly at them.

The bunch hung from a high branch, and the Fox had to jump for it. The first time he jumped he missed it by a long way. So he walked off a short distance and took a running leap at it, only to fall short once more. Again and again he tried, but in vain.

Now he sat down and looked at the grapes in disgust.

"What a fool I am," he said. "Here I am wearing myself out to get a bunch of sour grapes that are not worth gaping for."

And off he walked very, very scornfully.

There are many who pretend to despise and belittle that which is beyond their reach.

 

Here If you would like to make few changes like this

  • Fox to Bear
  • Grapes to Apples

 

You can notice there are multiple entries of the word Fox and Grapes in that story.

With the follwing playbook you can change the entire story.

---
- name: Change Fox to Bear and Grape to Apple
  hosts: localhost
  tasks:

  - name: Replace multiple lines and entries
    replace:
      path: story
      # Line to Search/Match against
      regexp: '{{item.From}}'
      # Line to Replace with
      replace: '{{item.To}}'
    with_items:
      - { From: '[fF]ox', To: 'Bear'}
      - { From: '[Gg]rapes', To: 'Apples'}

 

This is a simple example I have kept to make things easy to understand.  Ansible replace and line in file modules both support regex and backrefs

Additionally the replace module supports selection elements like before and after as well.

Refer the following articles to know more details and examples about Replace and line in file

 

This is how we can do the Multiple Search and Replace using Ansible lineinfile and replace modules

Hope this helps

Cheers
Sarav AK

Follow me on Linkedin My Profile
Follow DevopsJunction onFacebook orTwitter
For more practical videos and tutorials. Subscribe to our channel

Buy Me a Coffee at ko-fi.com

Signup for Exclusive "Subscriber-only" Content

Loading