Ansible lineinfile is not changing file as expect - ansible

THi, new to this. . . .
Testing out a Ansible play to update the swappiness setting on a test box.
---
- hosts: "{{ target }}"
become: yes
tasks:
- name: swapness
lineinfile:
path: /etc/sysctl.conf
state: present
regexp: vm.swappiness=*
line: vm.swappiness=6
Currently, it is set to vm.swappiness=4 but running the above does not change that.
the way I read the logic is...
look for a line with "vm.swappiness=" and replace it with "vm.swappiness=6"

I would do in this way:
---
- name: Playbook who modify swapiness.
hosts: "{{ target }}"
become: yes
tasks:
# Set vm.swappiness to 6 in /etc/sysctl.conf
- name: Set swapiness.
sysctl:
name: vm.swappiness
value: '6'
state: present
sysctl_set: yes
reload: yes
The reason for that is that If exists any module for it, you should be doing using that module specific instead a generic one.
Ansible has a sysctl module, so it's better to use it for this.
Note: Please, review the code and set 2 white spaces between them if not already.

Given the file
shell> cat sysctl.conf
vm.swappiness=4
The task below works as expected
- lineinfile:
path: sysctl.conf
regexp: vm.swappiness=*
line: vm.swappiness=6
Running the playbook with the options --check --diff gives abridged
TASK [lineinfile] *****************************************************
--- before: sysctl.conf (content)
+++ after: sysctl.conf (content)
## -1 +1 ##
-vm.swappiness=4
+vm.swappiness=6
Notes
The regexp vm.swappiness=* is probably not what you really want. This regexp matches the string vm.swappiness followed by 0 or mode =. For example, below are strings that match this regexp
vm.swappiness
vm.swappiness=
vm.swappiness==========
Instead, you want a regexp that matches the string vm.swappiness= followed by 0 or more characters. For example vm.swappiness=.*

Related

Ansible: lineinfile module using regexp and backrefs

I am trying to ensure that a line ends with 'audit=1"'. The before state is:
GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=vg00/lv_root rhgb
quiet"
The after state should be:
GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=vg00/lv_root rhgb quiet
audit=1"
Working with the Ansible lineinfile module I can add that statement if its missing, but repeated runs keep appending 'audit=1"' even if it's present. I have been playing with the regexp and negative look-ahead assertions, and just cannot get the syntax correct.
Here is example play I have:
- name: grub - adjust
lineinfile:
path: /home/vwadmin/grub-test
regexp: '(GRUB_CMDLINE_LINUX=.*)"(?!audit=1")'
line: '\1 audit=1"'
backrefs: yes
state: present
Edit: Using Pacifist's suggestion I have a working solution. Confirmed to add my audit=1 statement if missing, and do nothing if present.
- name: grub - check
shell: grep -c 'audit' /etc/default/grub
register: grub_file
ignore_errors: true
- name: grub - adjust
lineinfile:
path: /etc/default/grub
regexp: '(GRUB_CMDLINE_LINUX=.*)"'
line: '\1 audit=1"'
backrefs: yes
state: present
when: grub_file.stdout == "0"
Note: I can't help but feel the reason I couldn't get it working without a pre-step, and why it doesn't work properly with check_mode, is that the negative look-ahead is not defined correctly for this case. From what I understand, the regexp match should fail when the negative look-ahead succeeds, which should cause the module to not take action. Looking at another example of this on GG I am wondering if root issue is the greedy nature of the .* wildcard in the first group match. /shrug
lineinfile is doing its work that is adding whatever is given in line and line is identified by your regexp. So no matter what value your setting already has, it will be overridden by your new line.
There are two approaches that you can use :
Using check_mode with failed_when.
Using shell module to grep the content beforehand.
Check_Mode (I can not get this working though but it has been recommended everywhere else):
- name: grub - adjust
lineinfile:
name: /home/vwadmin/grub-test
regexp: '(GRUB_CMDLINE_LINUX=.*)'
line: '\1 audit=1"'
backrefs: yes
state: present
check_mode: yes
register: presence
failed_when: presence.changed
Using grep (This one is working fine for me)
- name: grub - adjust
shell: grep -c 'audit' /home/vwadmin/grub-test
register: file
ignore_errors: true
- name: Present
debug: msg="audit is present"
when: file.stdout != "0"
- name: Not Present
debug: msg="audit is not present"
when: file.stdout == "0"
i wanted to do something similar with console kernel options and ended up with this:
- name: "Ensure console kernel options are set"
lineinfile:
path: /etc/default/grub
regexp: ^GRUB_CMDLINE_LINUX=\"(?P<defaults>.*?)\s*(?P<console> console=.*)?\"$
line: GRUB_CMDLINE_LINUX="\g<defaults> {{ kernel_console }}"
backrefs: yes
register: grub_changed
- name: "Rebuild grub"
command: grub2-mkconfig –o /boot/grub2/grub.cfg >/dev/null
when:
- grub_changed.changed
the key part of the regexp is (?P<defaults>.*?): the last question mark - which makes the match less greedy, allows the optional console=.* to be picked up without continually appending another console to the end of the line in the line as it did with your audit. main issue is that it assumes that its always the last (set of) options in the line and i always end up with a white space if there is no console defined. but it works!

ansible error 'first argument must be string or compiled pattern'

I have this code in my playbook:
- hosts: standby
remote_user: root
tasks:
- name: replace hostname in config
replace:
path: /opt/agentd.conf
regexp: #\s+Hostname\=
replace: Hostname={{hname}}
backup: yes
- name: add database array in files
lineinfile:
path: /opt/zabbix_agent/share/scripts/{{ item }}
line: 'DBNAME_ARRAY=( {{dbname}} )'
insertafter: DB2PATH=/home/db2inst1/sqllib/bin/db2
backup: yes
with_items:
- Connections
- HadrAndLog
- Memory
- Regular
- name: restart service
shell: /etc/init.d/agent restart
register: command_output
become: yes
become_user: root
tags: restart
- debug: msg="{{command_output.stdout_lines}}"
tags: set_config_st
it will replace # Hostname= in a config file with Hostname= givenhostname and add an array in 4 scripts. array is the name of given database. then it will restart the agent to apply the changes.
when i run this command:
ansible-playbook -i /Ansible/inventory/hostfile /Ansible/provision/nconf.yml --tags set_config_st --extra-vars "hname=fazi dbname=fazidb"
i get this error:
first argument must be string or compiled pattern
i searched a bit but couldn't find the reason. what should i do?
The problem is in this line:
regexp: #\s+Hostname\=
You have to quote the regex because YAML comments start with #, so everything after the # will be ignored by ansible and that is why the error message occures.
So the correct line should be:
regexp: '#\s+Hostname\='
or
regexp: "#\s+Hostname\="
I think the problem is with indention. Please try as below.
- hosts: standby
remote_user: root
tasks:
- name: replace hostname in config
replace:
path: /opt/agentd.conf
regexp: #\s+Hostname\=
replace: Hostname={{hname}}
backup: yes
- name: add database array in files
lineinfile:
path: /opt/zabbix_agent/share/scripts/{{ item }}
line: 'DBNAME_ARRAY=( {{dbname}} )'
insertafter: DB2PATH=/home/db2inst1/sqllib/bin/db2
backup: yes
with_items:
- Connections
- HadrAndLog
- Memory
- Regular
- name: restart service
shell: /etc/init.d/agent restart
register: command_output
become: yes
become_user: root
tags: restart
- debug: msg="{{command_output.stdout_lines}}"
tags: set_config_st

Is there a better way to iterate through multiple files on the node machine using Ansible playbook and search n replace a particular line

Is there a better way to iterate through multiple files on the node machine using Ansible playbook and search n replace a particular line.
I have the following files in my directory and it needs to iterate through these files and check and replace a particular line in the file.
/opt/a1.conf
/opt/a2.con.f
/var/app1/conf/a3.conf
/etc/a5.conf
/etc/a6.conf
/etc/a7.conf
/etc/a8.conf
/etc/a9.conf
My Ansible Playbook can be formatted as follows:
-
name: Install nginx and other binaries using with_item and variables.
gather_facts: yes
hosts: aws1
become_method: sudo
become: yes
tasks:
- name: Modify line to include Timeout
become: yes
become_method: sudo
lineinfile:
path: {{ item }}
regexp: 'http\s+Timeout\s+\='
line: 'http Timeout = 10'
backup: yes
with-items
- /opt/a1.conf
- /opt/a2.con.f
- /var/app1/conf/a3.conf
- /etc/a5.conf
- /etc/a6.conf
- /etc/a7.conf
- /etc/a8.conf
- /etc/a9.conf
This will actually work and help me. I could also create a vars.yaml file and add all these files and use them in "with_items" syntax.
However this is actually making the playbook look to lengthy as the number of files to search are higher
We possibly can achieve the same thing effectively by using the jinja2 template using the "for" loop.
EX: {% for item in vars.yml %}
and that would rather be an effective way to do it and wont make my Ansible playbook clumsy but I'm unable to figure the exact command for looping it.
Is there a jinja command to achieve the same or a better way to iterate through multiple files and not writing each of them into the playbook.
Thank you
You don't need jinja2 for that. Why don't you use a separate file for the file list variable like vars.yml with the following contents:
---
files:
- /opt/a1.conf
- /opt/a2.con.f
- /var/app1/conf/a3.conf
- /etc/a5.conf
- /etc/a6.conf
- /etc/a7.conf
- /etc/a8.conf
- /etc/a9.conf
and include this file in your playbook:
---
- name: Install nginx and other binaries using with_item and variables.
gather_facts: yes
hosts: aws1
become_method: sudo
become: yes
vars_files:
- z.var
tasks:
- name: Modify line to include Timeout
lineinfile:
path: {{ item }}
regexp: 'http\s+Timeout\s+\='
line: 'http Timeout = 10'
backup: yes
loop:
"{{ files }}"

Ansible Playbook keeps adding ^M to my files

I have the below ansible playbook where i am identifying a string in a file and replacing it with another
---
- name: Ansible Playbook
hosts: webserver1
remote_user: user45
tasks:
- name: Replacing content with other
lineinfile:
path: /home/user45/run.sh
regexp: '^(.*)DEBUG=(.*)$'
line: 'DEBUG=ON'
the above works, but it adds ^M to the end of every other line in that file and every blank line
From what I have read online this normally occurs when you copy and paste from Windows to Linux but i typed this out manually so i am kind of stumped
Playbook is running on Linux Redhat 7
Please verify your script "/home/user45/run.sh".Looks like carriage-return character exist in there.
For whatever reason lineinfile was adding the ^M .. If I change it to use replace module it does not add the ^M bits
---
- name: Ansible Playbook
hosts: webserver1
remote_user: user45
tasks:
- name: Replacing content with other
replace:
dest: /home/user45/run.sh
regexp: 'DEBUG=.*'
line: 'DEBUG=ON'
This problem has been fixed with this solution on ansible 2.9:
---
- name: Ansible Playbook
hosts: webserver1
remote_user: user45
tasks:
- name: Replacing content with other
replace:
path: /home/user45/run.sh
regexp: 'DEBUG=.*'
replace: 'DEBUG=ON'
Enjoy ;)

Use lineinfile to fill ansible inventory file

I have trivial task to fill particular ansible inventory file with the new deployed VMs names under their roles.
Here is my playbook:
- hosts: 127.0.0.1
tasks:
- name: Add host to inventory file
lineinfile:
dest: "{{inv_path}}"
regexp: '^\[{{role}}\]'
insertafter: '^#\[{{role}}\]'
line: "{{new_host}}"
Instead of adding new line after [role], ansible replace the string with the hostname. My aim is to naturally insert after it. If there is no matched role it should skip add new line.
How to achieve this? Thanks!
[role] is getting replaced because the regexp parameter is the regular expression Ansible will look for to replace with the line parameter. Just move that value to insertafter and get rid of regexp.
As for the other requirement you will need another task that will check if [role] exists first. Then your lineinfile task will evaluate the result of the checker task to determine if it should run.
- name: Check if role is in inventory file
shell: grep [{{ role }}] {{ inv_path }}
ignore_errors: True
register: check_inv
- name: Add host to inventory file
lineinfile:
dest: "{{ inv_path }}"
insertafter: '^\[{{role}}\]$'
line: "{{new_host}}"
when: check_inv.rc == 0

Resources