Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assign values to variables using a loop (set_fact or other?)

Tags:

ansible

jinja2

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?]


2 Answers

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 someFooValue
  • bar and contain someBarValue

If 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
like image 122
β.εηοιτ.βε Avatar answered Mar 02 '26 15:03

β.εηοιτ.βε


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
like image 45
U880D Avatar answered Mar 02 '26 13:03

U880D