Nick Roz
Nick Roz

Reputation: 4230

Set fact with dynamic key name in ansible

I am trying to shrink several chunks of similar code which looks like:

- ... multiple things is going here
  register: list_register
- name: Generating list
  set_fact: my_list="{{ list_register.results | map(attribute='ansible_facts.list_item') | list }}"

# the same code repeats...

The only difference between them is list name instead of my_list.

In fact, I want to do this:

set_fact:
  "{{ some var }}" : "{{ some value }}"

I came across this post but didn't find any answer here.

Is it possible to do so or is there any workaround?

Upvotes: 41

Views: 71039

Answers (7)

Mike Reiche
Mike Reiche

Reputation: 460

My usecase is, to iterate over all items of a dictionary my_dict and update every item.

None of the answers above work for me, but this does:

- set_fact:
    my_dict:
      first:
        title: "First"
      second:
        title: "Second"

- set_fact:
    my_dict: "{{my_dict | combine({item.key:updated_item}, recursive=true) }}"
  vars:
    updated_item:
      name: "{{item.key}}"
  with_dict: "{{ my_dict }}"

Result:

"my_dict": {
    "first": {
         "name": "first",
         "title": "First"
    },
    "second": {
         "name": "second",
         "title": "Second"
    }
}

Upvotes: 1

Rafał W.
Rafał W.

Reputation: 119

Beware of a change in 2.9 – the behaviour changed rendering all the answers invalid. https://github.com/ansible/ansible/issues/64169

Upvotes: 1

Arash
Arash

Reputation: 314

- set_fact:
    var1={"{{variable_name}}":"{{ some value }}"}

This will create a variable "var1" with your dynamic variable key and value.


Example: I used this for creating dynamic tags in AWS Autoscaling group for creating kubernetes tags for the instances like this:

- name: Dynamic clustertag
  set_fact:
    clustertag={"kubernetes.io/cluster/{{ clustername }}":"owned"}
- name: Create the auto scale group
  ec2_asg:
    .
    .
    .
    tags:
      - "{{ clustertag }}"

Upvotes: 1

theenglishway
theenglishway

Reputation: 271

As of 2018, using ansible v2.7.1, the syntax you suggest in your post works perfectly well.

At least in my case, I have this in role "a" :

- name: Set fact
  set_fact: 
     "{{ variable_name }}": "{{ variable_value }}"

And that in role "b" :

- debug:
  msg: "variable_name = {{ variable_name }}"

And execution goes :

TASK [role a : Set fact] *******************************************************
ok: [host_name] => {
  "ansible_facts": {
    "variable_name": "actual value"
  }, 
  "changed": false
}

...

TASK [role b : debug] **********************************************************
ok: [host_name] => {}

MSG:

variable_name = actual value

Upvotes: 8

czerny
czerny

Reputation: 16644

- set_fact: '{{ some_var }}={{ some_value }}'

It creates a string of inline module parameter expression by concatenating value of some_var (fact name), separator = and value of some_value (fact value).

Upvotes: 4

user2854753
user2854753

Reputation: 311

The above does not work for me. What finally works is

- set_fact:
    example_dict: "{'{{ some var }}':'{{ some other var }}'}"

Which is in the end obvious. You construct a string (the outer double quotes) which is then interpreted as a hash. In hashes key and value must be single quotes (the inner single quotes around the variable replacements). And finally you just place your variable replacements as in any other string.

Stefan

Upvotes: 21

Konstantin Suvorov
Konstantin Suvorov

Reputation: 68269

take a look at this sample playbook:

---
- hosts: localhost
  vars:
    iter:
      - key: abc
        val: xyz
      - key: efg
        val: uvw
  tasks:
    - set_fact: {"{{ item.key }}":"{{ item.val }}"}
      with_items: "{{iter}}"
    - debug: msg="key={{item.key}}, hostvar={{hostvars['localhost'][item.key]}}"
      with_items: "{{iter}}"

Upvotes: 37

Related Questions