yaml multi line syntax without newline to space conversion - ansible

I have something like this dictionary:
env: qat
target_host: >
{%if env in ['prd'] %}one
{%elif env in ['qat','stg'] %}two
{%else%}three
{%endif%}
when I print it I get:
ok: [localhost] => {
"var": {
"target_host": "two "
} }
So it is converting the \n at the end of the line to a space. Which is exactly what it is supposed to do. However in this case I am just trying to spread out the lines to make the structure of the if/else more readable and I don't want the extra space. It works as expected if I put it all on one line without the > but I would like to be able to make it multiline just so its easier to read.
I found this question
Is there a way to represent a long string that doesnt have any whitespace on multiple lines in a YAML document?
So I could do:
env: qat
target_host: "{%if env in ['prd'] %}one\
{%elif env in ['qat','stg'] %}two\
{%else%}three\
{%endif%}"
And that gives the desired result.
Is there anyway to accomplish this without cluttering it up even more?

In Jinja* you can strip whitespaces/newlines by adding a minus sign to the start/end of a block. This should do the trick:
env: qat
target_host: >
{%if env in ['prd'] -%}one
{%- elif env in ['qat','stg'] -%}two
{%- else -%}three
{%- endif%}
* Jinja 2 is the templating engine used by Ansible.

Maybe what you need is the | literal?
env: qat
target_host: |
{%if env in ['prd'] %}one
{%elif env in ['qat','stg'] %}two
{%else%}three
{%endif%}
This will not 'fold' newlines into spaces, as oposed to >

Related

How do I add value of "-" to pillar?

I have pillar that is supposed to have value of "-" (without the quotation).
I tried:
my_pillar: -
my_pillar: '-'
my_pillar: "-"
my_pillar: {% raw %}"-"{% endraw %}
{% raw %}my_pillar: "-"{% endraw %}
None of those worked and I am getting error: "block sequence entries are not allowed in this context".
I understand what the problem here is, Salt thinks that it is part of YAML definition of values, not the value itself, but how do I work around that?
As OrangeDog mentions, any type of quoting will work:
docker run --rm -it saltstack/salt /bin/sh
mkdir -p /srv/pillar
cat <<EOF>/srv/pillar/top.sls
base:
'*':
- stuff
EOF
echo "my_pillar: -" >/srv/pillar/stuff.sls
salt-call --local pillar.items -ldebug
# Error happens ^^^^^^^^^^^^^^^^^^^^^^
echo "my_pillar: '-'" >/srv/pillar/stuff.sls
salt-call pillar.items
The output for me:
local:
----------
my_pillar:
-

lineinfile/regexp/line: why line at the end of file?

I don't understand how lineinfile works, I use:
- name: "configure"
lineinfile:
path: /etc/apt/apt.conf.d/50unattended-upgrades
regexp: '^\/\/ "\${distro_id}:\${distro_codename}-updates";'
line: ' "${distro_id}:${distro_codename}-updates";'
state: present
And I expect that line in file will be uncommented:
// "${distro_id}:${distro_codename}-updates";
instead of this, this line stay as it is, but at the end of file,
I see:
"${distro_id}:${distro_codename}-updates";
so "match" happens, but why there is new line at the end of file instead of replace?
Your regexp does not escape all of the special symbols and therefore there is no match which causes the addition of the new line instead of the replacement. Curly braces should be escaped, according to Python's re module documentation.
This task works as expected on my Ubuntu 18.04 server.
- name: "configure"
lineinfile:
path: /etc/apt/apt.conf.d/50unattended-upgrades
regexp: '^//\s+"\$\{distro_id\}:\$\{distro_codename\}-updates";'
line: ' "${distro_id}:${distro_codename}-updates";'
state: present
Diff
-// "${distro_id}:${distro_codename}-updates";
+ "${distro_id}:${distro_codename}-updates";
There must be other problem. The code works as expexted
shell> diff 50unattended-upgrades 50unattended-upgrades.orig
1c1
< "${distro_id}:${distro_codename}-updates";
---
> // "${distro_id}:${distro_codename}-updates";

How can I convert a decimal string to an hexadecimal string?

I have a playbook that queries a server for it's SystemID which can be converted to a model number using a vendor-provided table that maps the id to a model. The server returns a decimal value but the table uses the hexadecimal equivalent.
What I want to do is to convert the decimal string to an hexadecimal string that can be matched with an entry in the vendor-provided table.
Example:
Server returns: SystemID = 1792
Matching entry in vendor table: 0x0700
I've searched in the Ansible documentation and Web searched for either a native Ansible command or jinja2 expression to do the conversion.
I've only found the int(value, base=x) jinja2 function that does the opposite of what I am trying to do.
The native python hex() command can do it. But I'd like to avoid that if possible.
Here is the playbook task that parses the servers stdout to get systemid value:
set_fact:
server_model: "{{ ( server_model_results.stdout_lines | select('match','SystemID' ) | list| first ).split('=')[1] | regex_replace('^\ |\ /$', '' ) }}"
Environment:
Ansible 2.9.7
Python 3.8.0
macOS 10.15.4
You can use a python format with the % operator inside a jinja2 template string:
$ ansible localhost -m debug -a msg="{{ '%#x' % 1792 }}"
localhost | SUCCESS => {
"msg": "0x700"
}
You will probably still have to deal with the leading 0 that is present in your file (i.e. 0x0700).
If all your values are padded to 4 hexa digits in your file (i.e. after the 0x prefix) a quick and dirty solution could be:
$ ansible localhost -m debug -a msg="0x{{ '%04x' % 1792 }}"
localhost | SUCCESS => {
"msg": "0x0700"
}
If not, you will have to implement some kind of dynamic 0 padding to the next odd number of chars yourself.
You might want to switch the 'x' type specifier to 'X' (see doc link above) if hexa digits above nine are uppercase in your vendor table
$ ansible localhost -m debug -a msg="0x{{ '%04x' % 2569 }}"
localhost | SUCCESS => {
"msg": "0x0a09"
}
$ ansible localhost -m debug -a msg="0x{{ '%04X' % 2569 }}"
localhost | SUCCESS => {
"msg": "0x0A09"
}

Test a substring with special character in a list

I have a list with some application landscape names and I have to look for an specific application with special characters in Jinja2
landscape_list: ["cmdb:app1 landscape", "cmdb:app2 (ex app3) landscape",
"cmdb:app4 landscape"]
app_to_look: "app2 (ex app3)"
I'm trying to use this code to test the list:
{{landscape_list | select('search',land_key) | list | count > 0}}
But I'm always getting 0 when I tried to test "app2 (ex app3)".
I think this problem is related with special characters like ().
Is it possible to look into a list for that specific application in jinja2?
Thanks
Q: "This problem is related to special characters like ()."
A: Yes. The parenthesis must be escaped in the regex. For example
- set_fact:
land_key: 'app2 \(ex app3\)'
- debug:
msg: "{{ landscape_list|select('search', land_key)|list }}"
- debug:
msg: "{{ landscape_list|select('search', land_key)|list|length }}"
- debug:
msg: One or more items match the searched pattern.
when: landscape_list|select('search', land_key)|list|length > 0
give
"msg": [
"cmdb:app2 (ex app3) landscape"
]
"msg": "1"
"msg": "One or more items match the searched pattern."
I end up using a similar method. Instead of using search, I used contains as a search method
{{completed_list | select('contains',solution_search) | list | count > 0}}
solution_search contains the full name of what I'm looking.
{%-set solution_search = env_key ~' '~env_server_key ~' TEST'-%}
Where env_key is the application name that can contain special characters and env_server_key is the application environment.

Ansible won't let me add quotes to my variables when I try to use "blockinfile" and "block"

Using containers, I'm trying to create a .bashrc file with Python3 Ansible v0.2.4.2.0. I'm also using Ansible roles.
- name: Adding environment vars to .bashrc file
blockinfile:
path=/.bashrc
insertafter: EOF
block: |
export VAR1={{ var1 }}
export VAR2={{ var2 }}
export VAR3={{ var3 }}
Where all 3 variables are defined in my main file, play.yml. So, let's say var1 is equal to "-a -b -c" (including the quotes), var2 is equal to "d" and var3 is equal to "e"
Then after I run play.yml, my .bashrc file looks like:
export VAR1=-a -b -c
export VAR2=d
export VAR3=e
But what I really want is
export VAR1="-a -b -c"
export VAR2="d"
export VAR3="e"
If I don't have the quotes for VAR1, then running source /.bashrc gives me:
bash: export: `-a: not a valid identifier
bash: export: `-b: not a valid identifier
bash: export: `-c: not a valid identifier
I've tried this:
- name: Creating .bashrc file
blockinfile:
path=/.bashrc
insertafter: EOF
block: |
export VAR1=\"{{ var1 }}\"
export VAR2=\"{{ var2 }}\"
export VAR3=\"{{ var3 }}\"
but that does not add quotes to my .bashrc file. I still get the same results. What can I do to add quotes? I've also tried adding \"\", which adds exactly \"\" to the beginning of each line. So that doesn't work either when I try to run source /.bashrc
Set your variables like this:
var1: '"fred"'
var2: '"barney"'
var3: '"wilma"'

Resources