Using ansible lineinefile with colon in line - ansible

I am trying to make sure that a particular line is commented out in a source file.
The line is like this:
CFUNCTYPE(c_int)(lambda: None)
If it exists, I want to comment it out:
# CFUNCTYPE(c_int)(lambda: None)
If it doesn't exist, just ignore it.
If it exists and is already commented out, do nothing.
This is the playbook I wrote, but it doesn't work.
tasks:
- name: fix ctypes file
lineinfile: dest='/usr/local/lib/python2.7/ctypes/__init__.py' regexp="^#?CFUNCTYPE(c_int)(lambda: None)" line='# CFUNCTYPE(c_int)(lambda: None)'
The error says:
This one looks easy to fix. There seems to be an extra unquoted colon in the line
and this is confusing the parser. It was only expecting to find one free
colon. The solution is just add some quotes around the colon, or quote the
entire line after the first colon.
However, it is not easy to fix, and I've tried quoting it in every way I can think of, to no avail.

It's a YAML limitation; the parser likely wants to either see a name, colon, and name=value pairs with no more colons on the line, or just name, colon, and 1 quoted string value.
The lineinfile doc has an example for sudoers mentioning this (and another one further down that doesn't work...) and it references YAML as the problem. This means any time you need to have a colon in a value you may as well quote the entire string of arguments just to save yourself the debugging hassle.

I made it work with this quoting:
lineinfile: "dest='/usr/local/lib/python2.7/ctypes/__init__.py' regexp='^#?CFUNCTYPE(c_int)(lambda: None)' line='# CFUNCTYPE(c_int)(lambda: None)'"
In order to ignore a file that doesn't exist, I used this code:
- stat: path=/usr/local/lib/python2.7/ctypes/__init__.py
register: init
- name: fix ctypes file
replace: "dest='/usr/local/lib/python2.7/ctypes/__init__.py' regexp='^( CFUNCTYPE.c_int..lambda: None.)' replace=' # CFUNCTYPE(c_int)(lambda: None)'"
when: init.stat.exists == True
sudo: yes
I also had to change lineinfile to replace, because the line is prefixed with 4 spaces, and I couldn't get it to match correctly.

Related

before and after regex in replace block - caret isn't working as expected

Very difficult to understand ansible behavior. I'm trying to edit my /etc/postfix/master.cf file to turn on the submission block.
I copied the file to /tmp as I'm working on it, so my simple Ansible playbook should be:
- name: Edit the master.cf file
replace:
path: /tmp/master.cf
after: '^#tlsproxy'
before: '^#smtps'
regexp: '^#(.*)$'
replace: '\1'
But this doesn't work. It does work if I make one change, which is taking out the caret ^ in the before and after fields. This makes ... no sense to me at all. What makes even less sense, if I use:
after: '^#'
amazingly, it will do what I expect and uncomment all the lines after the first commented line.
But:
after: '^#t'
suddenly stops matching anything. I've read the Python page on regex and yet I'm baffled by this.
Any ideas? The playbook will work fine without the carets but I want to do this really correctly and match exactly what I want to match.
Thanks!
Ansible's replace module: uses DOTALL, which means the . special character can match newlines.
When you specify after: '^#tlsproxy', that caret is really saying: 'from the beginning of the search string, immediately followed by #tlsproxy', where the caret effectively means from the beginning of the file.
Ansible tries to match this:
"Pattern for before/after params did not match the given file: ^#tlsproxy(?P<subsection>.*?)^#smtps"
With re.DOTALL, if you want to match the patterns from the beginning of a line, use a newline character instead:
- name: Edit the master.cf file
replace:
path: master.cf
after: '\n#tlsproxy'
before: '\n#smtps'
regexp: '^#(.*)$'
replace: '\1'

Anisble Yaml file formating for quotes

I'm running an ansible playbook that allows me to (or should allow me to) replace two lines in a configuration file for a remote server. Most of the file replacements are dictionary style entries where neither the key nor the value have quotes. But there is one replacement where the name needs to be quoted. Here is the task from the ansible playbook:
- name: Enable traefikExporter within vars.jsonnet configuration file.
ansible.builtin.replace:
path: /home/bill/cluster-monitoring/vars.jsonnet
regexp: "name: 'traefikExporter',[\n\r].*[\n\r]"
replace: |6
name: 'traefikExporter',
enabled: true,
The error thrown is:
The offending line appears to be
replace: |6
name: 'traefikExporter'
^ here
and it notes that it is a mismatched quote. But I've tried changing the yaml replace parameter to > and using \n for line breaks on a single line as well as the | with quoted lines. They all throw versions of the mismatched quote error.
For reference, the following task, which is immediately above this task, runs correctly without errors:
- name: Enable k3s Monitoring within vars.jsonnet configuration file.
ansible.builtin.replace:
path: /home/bill/cluster-monitoring/vars.jsonnet
regexp: "\ k3s: {[^}]*},"
replace: |2
k3s: {
enabled: true,
master_ip: ['192.168.2.139'],
},
The closest thing I could find is here, but this didn't work. In both cases the regexp covers multiple lines and the replace covers the same lines identified by the regexp. What am I missing?
update
I also tried replacing the replacement text and now believe that the actual formatting issue is in the regexp: "name: 'traefikExporter',[\n\r].*[\n\r]" line. No matter what I place in the replace line it throws the error. I think the quotes in the regexp are the issue.
work around
I came up with a work around but it still isn't right. The following is very close to what I'd like - but a bit frustrated that it isn't exactly what I expected:
- name: Enable traefikExporter within vars.jsonnet configuration file.
ansible.builtin.replace:
path: /home/bill/cluster-monitoring/vars.jsonnet
regexp: "name: 'traefikExporter',[\n\r].*"
replace: >4
name: 'traefikExporter',
enabled: true,
The |6 or >6 was the problem - but not sure why. My expected behavior was to have a 6 space indent. But this is the thing throwing the error. When I put it to 4 there is no quote error. But as you can see - to get the formatting right I have to do some weird spacing (the name: is the correct indentation with the 4, but I have to add 6 actual spaces to get the next line to align. Not part of this question - but neither the | nor the > seems to impact the trailing return in both cases there is an extra line after the replacement.
YAML processes escape sequences in double-quoted scalars, so you should use
regexp: "name: 'traefikExporter',[\\n\\r].*[\\n\\r]"
I suggest however to use a block scalar to avoid escaping hell:
regexp: >-
name: 'traefikExporter',[\n\r].*[\n\r]
Regarding the indentation indicator, this cannot work:
replace: |6
name: 'traefikExporter',
enabled: true,
You are basically saying „the following block scalar has 6 spaces indentation in addition to the indentation of the replace: key“. However, it only has two, which makes the YAML parser immediately drop out of block scalar parsing mode. The following error results from the YAML parser trying to interpret what you intend to be the block scalar's content as part of the YAML structure.
I suggest doing:
replace: |-2
name: 'traefikExporter',
enabled: true,
to give the block scalar 2 space in front of each line (which seems to be what you want) and also to remove the trailing newline (with the -).

Remove last three lines from file using ansible

I want to remove last three lines of file using ansible. I tried using lineinfile but it removed all the lines from file. I have posted below my file and ansible-playbook. I want to remove nfs_config, nfs_share and mount_path using lines using ansible.Thanks in advance.
file.txt
[images]
[tickets]
[unix sockets]
[nfs_config]
nfs_share=
mount_path=
Ansible-playbook
- name: Remove mount path from daemon.conf for clean-daemon
linefile:
path: /etc/ovirt-imageio-daemon/daemon.conf
regexp: "[nfs_config]"
state: absent
Use ini_file. The task below will remove the nfs_config section from the configuration file
- ini_file:
path: /etc/ovirt-imageio-daemon/daemon.conf
section: nfs_config
state: absent
regexp: "[nfs_config]" is not doing what you want, you need to use "[nfs_config]", otherwise you are matching any character that is between the []. This is why it's removing multiple lines.
https://docs.python.org/2/library/re.html
Also, just make 3 lineinfile command to match nfs_config, nfs_share and mount_path
You could use onee lineinifile with a complex regex to match them all, but it will be easier to read/maintain with 3 that are clear.

Ansible lineinfile adding ^M to end of lines?

I am using ansible's lineinfile to update a file.
Once I've updated the file - which works - the file has ^M chars at the end of every line.
This behaviour is undesirable - how do I turn it off? It seems counter intuitive that I would then need to dos2unix in order to rectify?
- name: Update database.php - username
lineinfile:
dest: /var/www/html/database.php
regexp: '^\$username.*$'
line: "$username = '{{ mariadb_rc_user }}';"
backrefs: yes
edit note
Template and copy are possible but difficult to use in this situation for reasons I wont go into, but suffice to say: I'd use them if it made sense.
I found the answer and it was the opposite of what I expected. Neither lineinfile nor replace (see the duplicate link for a suggested solution) were the issue. In fact, they were doing their respective jobs - and ending lines with a line feed.
The problem arises because before that the file only has CLRF terminators, which are invisible when they exist exclusively.
When an LF is introduced, the CRLF (^M) is printed in vim to distinguish that there are now two types of line terminations.

ansible syntax for lineinfile search and replace

My current etc/group wheel is setup as the following
wheel:x:10:admin,sshgroup,domaingroup
I need it be
wheel:x:10:admin4,sshlocal,domainusers,domainadmins
- name: add a string to the new file
lineinfile:
dest=/etc/group
backrefs=true
regexp='wheel:x:10:'
line='wheel:x:10:admin4,sshlocal,domainusers,domainadmins'
state = present
error:
The offending line appears to be:
line='wheel:x:10:admin4,sshlocal,domainusers,domainadmins'
state = present
^ here
I tried both with and without escaping : and commmas but to no avail. Can you please suggest. Im using ansible 2.2.1.0
Nevermind guys, playbook ran this time. I think last line where state = present is listed, i looked like used tab spaces instead of spaces for yaml. After I deleted that line and readded it with spaces, it works now.
cat /etc/group | grep wheel
wheel:x:10:admin4,sshlocal,domainusers,domainadmins
Apparently, single quote is good enough to escape: characters in YAML - which is good.

Resources