[Bug]: Netbox ansible (prefix) fails when custom fields is an object
Ansible NetBox Collection version
v3.7.1
Ansible version
ansible [core 2.13.0]
config file = /home/something/ansible/etc/ansible.cfg
configured module search path = ['/home/somewhere/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/somewhere/bin/oci/lib/python3.8/site-packages/ansible
ansible collection location = /home/somewhere/.ansible/collections:/usr/share/ansible/collections
executable location = /home/somewhere/bin/oci/bin/ansible
python version = 3.8.10 (default, Mar 15 2022, 12:22:08) [GCC 9.4.0]
jinja version = 3.1.2
libyaml = True
NetBox version
v3.2.4
Python version
3.8
Steps to Reproduce
We have associated a custom field to prefixes of type Object (DCIM -> location). When trying to update or create a prefix with this object set to something different from null, netbox module fails.
- name: Update Netbox with new info
netbox.netbox.netbox_prefix:
netbox_token: "{{ netbox_conf.token }}"
netbox_url: "{{ netbox_conf.url }}"
data:
prefix: "{{ oci_status.subnet.cidr_block }}"
vrf: "{{ subnet.vrf.name }}"
status: "{{ subnet.status.value }}"
tags:
- Deployed
custom_fields:
ocid: "{{ oci_status.subnet.id }}"
Compartment: "{{ subnet.custom_fields.Compartment.id }}"
state: present
Expected Behavior
The expected behavior would be the creation of the prefix in netbox (and if it is a new object it is created, but ansible fails, parsing the netbox returned info).
changed: [localhost] => {
"changed": true,
"diff": {
"after": {
"state": "present"
},
"before": {
"state": "absent"
}
},
"invocation": {
"module_args": {
"cert": null,
"data": {
"custom_fields": {
"Compartment": 3,
"ocid": "ocid1.subnet.oc1.eu-frankfurt-1."
},
"description": null,
"family": null,
"is_pool": null,
"parent": null,
"prefix": "192.168.6.0/24",
"prefix_length": null,
"prefix_role": null,
"site": null,
"status": "active",
"tags": [
"Deployed"
],
"tenant": null,
"vlan": null,
"vrf": "quistor-fra1-vcn1"
},
"first_available": false,
"netbox_token": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"netbox_url": "https://someurl.eu",
"query_params": null,
"state": "present",
"validate_certs": true
}
},
"msg": "prefix 192.168.6.0/24 created",
"prefix": {
"_depth": 0,
"children": 0,
"created": "2022-06-09T16:12:27.387952Z",
"custom_fields": {
"Compartment": {
"_depth": 1,
"display": "Network",
"id": 3,
"name": "Network",
"slug": "network",
"url": "https://someurl.eu:443/api/dcim/locations/3/"
},
"ocid": "ocid1.subnet.oc1.eu-frankfurt-1."
},
"description": "",
"display": "192.168.6.0/24",
"family": 4,
"id": 27,
"is_pool": false,
"last_updated": "2022-06-09T16:12:27.387977Z",
"mark_utilized": false,
"prefix": "192.168.6.0/24",
"role": null,
"site": null,
"status": "active",
"tags": [
1
],
"tenant": null,
"url": "https://someurl.eu:443/api/ipam/prefixes/27/",
"vlan": null,
"vrf": 1
}
}
Observed Behavior
I've observed, if we are updating an existing record with custom field Compartment(Location) set. Ansible just fails (and I do not see the update in netbox), but if we a crating a new prefix, Ansible fails, but I can see the new record in netbox, prefectly fine, with even a Compartment(location) field set to correct values.
Here the errors:
The full traceback is:
Traceback (most recent call last):
File "/home/something/.ansible/tmp/ansible-tmp-1654791009.2730565-112190-53053182566011/AnsiballZ_netbox_prefix.py", line 107, in <module>
_ansiballz_main()
File "/home/something/.ansible/tmp/ansible-tmp-1654791009.2730565-112190-53053182566011/AnsiballZ_netbox_prefix.py", line 99, in _ansiballz_main
invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
File "/home/something/.ansible/tmp/ansible-tmp-1654791009.2730565-112190-53053182566011/AnsiballZ_netbox_prefix.py", line 47, in invoke_module
runpy.run_module(mod_name='ansible_collections.netbox.netbox.plugins.modules.netbox_prefix', init_globals=dict(_module_fqn='ansible_collections.netbox.netbox.plugins.modules.netbox_prefix', _modlib_path=modlib_path),
File "/usr/lib/python3.8/runpy.py", line 207, in run_module
return _run_module_code(code, init_globals, run_name, mod_spec)
File "/usr/lib/python3.8/runpy.py", line 97, in _run_module_code
_run_code(code, mod_globals, init_globals,
File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
exec(code, run_globals)
File "/tmp/ansible_netbox.netbox.netbox_prefix_payload_sqxfscu0/ansible_netbox.netbox.netbox_prefix_payload.zip/ansible_collections/netbox/netbox/plugins/modules/netbox_prefix.py", line 274, in <module>
File "/tmp/ansible_netbox.netbox.netbox_prefix_payload_sqxfscu0/ansible_netbox.netbox.netbox_prefix_payload.zip/ansible_collections/netbox/netbox/plugins/modules/netbox_prefix.py", line 270, in main
File "/tmp/ansible_netbox.netbox.netbox_prefix_payload_sqxfscu0/ansible_netbox.netbox.netbox_prefix_payload.zip/ansible_collections/netbox/netbox/plugins/module_utils/netbox_ipam.py", line 212, in run
File "/tmp/ansible_netbox.netbox.netbox_prefix_payload_sqxfscu0/ansible_netbox.netbox.netbox_prefix_payload.zip/ansible_collections/netbox/netbox/plugins/module_utils/netbox_utils.py", line 1315, in _ensure_object_exists
File "/tmp/ansible_netbox.netbox.netbox_prefix_payload_sqxfscu0/ansible_netbox.netbox.netbox_prefix_payload.zip/ansible_collections/netbox/netbox/plugins/module_utils/netbox_utils.py", line 1248, in _update_netbox_object
File "/home/something/bin/oci/lib/python3.8/site-packages/pynetbox/core/response.py", line 457, in serialize
ret[i] = flatten_custom(current_val)
File "/home/something/bin/oci/lib/python3.8/site-packages/pynetbox/core/response.py", line 61, in flatten_custom
return {
File "/home/something/bin/oci/lib/python3.8/site-packages/pynetbox/core/response.py", line 62, in <dictcomp>
k: v if not isinstance(v, dict) else v["value"] for k, v in custom_dict.items()
KeyError: 'value'
fatal: [localhost]: FAILED! => {
"changed": false,
"module_stderr": "Traceback (most recent call last):\n File \"/home/something/.ansible/tmp/ansible-tmp-1654791009.2730565-112190-53053182566011/AnsiballZ_netbox_prefix.py\", line 107, in <module>\n _ansiballz_main()\n File \"/home/something/.ansible/tmp/ansible-tmp-1654791009.2730565-112190-53053182566011/AnsiballZ_netbox_prefix.py\", line 99, in _ansiballz_main\n invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n File \"/home/something/.ansible/tmp/ansible-tmp-1654791009.2730565-112190-53053182566011/AnsiballZ_netbox_prefix.py\", line 47, in invoke_module\n runpy.run_module(mod_name='ansible_collections.netbox.netbox.plugins.modules.netbox_prefix', init_globals=dict(_module_fqn='ansible_collections.netbox.netbox.plugins.modules.netbox_prefix', _modlib_path=modlib_path),\n File \"/usr/lib/python3.8/runpy.py\", line 207, in run_module\n return _run_module_code(code, init_globals, run_name, mod_spec)\n File \"/usr/lib/python3.8/runpy.py\", line 97, in _run_module_code\n _run_code(code, mod_globals, init_globals,\n File \"/usr/lib/python3.8/runpy.py\", line 87, in _run_code\n exec(code, run_globals)\n File \"/tmp/ansible_netbox.netbox.netbox_prefix_payload_sqxfscu0/ansible_netbox.netbox.netbox_prefix_payload.zip/ansible_collections/netbox/netbox/plugins/modules/netbox_prefix.py\", line 274, in <module>\n File \"/tmp/ansible_netbox.netbox.netbox_prefix_payload_sqxfscu0/ansible_netbox.netbox.netbox_prefix_payload.zip/ansible_collections/netbox/netbox/plugins/modules/netbox_prefix.py\", line 270, in main\n File \"/tmp/ansible_netbox.netbox.netbox_prefix_payload_sqxfscu0/ansible_netbox.netbox.netbox_prefix_payload.zip/ansible_collections/netbox/netbox/plugins/module_utils/netbox_ipam.py\", line 212, in run\n File \"/tmp/ansible_netbox.netbox.netbox_prefix_payload_sqxfscu0/ansible_netbox.netbox.netbox_prefix_payload.zip/ansible_collections/netbox/netbox/plugins/module_utils/netbox_utils.py\", line 1315, in _ensure_object_exists\n File \"/tmp/ansible_netbox.netbox.netbox_prefix_payload_sqxfscu0/ansible_netbox.netbox.netbox_prefix_payload.zip/ansible_collections/netbox/netbox/plugins/module_utils/netbox_utils.py\", line 1248, in _update_netbox_object\n File \"/home/something/bin/oci/lib/python3.8/site-packages/pynetbox/core/response.py\", line 457, in serialize\n ret[i] = flatten_custom(current_val)\n File \"/home/something/bin/oci/lib/python3.8/site-packages/pynetbox/core/response.py\", line 61, in flatten_custom\n return {\n File \"/home/something/bin/oci/lib/python3.8/site-packages/pynetbox/core/response.py\", line 62, in <dictcomp>\n k: v if not isinstance(v, dict) else v[\"value\"] for k, v in custom_dict.items()\nKeyError: 'value'\n",
"module_stdout": "",
"msg": "MODULE FAILURE\nSee stdout/stderr for the exact error",
"rc": 1
}
https://github.com/netbox-community/pynetbox/issues/457
Should be fixed in collection 3.11.0 and pynetbox version 7.0.1.