Access value through index number from ansible gather facts variable - ansible

I am using gather fact variable to get size information about host. for some server I am getting variable "ansible_devices": { "sda" and for few server getting "ansible_devices": { "cciss!c0d0".
Problem:- When I am using variable {{ ansible_devices.sda.size }} in my playbook and if sda key not found in ansible_device variable then obviously it gives me error
fatal: [xyz101] =>One or more undefined variables: dict object has no element sda
Getting value in ansible_device variable like below
"ansible_devices": {
"sda": {
"size": "68.33 GB",
........
}
},
"item": ""
or
"ansible_devices": {
"cciss!c0d0": {
"size": "68.33 GB",
........
}
},
"item": ""
Also I can access size here using {{ ansible_devices.sda.size }} in first case But unable to fetch value in {{ ansible_devices.cciss!c0d0.size }} in second case.
It might be the case special character in a json key that's why I am unable to fetch its value.
Is there any way to access this variable through key index {{ ansible_devices[0].size }} ?
or any other better way to access it.

You could use a conditional?
when: ansible_devices.sda exists
Or you can iterate through ansible_devices.keys() and with_items.

We can check key by using has_key in ansible playbook like below.
when: ansible_devices.has_key('sda')
Above check resolve my fetal error as I have added two task for these two keys. But still I am looking the solution where I can get these key value through index number. It will replace multiple condition into one.

Related

How can I work with multi level dictionnary?

I have the following json data to work with:
"result": {
"json": {
"licences": {
"4216": {
"license": "4512-5421-5134-7413"
}
}
}
}
I first tried to get my expected value with the following debug task:
- name: Display Licence ID
ansible.builtin.debug:
var: result.json.licences[0].license
But it returns :
"VARIABLE IS NOT DEFINED!"
As a work-around I'm currently using :
- name: Display Licence ID
ansible.builtin.debug:
var: result.json.licences[result.json.licences|first].license
This works but isn't there a better way than repeating the whole variable name?
Your input data is effectively a dict but you are trying to use it as a list. There is no element named 0 (i.e. having a key which value is 0) in your dict called licences (and since it is not a list, there is no first element at index 0 either).
What I understand from your question is that your licences dict will always contain a single key and that you want to get the licence number inside that key whatever the key name is. Please edit your question to be more specific if my understanding is wrong.
One way to do this is:
- name: Display licence ID
debug:
msg: "{{ result.json.licences | dict2items | map(attribute='value.license') | first }}"
Explanation:
the dict2items filter transforms your result.json.licenses dict
{
"4216": {
"license": "4512-5421-5134-7413"
}
}
into a list of key/value dicts
[
{
"key": "4216",
"value": {
"license": "4512-5421-5134-7413"
}
}
]
the map(attribute='value.license)` filter extracts the nested attribute from each element into a list
[
"4512-5421-5134-7413"
]
the first filter keeps only the first element from that list:
"4512-5421-5134-7413"
If you ever have several results and want to get a list of license number, just remove the first filter at the end. You can also build up on this example to get the key for the license if you need it one day.
Create the complete path. Attribute '4216' is a string. It must be quoted. Put it into the brackets
- debug:
var: result.json.licences['4216'].license
vars:
result:
json:
licences:
'4216':
license: 4512-5421-5134-7413
gives
result.json.licences['4216'].license: 4512-5421-5134-7413
If you don't know the number, or, in general, the name of the attribute, use json_query. For example,
- debug:
var: result.json.licences|json_query('*.license')|first
As a side note: If the attribute were a number 4216 you could have used it without quotes and brackets. For example,
- debug:
var: result.json.licences.4216.license
vars:
result:
json:
licences:
4216:
license: 4512-5421-5134-7413
gives
result.json.licences.4216.license: 4512-5421-5134-7413
For details see Referencing key:value dictionary variables.

How to render a literal 'null' in Jinja2 Template

I'm working on an ansible role that allow users to interact with a REST API. I create json.j2 templates that allow me to build the message payload and eventually submit. One of the fields expects either a string value ("") or null.
{
"value": "{{ example.value | default(null, true) }}"
}
This doesn't work and I get this error:
The task includes an option with an undefined variable. The error was: 'null' is undefined
I need that null value and I need to come in as the default value if no other value is provided.
How do I do this?
As pointed in the comments, null has no meaning in Python, None is the Python representation of what your are looking for.
Now, if you want to convert this to a JSON value, then there is a to_json filter in Ansible, so:
'{ "value": {{ example.value | default(None, true) | to_json }} }'
Would end up as:
{ "value": null }

Jinja2 - create a dynamic variable using value of variable as part of the key of another variable

I am writing a jinja2 template for an Ansible role. I have this in my role/x/vars/main.yml
switches:
- hostname: foo
customer: abc
abc_secret_key: myP#$$word
xyz_secret_key: myS3cr3t
In my template, I want to reference the secret key based on the value of customer variable.
I can reference abc_secret_key by using {{ item.abc_secret_key }}. That works, no problem. However I really want to build the variable name dynamically and use the value of the "customer" variable (in the case abc) as part of variable name abc_secret_key.
This does not work.
I get
"msg": "AnsibleUndefinedVariable: 'dict object' has no attribute u'abc'"
but, hopefully it illustrates what I am trying to do
my secret key is {{ item[item.customer]['_secret_key'] }}
I would like it to render like this:
my secret key is myP#$$word
I have tried about 10-15 different renditions but, can not pin down the right syntax.
As you see the dict key lookup with a literal string key, you can compose a dynamic string to serve as the dict key:
- debug:
msg: my secret key is {{ item[ item.customer ~ '_secret_key'] }}
Where the ~ is jinja2 syntax for string concatenation where either side is first coerced to a string, and then concatenated. You are welcome to use +, too, if you are certain that both sides are already strings (as is likely the case here, base on your cited example):
- debug:
msg: my secret key is {{ item[ item.customer + '_secret_key'] }}

How do you retrieve the value of a dynamic key name from the results of a register command in ansible

I am looking to retrieve the value of a key (which will have a different key name each time) from a third-party module output.
A simple replication of what I am trying to achieve is as follows:
I have a variable -
secure_name: "ALIAS_HTTPD_HOSTNAME1'
I then run the task:
- name: retrieve param name
shell:
cmd: "echo {{ secure_name }} | cut -'_' -f2-"
register secure_param_name
I have a third module which takes the above {{ secure_param_name.stdout|upper }} as a parameter to retrieve the name value pair from a third party software for holding secure key pairs.
The output of the third party module is stored in a register var called: secure_results
The output of the third party module call is:
{
"changed": false,
"_ansible_no_log: false,
"HTTPD_HOSTNAME1": "SERVERNAME1"
}
if i issue:
-debug: msg="{{ secure_results.HTTPD_HOSTNAME1 }}"
i get the required output SERVERNAME1
I don't however want to have to hardcode every param I wish to retrieve. I wish to be able to use the value of secure_param_name.stdout to make up the variable_name
I have tried:
-debug: msg="{{'secure_results.'+secure_param_name.stdout }}
but this only returns: secure_results.HTTPD_HOSTNAME1
How do I resolve the above dynamic variable name?
using 2 sets of {{ {{ }} }} doesn't work.
I have also tried:
- debug: msg="{{ vars['secure_results.' ~ secure_param_name.stdout] }}"
this errors with 'dict object' has no attibute u'secure_results.HTTPD_HOSTNAME1'
I am a little confused as to why its not finding the dictionary object 'secure_results.HTTPD_HOSTNAME1' when placing that same string in {{ }} retrieves the value as shown in the first debug above.
Any help much appreciated
I think I have this working now by using the following:
- debug: msg="{{ hostvars[inventory_hostname]['secure_results'][secure_param_name.stdout] }}"
would that be the best way to do this?

get dict value from variable key in ansible

Here is my problem I need to get a dict value from key. But the key is also a var.
For example, I had an ansible role.
In vars/main.yml, I defined vars as below:
---
location: "USA"
source: {
"China": "/net/server1/patha",
"USA": "/net/server2/pathb",
"Japan": "/net/server3/pathc"
}
So in my tasks: tasks/main.yml. How do get "/net/server2/pathb" using the vars. I tried below in tasks, all did not work.
-shell: "perl run.perl {{ source.location }}/script.pl"
-shell: "perl run.perl {{ source.{{ location }} }}/script.pl"
This may be a simple question. But I searched many posts for a long time and still cannot get a right answer. So please help and many thanks.
The answer is {{ source[location] }}.

Resources