diff --git a/docs/release-notes/version-2.9.md b/docs/release-notes/version-2.9.md index 63e5d7117..f96eac458 100644 --- a/docs/release-notes/version-2.9.md +++ b/docs/release-notes/version-2.9.md @@ -6,6 +6,7 @@ * [#5304](https://github.com/netbox-community/netbox/issues/5304) - Return server error messages as JSON when handling REST API requests * [#5310](https://github.com/netbox-community/netbox/issues/5310) - Link to rack groups within rack list table +* [#5327](https://github.com/netbox-community/netbox/issues/5327) - Be more strict when capturing anticipated ImportError exceptions ### Bug Fixes diff --git a/netbox/dcim/api/views.py b/netbox/dcim/api/views.py index 427aecd5f..2d7107ef4 100644 --- a/netbox/dcim/api/views.py +++ b/netbox/dcim/api/views.py @@ -396,9 +396,7 @@ class DeviceViewSet(CustomFieldModelViewSet, ConfigContextQuerySetMixin): if device.platform is None: raise ServiceUnavailable("No platform is configured for this device.") if not device.platform.napalm_driver: - raise ServiceUnavailable("No NAPALM driver is configured for this device's platform {}.".format( - device.platform - )) + raise ServiceUnavailable(f"No NAPALM driver is configured for this device's platform: {device.platform}.") # Check for primary IP address from NetBox object if device.primary_ip: @@ -407,21 +405,25 @@ class DeviceViewSet(CustomFieldModelViewSet, ConfigContextQuerySetMixin): # 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.") + "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.") + f"Name lookup failure, unable to resolve IP address for {device.name}. Please set Primary IP or " + f"setup name resolution.") # Check that NAPALM is installed try: import napalm from napalm.base.exceptions import ModuleImportError - except ImportError: - raise ServiceUnavailable("NAPALM is not installed. Please see the documentation for instructions.") + except ModuleNotFoundError as e: + if getattr(e, 'name') == 'napalm': + raise ServiceUnavailable("NAPALM is not installed. Please see the documentation for instructions.") + raise e # Validate the configured driver try: diff --git a/netbox/netbox/authentication.py b/netbox/netbox/authentication.py index 21fb3e229..0eee2c13e 100644 --- a/netbox/netbox/authentication.py +++ b/netbox/netbox/authentication.py @@ -137,19 +137,24 @@ class LDAPBackend: def __new__(cls, *args, **kwargs): try: - import ldap from django_auth_ldap.backend import LDAPBackend as LDAPBackend_, LDAPSettings - except ImportError: - raise ImproperlyConfigured( - "LDAP authentication has been configured, but django-auth-ldap is not installed." - ) + import ldap + except ModuleNotFoundError as e: + if getattr(e, 'name') == 'django_auth_ldap': + raise ImproperlyConfigured( + "LDAP authentication has been configured, but django-auth-ldap is not installed." + ) + raise e try: from netbox import ldap_config - except ImportError: - raise ImproperlyConfigured( - "ldap_config.py does not exist" - ) + except ModuleNotFoundError as e: + if getattr(e, 'name') == 'ldap_config': + raise ImproperlyConfigured( + "LDAP configuration file not found: Check that ldap_config.py has been created alongside " + "configuration.py." + ) + raise e try: getattr(ldap_config, 'AUTH_LDAP_SERVER_URI') diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 36d3fb980..824739345 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -38,10 +38,12 @@ if platform.python_version_tuple() < ('3', '6'): # Import configuration parameters try: from netbox import configuration -except ImportError: - raise ImproperlyConfigured( - "Configuration file is not present. Please define netbox/netbox/configuration.py per the documentation." - ) +except ModuleNotFoundError as e: + if getattr(e, 'name') == 'configuration': + raise ImproperlyConfigured( + "Configuration file is not present. Please define netbox/netbox/configuration.py per the documentation." + ) + raise # Enforce required configuration parameters for parameter in ['ALLOWED_HOSTS', 'DATABASE', 'SECRET_KEY', 'REDIS']: @@ -183,11 +185,13 @@ if STORAGE_BACKEND is not None: try: import storages.utils - except ImportError: - raise ImproperlyConfigured( - "STORAGE_BACKEND is set to {} but django-storages is not present. It can be installed by running 'pip " - "install django-storages'.".format(STORAGE_BACKEND) - ) + except ModuleNotFoundError as e: + if getattr(e, 'name') == 'storages': + raise ImproperlyConfigured( + f"STORAGE_BACKEND is set to {STORAGE_BACKEND} but django-storages is not present. It can be " + f"installed by running 'pip install django-storages'." + ) + raise e # Monkey-patch django-storages to fetch settings from STORAGE_CONFIG def _setting(name, default=None): @@ -596,11 +600,13 @@ for plugin_name in PLUGINS: # Import plugin module try: plugin = importlib.import_module(plugin_name) - except ImportError: - raise ImproperlyConfigured( - "Unable to import plugin {}: Module not found. Check that the plugin module has been installed within the " - "correct Python environment.".format(plugin_name) - ) + except ModuleNotFoundError as e: + if getattr(e, 'name') == plugin_name: + raise ImproperlyConfigured( + "Unable to import plugin {}: Module not found. Check that the plugin module has been installed within the " + "correct Python environment.".format(plugin_name) + ) + raise e # Determine plugin config and add to INSTALLED_APPS. try: