Explorar o código

Merge pull request #4844 from jvanderaa/napalm_lookup_hostname

Adds name lookup to NAPALM if no primary IP address exists for device
Jeremy Stretch %!s(int64=5) %!d(string=hai) anos
pai
achega
df20abf283
Modificáronse 1 ficheiros con 20 adicións e 6 borrados
  1. 20 6
      netbox/dcim/api/views.py

+ 20 - 6
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:
@@ -380,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
@@ -399,10 +414,8 @@ 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])
-        ip_address = str(device.primary_ip.address.ip)
         username = settings.NAPALM_USERNAME
         password = settings.NAPALM_PASSWORD
         optional_args = settings.NAPALM_ARGS.copy()
@@ -422,8 +435,9 @@ class DeviceViewSet(CustomFieldModelViewSet):
             elif key:
                 optional_args[key.lower()] = request.headers[header]
 
+        # Connect to the device
         d = driver(
-            hostname=ip_address,
+            hostname=host,
             username=username,
             password=password,
             timeout=settings.NAPALM_TIMEOUT,
@@ -432,7 +446,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: