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
toBear
Grapes
toApples
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
Signup for Exclusive "Subscriber-only" Content