As I am stuck, I need some help. I want to update a value of a dict in a list of dict (ideally, I don't want to create another list)
Under an Ansible playbook, I have a variable declared:
a:
- id: 'test1id'
name: 'test1name'
description: ''
- id: 'test2id'
name: 'test2name'
description: 'init'
- id: 'test3id'
name: 'test3name'
description: 'init3'
I have a task that loop into "a" should update the description.
- name: Update description in a
when: a is defined
set_fact:
a: "{{ item | combine({'description': new_description}) }}"
vars:
new_description: "{{ item.description + "test" + item.id }}"
loop: a
Expected result:
a:
- id: 'test1id'
name: 'test1name'
description: 'test test1id'
- id: 'test2id'
name: 'test2name'
description: 'init test test2id'
- id: 'test3id'
name: 'test3name'
description: 'init3 test test3id'
Actual result:
a:
- id: 'test3id'
name: 'test3name'
description: 'init3 test test3id'
Looks like I'm missing something, I just have the last item. I also tried other format, but that never give me the expected result.
What you've done is right.
There were some errors, but I think it was caused by a typo, like loop: "{{ a }}"
and spaces around the word test
here new_description: '{{ item.description + " test " + item.id }}'
.
If you run it in debug mode:
ok: [localhost] => (item={'id': 'test1id', 'name': 'test1name', 'description': ''}) => {
"ansible_facts": {
"a": {
"description": " test test1id",
"id": "test1id",
"name": "test1name"
}
},
"ansible_loop_var": "item",
"changed": false,
"item": {
"description": "",
"id": "test1id",
"name": "test1name"
}
}
ok: [localhost] => (item={'id': 'test2id', 'name': 'test2name', 'description': 'init'}) => {
"ansible_facts": {
"a": {
"description": "init test test2id",
"id": "test2id",
"name": "test2name"
}
},
"ansible_loop_var": "item",
"changed": false,
"item": {
"description": "init",
"id": "test2id",
"name": "test2name"
}
}
ok: [localhost] => (item={'id': 'test3id', 'name': 'test3name', 'description': 'init3'}) => {
"ansible_facts": {
"a": {
"description": "init3 test test3id",
"id": "test3id",
"name": "test3name"
}
},
"ansible_loop_var": "item",
"changed": false,
"item": {
"description": "init3",
"id": "test3id",
"name": "test3name"
}
}
You just need to read the values back from ansible_facts
you set.
The result should be registered temporarily and then convert the results to the original format with the updated values.
- hosts: localhost
gather_facts: no
vars:
a:
- id: 'test1id'
name: 'test1name'
description: ''
- id: 'test2id'
name: 'test2name'
description: 'init'
- id: 'test3id'
name: 'test3name'
description: 'init3'
tasks:
- name: Update description in a
when: a is defined
set_fact:
a: "{{ item | combine({'description': new_description}) }}"
vars:
new_description: '{{ item.description + " test " + item.id }}'
loop: "{{ a }}"
register: temporary_a
- name: Results
set_fact:
a: "{{ temporary_a.results | map(attribute='ansible_facts.a') | list }}"
- debug:
var: a
Results:
ok: [localhost] => {
"a": [
{
"description": " test test1id",
"id": "test1id",
"name": "test1name"
},
{
"description": "init test test2id",
"id": "test2id",
"name": "test2name"
},
{
"description": "init3 test test3id",
"id": "test3id",
"name": "test3name"
}
]
}