How can I add new line "\n" characters to Ansible variable mailbody
I set the below variable to ansible's mail module body attribute.
- set_fact:
mailbody: "{{ mailbody | default('') + 'PROFILE_NAME:' + PROFILE_NAME ~ '\n\nSERVER_NAME:' + SERVER_NAME ~ '\n\nNODE_NAME:' + NODE_NAME ~ '\n\n\n\n' }}"
But the body of the email has '\n\n' printed instead of new lines.
Can you please suggest what changes are needed?
Please try something like this :
as stated on the documentation I share in comment "The difference between single quotes and double quotes is that in double quotes you can use escapes : foo: "a \t TAB and a \n NEWLINE"
so
1.first thing to try:
mailbody: "{{ mailbody | default('') + 'PROFILE_NAME:' + PROFILE_NAME ~}} {{ 'SERVER_NAME:' + SERVER_NAME ~ }}\n\n{{'NODE_NAME:' + NODE_NAME ~ }}\n\n\n\n"
2.if that doesn help then:
mailbody: >
"{{ mailbody | default('') + 'PROFILE_NAME:' + PROFILE_NAME ~}}"
"{{ 'SERVER_NAME:' + SERVER_NAME ~ }}"
"{{'NODE_NAME:' + NODE_NAME ~ }}"
3.if still won't work:
mailbody: |
"{{ mailbody | default('') + 'PROFILE_NAME:' + PROFILE_NAME ~}}"
"{{ 'SERVER_NAME:' + SERVER_NAME ~ }}"
"{{'NODE_NAME:' + NODE_NAME ~ }}"
4.if this still isn't working try removing double quotes to this last 2 and 3.
I created an example playbook using the 4th suggestion from MikZuit's answer with the literal block syntax and it works like a charm. It sets the variable with set_fact which I tried to both debug and copy (print to a file). This is it:
- name: variable test
hosts: 127.0.0.1
connection: local
vars:
mailbody: "I am a mail body."
PROFILE_NAME: "my profile"
SERVER_NAME: "myserver.example.org"
NODE_NAME: "I feel on edge today."
tasks:
- name: variable test | set variable
ansible.builtin.set_fact:
mailbody: |
{{ mailbody | default('') }}
PROFILE_NAME: {{ PROFILE_NAME }}
SERVER_NAME: {{ SERVER_NAME }}
NODE_NAME: {{ NODE_NAME }}
- name: variable test | print variable to stdout
ansible.builtin.debug:
var: mailbody
- name: variable test | print variable to file
ansible.builtin.copy:
content: "{{ mailbody }}"
dest: "/tmp/mailbody.txt"
When I run the playbook the debug output looks like this:
ok: [localhost] => {
"mailbody": "I am a mail body.\n\nPROFILE_NAME: my profile\n\nSERVER_NAME: myserver.example.org\n\nNODE_NAME: I feel on edge today.\n"
}
Note that the debug module prints the output as JSON and escapes any special characters, unlike the copy module which, in this playbook, prints the following output to /tmp/mailbody.txt:
I am a mail body.
PROFILE_NAME: my profile
SERVER_NAME: myserver.example.org
NODE_NAME: I feel on edge today.
Some general notes:
Since v2.10 or so, Ansible has been strongly modularized. This means that task names should now be fully qualified collection names (e.g. ansible.builtin.copy instead of copy) in order to avoid possible name collisions with other collections. Also it does not accept any plays or tasks without a name anymore.
When using the literal block syntax, it will truncate trailing newlines (like the empty line after NODE_NAME: {{ NODE_NAME }}) down to at most one. Btw, you don't need any quotes inside these blocks except for literals in evaluated expressions, e.g. {{ mailbody | default('') }}.
Quoting in Ansible works very similar to quoting in Linux shells. Double quotes can evaluate expressions and escaped characters while single quotes pass everything "as is".
Concerning the unexpected end of print statement error in Ashar's comment: the error occurs because the concatenation operator (~) expects a second operand but instead finds closed curly braces which mark the end of the expression. Just delete all the tildes shown in your error message and you should be good to go.
Related
I have a configmap and the data is being set dynamically with double curly strings like this
{{ default variable.path | quote }}
I'm wondering what the "default" before the variable path and the " | quote " after the variable path mean
I've been looking at many documentation about configmaps but haven't found anything regarding this
In Ansible, I am trying to build a URL string starting from a dictionary.
This is the source dict:
query_string:
UserName: myname
Notes: abcd
GenericField1: foo
This is what I would like to obtain:
UserName=myname&Notes=abcd&GenericField1=foo
I tried several combinations of jinja filers (urlencode, flatten, etc) but I cannot reach my goal.
Anyone has a suggestion?
This solution is working properly:
- name: Create query string from input params
set_fact:
URL_params: "{{ URL_params }}{{ (index > 0)|ternary('&','') }}{{ item.key }}={{ item.value | urlencode }}"
loop: "{{ query_string | dict2items }}"
loop_control:
index_var: index
Is this the code that you're looking for?
- set_fact:
my_url: >
UserName={{ query_string.UserName -}}
&Notes={{ query_string.Notes -}}
&GenericField1={{ query_string.GenericField1 -}}
If the query_string dictionary has more properties, this code provides you with the flexibility to use more field as needed
- name: build the url
set_fact:
myurl: "{{ myurl | default('') + item.key + '=' + item.value + '&' | regex_replace('\\&$', '') }}"
loop: "{{ query_string|dict2items }}"
Almost same as #EBAH:
- set_fact:
url_str: "{{ (url_str | default('')) + ('&' if (index > 0) else '') + (item.key+'='+item.value| urlencode) }}"
loop: "{{ query_string | dict2items }}"
loop_control:
index_var: index
I am using ansible v2.2.1 and I need to remove only the first occurrence of a line in file. So my ansible playbook is as follows.
---
- hosts: localhost
tasks:
- name: read file content
command: cat occurence.txt
register: fc
- debug: var=fc
- debug: msg="{{ item }}"
with_items:
- "{{ fc.stdout_lines }}"
- name: first occurence in file
shell: sed -i '0,/{{ item }}/{/{{ item }}/d;}' occurence.txt
with_items:
- "{{ fc.stdout_lines }}"
register: remove
- debug: var=remove
And occurence.txt file has following content
this is apple
this is apple
this is banana
this is apple
this is orange
How can I delete only the first occurrence of line "this is apple" and leave rest of the lines?
I'm liking Yunnosch's interpretation of the question. An alternative would be this:
sed '0,/^this is apple$/{//d}'
From the beginning of the file to the first occurrence of the apple line, delete only lines matching the previous match.
Find line, when found replace by (initially empty) hold space.
For later occurences, swapping to the identical hold space will basically print unchanged line, even if it, strictly speaking, it is the previous identical line.
Delete in case of (only the first) empty line coming from hold space.
sed "/^this is apple$/{x;/^$/d}"
I solved it as follows by using set_fact variable.
---
- hosts: localhost
tasks:
- name: read file content
command: cat occurence.txt
register: fc
- debug: var=fc
- debug: msg="{{ item }}"
with_items:
- "{{ fc.stdout_lines }}"
- set_fact: value="this is apple"
- debug: var=value
- name: first occurrence in file
shell: sed -i '0,/{{ value }}/{/{{ value }}/d;}' occurence.txt
register: remove
- debug: var=remove
I am using [file lookup] which reads the whole file and stores the content in a variable. My play looks something like this:
- name: Store foo.xml contents in a variable
set_fact:
foo_content: "{{ lookup('file', 'foo.xml' ) | replace('\n', '')}}"
So the above code reads the foo.xml file and stores it in the variable, but the problem is when the foo.xml has line breaks in it, it also includes the line break in the variable.
My foo.xml is this file:
<?xml version="1.0" encoding="utf-8"?>
<initialize_param>
<secrets>
<my_secret id="99">3VMjII6Hw+pd1zHV5THSI712y421USUS8124487128745812sajfhsakjfasbfvcasvnjasjkvbhasdfasgfsfaj5G8A9+n8CkLxk7Dqu0G8Jclg0eb1A5xeFzR3rrJHrb2GBBa7PJNVx8tFJP3AtF6ek/F/WvlBIs2leX2fq+/bGryKlySuFmbcwBsThmPJC5Z5AwPJgGZx</my_secret>
</secrets>
</initialize_param>
The output removes line break \n but also incudes the tabs \r & \t
I need to got rid of the \n , need to get rid of extra formatting too (\r & \t), Moreover after the replace filter I get the error while firing a DB Update query as
stderr: /bin/sh: 1: cannot open ?xml: No such file
Use the Jinja trim filter:
"{{ lookup('file', 'foo.xml' ) | trim }}"
You can do that with the replace filter?
contents: "{{ lookup('file', '/etc/foo.txt') | replace('\n', '')}}"
You may use the regex_replace filter since the trim doesn't clear other line break characters as you mentioned in the question.
"{{ some_stdout_to_clear | regex_replace('[\\r\\n\\t]+','') }}"
I need to do base64 encoding of something like: "https://myurl.com". Because there is a colon in that string, I need to enclose everything in quotes. So I have something like:
- name: do the encode
shell: 'echo "https://myurl.com" | /usr/bin/base64'
register: bvalue
But I get a blank when I use:
{{ bvalue.stdout }}
So I want to use the Ansible construct, but I don't know how and the documentation is not clear. It's something like:
- name: do the encode
shell: '{{ "https://myurl.com" | b64encode }}'
But I know that is wrong. And I can't find any examples. Help!
I think this is how to do it. Define a variable in a playbook:
MYVAR: "https://myurl.com"
Then in the role, do:
- name: do the encode
shell: echo {{ MYVAR | b64encode }} > /tmp/output