Reputation: 71
I am reading from a CSV file, register a variable and loop through the variable's list. It's as easy as below example:
---
- hosts: localhost
vars:
csv: |
some;val;ues
string;1;2
tasks:
- name: copy
copy:
content: "{{csv}}"
dest: "vm.csv"
- name: read csv
community.general.read_csv:
path: "vm.csv"
delimiter: ";"
register: vms
- name: debug
debug:
var: vms
- name: Trigger AWX
awx.awx.workflow_launch:
name: "Do the job!"
extra_vars:
some_string: "{{ item.some }}"
an_integer: "{{ item.val }}"
another_integer: "{{ item.ues }}"
with_items: "{{ vms.list }}"
Now let's get into the issue. When triggering the last task, integers are required for an_integer
and another_integer
. Otherwise the API below will fail.
The problem: the Jinja2 template engine will ALWAYS return a string. an_integer: "{{ item.val | int }}"
, for example, won't change that behavior.
As you can see from the output of task 3 (debug), the values are already string when read from csv / registered.
ok: [localhost] => {
"vms": {
"changed": false,
"dict": {},
"failed": false,
"list": [
{
"some": "string",
"ues": "2",
"val": "1"
}
]
}
}
How can I force a module parameter to be set as integer?
Upvotes: 3
Views: 4446
Reputation: 71
Thanks to Vladimir for his answer, on which this solution is based on.
Instead of passing each parameter on its own, the solution is to build a dictionary and pass it directly to extra_vars
like below.
- set_fact:
vm_list: "{{ vm_list|d([]) + [vm] }}"
loop: "{{ vms.list }}"
vars:
vm: "{{ {
'some_string': item.some,
'val': item.val|int,
'ues': item.ues|int
} }}"
- name: Trigger AWX
awx.awx.workflow_launch:
name: "Do the job!"
extra_vars: "{{ item }}"
with_items: "{{ vm_list }}"
This keeps the dictionaries' value types and the API is happy.
The below example will not work!
- set_fact:
vm_list: "{{ vm_list|d([]) + [vm] }}"
loop: "{{ vms.list }}"
vars:
vm: "{{ {
'some': item.some,
'val': item.val|int,
'ues': item.ues|int
} }}"
- name: Trigger AWX
awx.awx.workflow_launch:
name: "Do the job!"
extra_vars:
some_string: "{{ item.some }}"
val: "{{ item.val|int }}"
ues: "{{ item.ues|int }}"
with_items: "{{ vm_list }}"
As the debug output shows it converts the values into strings, even if you add the int
filter.
[...]
"extra_vars": {
"some_string": "string",
"ues": "2",
"val": "1"
[...]
},
"item": {
"some": "string",
"ues": 2,
"val": 1
},
[...]
Upvotes: 0
Reputation: 68034
The items on the list are strings. For example
- debug:
msg: |
vms.list.0.val: {{ vms.list.0.val }} {{ vms.list.0.val|type_debug }}
gives (Use yaml callback plugin. See shell> ansible-doc -t callback yaml
)
msg: |-
vms.list.0.val: 1 AnsibleUnicode
Convert the items of the list to integers. Create the list first, e.g.
- set_fact:
_list: "{{ _list|d([]) + [item|combine(_item)] }}"
loop: "{{ vms.list }}"
vars:
_item: "{{ {'ues': item.ues|int, 'val': item.val|int} }}"
gives
_list:
- some: string
ues: 2
val: 1
Then update the list in the dictionary
- set_fact:
vms: "{{ vms|combine({'list': _list}) }}"
gives
vms:
changed: false
dict: {}
failed: false
list:
- some: string
ues: 2
val: 1
The debug task will show the type is integer now
msg: |-
vms.list.0.val: 1 int
Upvotes: 2