How to execute a shell script and use the result in ansible - linux

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 }}"

Related

Filter out content from Ansible output

I want to filter out ip address alone from the ansible output. When I tried to filter out with the awk command, it failed. Please see my code, output, and required output.
- name: Gather all VMs from a specific folder
community.vmware.vmware_vm_info:
hostname: hostname_local
username: vmwarelogin
password: passwordvmware
folder: "/VMFS/"
validate_certs: False
delegate_to: localhost
register: vm_info
- debug:
var: ip
vars:
ip: "{{ vm_info.virtual_machines|
selectattr('guest_name', 'eq', 'My-Machine')|
map(attribute='ip_address')|first }}"
register: ip
- name: add ip
shell: echo "{{ip}}"| awk '{print $2}'
Output after running the above code
{'ip': '192.168.1.32', 'failed': False, 'changed': False}
Expected output is
192.168.1.32
Any help would be appreciated to use this IP address as a variable for other places in the same playbook
If I understand what you want to convey using YAML tag you are implying
{'ip': '192.168.1.32', 'failed': False, 'changed': False}
should be treated as YAML file. If this is case you should if allowed use YAML parser, if you want parser which can be used as part of pipelined command then I suggest trying yq. If you are forced to use AWK for this then be warned that it is best suited for working with entities which belong to Chomsky Type-3 while YAML is not Chomsky Type-3 contraption. Anyway it might suffice for your case. I would propose following heurestic: grab 1st thing which looks like IP address in decimal notation, this could be done following way in GNU AWK let say you are using standard input to deliver
{'ip': '192.168.1.32', 'failed': False, 'changed': False}
then
awk 'BEGIN{FPAT="[0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}[.][0-9]{1,3}"}{print $1}'
output
192.168.1.32
Explanation: I use field pattern (FPAT) to inform GNU AWK that field is 1 to 3 digits followed by literal dot followed by 1 to 3 digits followed by dot followed by 1 to 3 digits followed by dot followed by 1 to 3 digits. Note that this does consider solely IP addresses in decimal notation and could also give false positives (e.g. it will find 999.999.999.999) but hopefully your input is not such malicious. I print 1st such field found for each line.
(tested in gawk 4.2.1)
Regarding how to
... use this IP address as a variable for other places in the same playbook?
and reviewing the provided example it looks that you can simplify your case as follows:
---
- hosts: localhost
become: false
gather_facts: false
vars:
IP: "192.168.2.1"
tasks:
- name: Show vars
debug:
var: IP
register: result
- name: Show result
debug:
var: result
- name: Show IP
debug:
msg: "{{ result.IP }}"
Just by using finally echo "{{ ip.ip }}" in your case.
I want to filter out IP address alone from the Ansible output.
There is no need for awk at all as the content is already there and direct accessible.
Expected output is ...
The result would be as required
TASK [Show vars] ***
ok: [localhost] =>
IP: 192.168.2.1
TASK [Show result] ***
ok: [localhost] =>
result:
IP: 192.168.2.1
changed: false
failed: false
TASK [Show IP] ***
ok: [localhost] =>
msg: 192.168.2.1
Further Documentation
Registering variables
Dictionary variables
debug module – Print statements during execution

Ansible search and replace without regex only string literals to avoid escaping

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\"]"'

Build URL string from dictionary in ansible with filters

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

Delete only the first occurence of the line in a file using Ansible

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

how to use ansible b64encode

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

Resources