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

[Bug]: int not of type integer if jinja2 expressions are used in custom attributes #985

Open
agowa opened this issue Apr 19, 2023 · 10 comments
Labels
bug Something isn't working

Comments

@agowa
Copy link

agowa commented Apr 19, 2023

Ansible NetBox Collection version

v3.12.0

Ansible version

ansible [core 2.14.3]
  config file = /workspaces/ansible.cfg
  configured module search path = ['/home/vscode/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /workspaces/.pyenv/versions/3.10.4/envs/ansible.venv/lib/python3.10/site-packages/ansible
  ansible collection location = /workspaces/collections
  executable location = /workspaces/.pyenv/versions/ansible.venv/bin/ansible
  python version = 3.10.4 (main, Mar  2 2023, 17:18:28) [GCC 10.2.1 20210110] (/workspaces/.pyenv/versions/3.10.4/envs/ansible.venv/bin/python3.10)
  jinja version = 3.1.2
  libyaml = True

NetBox version

v3.4.5

Python version

3.10

Steps to Reproduce

local_action:
  module: netbox.netbox.netbox_vm_interface
  state: present
  data:
...
    custom_fields:
      some_integer_field: "{{ some_ansible_variable|default(omit) }}"

with:
some_ansible_variable: 3

Expected Behavior

correct serialization of custom fields using their correct datatype.

Observed Behavior

API Post request is formed incorrectly with "3" as string instead of integer. Doing a "type_debug" in the playbook outputs that it is of type int. But when I try to use it in the netbox.netbox.netbox_vm_interface module for example it gets serialized as string and an error message of "msg": "{\"__all__\":[\"Invalid value for custom field 'some_integer_field': Value must be an integer.\"]}" is printed

If I add an explicit int cast in _normalize_data, then the custom fields are also sent correctly. I don't know how to write a generic version that would query the custom field type and serialize it correctly though. Also I don't know if there is a possibility to use the same datatype ansible outputs for ansible.builtin.type_debug filter.

Edit: I found a workaround. To set [defaults] jinja2_native=True within the ansible.cfg, but as it is not required for other modules, there may be an attribute to set within the module.

@agowa agowa added the bug Something isn't working label Apr 19, 2023
@sc68cal
Copy link
Contributor

sc68cal commented Apr 24, 2023

Did you try casting it to int?

some_integer_field: "{{ some_ansible_variable | int or default(omit) }}"

@lasse-jorgensen
Copy link

Did you try casting it to int?

some_integer_field: "{{ some_ansible_variable | int or default(omit) }}"

I have encountered the same issue and I can confirm that casting a variable to int does not work.
I have tested sending custom_fields using a variable which I casted to to_json which did not work.

"{{ customfields | to_json }}"

I also tried casting it to from_json again just to test it out, which also did not work.

"{{ customfields | to_json | from_json }}"

@sc68cal
Copy link
Contributor

sc68cal commented Apr 26, 2023

OK. I think at the very least, we should add the note about using jinja2_native to our documentation about custom types in the meantime.

We probably need to query the custom_field API and get the types, and use that to then cast each custom field passed in to the correct type.

@ThomasADavis
Copy link
Contributor

Ansible jinja filter always return strings, unless you set jinja2_native=true in your ansible.cfg or do ANSIBLE_JINJA2_NATIVE=1 ansible-playbook This will break async however, until you get to v2.14.5..

I ran into this when using id's against netbox, it wants them to be ints not strings.

ie, id="1" is not the same as id=1

@agowa
Copy link
Author

agowa commented Apr 27, 2023

Hi @ThomasADavis that's just a workaround, the netbox module itself knows which datatype the netbox API expects (or could query the schema for custom objects GET /extras/custom-fields/ and GET /extras/custom-fields/{id}).
So this module could (and like many in the ansible matrix channel pointed out even should) do type conversion.
So if the field is int, it should always do a int(value_privided_by_ansible) before passing it off to the API.

Probably would also prevent injection attacks in some cases. But at a bare minimum, it would improve UX and also provide better error messages when users provide incorrect data.

(Btw, I just noticed the API calls I just mentioned also return any defined validation min/max/regex, so technically we could do the validation before even calling the actual API)

@ThomasADavis
Copy link
Contributor

That is true, I ran into this when doing bulk updates via URL to netbox in ansible - it much faster to do bulk update of a large number of interfaces than do a loop with the netbox module. There is also other places in the modules that look/ask for a id, and I'm not sure if it's doing right conversion there either; ie, if it's a object_id, it's always going to be an int..

To get the bulk updates to work correctly, I had to turn on the jinja native type, which promptly broke ansible_async (another collection used this feature). So the modules need to be able to work no matter what the jinja_native setting is.

@agowa

This comment was marked as off-topic.

@edvinaskairys
Copy link

even when running python filter, which converts the data from string to int (confirmed with type_debug) - the module doesn't recognize it as a integer.

The only workaround is inja2_native=true in ansible.cfg. But the problem comes - how to do it if i'm using AWX ?

@rodvand
Copy link
Contributor

rodvand commented Aug 9, 2023

The only workaround is inja2_native=true in ansible.cfg. But the problem comes - how to do it if i'm using AWX ?

Add ansible.cfg with the option to your project root.

@cpund
Copy link

cpund commented Nov 16, 2023

The workaround I used when encountering this issue is setting my custom field to text, and then setting a regex validation field of ^\d+$, which essentially forces it to be an integer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

7 participants