From 7788bf3ce34aaa98d83bfafdb14bc82a7079e7a5 Mon Sep 17 00:00:00 2001 From: Josh VanDeraa Date: Fri, 10 Jul 2020 15:12:25 -0500 Subject: [PATCH 1/3] Adds to NAPALM, name lookup if no primary IP address for device --- netbox/dcim/api/views.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index ea875d8c8..1493caec9 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -1,3 +1,4 @@ +import socket from collections import OrderedDict from django.conf import settings @@ -371,8 +372,6 @@ class DeviceViewSet(CustomFieldModelViewSet): Execute a NAPALM method on a Device """ device = get_object_or_404(Device, pk=pk) - if not device.primary_ip: - raise ServiceUnavailable("This device does not have a primary IP address configured.") if device.platform is None: raise ServiceUnavailable("No platform is configured for this device.") if not device.platform.napalm_driver: @@ -402,7 +401,18 @@ class DeviceViewSet(CustomFieldModelViewSet): # Connect to the device napalm_methods = request.GET.getlist('method') response = OrderedDict([(m, None) for m in napalm_methods]) - ip_address = str(device.primary_ip.address.ip) + + # Check for primary IP address from NetBox object + if device.primary_ip: + host = str(device.primary_ip.address.ip) + else: + # Attempt to complete a DNS name resolution if no primary_ip is set + try: + host = socket.gethostbyname(device.name) + except socket.gaierror: + # Name lookup failure + raise ServiceUnavailable(f"Name lookup failure, unable to resolve IP address for {device.name}. Please set Primary IP or setup name resolution.") + username = settings.NAPALM_USERNAME password = settings.NAPALM_PASSWORD optional_args = settings.NAPALM_ARGS.copy() @@ -423,7 +433,7 @@ class DeviceViewSet(CustomFieldModelViewSet): optional_args[key.lower()] = request.headers[header] d = driver( - hostname=ip_address, + hostname=host, username=username, password=password, timeout=settings.NAPALM_TIMEOUT, @@ -432,7 +442,7 @@ class DeviceViewSet(CustomFieldModelViewSet): try: d.open() except Exception as e: - raise ServiceUnavailable("Error connecting to the device at {}: {}".format(ip_address, e)) + raise ServiceUnavailable("Error connecting to the device at {}: {}".format(host, e)) # Validate and execute each specified NAPALM method for method in napalm_methods: From cac48924aeba4c1116af3e4b2cca9991e3b077f8 Mon Sep 17 00:00:00 2001 From: Josh VanDeraa Date: Fri, 10 Jul 2020 16:18:58 -0500 Subject: [PATCH 2/3] Adds verification of device.name configured --- netbox/dcim/api/views.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index 1493caec9..007217e44 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -398,21 +398,22 @@ class DeviceViewSet(CustomFieldModelViewSet): if not request.user.has_perm('dcim.napalm_read'): return HttpResponseForbidden() - # Connect to the device - napalm_methods = request.GET.getlist('method') - response = OrderedDict([(m, None) for m in napalm_methods]) - # Check for primary IP address from NetBox object if device.primary_ip: host = str(device.primary_ip.address.ip) else: - # Attempt to complete a DNS name resolution if no primary_ip is set + # Raise exception for no IP address and no Name if device.name does not exist + if not device.name: + raise ServiceUnavailable("This device does not have a primary IP address or device name to lookup configured.") try: + # Attempt to complete a DNS name resolution if no primary_ip is set host = socket.gethostbyname(device.name) except socket.gaierror: # Name lookup failure raise ServiceUnavailable(f"Name lookup failure, unable to resolve IP address for {device.name}. Please set Primary IP or setup name resolution.") + napalm_methods = request.GET.getlist('method') + response = OrderedDict([(m, None) for m in napalm_methods]) username = settings.NAPALM_USERNAME password = settings.NAPALM_PASSWORD optional_args = settings.NAPALM_ARGS.copy() @@ -432,6 +433,7 @@ class DeviceViewSet(CustomFieldModelViewSet): elif key: optional_args[key.lower()] = request.headers[header] + # Connect to the device d = driver( hostname=host, username=username, From ba8b99d3b8fb1a31781c563b9b511c383abc4731 Mon Sep 17 00:00:00 2001 From: Josh VanDeraa Date: Mon, 13 Jul 2020 08:36:15 -0500 Subject: [PATCH 3/3] Moves location of the IP address / hostname check and assignment --- netbox/dcim/api/views.py | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index 007217e44..2aff33840 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -379,6 +379,22 @@ class DeviceViewSet(CustomFieldModelViewSet): device.platform )) + # Check for primary IP address from NetBox object + if device.primary_ip: + host = str(device.primary_ip.address.ip) + else: + # Raise exception for no IP address and no Name if device.name does not exist + if not device.name: + raise ServiceUnavailable( + "This device does not have a primary IP address or device name to lookup configured.") + try: + # Attempt to complete a DNS name resolution if no primary_ip is set + host = socket.gethostbyname(device.name) + except socket.gaierror: + # Name lookup failure + raise ServiceUnavailable( + f"Name lookup failure, unable to resolve IP address for {device.name}. Please set Primary IP or setup name resolution.") + # Check that NAPALM is installed try: import napalm @@ -398,20 +414,6 @@ class DeviceViewSet(CustomFieldModelViewSet): if not request.user.has_perm('dcim.napalm_read'): return HttpResponseForbidden() - # Check for primary IP address from NetBox object - if device.primary_ip: - host = str(device.primary_ip.address.ip) - else: - # Raise exception for no IP address and no Name if device.name does not exist - if not device.name: - raise ServiceUnavailable("This device does not have a primary IP address or device name to lookup configured.") - try: - # Attempt to complete a DNS name resolution if no primary_ip is set - host = socket.gethostbyname(device.name) - except socket.gaierror: - # Name lookup failure - raise ServiceUnavailable(f"Name lookup failure, unable to resolve IP address for {device.name}. Please set Primary IP or setup name resolution.") - napalm_methods = request.GET.getlist('method') response = OrderedDict([(m, None) for m in napalm_methods]) username = settings.NAPALM_USERNAME