Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ansible - variable within variable

Ansible 1.9.2 version.

Does Ansible supports variable expansion within a variable while evaluating it.

I have a task to download 3 zip files from Artifactory.

Instead of writing 3 separate tasks within the role, I used ansible's loop in the playbook. In Ansible role's default/main.yml, I have all the required variables defined/available to the role i.e. jmeterplugins_extras_artifactory_url and other (standard / webdriver) are visible to perf_tests role.

---
#- Download and install JMeterPlugins
# Use get_url when Ansible is 2.0+ is available on the machine (otherwise, we can't use get_url) thus, using wget.
- name: Download JMeterPlugins-*
  command: wget {{ jmeterplugins_{{ item.plugin }}_artifactory_url }}  
    chdir="{{ common_download_dir }}"
    creates="{{ common_download_dir }}/{{ jmeterplugins_{{ item.plugin }}_file }}"
  with_items:
    - { plugin: 'extras' }
    - { plugin: 'standard' }  
    - { plugin: 'webdriver' }   

But with the above code, I'm getting an error (as shown below):

15:58:57 TASK: [perf_tests | Download JMeterPlugins-*] ********************************* 
15:58:57 <jmeter01.super.fast.jenkins> ESTABLISH CONNECTION FOR USER: cmuser on PORT 22 TO jmeter01.super.fast.jenkins
15:58:57 fatal: [jmeter01.super.fast.jenkins] => Failed to template wget {{ jmeterplugins_{{ item.plugin }}_artifactory_url }} chdir="{{ common_download_dir }}" creates="{{ common_download_dir }}/{{ jmeterplugins_{{ item.plugin }}_file }}": template error while templating string: expected token 'variable_end', got '{'
15:58:57 
15:58:57 FATAL: all hosts have already failed -- aborting
15:58:57 
15:58:57 PLAY RECAP ******************************************************************** 
15:58:57            to retry, use: --limit @/home/cmuser/perf_tests.retry
15:58:57 
15:58:57 jmeter01.super.fast.jenkins : ok=23   changed=6    unreachable=1    failed=0   

Doesn't ansible supports variable expansion/evaluation if a variable contains another variable (especially when I'm using a loop).

I just dont want to expand my simple loop task into 3 different -name tasks for downloading zip files for jmeterplugins_extras, jmeterplugins_standard and jmeterplugins_webdriver separately. It seems like the error is related due to Jinja.

How can I use var's value giga in another variable i.e. if var contains giga, then I should get the value of variable "special_giga_variable" ({{special_{{ var }}_variable}})? where var was defined in defaults/main.yml as:

var: giga

like image 925
AKS Avatar asked Sep 21 '15 20:09

AKS


People also ask

How do you pass extra vars in Ansible?

To pass a value to nodes, use the --extra-vars or -e option while running the Ansible playbook, as seen below. This ensures you avoid accidental running of the playbook against hardcoded hosts.

How do you pass arguments in Ansible playbook?

The easiest way to pass Pass Variables value to Ansible Playbook in the command line is using the extra variables parameter of the “ansible-playbook” command. This is very useful to combine your Ansible Playbook with some pre-existent automation or script.

How does Ansible Group_vars work?

The group_vars in Ansible are a convenient way to apply variables to multiple hosts at once. Group_vars is an Ansible-specific folder as part of the repository structure. This folder contains YAML files created to have data models, and these data models apply to all the devices listed in the hosts. ini file.


2 Answers

It does.

You can use

set_fact:
  variable: '{{ vars['my_' + variablename + '_variable'] }}'

the only downside of this approach so far is, it won't dynamically expand variables that get the value of another variable. an example:

roles/xxx/defaults/main.yml:

var1: foo
var2: '{{ var1 }}'

This, unfortunately will not work when trying to use the resolved value in var2. Hence,

- debug: msg='{{ vars["var2"] }}'

will output {{ var1 }} instead of foo.

Workaround:

In your vars declaration, instead of using var2: {{ var1 }}, use var2: '{{ vars["var1"] }}'. That way, it will work.

like image 156
karolyi Avatar answered Sep 27 '22 21:09

karolyi


No it doesn't. But it doesn't mean that you have to expand it into 3 different tasks. What you can do is actually expand you "dictionary" to look similar to this:

with_items:
 - {"url": "https://xxxxx", "file": "/tmp/xxxxx" }
 - {"url": "https://yyyyy", "file": "/tmp/yyyyy" }
 - {"url": "https://zzzzz", "file": "/tmp/zzzzz" }

Then in your task just call different parameters: {{ item.url }} and {{ item.file }}

Alternative Options:

  1. Write your own filter that will expand your variable according to the value {{ jmeterplugins_url | my_custom_filter(item.plugin) }}

  2. Write a custom module, that will encapsulate all of the functionality of fetching url into the file based on your inputs

  3. Write custom lookup_plugin that will iterate through your list of variables and produce correct result.

  4. Since you are using command module you can leverage bash to concatenate your url, file in the same command ( this would probably be the messiest solution )

like image 45
Vor Avatar answered Sep 27 '22 23:09

Vor