I have a use case where I want to add values to a list dependant on host groups. I will then use the resulting list as an argument to another task.
For some reason, as soon as a set_fact task is run against the same host and variable for a second time, Ansible explodes with an unintuitive Python/Jinja2 error, saying it's getting a list when it doesn't expect a list (which makes NO sense to me, because union() wants two lists are arguments surely?!).
Can anybody shed any light on this? Am I doing something particularly silly? Is there a better way to achieve what I want to do?
To illustrate the problem, I have tried to distill the issue down to this simple example:
nicola $ ls -1 *
fruit.yaml
inventory
group_vars:
all
nicola $ cat group_vars/all
fruit:
- UniversalFruit1-Foo
nicola $ cat inventory
[tropical]
host1-asia ansible_ssh_host=172.18.32.89
host2-asia ansible_ssh_host=172.18.97.157
[domestic]
host3-uk ansible_ssh_host=172.18.128.12
host4-uk ansible_ssh_host=172.18.128.13
[berries]
host4-uk ansible_ssh_host=172.18.128.13
nicola $ cat fruit.yaml
---
- hosts: all
tasks:
- debug: var=fruit
- hosts: tropical
tasks:
- set_fact: fruit="{{ fruit | union([ 'Kiwi', 'Mango' ]) }}" #"
- hosts: all
tasks:
- debug: var=fruit
- hosts: domestic
tasks:
- set_fact: fruit="{{ fruit | union([ 'Apple', 'Blackberry' ]) }}" #"
- hosts: all
tasks:
- debug: var=fruit
- hosts: berries
tasks:
- set_fact: fruit="{{ fruit | union([ 'Goosberry', 'Blackberry' ]) }}" #"
- hosts: all
tasks:
- debug: var=fruit
- hosts: all
tasks:
- set_fact: fruit="{{ fruit | union([ 'UniversalFruit1-Foo', 'UniversalFruit2-Bar' ]) }}" #"
- hosts: all
tasks:
- debug: var=fruit
nicola $ ansible-playbook -i inventory fruit.yaml
PLAY [all] ********************************************************************
GATHERING FACTS ***************************************************************
ok: [host3-uk]
ok: [host4-uk]
ok: [host1-asia]
ok: [host2-asia]
TASK: [debug var=fruit] *******************************************************
ok: [host1-asia] => {
"var": {
"fruit": [
"UniversalFruit1-Foo"
]
}
}
ok: [host2-asia] => {
"var": {
"fruit": [
"UniversalFruit1-Foo"
]
}
}
ok: [host4-uk] => {
"var": {
"fruit": [
"UniversalFruit1-Foo"
]
}
}
ok: [host3-uk] => {
"var": {
"fruit": [
"UniversalFruit1-Foo"
]
}
}
PLAY [tropical] ***************************************************************
GATHERING FACTS ***************************************************************
ok: [host1-asia]
ok: [host2-asia]
TASK: [set_fact fruit="{{ fruit | union([ 'Kiwi', 'Mango' ]) }}"] *************
ok: [host1-asia]
ok: [host2-asia]
PLAY [all] ********************************************************************
GATHERING FACTS ***************************************************************
ok: [host3-uk]
ok: [host4-uk]
ok: [host1-asia]
ok: [host2-asia]
TASK: [debug var=fruit] *******************************************************
ok: [host4-uk] => {
"var": {
"fruit": [
"UniversalFruit1-Foo"
]
}
}
ok: [host1-asia] => {
"var": {
"fruit": [
"UniversalFruit1-Foo",
"Kiwi",
"Mango"
]
}
}
ok: [host2-asia] => {
"var": {
"fruit": [
"UniversalFruit1-Foo",
"Kiwi",
"Mango"
]
}
}
ok: [host3-uk] => {
"var": {
"fruit": [
"UniversalFruit1-Foo"
]
}
}
PLAY [domestic] ***************************************************************
GATHERING FACTS ***************************************************************
ok: [host3-uk]
ok: [host4-uk]
TASK: [set_fact fruit="{{ fruit | union([ 'Apple', 'Blackberry' ]) }}"] *******
ok: [host3-uk]
ok: [host4-uk]
PLAY [all] ********************************************************************
GATHERING FACTS ***************************************************************
ok: [host4-uk]
ok: [host3-uk]
ok: [host1-asia]
ok: [host2-asia]
TASK: [debug var=fruit] *******************************************************
ok: [host2-asia] => {
"var": {
"fruit": [
"UniversalFruit1-Foo",
"Kiwi",
"Mango"
]
}
}
ok: [host1-asia] => {
"var": {
"fruit": [
"UniversalFruit1-Foo",
"Kiwi",
"Mango"
]
}
}
ok: [host4-uk] => {
"var": {
"fruit": [
"UniversalFruit1-Foo",
"Apple",
"Blackberry"
]
}
}
ok: [host3-uk] => {
"var": {
"fruit": [
"UniversalFruit1-Foo",
"Apple",
"Blackberry"
]
}
}
PLAY [berries] ****************************************************************
GATHERING FACTS ***************************************************************
ok: [host4-uk]
TASK: [set_fact fruit="{{ fruit | union([ 'Goosberry', 'Blackberry' ]) }}"] ***
fatal: [host4-uk] => Failed to template fruit="{{ fruit | union([ 'Goosberry', 'Blackberry' ]) }}": an unexpected type error occurred. Error was coercing to Unicode: need string or buffer, list found
FATAL: all hosts have already failed -- aborting
PLAY RECAP ********************************************************************
to retry, use: --limit @/home/nworthington/fruit.yaml.retry
host1-asia : ok=8 changed=0 unreachable=0 failed=0
host2-asia : ok=8 changed=0 unreachable=0 failed=0
host3-uk : ok=8 changed=0 unreachable=0 failed=0
host4-uk : ok=9 changed=0 unreachable=1 failed=0
nicola $