Multiline Template - string escaping in Ansible - ansible

I'm trying to get an effect similar to this article: https://gryzli.info/2017/12/21/ansible-debug-print-variables/
Which means in my case:
- name: Gather facts
vars:
msg: |
"{{ansible_distribution}}"
"{{ansible_distribution_major_version}}"
"{{ansible_distribution_release}}"
"{{ansible_distribution_version}}"
The problem ist that without quotes it throws an error to add the quotes. With quotes it throws the same error:
We could be wrong, but this one looks like it might be an issue with missing quotes. Always quote template expression brackets when theystart a value....
How do I correctly escape this multiline string so that Ansible can parse it? Or does this kind of code no longer work?

Q: "How do I correctly escape this multiline string so that Ansible can parse it?"
A: The problem is the indentation of the block. Quoting from Example 8.3. Invalid Block Scalar Indentation Indicators
ERROR:
A leading all-space line must not have too many spaces.
A following text line must not be less indented.
The text is less indented than the indicated level.
The correct syntax is (with or without quotation)
vars:
msg: |
"{{ansible_distribution}}"
"{{ansible_distribution_major_version}}"
"{{ansible_distribution_release}}"
"{{ansible_distribution_version}}"

Related

Yaml Syntax - can not read a block mapping entry; a multiline key may not be an implicit key

I have a .yaml file like this:
title: 'We'll do cool stuff'
draft: true
However, I get the following error:
Error parsing YAML: YAMLException: can not read a block mapping entry;
a multiline key may not be an implicit key at line 2, column 6:
draft: true
^
How can I fix it?
Note: this setup seems different than the other questions where this same error was raised, including the following posts:
Error parsing YAML
Getting following error on serverless.yaml
yaml syntax issues?
You can use a site like YAML Formatter to format and validate your yaml:
In this case, the error message and location is a bit of red-herring.
The error is actually caused by a string that was accidentally terminated because of an unescaped quote symbol within the string. A hint for this is the syntax highlighting of 'We'll do cool stuff'.
To fix, in this case, you can just skip wrapping the string quotes and rewrite like this:
title: We'll do cool stuff
draft: true
Further Reading
Do I need quotes for strings in YAML?
How to escape double and single quotes in YAML
title: "We'll do cool stuff"
draft: true
I have got the exact same issue, The problem with it is, we are using a single quote' in between the string and also wrapping the string with a single quote.
I resolved it by wrapping the string with a double quote.
You can also trace the issue more by reading this

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 -).

How to use escape characters in Ansible shell/grep command

I need to extract a hostname from a URL in a file on my remote host to then use that value in another task.
I have the following task in my playbook:
- name: Extract server name
shell: "grep ^serverURL=https:\/\/(.*)\/XMLRPC <filename>"
register: <variable>
But when I try and run it I get the following error (cut down to relevant bits):
Found unknown escape character. The offending line appears to be:
- name: Extract server name
shell: "grep ^serverURL=https:\/\/(.*)\/XMLRPC <filename>"
^ here
It seems there is a value started with a quote and the YAML parser is expecting to see the line ended with the same kind of quote.
Obviously it does start and finish with double quotes but the carat is at the escape character in my grep query, so it seems reasonable to think that this is the cause of the problem; if I remove the backslashes my grep query doesn't return anything.
How can I escape this correctly please?

Got an error message Syntax Error in ansible-playbook [duplicate]

This question already has answers here:
Quotes in ansible lineinfile
(4 answers)
Closed 4 years ago.
ERROR! Syntax Error while loading YAML.
did not find expected key
The error appears to have been in '/etc/ansible/main.yml': line 73, column 50, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
- name: Ensure IP forwarding is disabled
shell: "sysctl net.ipv4.ip_forward ; grep "net\.ipv4\.ip_forward" /etc/sysctl.conf /etc/sysctl.d/*"
^ here
We could be wrong, but this one looks like it might be an issue with
unbalanced quotes. If starting a value with a quote, make sure the
line ends with the same set of quotes. For instance this arbitrary
example:
I using grep with "" into shell module in ansible playbook and got an ERROR message as follow "ERROR! Syntax Error while loading YAML."
- name: Ensure IP forwarding is disabled
shell: "sysctl net.ipv4.ip_forward ; grep "net\.ipv4\.ip_forward" /etc/sysctl.conf /etc/sysctl.d/*"
register: CIS_3.1.1
ignore_errors: True
That configuration file for ansible is in the YAML format and in YAML a scalar that represents a string can be in multiple formats:
plain: no quotes, has restrictions on the start character and internal character sequences, no escapes
single quoted: can contain double quotes, no escapes except for repeating single quotes
double quoted: backslash escapes in string, in string double quotes need to be escaped
literal: newlines are preserved, no escapes
folded: newlines are converted to spaces, no escapes
You are using double quoted style, and in that you would need to escape the internal double quotes (") and backslashes (\). That gets ugly and unreadble real soon. It is much more useful to use literal style in such cases:
- name: Ensure IP forwarding is disabled
shell: |-
sysctl net.ipv4.ip_forward ; grep "net\.ipv4\.ip_forward" /etc/sysctl.conf /etc/sysctl.d/*
I.e. you put |- (the minus is to strip the final newline of the following line), then put the line without starting or end quotes, indented, on the next line.

Using ansible lineinefile with colon in line

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.

Resources