i like to search and replace string which makes me to escape allot of if i use the regexp search / replace :
in the mystuff.txt (soory about the blah blah but is allot of personal text ) i have allot of string but i like to search and replace those:
Blah Blah ${DBNname.db_name} Blah Blah
Blah Blah ${DBNname.db_name} Blah Blah
Blah Blah ${DBName.ip}
In ansible playbook i have this :
- name: search
replace:
path: "foo/mystuff.txt"
regexp: "{{ item.split('|')[0] }}"
replace: "{{ item.split('|')[1] }}"
with_items: "{{ config_list }}"
And in command line i passing :
config_list =['\\\${DBNname\\\.db_name}|MySql','\\\${DBName\\\.ip}|127.0.0.1']
and this is working fine .
As you can see i have allot of escaping going on i like to avoid it as the paramters can be long.
Are you required to pass in your config_list variable on the command line? Because if you put it in a file instead, the escaping is much simpler. For example, if I place the following content in config_list.yml:
config_list:
- search: '\${DBNname\.db_name}'
replace: 'MySql'
- search: '\${DBNname\.ip}'
replace: '127.0.0.1'
I can run this playbook:
- hosts: localhost
gather_facts: false
tasks:
- replace:
path: mystuff.txt
regexp: '{{ item.search }}'
replace: '{{ item.replace }}'
loop: '{{ config_list }}'
Like this:
ansible-playbook playbook.yml -e #config_list.yml
And it transforms this:
${DBNname.db_name}
${DBNname.ip}
Into:
MySql
127.0.0.1
If you really need to pass parameters on the command line using the format shown in your question, this seems
to work:
$ ansible-playbook playbook.yml -e '{"config_list": ["\\${DBNname\\.db_name}|MySql", "\\${DBNname\\.ip}|127.0.0.1"]}'
If you write the playbook like this:
- hosts: localhost
gather_facts: false
tasks:
- replace:
path: mystuff.txt
regexp: '{{ x.0 }}'
replace: '{{ x.1 }}'
vars:
x: "{{ item.split('|') }}"
loop: '{{ config_list }}'
The above playbook also works with this input:
ansible-playbook playbook.yml -e 'config_list="[\"\\${DBNname\\.db_name}|MySql\", \"\\${DBNname\\.ip}|127.0.0.1\"]"'
Related
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.
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
First of all, I'm still an ansible newbie, so please excuse my ignorance.
I don't know if that's even possible, but I'm trying to get the URL produced by this command:
curl -s https://api.github.com/repos/Radarr/Radarr/releases | grep linux.tar.gz | grep browser_download_url | head -1 | cut -d \" -f 4
and use it in play to download the package:
here is my play:
- name: download Radarr
get_url:
url: "{{ Radarr_exe_url }}" #should be the url from above
dest: "{{ Radarr_data_path }}"
become: true
become_user: "{{ Radarr_user_name }}"
notify:
- Restart Radarr service
- name: Get Radar exe url
shell: curl -s https://api.github.com/repos/Radarr/Radarr/releases | grep linux.tar.gz | grep browser_download_url | head -1 | cut -d \" -f 4
register: shell_output
- set_fact:
Radarr_exe_url : "{{ shell_output.stdout }}"
Here is pure Ansible solution, as calling shell commands when there is module available considered bad practice:
- hosts: localhost
gather_facts: no
tasks:
- uri:
url: https://api.github.com/repos/Radarr/Radarr/releases
return_content: yes
body_format: json
changed_when: no
register: radarr_releases
- set_fact:
Radarr_exe_url: "{{ radarr_releases.json | json_query('[0].assets[].browser_download_url') | select('search','linux.tar.gz') | first }}"
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 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