Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assigning an integer variable to another variable results in unexpected behavior #55891

Closed
huguesdk opened this issue Apr 29, 2019 · 2 comments
Closed
Labels
affects_2.9 This issue/PR affects Ansible v2.9 bug This issue/PR relates to a bug. support:core This issue/PR relates to code supported by the Ansible Engineering Team.

Comments

@huguesdk
Copy link

SUMMARY

When an integer variable is assigned to another variable using a string template, that variable still behaves internally as an integer, but is displayed as a string, resulting in unexpected behavior.

ISSUE TYPE
  • Bug Report
COMPONENT NAME
ANSIBLE VERSION
ansible 2.9.0.dev0
CONFIGURATION
OS / ENVIRONMENT

(not relevant)

STEPS TO REPRODUCE

test.yaml:

- hosts: all
  gather_facts: False
  vars:
    - test_var_1: 42
    - test_var_2: "42"
    - test_var_3: "{{ test_var_1 }}"
    - test_var_4: "{{ test_var_1 * 1 }}"
    - test_var_5: "{{ test_var_3 }}"
    - result_1: "{{ test_var_1 * 2 }}"
    - result_2: "{{ test_var_2 * 2 }}"
    - result_3: "{{ test_var_3 * 2 }}"
    - result_4: "{{ test_var_4 * 2 }}"
    - result_5: "{{ test_var_5 * 2 }}"
  tasks:
    - debug:
        var: test_var_1
    - debug:
        var: result_1
    - debug:
        var: test_var_2
    - debug:
        var: result_2
    - debug:
        var: test_var_3
    - debug:
        var: result_3
    - debug:
        var: test_var_4
    - debug:
        var: result_4
    - debug:
        var: test_var_5
    - debug:
        var: result_5

Run with:

ansible-playbook test.yaml -i localhost, -c local
EXPECTED RESULTS

I would expect result_1 to equal "84" and all others to equal "4242", as they are all string multiplications.

ACTUAL RESULTS

result_3 equals "84", even though test_var_3 is displayed as a string ("42"). Internally it still behaves as an integer. Although it can be desirable for an integer value to stay as integer when assigned to another variable, the syntax to do so is misleading. Moreover, if an arithmetic operation is done on the initial value when assigning, the resulting value is a string (test_var_4), and if the internally-integer-value is assigned to another variable, the resulting value is also a string (test_var_5).

As explicit is better than implicit, I think that whenever a string value is assigned to a variable, the resulting value should be a string, whatever the contents of the string. To use that value as an integer, an explicit conversion should be needed: (some_string_variable | int). If it should be possible to assign an integer variable to another variable, while keeping the integer type, then another special syntax (without quotes if possible) is needed.

PLAY [all] ********************************************************************************************************************************************************************

TASK [debug] ******************************************************************************************************************************************************************
ok: [localhost] => {
    "test_var_1": 42
}

TASK [debug] ******************************************************************************************************************************************************************
ok: [localhost] => {
    "result_1": "84"
}

TASK [debug] ******************************************************************************************************************************************************************
ok: [localhost] => {
    "test_var_2": "42"
}

TASK [debug] ******************************************************************************************************************************************************************
ok: [localhost] => {
    "result_2": "4242"
}

TASK [debug] ******************************************************************************************************************************************************************
ok: [localhost] => {
    "test_var_3": "42"
}

TASK [debug] ******************************************************************************************************************************************************************
ok: [localhost] => {
    "result_3": "84"
}

TASK [debug] ******************************************************************************************************************************************************************
ok: [localhost] => {
    "test_var_4": "42"
}

TASK [debug] ******************************************************************************************************************************************************************
ok: [localhost] => {
    "result_4": "4242"
}

TASK [debug] ******************************************************************************************************************************************************************
ok: [localhost] => {
    "test_var_5": "42"
}

TASK [debug] ******************************************************************************************************************************************************************
ok: [localhost] => {
    "result_5": "4242"
}

PLAY RECAP ********************************************************************************************************************************************************************
localhost                  : ok=10   changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
@ansibot ansibot added affects_2.9 This issue/PR affects Ansible v2.9 bug This issue/PR relates to a bug. needs_triage Needs a first human triage before being processed. support:core This issue/PR relates to code supported by the Ansible Engineering Team. labels Apr 29, 2019
@sivel
Copy link
Member

sivel commented Apr 29, 2019

This behavior is due to a historical integration between ansible and jinja2. jinja2 versions before 2.10 only had the ability to return strings when performing templating.

As of Ansible 2.7 and Jinja2 2.10, you can now enable jinja2 native types to solve this issue:

https://docs.ansible.com/ansible/latest/reference_appendices/config.html#default-jinja2-native

If you have further questions please stop by IRC or the mailing list:

@sivel sivel closed this as completed Apr 29, 2019
@huguesdk
Copy link
Author

Thanks for your quick answer!

While I understand that integer variables become strings, why is test_var_3 still an integer internally (but displayed as a string)? Don’t you think that this default behavior is confusing and should change (simply be and behave like a string)? I’m pretty sure many people had bad surprises because of this.

I just tried with the jinja2_native option, and while it’s nice to be able to keep the type of values like this, I still think it’s confusing to assign integer values with a string syntax (I know it’s due to YAML). But at least the behavior is consistent once one gets used to it.

@sivel sivel removed the needs_triage Needs a first human triage before being processed. label Apr 30, 2019
@ansible ansible locked and limited conversation to collaborators Jul 30, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
affects_2.9 This issue/PR affects Ansible v2.9 bug This issue/PR relates to a bug. support:core This issue/PR relates to code supported by the Ansible Engineering Team.
Projects
None yet
Development

No branches or pull requests

3 participants