Yesterday managed to get netbox and my lab connected. So today followed up with the original article, and found a new issue that took me several hours.
Initially I was seeing an error that I couldn’t undestand “
netbox.exceptions.CreateException: This field is required
From
(venv) /netbox-example/nornir-napalm-netbox-demo master$ python scripts/create_interfaces.py nb_url = http://0.0.0.0:8080 Creating Netbox Interface for device r1, interface Loopback1 Traceback (most recent call last): File "scripts/create_interfaces.py", line 42, in task=create_netbox_interface, File "/home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/nornir/core/init.py", line 146, in run result = self._run_serial(task, run_on, **kwargs) File "/home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/nornir/core/init.py", line 72, in _run_serial result[host.name] = task.copy().start(host, self) File "/home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/nornir/core/task.py", line 85, in start r = self.task(self, **self.params) File "scripts/create_interfaces.py", line 34, in create_netbox_interface device_id=device_id, File "/home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/netbox/dcim.py", line 431, in create_interface return self.netbox_con.post('/dcim/interfaces/', required_fields, **kwargs) File "/home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/netbox/connection.py", line 124, in post raise exceptions.CreateException(resp_data) netbox.exceptions.CreateException: This field is required.
So I started to follow the trace, adding “print” and using “ipdb” to see what was going on:
.... /home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/netbox/connection.py(71)__request() 70 finally: ---> 71 self.close() 72 ipdb> dir(response) ['attrs', 'bool', 'class', 'delattr', 'dict', 'dir', 'doc', 'enter', 'eq', 'exit', 'format', 'ge', 'getattribute', 'getstate', 'gt', 'hash', 'init', 'init_subclass', 'iter', 'le', 'lt', 'module', 'ne', 'new', 'nonzero', 'reduce', 'reduce_ex', 'repr', 'setattr', 'setstate', 'sizeof', 'str', 'subclasshook', 'weakref', '_content', '_content_consumed', '_next', 'apparent_encoding', 'close', 'connection', 'content', 'cookies', 'elapsed', 'encoding', 'headers', 'history', 'is_permanent_redirect', 'is_redirect', 'iter_content', 'iter_lines', 'json', 'links', 'next', 'ok', 'raise_for_status', 'raw', 'reason', 'request', 'status_code', 'text', 'url'] ipdb> response.url 'http://0.0.0.0:8080/api/dcim/interfaces/' ipdb> response.text '{"type":["This field is required."]}' ipdb> response.status_code 400 ipdb> response.content b'{"type":["This field is required."]}' ipdb> response.reason 'Bad Request' ipdb> response.request ipdb> prepared_request ipdb> prepared_request.url 'http://0.0.0.0:8080/api/dcim/interfaces/' ipdb> dir(prepared_request) ['class', 'delattr', 'dict', 'dir', 'doc', 'eq', 'format', 'ge', 'getattribute', 'gt', 'hash', 'init', 'init_subclass', 'le', 'lt', 'module', 'ne', 'new', 'reduce', 'reduce_ex', 'repr', 'setattr', 'sizeof', 'str', 'subclasshook', 'weakref', '_body_position', '_cookies', '_encode_files', '_encode_params', '_get_idna_encoded_host', 'body', 'copy', 'deregister_hook', 'headers', 'hooks', 'method', 'path_url', 'prepare', 'prepare_auth', 'prepare_body', 'prepare_content_length', 'prepare_cookies', 'prepare_headers', 'prepare_hooks', 'prepare_method', 'prepare_url', 'register_hook', 'url'] ipdb> prepared_request.path_url '/api/dcim/interfaces/' ipdb> response.__content *** AttributeError: 'Response' object has no attribute '__content' ipdb> response._content b'{"type":["This field is required."]}' ipdb> response.content b'{"type":["This field is required."]}' ipdb> response.headers {'Server': 'nginx', 'Date': 'Wed, 08 Jul 2020 12:36:35 GMT', 'Content-Type': 'application/json', 'Content-Length': '36', 'Connection': 'keep-alive', 'Vary': 'Accept, Cookie, Origin', 'Allow': 'GET, POST, HEAD, OPTIONS, TRACE', 'API-Version': '2.8', 'X-Content-Type-Options': 'nosniff', 'X-Frame-Options': 'SAMEORIGIN'} ipdb> response.reason 'Bad Request' ipdb> response.request ipdb> response.test *** AttributeError: 'Response' object has no attribute 'test' ipdb> response.text '{"type":["This field is required."]}' ipdb> response.url 'http://0.0.0.0:8080/api/dcim/interfaces/' ipdb> quit Create Netbox Interfaces r1 ** changed : False vvvv Create Netbox Interfaces ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv ERROR ---- napalm_get ** changed : False --------------------------------------------- INFO (venv) go:1.12.5|py:3.7.3|tomas@athens:~/storage/technology/netbox-example/nornir-napalm-netbox-demo master$ python scripts/create_interfaces.py nb_url = http://0.0.0.0:8080 url3=http://0.0.0.0:8080/api/dcim/interfaces?limit=0 Creating Netbox Interface for device r1, interface Loopback1 url3=http://0.0.0.0:8080/api/dcim/devices/?name=r1&limit=0 device_id = 1 url3=http://0.0.0.0:8080/api/dcim/interfaces/ resp_ok=False resp_status=400 body_data= {'name': 'Loopback1', 'form_factor': 1200, 'device': 1} params= /dcim/interfaces/ resp_data= {'type': ['This field is required.']} Traceback (most recent call last): File "scripts/create_interfaces.py", line 43, in task=create_netbox_interface, File "/home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/nornir/core/init.py", line 146, in run result = self._run_serial(task, run_on, **kwargs) File "/home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/nornir/core/init.py", line 72, in _run_serial result[host.name] = task.copy().start(host, self) File "/home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/nornir/core/task.py", line 85, in start r = self.task(self, **self.params) File "scripts/create_interfaces.py", line 35, in create_netbox_interface device_id=device_id, File "/home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/netbox/dcim.py", line 431, in create_interface return self.netbox_con.post('/dcim/interfaces/', required_fields, **kwargs) File "/home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/netbox/connection.py", line 130, in post raise exceptions.CreateException(resp_data) netbox.exceptions.CreateException: This field is required.
So it seems that at the end I realised that I was missing the parameter “type” !!!
I was checking the documentation from netbox in github but I couldnt see clearly what kind of config I had to provide…
I checked the “type” value for the only interfaces I already had in netbox: “http://0.0.0.0:8080/api/dcim/interfaces/“
So I tried to pass exactly that but it was still failing…
(venv) go:1.12.5|py:3.7.3|tomas@athens:~/storage/technology/netbox-example/nornir-napalm-netbox-demo master$ python scripts/create_interfaces.py nb_url = http://0.0.0.0:8080 url3=http://0.0.0.0:8080/api/dcim/interfaces?limit=0 Creating Netbox Interface for device r1, interface Loopback1 url3=http://0.0.0.0:8080/api/dcim/devices/?name=r1&limit=0 device_id = 1 url3=http://0.0.0.0:8080/api/dcim/interfaces/ resp_ok=False resp_status=400 body_data= {'name': 'Loopback1', 'form_factor': 1200, 'device': 1, 'type': {'value': '1000base-t', 'label': '1000BASE-T (1GE)', 'id': 1000}} params= /dcim/interfaces/ resp_data= {'type': ['Value must be passed directly (e.g. "foo": 123); do not use a dictionary or list.']} Traceback (most recent call last): File "scripts/create_interfaces.py", line 50, in task=create_netbox_interface, File "/home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/nornir/core/init.py", line 146, in run result = self._run_serial(task, run_on, **kwargs) File "/home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/nornir/core/init.py", line 72, in _run_serial result[host.name] = task.copy().start(host, self) File "/home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/nornir/core/task.py", line 85, in start r = self.task(self, **self.params) File "scripts/create_interfaces.py", line 42, in create_netbox_interface **interface_type, File "/home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/netbox/dcim.py", line 431, in create_interface return self.netbox_con.post('/dcim/interfaces/', required_fields, **kwargs) File "/home/tomas/storage/technology/netbox-example/venv/lib/python3.7/site-packages/netbox/connection.py", line 130, in post raise exceptions.CreateException(resp_data) netbox.exceptions.CreateException: Value must be passed directly (e.g. "foo": 123); do not use a dictionary or list. (venv) go:1.12.5|py:3.7.3|tomas@athens:~/storage/technology/netbox-example/nornir-napalm-netbox-demo master$
Somehow the API had to be documented… by chance, looking at the bottom of the netbox page, there was an”API” link….
So, now I needed to look up the correct API call. Based on the script and logs, it was a “POST” for “/dcim/interfaces/”. Here we go!
So finally, I had the info. I confirmed what fields were mandatory and the value they needed!
interface_type = {}
interface_type["type"] = "1000base-t"
for interface_name in interfaces.keys():
if not is_interface_present(nb_interfaces, f"{task.host}", interface_name):
print(
f"* Creating Netbox Interface for device {task.host}, interface {interface_name}"
)
device_id = get_device_id(f"{task.host}", netbox)
print("device_id = %s" % device_id)
netbox.dcim.create_interface(
name=f"{interface_name}",
form_factor=1200, # default
device_id=device_id,
**interface_type,
)
So the script ran fine for all my devices:
netbox-example/nornir-napalm-netbox-demo master$ python scripts/create_interfaces.py nb_url = http://0.0.0.0:8080 url3=http://0.0.0.0:8080/api/dcim/interfaces?limit=0 Create Netbox Interfaces r1 ** changed : False vvvv Create Netbox Interfaces ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO ---- napalm_get ** changed : False --------------------------------------------- INFO ^^^^ END Create Netbox Interfaces ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ r2 ** changed : False vvvv Create Netbox Interfaces ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO ---- napalm_get ** changed : False --------------------------------------------- INFO ^^^^ END Create Netbox Interfaces ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ r3 ** changed : False vvvv Create Netbox Interfaces ** changed : False vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv INFO ---- napalm_get ** changed : False --------------------------------------------- INFO ^^^^ END Create Netbox Interfaces ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
And it is updated in GUI: