jay
jay

Reputation: 71

How to change var type to integer?

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

Answers (2)

jay
jay

Reputation: 71

Thanks to Vladimir for his answer, on which this solution is based on.

Working example

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.


Not working example

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

Vladimir Botka
Vladimir Botka

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

Related Questions