Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't set Ansible fact as integer

I am trying to extract the major distro version (which ansible_facts holds as a string) and store it as an integer for later < or > comparison to an integer. When I do this:

- set_fact:
    distromajor: "{{ ansible_facts['distribution_major_version'] | int }}"

I find distromajor holds "7" instead of 7.
So later comparisons fail. In fact, the only way I can get it to work is to compare like this:

(distromajor|int >=6) and (distromajor|int <= 8)

Is this expected behaviour?
Why can I not save the distro major version as an int?

The closest SO question does not explain why a later integer comparison fails without reconverting the distromajor variable to integer at time of comparison.

like image 607
TSG Avatar asked Jan 26 '26 16:01

TSG


1 Answers

Q: "Is this expected behavior?"

A: Yes. This is the expected behavior, in Ansible.


Q: "Why can I not save the distro major version as an int?"

A: Ansible decided you can't (todo: reference to source code needed). In YAML, there are three basic primitives:

  • mappings (hashes/dictionaries)
  • sequences (arrays/lists)
  • scalars (strings/numbers)

As you can see, the scalars are both strings and numbers. But, for some reason unknown to me, Ansible decided that any "{{ scalar }}" expression can return only string or boolean. For example,

    - set_fact:
        distromajor: "{{ ansible_facts['distribution_major_version'] | int }}"
    - debug:
        var: distromajor
    - debug:
        msg: "{{ distromajor | type_debug }}"

gives a string despite the explicit conversion to integer, as you've already found out

  distromajor: '20'
  msg: AnsibleUnsafeText

Note: In the above example, scalar represents a scalar result of the Jinja expression. If there is no expression Ansible doesn't call Jinja. As a result, this will preserve the evaluated variable's type. For example,

    - set_fact:
        v2: "{{ v1 }}"
      vars:
        v1: 123
    - debug:
        msg: |
          v2: {{ v2 }}
          v2 is {{ v2 | type_debug }}

gives

  msg: |-
    v2: 123
    v2 is int

However, if there is any expression, even an arithmetic one, Ansible calls Jinja to evaluate the expression and the result will be a string

    - set_fact:
        v3: "{{ v1 + 1 }}"
      vars:
        v1: 123
    - debug:
        msg: |
          v3: {{ v3 }}
          v3 is {{ v3 | type_debug }}

gives

  msg: |-
    v3: 124
    v3 is str

Update.

If you want to keep a variable as integer put it into a dictionary. For example,

  my_dict_yaml: |
    distromajor: {{ ansible_distribution_major_version }}
  my_dict: "{{ my_dict_yaml | from_yaml }}"

gives

  my_dict.distromajor: 20
  my_dict.distromajor | type_debug: int

Example of a complete playbook for testing

- hosts: localhost

  vars:

    my_dict_yaml: |
      distromajor: {{ ansible_distribution_major_version }}
    my_dict: "{{ my_dict_yaml | from_yaml }}"

  tasks:

    - setup:
        gather_subset: distribution_major_version
    - debug:
        var: ansible_distribution_major_version
    - debug:
        var: ansible_distribution_major_version | type_debug

    - debug:
        var: my_dict
    - debug:
        var: my_dict.distromajor | type_debug

source code

like image 86
Vladimir Botka Avatar answered Jan 29 '26 11:01

Vladimir Botka



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!