get dict value from variable key in ansible - 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] }}.

Related

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'] }}

Passing sub vars to Ansible command line

I have an ansible playbook that gets its vars passed in from an extra-vars.json file. It gets passed in at the command line with --extra-vars "#extra-vars.json".
This is an abbreviated version of the var file
{
"source" : {
"access_token" : "abc",
"git_instance_url" : "foo.com",
"repo" : "some-group/some-project/some-repo"
},
"target" : {
"access_token" : "xyz",
"git_instance_url" : "foo.bar.com",
"repo_path" : "lorem/ipsum"
}
}
Because of the var structure, when I call the vars in my playbook I have to use dot notation i.e. {{ source.repo_path }} or {{ target.access_token }}. My problem is that I would like to remove a couple of these vars from the extra-vars.json and pass them individually at the command line. If I remove source.git_instance_url from extra-vars.json I can pass it in without any precedence conflicts.
My issue is that I can't figure out how to pass dot notation vars in at the command line. I don't want to change my playbook to do this. If I pass in --extra-vars "source.git_instance_url=bar.baz.com" I get an error source is undefined.
I tried using bracket notation source[git_instance_url]=bar.baz.com with no success.
Is there a way to pass dot notation vars at the command line or am I going to have to change my playbook from {{ source.git_instance_url }} ==> {{ source_git_instance_url }} to be able to accomplish this?
When passing extra vars, these are always "string variables". I learned it the hard way when trying to pass in boolean variables.
You could pass them as json:
ansible-playbook -e '{"source": { "git_instance_url": "foo" }}' playbook.yml
But I don't know right now, if they get merged with the source var from your vars file. I'd guess, one overwrites the other. So you probably end up with either the source var from your string or with the one from the file.

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?

Check if arrays are defined and not empty in ansible

I have the following code
- set_fact:
MY_HOSTNAME: "SOME VALUE"
MY_SERVER: "00.00.00.00"
- name: Get MY server
set_fact:
MY_SERVER: "{{ groups[MY_HOSTNAME][0] }}"
when: groups[MY_HOSTNAME] is defined
In the above code, groups[MY_HOSTNAME] is an array. What is the best way to check that groups[MY_HOSTNAME] is defined and also that it is not empty
If it is either of that I want the value 00.00.00.00 to be assigned to MY_SERVER
I don't know if it's version specific, but I'm currently running ansible-2.3.2 on RHEL6 and I had to put quotes around the group name to get it to work for me:
when: groups["GROUP_NAME"] is defined and (groups["GROUP_NAME"]|length>0)
Edit: I couldn't add this as a comment to techraf's answer because I don't have enough reputation.
list | length filter returns the number of elements. If it is zero, the list is empty.
For a conditional value use if or ternary filter (example in this answer).
For a composite conditional (groups[MY_HOSTNAME]| default([])) | length.
You can first check if it is indeed a list and then check if it has more than one element:
when: (groups['MY_HOSTNAME'] is defined) and (groups['MY_HOSTNAME'] | type_debug == 'list') and (groups['MY_HOSTNAME'] | length > 0)
try this one (it checks if variable is defined and if it is a iterable like list)
when: (groups["GROUP_NAME"] is defined) and (groups["GROUP_NAME"] is iterable)

Access value through index number from ansible gather facts variable

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.

Resources