-
Notifications
You must be signed in to change notification settings - Fork 24k
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
Integers passed around using jinja variable references are converted to strings #9362
Comments
The same is true for Booleans I discovered and that is broken in 1.6.0 I would love to see this get a higher priority since it is preventing us from upgrading past 1.5.5. |
Ok, thanks, in the case of your suggestion for the change above, it doesn't work because Y is actually a complex data structure which has an attribute that is an integer. |
@feanil you can still do that: |
Yes but the whole point of searializing the data structure as is that we don't have template out all of its content. We can just add new vars to defaults and start using them during the ansible run and for the data that the application also needs, we serialize that to disk for it to reference. |
So this is it? We can't create complex data (eg, marathon deploy) that contains non-string values? No workaround? This is pretty limiting. |
Strange, it only applies to variables
Yields an int value for instances after to_json.
But here instances is a string after to_json. |
So this means for something line
Every value that needs to be an int needs to be hard coded. |
@memelet We ran into the exact same issue. I worked around it by breaking out my JSON information into a separate file and using the template command + file lookup to create JSON request bodies. That mechanism allowed us to use variables for those integer/numeric values. I wrote about it more detail here: https://sdwr98.wordpress.com/2015/06/01/using-ansible-for-marathonchronos-deployments/ |
@sdwr98 Thanks Scott. Nice workaround. Did you try using lookup('template') and do away with the temporary file? |
@memelet Cool! I didn't even see the template lookup. That makes it even simpler. |
This is broken for me in |
Any news on this or workarounds? |
Still broken |
As I understand it, the mentioned PR (#10465) doesn't solve the problem at the root, but only one of its manifestations. It detects the case of a jinja2 template that only contains a single variable name, but this is not enough when the code is more complex and expected to evaluate as a non-string. For those of you still having problems with this, I think it's the following you may be seeing: #18722 |
(Mentioning #17992 here to keep track of related issues) |
still broken for me in 2.2.0.0 |
@simplesteph @shaharmor @pzhuk Post the playbooks that fail and the verbose output from the failed ansible-playbook invocation. |
@alikins , my usecases are all about making a config dictionary in yaml, and than deploy them as json. So I found that some int vars are getting exposed in json with quotes like strings... Test1 (typecasting string to int during variable exposure)Playbook:
Result (variable foo, which was typecasted as int, still was exposed quoted like string. While actual int var called bar - exposed properly):
Test2 (variables which are pointing to int variables became strings!)Playbook:
Result (no way to expose bar variable as int, even though it's just pointing to a int var):
|
I would vote for reopening this until it is fixed, or a workaround is presented. Update: Best workaround is from @sdwr98 above. See #9362 (comment) |
Just to embarrass myself I found that for my use case i can just brute force it with a {{ my_var | to_json | regex_replace('"([0-9]+)"','\1') }} This appears to be working sufficiently for me when passing the output to other JSON aware tools that check on the type of things (awscli). |
Some examples showing current behavior and what is desired (some of which currently doesnt work) ---
- hosts: localhost
gather_facts: false
vars:
foo_string: '123'
bar_int: 123
config:
foo2: "{{ foo_string | int }}"
bar2: "{{ bar_int }}"
foo_int: 123
bar_string: "{{ foo_int }}"
config2:
bar_raw: "{{ bar_string }}"
bar_int: "{{ bar_string|int }}"
tasks:
- name: debug foo_string type and value
debug:
msg: "foo_string value={{foo_string}} type={{foo_string | type_debug}}"
- name: debug foo_string pipe int type and value
debug:
msg: "foo_string|int value={{foo_string|int}} type={{ foo_string| int| type_debug }}"
- name: debug bar_int type and value
debug:
msg: "bar_int value={{bar_int }} type={{ bar_int|type_debug}}"
- name: debug config.foo2 type and value
debug:
msg: "config.foo2 value={{config.foo2}} type={{config.foo2 | type_debug}}"
- name: debug config.foo2 pipe int type and value
debug:
msg: "config.foo2|int value={{ config.foo2 | int }} type={{ config.foo2 | int | type_debug}}"
- name: debug config.bar2 type and value
debug:
msg: "config.bar2 value={{ config.bar2 }} type={{ config.bar2 | type_debug }}"
- name: config debug var
debug:
var: config
- name: debug config to json
debug:
msg: "{{ config | to_nice_json }}"
- name: config2 debug var
debug:
var: config2
- name: debug config2 to json
debug:
msg: "{{ config2 | to_nice_json }}"
- name: debug config2 to json and from json
debug:
msg: "{{ config2 | to_nice_json | from_json}}"
- name: assert config.bar2 is an int 123 and not a string "123"
assert:
that:
- config.bar2 == 123
ignore_errors: true
- name: assert config.bar2 is not a string "123"
assert:
that:
- config.bar2 != "123"
- name: assert config.foo2 is an int 123 and not a string "123"
assert:
that:
- config.foo2 == 123
ignore_errors: true
- name: assert config.foo2 is not a string "123"
assert:
that:
- config.foo2 != "123"
ignore_errors: true
- name: odd assert config.foo2 pipe int is an int 123 and not a string "123"
assert:
that:
- '{{ config.foo2 | int }} == 123'
- '{{ config.foo2 | int }} != 134323'
- '"123" != {{ config.foo2 | int}}'
- '"{{config.foo2 | int | type_debug}}" == "int"'
- name: odd assert config2.bar_int is an int 123 and not a string "123"
assert:
that:
- '{{ config2.bar_int| int }} == 123'
- '"123" != {{ config2.bar_int | int}}'
- name: assert config2.bar_int is an int 123 and not a string "123"
assert:
that:
- config2.bar_int == 123
ignore_errors: true
- name: assert config2.bar_int is not a string "123"
assert:
that:
- config2.bar_int != "123"
ignore_errors: true
- name: assert config2.bar_raw ais an int 123 and not a string "123"
assert:
that:
- config2.bar_raw == 123
ignore_errors: true
- name: assert config2.bar_raw is not a string "123"
assert:
that:
- config2.bar_raw != "123"
ignore_errors: true current output
|
This is still broken in
And the in a template file:
Results in:
But I need it to be:
Also noticed that booleans work just fine whatever reason. |
Still broken in 2.3.0rc3, why not reopen this issue? |
Yes ansible team, are you declaring that this is really fixed? |
Still happening in released 2.3.0 and in latest devel branch |
Unfortunately, jinja2 is a templating language and it always returns strings at the end of its run so there isn't much that we can do about it in Ansible code. feanil's work allowed us to turn the strings back into their given types in certain restricted circumstances where we knew what the type was supposed to be but it cannot handle more complex statements. For instance, with a filter involved, Ansible would know something like this:
Ansible knows that we start with an integer (9) but it does not know the return value of the add_one filter. The jinja2 templating engine which handles the substitution of the variables internally knows the results of add_one but it transforms the result into a string before it passes it back to us so the information is lost before we get it. One of our developers has worked on an enhancement to jinja2 that would allow it to return python values instead of strings so that we had enough information but it is currently being evaluated by upstream. It's hard to say, at this point, whether upstream will accept the change or not. They've been very nice to us in looking over the change but it falls outside of jinja2's primary use case. As a templating language, it's bread and butter is to turn templates with values into text; returning python types is an additional feature that's not directly applicable to this core pattern. We're waiting to see what the Jinja2 upstream devs decide as the information Ansible code would need to output the user's expected type in this case is simply lacking without more information from jinja2. |
I'm going to lock this issue. The reasons are:
|
There is a light at the end of the tunnel. We made a change to Jinja2 so we don't see all variable types changed into strings. See: pallets/jinja#708 |
Issue Type: Bug Report
Ansible Version: 1.6.9
Environment: Ubuntu 12.04
Summary:
In Ansible 1.6.9 a change was made that changed how the behavior of 'to_nice_json'. Previously numbers being passed around as jinja variable references would be converted to numbers in the json output but now the numbers are returned as quoted.
Steps To Reproduce:
test.yml
test_vars.yml
Command:
ansible-playbook test.yml -i localhost, -c local -vvv
Expected Results:
Output from 1.6.8
Actual Results:
Output from 1.6.9
The text was updated successfully, but these errors were encountered: