Ansible JSON Query sabznbd Linux tarball only, not the whole source code - ansible

I am trying to download the latest version of sabnzbd from Github API via Ansible. I know how to get the whole tarball like so;
---
- name: Install sabnzbd
hosts: all
become: true
tasks:
- name: Get URL of latest sabnzbd
ansible.builtin.uri:
url: https://api.github.com/repos/sabnzbd/sabnzbd/releases/latest
body_format: json
return_content: true
remote_src: yes
register: json_reponse
- name: Download sabnzbd tarball
ansible.builtin.get_url:
url: "{{ json_reponse.json.tarball_url }}"
dest: /tmp
register: sabnzbd_tarball
However, I would rather just get the *src.tar.gz Linux tarball to keep the directory as clean as possible.
I have tried;
---
- name: Install sabnzbd
hosts: all
become: true
gather_facts: false
tasks:
- name: Get latest version
uri:
url: "https://api.github.com/repos/sabnzbd/sabnzbd/releases/latest"
return_content: yes
register: github_response
- set_fact:
binary_asset_url: "{{ github_response.json|json_query(query) }}"
vars:
query: "[? browser_download_url=='[*]]-src.tar.gz'"
- debug:
var: binary_asset_url
Just to see if I can get the URL, but I can't. I know I can use a shell one liner, but it's not as clean. I also would like to understand how to query json better by seeing this in action.

If you aren't stuck on using query you could just select the attribute using a search like this.
$ cat stack.yml
---
- name: Install sabnzbd
hosts:
localhost
tasks:
- name: Get URL of latest sabnzbd
ansible.builtin.uri:
url: https://api.github.com/repos/sabnzbd/sabnzbd/releases/latest
body_format: json
return_content: true
remote_src: yes
delegate_to: localhost
register: json_response
- name: Debug json_response
debug:
msg: "{{ (json_response.json.assets | selectattr('browser_download_url', 'search', 'src.tar.gz') | list | first).browser_download_url }}"
Yielding:
$ ansible-playbook stack.yml
PLAY [Install sabnzbd] *********************************************************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************************************************
ok: [localhost]
TASK [Get URL of latest sabnzbd] ***********************************************************************************************************************************************************
ok: [localhost]
TASK [Debug json_response] *****************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "https://github.com/sabnzbd/sabnzbd/releases/download/3.7.0/SABnzbd-3.7.0-src.tar.gz"
}

Related

Errors when use "json_query" in Ansible

When use json_query in Ansible, got the error along with my code as shown below.
The Python used in Ansible is 3.6.8, and used the same version installed jmespath: pip install jmespath, so, this should not be the issue. The Ansible code should be fine as well.
fatal: [localhost]: FAILED! => {"msg": "template error while templating string: no filter named 'json_query'. String: {{ jsondata | json_query(jmesquery) }}"
The following is the Ansible codes:
---
- name: ReadJsonfile
hosts: localhost
tasks:
- name: Display the JSON file content
shell: cat config.json
register: result
- name: save the JSON data to a Variable as a Fact
set_fact:
jsondata: "{{ result.stdout | from_json }}"
- name: setDomainName
set_fact:
domain_name: "{{ jsondata | json_query(jmesquery) }}"
vars:
jmesquery: 'domain.name'
- name: setDomainUsername
set_fact:
domain_username: "{{ jsondata | json_query(jmesquery) }}"
vars:
jmesquery: 'domain.user'
- name: setDomainPassword
set_fact:
domain_password: "{{ jsondata | json_query(jmesquery) }}"
vars:
jmesquery: 'domain.password'
- name: setadmin_Listenport
set_fact:
admin_ListenPort: "{{ jsondata | json_query(jmesquery) }}"
vars:
jmesquery: 'domain.admin.listenport'
- name: Debug the values
debug: msg=" Admin Listen Port => {{ admin_ListenPort }}, DomainName => {{ domain_name }}, DomainUserName => {{ domain_username }} , Domain Password => {{ domain_password }}"
From the error message, I suspect you are using ansible 2.10
The json_query filter is part of the community.general collection which needs to be installed separately starting from this version (this is clearly stated in the documentation)
ansible-galaxy collection install community.general
That being said:
your actual jmespath queries will not return what you expect
using shell to get a file content from remote is a bad practice
that's lots of set_facts and json_query to simply get data that is readily available
Since yaml is a strict superset of json, any valid json is also a valid yaml. In your case, you only have to load the content of the file and you have the data.
One solution is to fetch the file locally and then use include_vars.
In this particular case, using slurp looks like the best option.
This is what (I believe, since you did not provide an example) your config file looks like. I pushed that file in /tmp/config.json for my example.
{
"domain": {
"name": "toto",
"user": "doejohn",
"password": "sosecret",
"admin": {
"listenport": 5501
}
}
}
This is the demo playbook
---
- name: Load remote json content demo
hosts: localhost
gather_facts: false
vars:
config_file: /tmp/config.json
# Of course the below vars will fire errors
# if you call them before slurping data from remote.
# Note: loading `data` in a jinja expression on its own
# forces to transform it back rom string to json data.
# You can accomplish the same result in one go
# using the `from_json` filter
# i.e. => domain: "{{ (slurped_config.content | b64decode | from_json).domain }}"
data: "{{ slurped_config.content | b64decode }}"
domain: "{{ data.domain }}"
# Note2: the above will work and adapt to N hosts in your play: you will get
# the correct data for each host in every task.
tasks:
- name: Slurp config file content
slurp:
src: "{{ config_file }}"
register: slurped_config
- name: Show result
vars:
message: |-
name is: {{ domain.name }}
user is: {{ domain.user }}
password is: {{ domain.password }}
port is: {{ domain.admin.listenport }}
debug:
msg: "{{ message.split('\n') }}"
which gives:
PLAY [Load remote json content demo] ******************************************************
TASK [Slurp config file content] **********************************************************
Wednesday 21 April 2021 17:57:47 +0200 (0:00:00.010) 0:00:00.010 *******
ok: [localhost]
TASK [Show result] ************************************************************************
Wednesday 21 April 2021 17:57:48 +0200 (0:00:00.199) 0:00:00.209 *******
ok: [localhost] => {
"msg": [
"name is: toto",
"user is: doejohn",
"password is: sosecret",
"port is: 5501"
]
}
PLAY RECAP ********************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Wednesday 21 April 2021 17:57:48 +0200 (0:00:00.027) 0:00:00.237 *******
===============================================================================
Slurp config file content ---------------------------------------------------------- 0.20s
Show result ------------------------------------------------------------------------ 0.03s

Ansible only run when subelement of variable exists

I have some variables defined like this:
x_php_versions_installed:
php70:
- php70-curl
- php70-xml
- php70-xmlrpc
- php70-zip
- pecl-memcached
php71:
- php71-curl
- php71-xml
- php71-xmlrpc
- php71-zip
php72:
- php72-curl
- php72-xml
- php72-xmlrpc
- php72-zip
- pecl-memcached
And I would like to check all of the vars (php70, php71, php72 and so on) has this variable: pecl-memcached and if one has, then run a command. My playbook looks like this:
- name: memcached pecl install
pear:
executable: '/usr/local/{{ item }}/bin/pecl'
name: 'pecl/memcached'
state: 'latest'
with_items: '{{ x_php_versions_installed | list }}'
when: 'item.pecl-memcached is defined'
this should call the /usr/local/php70/bin/pecl and /usr/local/php72/bin/pecl binary to install memcached. As soon as I remove the when condition, it works very well, but it will call every variable inside x_php_versions_installed not only where pecl-memcached is defined. So I need to fix the when condition in this case, but all of my tries are gives me an error.
If you want your when to check a list properly, you'll have to use the test operator in of Jinja:
- name: memcached pecl install
pear:
executable: '/usr/local/{{ item }}/bin/pecl'
name: 'pecl/memcached'
state: 'latest'
with_items: '{{ x_php_versions_installed | list }}'
when: "'pecl-memcached' in x_php_versions_installed[item]"
Given the playbook:
- hosts: localhost
gather_facts: no
vars:
x_php_versions_installed:
php70:
- php70-curl
- php70-xml
- php70-xmlrpc
- php70-zip
- pecl-memcached
php71:
- php71-curl
- php71-xml
- php71-xmlrpc
- php71-zip
php72:
- php72-curl
- php72-xml
- php72-xmlrpc
- php72-zip
- pecl-memcached
tasks:
- debug:
msg: "{{ item }}"
with_items: "{{ x_php_versions_installed | list }}"
when: "'pecl-memcached' in x_php_versions_installed[item]"
The recap would be:
TASK [debug] *******************************************************************
ok: [localhost] => (item=php70) => {
"msg": "php70"
}
skipping: [localhost] => (item=php71)
ok: [localhost] => (item=php72) => {
"msg": "php72"
}
Your subelement is a list not a dictionary, so accessing an element key like your are trying here, i.e.:
when: "x_php_versions_installed[item]['pecl-memcached'] is defined"
would work on a dictionary like this one:
x_php_versions_installed:
php70:
php70-curl:
php70-xml:
php70-xmlrpc:
php70-zip:
pecl-memcached:
# same goes for the other versions of PHP
Given the playbook:
- hosts: localhost
gather_facts: no
vars:
x_php_versions_installed:
php70:
php70-curl:
php70-xml:
php70-xmlrpc:
php70-zip:
pecl-memcached:
php71:
php71-curl:
php71-xml:
php71-xmlrpc:
php71-zip:
php72:
php72-curl:
php72-xml:
php72-xmlrpc:
php72-zip:
pecl-memcached:
tasks:
- debug:
msg: "{{ item }}"
with_items: "{{ x_php_versions_installed | list }}"
when: "x_php_versions_installed[item]['pecl-memcached'] is defined"
The recap would be:
TASK [debug] *******************************************************************
ok: [localhost] => (item=php70) => {
"msg": "php70"
}
skipping: [localhost] => (item=php71)
ok: [localhost] => (item=php72) => {
"msg": "php72"
}

Not able to print output

I want to print storage filer version output generated by the na_ontap_command module using ansible-playbooks.
I tried to register the result in a variable and print it using a debug message, but I am getting error.
`---
- hosts: localhost
name: run ontap cli command
gather_facts: no
connection: local
vars_files:
- var_file.yml
tasks:
- name: run ontap cli command
na_ontap_command:
command: ['version']
https: true
validate_certs: false
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
register: command_result
- debug:
var: command_result.stdout_lines
`
My playbook should return the version of the storage filer NetApp Release 9.1P8
This is the debug I am getting:
>TASK [debug] ***********************************************************************************************************************************************************************************************************
ok: [localhost] => {
"command_result.stdout_lines": "VARIABLE IS NOT DEFINED!"
}
---
- hosts: localhost
name: run ontap cli command
gather_facts: no
connection: local
vars_files:
- var_file.yml
tasks:
- name: run ontap cli command
na_ontap_command:
command: ['version']
https: true
validate_certs: false
hostname: "{{ hostname }}"
username: "{{ username }}"
password: "{{ password }}"
register: command_result
- debug:
var: command_result
Result after executing:
TASK [debug] ***********************************************************************************************************************************************************************************************************
ok: [localhost] => {
"command_result": {
"changed": true,
"failed": false,
"msg": "<results xmlns=\"http://www.netapp.com/filer/user\" status=\"passed\"><cli-output>NetApp Release 9.1P8: Wed Aug 30 13:33:41 UTC 2017\n\n</cli-output><cli-result-value>1</cli-result-value></results>"
}
}
Try this:
register: output
- name: print CLI Output
debug:
msg:
- "output": "{{output.msg.split('\n')}}

ansible vars_files and extra_vars to read input

looking to pass the dict to read a set of key value pairs based on the location. When values are hardcoded to the playbook, it works fine but calling through extra_vars giving an error message. Not sure even if it supports. appreciate, your thoughts and inputs.
ansible-playbook play3.yml -e '{"var1":"loc2"}' -vv
play3.yml
---
- name: testing
hosts: localhost
connection: local
gather_facts: no
vars_files:
- var_file.yml
tasks:
- debug:
msg: "{{ var1['first'] }}"
var_file.yml
---
loc1:
first: name1
last: name2
loc2:
first: python
last: perl
...
"Anything's possible in an animated cartoon." -Bugs Bunny
This playook:
---
- name: testing
hosts: localhost
connection: local
gather_facts: no
vars_files:
- var_file.yml
tasks:
- debug:
var: "{{ item }}.first"
with_items: "{{ var1 }}"
Gave me this output:
TASK [debug] **********************************************************************************************************************************
task path: /home/jack/Ansible/CANES/PLAYBOOKS/play3.yml:9
ok: [localhost] => (item=None) => {
"loc2.first": "python"
}

Ansible : error in calling the groups through restapi

I am trying fetch to distinct groups in the inventory through a variable.this is the command am trying to run in the playbook to add hosts to the Nagios XI. Am trying to do this using Rest API through CURL command. Am getting error as Incorrect pattern. Can some one please advise about the issue. or help me out with how we can call two groups from the inventory in the same command.
- name: add host to nagios XI.
shell: curl -XPOST "http://16.231.22.60/nagiosxi/api/v1/config/host?apikey=qfOQpKFORCNo7HPunDUsSjW7f2rNNmrdVv3kvYpmQcNdSS2grV2jeXKsgbv3QgfL&pretty=1" -d "host_name={{ item.hostname }}&address={{ item.address }}&use=xiwizard_ncpa_host&max_check_attempts=5&check_period=xi_timeperiod_24x7&notification_interval=60&notification_period=xi_timeperiod_24x7&notifications_enabled=0&contacts=nagiosadmin&contact_groups=Candle Admins,Candle-L1-L2-Internal&applyconfig=1"
with_items:
- { hostname: "{{ groups['grp1'] }}", address: "{{ groups['grp2'] }}"}
EDIT: code formatting
Understanding that your hostname and address from each group match each other you can do the following:
Inventory:
[grp1]
host1
host2
host3
[grp2]
10.100.10.1
10.100.10.2
10.100.10.3
Play:
---
- name: Debug Together
hosts: localhost
gather_facts: False
tasks:
- name: Add host to nagios XI
shell: shell: curl -XPOST "http://16.231.22.60/nagiosxi/api/v1/config/host?apikey=qfOQpKFORCNo7HPunDUsSjW7f2rNNmrdVv3kvYpmQcNdSS2grV2jeXKsgbv3QgfL&pretty=1" -d "host_name={{ item.0 }}&address={{ item.1 }}&use=xiwizard_ncpa_host&max_check_attempts=5&check_period=xi_timeperiod_24x7&notification_interval=60&notification_period=xi_timeperiod_24x7&notifications_enabled=0&contacts=nagiosadmin&contact_groups=Candle Admins,Candle-L1-L2-Internal&applyconfig=1"
with_together:
- "{{ groups['grp1'] }}"
- "{{ groups['grp2'] }}"
You will get something like:
TASK [debug] ******************************************************************************************************************
ok: [localhost] => (item=None) => {
"item.0, item.1": "(u'host1', u'10.100.10.1')"
}
ok: [localhost] => (item=None) => {
"item.0, item.1": "(u'host2', u'10.100.10.2')"
}
ok: [localhost] => (item=None) => {
"item.0, item.1": "(u'host3', u'10.100.10.3')"
}
Comming from my test:
- name:
debug:
var: item.0, item.1
with_together:
- "{{ groups['grp1'] }}"
- "{{ groups['grp2'] }}"

Resources