From d665d4d62a883940b84b1ee484b189ea163f870c Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 18 Jul 2018 14:46:15 -0400 Subject: [PATCH] Fixes #1992: Isolate errors when one of multiple NAPALM methods fails --- netbox/dcim/api/views.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index ce8b4c349..befde771f 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -267,7 +267,7 @@ class DeviceViewSet(CustomFieldModelViewSet): import napalm except ImportError: raise ServiceUnavailable("NAPALM is not installed. Please see the documentation for instructions.") - from napalm.base.exceptions import ConnectAuthError, ModuleImportError + from napalm.base.exceptions import ModuleImportError # Validate the configured driver try: @@ -281,16 +281,8 @@ class DeviceViewSet(CustomFieldModelViewSet): if not request.user.has_perm('dcim.napalm_read'): return HttpResponseForbidden() - # Validate requested NAPALM methods + # Connect to the device napalm_methods = request.GET.getlist('method') - for method in napalm_methods: - if not hasattr(driver, method): - return HttpResponseBadRequest("Unknown NAPALM method: {}".format(method)) - elif not method.startswith('get_'): - return HttpResponseBadRequest("Unsupported NAPALM method: {}".format(method)) - - # Connect to the device and execute the requested methods - # TODO: Improve error handling response = OrderedDict([(m, None) for m in napalm_methods]) ip_address = str(device.primary_ip.address.ip) d = driver( @@ -302,12 +294,23 @@ class DeviceViewSet(CustomFieldModelViewSet): ) try: d.open() - for method in napalm_methods: - response[method] = getattr(d, method)() except Exception as e: raise ServiceUnavailable("Error connecting to the device at {}: {}".format(ip_address, e)) + # Validate and execute each specified NAPALM method + for method in napalm_methods: + if not hasattr(driver, method): + response[method] = {'error': 'Unknown NAPALM method'} + continue + if not method.startswith('get_'): + response[method] = {'error': 'Only get_* NAPALM methods are supported'} + continue + try: + response[method] = getattr(d, method)() + except NotImplementedError: + response[method] = {'error': 'Method not implemented for NAPALM driver {}'.format(driver)} d.close() + return Response(response)