Ansible lineinfile module to replace - replace

I have been trying to replace a option #$ActionFileEnableSync on
for /etc/rsyslog.conf file with $ActionFileEnableSync on. I have used replace module
- replace:
path: /etc/rsyslog.conf
regexp: '^#\s*^$\s*ActionFileEnableSync on.*$'
line: '$ActionFileEnableSync on'
And also I have tried to use lineinfile module
- lineinfile:
dest: /etc/rsyslog.conf
regexp: (^#\\$ActionFileEnableSync on)
line: "$ActionFileEnableSync on"
But none seems to work,either it doesn't replace or keeps on adding a new line

Use lineinfile to set a specific line in a file.
Your regexp looks wrong. Why is 'on' in the regexp? Isn't it supposed to set the value to 'on' when the existing line says 'off'?
Also, the regexp should match the line when it's already 'on', commented out or not. Otherwise, Ansible will append a line at every run.
Try something like:
regexp: ^[#\s]*\$ActionFileEnableSync
This should replace $ActionFileEnableSync following any combination of comment marks and whitespace.

Related

How to replace all occurences of one word with another using Regular Expression

I am trying to replace a tag value in a web.config file using Regex with ansible playbook.
This is my sample file.
TXWebSocketHandler="Data =localhost;Catalog Name=catalogname;User =user;key=key;
TXWebSocketHandler="Data =localhost;Catalog Name=catalogname;User =user;key=key;
TXWebSocketHandler="Data =localhost;Catalog Name=catalogname;User =user;key=key;
My Desired output should be
TXWebSocketHandler="Data =127.0.0.1;Catalog Name=catalogname;User =user;key=key;
TXWebSocketHandler="Data =127.0.0.1;Catalog Name=catalogname;User =user;key=key;
TXWebSocketHandler="Data =127.0.0.1;Catalog Name=catalogname;User =user;key=key;
All the localhost should be replaced as 127.0.0.1.
And the playbook I have used is
- name: replace_config
community.windows.win_lineinfile:
path: 'D:\Apps\project\web.config'
regexp: /localhost/g
line: 127.0.0.1
For this I am getting a output like,
TXWebSocketHandler="Data =localhost;Socket Name=Socketname;User =user;key=key;
TXWebSocketHandler="Data =localhost;Socket Name=Socketname;User =user;key=key;
TXWebSocketHandler="Data =localhost;Socket Name=Socketname;User =user;key=key;
127.0.0.1
Substitution value that I am adding is not replaced in localhost, but it is getting added in end of the file. when I try in any of regex generator this works fine like I wanted.
Is it an issue with regex or am I missing any argument in this ansible playbook? Please suggest some method to replace all occurences of one word with another .
Single-line restriction
The module community.windows.win_lineinfile seems to work on single lines only:
Ensure a particular line is in a file, or replace an existing line using a back-referenced regular expression
From Synopsis:
This is primarily useful when you want to change a single line in a file only.
Still you could use backrefs: true to replace a single line, see the docs (restriction emphasized in bold):
If the regexp does match, the last matching line will be replaced by the expanded line parameter.
See also
Ansible lineinfile module syntax error when using multiple variables in string.
In your playbook:
- name: replace_config
community.windows.win_lineinfile:
path: 'D:\Apps\project\web.config'
backrefs: true
regexp: '^(.*)localhost(.*)$'
line: '$1 127.0.0.1 $2'
This should replace the matched localhost with the loopback IP 127.0.0.1, and set the captured parts before (backreferenced by $1) and after (backreferenced by $2) back in.
Note: If it worked, try to remove the surrounding spaces from IP-address.
Replace as built-in module
As seshadri_c suggested:
ansible.builtin.replace module can be used:
Replace all instances of a particular string in a file using a back-referenced regular expression
See Synopsis:
This module will replace all instances of a pattern within a file.
From the docs, adapt the first example "Replace old hostname with new hostname" to your use-case:
- name: Replace old hostname with new hostname (requires Ansible >= 2.4)
ansible.builtin.replace:
path: D:/Apps/project/web.config
regexp: '(.*)localhost(.*)$'
replace: '\1 127.0.0.1 \2'
Note: I replaced the backslashes (Windows path-separator) to forward-slashes (safer with Python). The added spaces after back-ref \1
and before \2 might be removed (not sure if it works because numbers of back-ref and IP-address could collide). See the other example in docs "Explicitly specifying named matched groups" for another way.

Ansible lineinfile regexp line with spaces

I have a line in a config file, to which I would like to modify the line. I use the below code
- name: insert line
lineinfile:
path: /etc/config
regexp: '^(.*)password root(.*)$'
line: password root {{ hello }}
so in above case, when even i run the ansible task it just inserts a new line, but never modifies the line. How do i avoid the space of the string in the regexp ? Ive tried "\s" and "/\s" but couldnt fix it.
the output file /etc/config looks like below for example.
password root alpha
next time I run the code it becomes
password root beta
here in my case the {{ hello }} variables keeps changing so I want to replace instead of adding new line.
The problem identified in this case is, since the output line (i.e in /etc/config) starts with no spaces,
regexp: '^password root(.*)$'
the regex should be as above and no need of \s to overcome space between password and root.

Ansible "replace" regexp (one OR the other)

I'm trying to replace a value in a config file, using the replace module.
However, I was wondering if there is an OR function or similar.
Currently, I have the following play:
- name: Replace "DebugLevel" variable-value"
become: yes
replace:
path: /etc/zabbix/zabbix_proxy.conf
regexp: '^# DebugLevel=3'
replace: 'DebugLevel=3'
This play uncomments DebugLevel=3, but when the playbook is run a second time the replace wont work because the regex does not match (value already uncommeted).
I want to always replace the value even if DebugLevel=3 already was uncommented.
This will make any manual changes made by a person to be overwritten and the Ansible playbook sets it back to original config.
By creating a new play with a regex that is using the value that is already uncommented, I can accomplish this, but is there a shorter version by using an "OR" after the first regex value or something similar?
Example of what I mean:
- name: Replace "DebugLevel" variable-value"
become: yes
replace:
path: /etc/zabbix/zabbix_proxy.conf
regexp: '^# DebugLevel=3' OR '^DebugLevel=.*'
replace: 'DebugLevel=3'
if you want to use regex the or is |
- name: Replace "DebugLevel" variable-value"
replace:
path: /etc/zabbix/zabbix_proxy.conf
regexp: '^# DebugLevel=3|^DebugLevel=.*'
replace: 'DebugLevel=3'
If the configuration file should contain every time a certain debug level you could probably declare just that the line exists independent of comment and value. To do so
- name: Replace "DebugLevel" variable-value"
lineinfile:
path: /etc/zabbix/zabbix_proxy.conf
regexp: 'DebugLevel'
line: 'DebugLevel=3'
It will make sure that the debug level is set with the given value and active.
Documentation
lineinfile module – Manage lines in text files

Ansible: Insert word in GRUB cmdline

I'd like to use Ansible's lineinfile or replace module in order to add the word splash to the cmdline in GRUB.
It should work for all the following examples:
Example 1:
Before: GRUB_CMDLINE_DEFAULT=""
After: GRUB_CMDLINE_DEFAULT="splash"
Example 2:
Before: GRUB_CMDLINE_DEFAULT="quiet"
After: GRUB_CMDLINE_DEFAULT="quiet splash"
Example 3:
Before: GRUB_CMDLINE_DEFAULT="quiet nomodeset"
After: GRUB_CMDLINE_DEFAULT="quiet nomodeset splash"
The post Ansible: insert a single word on an existing line in a file explained well how this could be done without quotes. However, I can't get it to insert the word within the quotes.
What is the required entry in the Ansible role or playbook in order to add the word splash to the cmdline as shown?
You can do this without a shell output, with 2 lineinfiles modules.
In your example you're searching for splash:
- name: check if splash is configured in the boot command
lineinfile:
backup: true
path: /etc/default/grub
regexp: '^GRUB_CMDLINE_LINUX=".*splash'
state: absent
check_mode: true
register: grub_cmdline_check
changed_when: false
- name: insert splash if missing
lineinfile:
backrefs: true
path: /etc/default/grub
regexp: "^(GRUB_CMDLINE_LINUX=\".*)\"$"
line: '\1 splash"'
when: grub_cmdline_check.found == 0
notify: update grub
The trick is to try to remove the line if we can find splash somewhere, but doing a check only check_mode: true. If the term was found (found > 0) then we don't need to update the line. If it's not found, it means we need to insert it. We append it at the end with the backrefs.
Inspired by Adam's answer, I use this one to enable IOMMU:
- name: Enable IOMMU
ansible.builtin.lineinfile:
path: /etc/default/grub
regexp: '^GRUB_CMDLINE_LINUX_DEFAULT="((:?(?!intel_iommu=on).)*?)"$'
line: 'GRUB_CMDLINE_LINUX_DEFAULT="\1 intel_iommu=on"'
backup: true
backrefs: true
notify: update-grub
Please note I've had to set backrefs to true in order to \1 reference to work otherwise the captured group was not replaced.
Idempotency works fine as well.
EDIT: Please note this snippet only works with an Intel CPU and might to be updated to fit your platform.
A possible solution is the definition of two entries as follows:
- name: "Checking GRUB cmdline"
shell: "grep 'GRUB_CMDLINE_LINUX_DEFAULT=.*splash.*' /etc/default/grub"
register: grub_cfg_grep
changed_when: false
failed_when: false
- name: "Configuring GRUB cmdline"
replace:
path: '/etc/default/grub'
regexp: '^GRUB_CMDLINE_LINUX_DEFAULT="((\w.?)*)"$'
replace: 'GRUB_CMDLINE_LINUX_DEFAULT="\1 splash"'
when: '"splash" not in grub_cfg_grep'
Explanation: We first check if the splash keyword is present in the required line using grep. Since grep gives a negative return code when a string is not found, we suppress the errors using failed_when: false. The output of grep is saved to the grub_cfg_grep variable.
Next, we bind the replace module to the condition that the keyword splash is in the standard output of grep. The regular expression takes the old content in the quotes and adds the splash keyword behind it.
Note: In the case of an empty string before the execution, the result reads " splash" (with a space in front) but it is still a valid cmdline.
The difficulty is this line in the replace module page: "It is up to the user to maintain idempotence by ensuring that the same pattern would never match any replacements made."https://docs.ansible.com/ansible/latest/modules/replace_module.html#id4 It's easy to insert the item but actually quite tricky to make it idempotent, so the target file doesn't grow every time you run the task.
I found a way to do it in one shot with the replace module. You should be able to adapt this. My task checks the GRUB_CMDLINE_LINUX_DEFAULT line for "vt.default_red" and inserts some colour codes if not found.
My method was to copy-and-paste various nearly-there examples into the regex tester website and fiddle until it worked. I still don't grok the result, but it worked in my tests at https://www.regextester.com/ and it works in my playbook.
One problem I had was that Ansible's regex implementation apparently doesn't support conditionals, which gave me odd errors for a while.
- name: colours | configured grub command
replace:
path: /etc/default/grub
regexp: '^GRUB_CMDLINE_LINUX_DEFAULT="((:?(?!vt\.default_red).)*?)"$'
replace: 'GRUB_CMDLINE_LINUX_DEFAULT="\1 vt.default_red=0xee,..."'
The regex matches the literal string ("GRUB_CMDLINE_LINUX_DEFAULT=" and a double quote mark) at the start and the double quote mark at the end. Deconstructing the rest...
( - open capture group #1 (creates backref #1)
(:? - open a non-capturing group (not sure what the question mark is here)
(?! - negative lookahead (ie. don't match if the following string comes next)
vt\.default_red - the string to look for, literal dot is escaped
) - close negative lookahead
.) - match a single char (why?) and close the non-capturing group
* - try to match the non-capturing group zero or more times
? - ... lazily (ie. get the smallest possible match)
) - close capture group #1
What about doing this in Ansible, use perl to address your need.
- name: Change items in the file
ansible.builtin.command:
command: perl -i pe 's/DEFAULT="/DEFAULT="splash"/'
Another way of looking at it. This is an old conversation, but it is still relevant.

regexp in ansible for replacing 'localhost'

I am using the replace module in ansible to replace a line in my file
original line is #listen_addresses = 'localhost'
I want to replace it to the following listen_addresses = '*'
This my playbook entry
replace: path=/usr/pgsql-9.6/data/postgresql.conf regexp='#listen_addresses(\s)*=\'locahost'\' replace='listen_addresses = *' remote_src=yes backup=yes
The above playbook is unable to make the substituion. Pls guide me with the actual regexp
You don't need to put the full line to replace it, just match the beginning of the line (using ^) the text plus a greedy matching (.*)
tasks:
- replace:
path: /usr/pgsql-9.6/data/postgresql.conf
regexp: '^#listen_addresses.*'
replace: 'listen_addresses = *'
remote_src: yes
backup: yes
I suggest also to reformat the code this way (mind = were replaced by :) this is more readable