Using an Ansible task, I'm trying to create variables and associated values from a returned loop object.
Ref: https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html
- name: Get values
someModule:
input_from_loop: "{{ item }}"
loop:
- "foo"
- "bar"
register: get_result
Gives
get_result:
changed: false
msg: All items completed
results:
- ansible_loop_var: item
item: foo
alpha:
beta:
content: someFooValue
- ansible_loop_var: item
item: bar
alpha:
beta:
content: someBarValue
With this get_result object, I'm trying to create variables and associated values such that:
Pseudocode:
- name: Assign values
set_fact:
"{{ item.item }}":"{{ item.alpha.beta.content }}"
loop: get_result.results
To result in:
foo:someFooValue
bar:someBarValue
I can't seem to get around the error
Implicit map keys need to be followed by map values"
I do not want to create a new object, just variables with values for later use (in existing tasks).
I've tried a few approaches to no avail.
[Or can it happen on each iteration of the initial loop calling the module?]
Now that I am rereading your your requirements, I am wondering if you are not looking for variables at the top level of your host that would be named
foo and contain someFooValuebar and contain someBarValueIf this is the case, then most of that is above does still apply, the registering of the fact only change:
- set_fact: { "{{ item.0 }}": "{{ item.1 }}" }
loop: "{{
get_result.results | map(attribute='item') | zip(
get_result.results | map(attribute='alpha.beta.content')
)
}}"
Which gives you the two expected variables with the corresponding values.
ok: [localhost] =>
foo: someFooValue
ok: [localhost] =>
bar: someBarValue
What you can do in those kind of cases is to break down the dictionary in multiple lists, all containing one of the field you are interested into, with the map filter, then reconstruct a list of list with the help of the zip filter. And finally, join everything together.
So, with a task like:
- set_fact:
formatted_fact: "{{
get_result.results | map(attribute='item') | zip(
get_result.results | map(attribute='alpha.beta.content')
) | map('join', ':') | join('\n')
}}"
You get your expected output:
formatted_fact: |-
foo:someFooValue
bar:someBarValue
Given those couple of tasks, we have the two possibilities:
- set_fact:
formatted_fact: "{{
get_result.results | map(attribute='item') | zip(
get_result.results | map(attribute='alpha.beta.content')
) | map('join', ':') | join('\n')
}}"
vars:
get_result:
changed: false
msg: All items completed
results:
- ansible_loop_var: item
item: foo
alpha:
beta:
content: someFooValue
- ansible_loop_var: item
item: bar
alpha:
beta:
content: someBarValue
- debug:
var: formatted_fact
- set_fact: { "{{ item.0 }}": "{{ item.1 }}" }
loop: "{{
get_result.results | map(attribute='item') | zip(
get_result.results | map(attribute='alpha.beta.content')
)
}}"
vars:
get_result:
changed: false
msg: All items completed
results:
- ansible_loop_var: item
item: foo
alpha:
beta:
content: someFooValue
- ansible_loop_var: item
item: bar
alpha:
beta:
content: someBarValue
- debug:
var: foo
- debug:
var: bar
They would yield:
TASK [set_fact] **************************************************************
ok: [localhost]
TASK [debug] *****************************************************************
ok: [localhost] =>
formatted_fact: |-
foo:someFooValue
bar:someBarValue
TASK [set_fact] **************************************************************
ok: [localhost] => (item=['foo', 'someFooValue'])
ok: [localhost] => (item=['bar', 'someBarValue'])
TASK [debug] *****************************************************************
ok: [localhost] =>
foo: someFooValue
TASK [debug] *****************************************************************
ok: [localhost] =>
bar: someBarValue
Regarding the question in the headline
How to assign values to variables using a loop (set_fact)?
and the mentioned "pseudocode" I like to note that such approach might work, as the following test
---
- hosts: localhost
become: false
gather_facts: false
vars:
varKey: "TEST"
varVal: "testValue"
tasks:
- name: Create variable dynamic
set_fact:
"{{ varKey }}_{{ item }}": "{{ varVal }}_{{ item }}"
loop: [1, 2, 3]
- name: Show variable
debug:
var: TEST_{{ item }}
loop: ["1", "2", "3"]
results into an output of
TASK [Create variable dynamic] *********
ok: [localhost] => (item=1)
ok: [localhost] => (item=2)
ok: [localhost] => (item=3)
TASK [Show variable] *********
ok: [localhost] => (item=1) =>
TEST_1: testValue_1
ansible_loop_var: item
item: '1'
ok: [localhost] => (item=2) =>
TEST_2: testValue_2
ansible_loop_var: item
item: '2'
ok: [localhost] => (item=3) =>
TEST_3: testValue_3
ansible_loop_var: item
item: '3'
and also
- name: Create variable dynamic
set_fact:
"{{ item }}": "{{ item }}"
loop: [A1, A2, A3]
- name: Show variable
debug:
var: "{{ item }}"
loop: [A1, A2, A3]
into
TASK [Create variable dynamic] **********
ok: [localhost] => (item=A1)
ok: [localhost] => (item=A2)
ok: [localhost] => (item=A3)
TASK [Show variable] **********
ok: [localhost] => (item=A1) =>
A1: A1
ansible_loop_var: item
item: A1
ok: [localhost] => (item=A2) =>
A2: A2
ansible_loop_var: item
item: A2
ok: [localhost] => (item=A3) =>
A3: A3
ansible_loop_var: item
item: A3
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With