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!
Related
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=.*
The code:
- name: Mark ending
delegate_to: localhost
lineinfile:
create: yes
insertafter: 'EOF'
path: '{{ output_file }}'
line: '=================='
Ansible version 2.8.6
This line is only added the first time the command is executed. I would expect it to add it every time.
The documentation recommends insertafter: 'EOF' for inserting lines at the end of a file, so that's what I'm using.
But now it seems to ignore every insert of this after the first.
More is inserted in between. I'm just using this command to indicate a particular thing has passed.
Setting validate: '' Changes nothing. How do I fix this?
Trying to make sure an exact string exists for a when condition, but right now trying to get the function working in a simple playbook, but can't seem to get it to work. Also tried escaping characters too
I have tried different variations and tried switching to " instead of ' and vise-versa
my.conf
JAVA_HOME="/opt/java/hotspot/64_bit/jdk1.8.0_201/"
JAVA_HOME=/opt/java/hotspot/64_bit/jdk1.8.0_201/
JAVA_HOME=/opt/java/hotspot/64_bit/jdk1.8.0_202/
JAVA_HOME="/opt/java/hotspot/64_bit/jdk1.8.0_202/"
SUN_JAVA_HOME=/opt/java/hotspot/64_bit/jdk1.8.0_201/
SUN_JAVA_HOME="/opt/java/hotspot/64_bit/jdk1.8.0_201/"
BAE_JAVA_HOME=/opt/java/hotspot/64_bit/jdk1.8.0_201/
BAE_JAVA_HOME=/opt/java/hotspot/64_bit/jdk1.8.0_202/
BAE_JAVA_HOME="/opt/java/hotspot/64_bit/jdk1.8.0_201/"
BAE_JAVA_HOME="/opt/java/hotspot/64_bit/jdk1.8.0_202/"
playbook
---
- hosts: localhost
tasks:
- name: read the passwd file
shell: cat /tmp/my.conf
changed_when: False
register: user_accts
- name: set regex pattern
set_fact:
regex_pattern: ".*^JAVA_HOME=\"/opt/java/hotspot/64_bit/jdk1.8.0_201/\"$"
- name: a task that only happens if the user exists
when: user_accts.stdout |match('{{regex_pattern}}')
debug: msg="user hillsy exists"
I want to make sure it finds this JAVA_HOME="/opt/java/hotspot/64_bit/jdk1.8.0_201/"
and if I change this line to
JAVA_HOME="/opt/java/hotspot/64_bit/jdk1.8.0_209/"
it doesn't find it
I'm wanting to get that exact string so I don't get the other ones in the example above
If you are looking for that exact string, then you don't need a regular expression
- debug:
msg: it matches
# because an empty list is considered "false", if none of the lines
# are equal, this will not run
when: user_accts.stdout_lines | select('eq', the_string) | list
vars:
the_string: JAVA_HOME="/opt/java/hotspot/64_bit/jdk1.8.0_201/"
- name: Cassandra cassandra.yaml
lineinfile:
dest: "{{ home}}/conf/cassandra.yaml"
state: present
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
# backup: yes
with_items:
- { regexp: "data_file_directories:", line: "data_file_directories: \n - {{ data_directory }}" }
in the first file first run it looks good but in the second run it keeps adding new line. what needs to be done in order to the second run also looks good.
data_file_directories:
- /mount1/data
second run
data_file_directories:
- /mount1/data
- /mount1/data
- /mount1/data
I want some thing like
data_file_directories:
- /mount1/data
lineinfile ― as its name suggest ― is a module to ensure a certain line is in the target file; not lines.
To deal with multiple lines either:
use regexp module with matchgroup and backreference ― the exact implementation is dependent on other constructs in the target file,
use blockinfile module ― the exact implementation is dependent on other constructs in the target file,
or (preferably) use template module.
I'm very new to Ansible
Is it possible to check if a string exists in a file using Ansible.
I want to check is a user has access to a server.
this can be done on the server using cat /etc/passwd | grep username
but I want Ansible to stop if the user is not there.
I have tried to use the lineinfile but can't seem to get it to return.
code
- name: find
lineinfile: dest=/etc/passwd
regexp=[user]
state=present
line="user"
The code above adds user to the file if he is not there. All i want to do is check. I don't want to modify the file in any way, is this possible
Thanks.
It's a tricky one. the lineinfile module is specifically intended for modifying the content of a file, but you can use it for a validation check as well.
- name: find
lineinfile:
dest: /etc/passwd
line: "user"
check_mode: yes
register: presence
failed_when: presence.changed
check_mode ensures it never updates the file.
register saves the variable as noted.
failed_when allows you to set the failure condition i.e. by adding the user because it was not found in the file.
There are multiple iterations of this that you can use based on what you want the behavior to be. lineinfile docs particular related to state and regexp should allow you to determine whether or not presence or absence is failure etc, or you can do the not presence.changed etc.
I'd probably register and evaluate a variable.
The following simple playbook works for me:
- hosts: localhost
tasks:
- name: read the passwd file
shell: cat /etc/passwd
register: user_accts
- name: a task that only happens if the user exists
when: user_accts.stdout.find('hillsy') != -1
debug: msg="user hillsy exists"
If you want to fail if there is no user:
tasks:
- shell: grep username /etc/passwd
changed_when: false
By default shell module will fail if command exit code is non zero.
So it will give you ok if username is there and fails otherwise.
I use changed_when: false to prevent changed state when grepping.
I am using the following approach, using only a grep -q and a registered variable.
Upside is that it's simple, downside is that you have a FAILED line in your output. YMMV.
- name: Check whether foobar is defined in /bar/baz
command:
cmd: 'grep -q foobar /bar/baz'
register: foobar_in_barbaz
changed_when: false
ignore_errors: true
- when: not foobar_in_barbaz.failed
name: Do something when foobar is in /bar/baz
....
- when: foobar_in_barbaz.failed
pause:
seconds: 1
content: |
You do not seem to have a foobar line in /bar/baz
If you add it, then magic stuff will happen!