Dynamic variable name in Jinja for loop [duplicate] - ansible

I have vars where I put something like this:
vars/main.yml
hello_port: 80
world_port: 81
in my ansbile file I load the vars with
vars_files:
- ./vars/main.yml
This is how I initialize m_name:
- name: set_fact
set_fact:
m_name:
- 'hello'
- 'world'
and after that I have task with iterate using with_items:
- debug:
msg: "{{ (item + '_port') }}"
with_items: "{{ m_name }}"
But I've got as output
hello_port
world_port
not their values.
OK I find that if I use debug var it is working. But If I want to put this expression "{{ (item + '_port') }}" for an example in shell task it does not evaluate it. Is there a way to evaluate the dynamically created variables name - to get the value?

https://docs.ansible.com/ansible/2.5/plugins/lookup/vars.html
- name: Show value of 'variablename'
debug: msg="{{ lookup('vars', 'variabl' + myvar)}}"
vars:
variablename: hello
myvar: ename

{{ hostvars[inventory_hostname][item + '_port'] }}
http://docs.ansible.com/ansible/latest/faq.html#how-do-i-access-a-variable-name-programmatically

I think you are searching for:
{{ vars[item ~ '_port'] }}

I guess best way is to use varnames_lookup
- name: List variables that start with qz_
debug: msg="{{ lookup('varnames', '^qz_.+')}}"
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/varnames_lookup.html

Related

ansible lookup: issue in displaying as a list

I have a var file named prop.yml and contains:
var1:
- 'a'
- 'b'
var2:
- 'blah'
- 'blab'
Now, my playbook looks like:
task:
- name: including a variety file
include_vars:
file: prop.yml
name: property
- set_fact:
project: "{{ lookup ('vars', 'property') }}"
- debug:
msg: "{{ project }}"
Now, my output is
var1[
"a"
"b"]
var2[ "blah" , "blab"]
What I want as output is
["a", "b", "blah", "blab"]
Simply add the lists.
- debug:
msg: "{{ project.var1 + project.var2 }}"
The following should get you going:
task:
- name: including a variety file
include_vars:
file: prop.yml
name: property
- set_fact:
project: "{{ property.var1 + property.var2 }}"
- debug:
msg: "{{ project }}"
Rather than using the vars statically we can concatenate all lists in the included vars file by replacing the set_fact task with the following one.
This will only work if all declared vars in the file are all lists. Note the use of the default filter to make sure our result var is always defined. This also uses a loop over a dict
- name: Iteratively concatenate our lists
set_fact:
project: "{{ project | default([]) + item.value }}"
loop: "{{ property | dict2items }}"

Ansible how to ignore undefined item in a loop

I'm trying to have list of paths.
The variables folder (web_folder, app_folder or db_folder ) may be undefined and is expected to be undefined.
In this case I just don't want the undefined value in the the list.
- set_fact: root_paths="{{ root_paths | default([]) + [ item ] }}"
loop:
- "{{ web_folder }}"
- "{{ app_folder }}"
- "{{ db_folder }}"
when: item is defined
When I do this I get an error message 'The task includes an option with an undefined variable.'
I can make this work if I define default values e.g. '-' and replace the when condition with
when: item != '-'
I don't like this solution.
I tried a few things like
'when: vars[item] is undefined' from this post, but it didn't work for me.
I also replaces 'loop' with 'with_items' didn't work either
Any suggestions?
The variables folder (web_folder, app_folder or db_folder ) may be undefined and is expected to be undefined.
you could use the default filter to initialize them to an empty array, in case they are not defined:
- set_fact: root_paths="{{ root_paths | default([]) + [ item ] }}"
loop:
- "{{ web_folder | default([]) }}"
- "{{ app_folder | default([]) }}"
- "{{ db_folder | default([]) }}"
when: item is defined
hope it helps.
Q: I get an error message 'The task includes an option with an undefined variable.' I can make this work if I define default values e.g. '-' and replace the when condition with when: item != '-'. I don't like this solution.
A: The expansion of an undefined variable causes the error. Either the variables are tested explicitly or default filter is used.
Testing each variable is cumbersome
tasks:
- set_fact:
folders_defined: []
- set_fact:
folders_defined: "{{ folders_defined + [web_folder] }}"
when: web_folder is defined
- set_fact:
folders_defined: "{{ folders_defined + [app_folder] }}"
when: app_folder is defined
- set_fact:
folders_defined: "{{ folders_defined + [db_folder] }}"
when: db_folder is defined
- debug:
var: folders_defined
The next option (which is very similar to the one you don't like) is to test a default value assigned to undefined variables. For example, the playbook below tests default empty string. If necessary fit this condition to your needs.
- hosts: localhost
vars:
web_folder: /my/web/folder
app_folder: /my/app/folder
folders: [web_folder, app_folder, db_folder]
tasks:
- set_fact:
folders_defined: "{{ folders_defined|default([]) +
[lookup('vars', item)] }}"
loop: "{{ folders }}"
when: lookup('vars', item, default='')|length > 0
- debug:
var: folders_defined
gives
ok: [localhost] => {
"folders_defined": [
"/my/web/folder",
"/my/app/folder"
]
}

Ansible Registers - Dynamic naming

I am trying to use a register in Ansible playbook to store my output. Below is the code which i am using.
I have tried below code
- name: Check if Service Exists
stat: path=/etc/init.d/{{ item }}
register: {{ item }}_service_status
with_items:
- XXX
- YYY
- ZZZ
I need different outputs to be stored in different register variables based on the items as mentioned in the code. It is failing and not able to proceed. Any help would be appreciated.
Updated answer
I think you need to put quotes around it:
register: "{{ item }}_service_status"
Or you can use set_fact (1, 2, 3, 4)
register all the output to a single static variable output and then use a loop to iteratively build a new variable service_status (a list) by looping over each item in the static variable output
- name: Check if Service Exists
stat: path=/etc/init.d/{{ item }}
register: output
with_items:
- XXX
- YYY
- ZZZ
- name: Setting fact using output of loop
set_fact:
service_status:
- rc: "{{ item.rc }}"
stdout: "{{ item.stdout }}"
id: "{{ item.id }}"
with_items:
- "{{ output }}"
- debug:
msg: "ID and stdout: {{ item.id }} - {{ item.stdout }}"
with_items:
- "{{ service_status }}"
Initial Answer
IIUC, this link from the Ansible docs shows how to use register inside a loop (see another example in this SO post).
A couple of points
it may be more convenient to assign the list (XXX, YYY, ZZZ) to a separate variable (eg. 1, 2)
I don't know if this is part of the problem, but with_items is no longer the recommended approach to loop over a variable: instead use loop - see here for an example
vars:
items:
- XXX
- YYY
- ZZZ
- name: Check if Service Exists
stat: path=/etc/init.d/{{ item }}
register: service_status
loop: "{{ items|flatten(levels=1) }}"
- name: Show the return code and stdout
debug:
msg: "Cmd {{ item.cmd }}, return code {{ item.rc }}, stdout {{ item.stdout }}"
when: item.rc != 0
with_items: "{{ service_status.results }}"

How to dynamically create an ansible list out of hostvars?

I have a few variables defined for every host. Like...
hosts:
- hostA:
vars:
self_ip: "192.168.1.10"
self_port: "8001"
- hostB:
vars:
self_ip: "192.168.1.11"
self_port: "8002"
Inside one of the roles, I want to define a variable, which is a combination of few host variables. For example...
all_endpoints: 192.168.1.10:8001,192.168.1.11:8002
How can I do this?
I tried using Jinja2 for loops like below:
rs_members:
"{% for host in groups['all_hosts'] %}
- {{hostvars[host]['self_ip']}}:{{hostvars[host]['self_port']}}
{% endfor %}"
This seems to be creating a string. Not a list.
Can someone tell me what is wrong? And is there a way to use ansible filters to achieve this?
- set_fact:
all_endpoints: "{{ hosts|json_query('[].vars.[self_ip, self_port]') }}"
- set_fact:
touples: "{{ touples|default([]) + [ item.0 + ':' + item.1 ] }}"
loop: "{{ all_endpoints }}"
- debug:
var: touples
gives
"touples": [
"192.168.1.10:8001",
"192.168.1.11:8002"
]

Ansible: Access facts set by set_fact

I need to be able to set variables using tasks in Ansible. I use set_fact for this, but cannot seem to access the fact I set with this. What is wrong with the code below:
- name: kludge1
set_fact: fake_y = "{{ [] }}"
- name: Loop
debug:
msg: "{{ item }}"
with_items: "{{ fake_y }}"
You have spaces before and after =...
- name: kludge1
set_fact: fake_y="{{ [] }}"
Avoid var= shortcut syntax. Use original YAML syntax instead, it gives less errors:
- name: kludge1
set_fact:
fake_y: "{{ [] }}"

Resources