Skip to content

Commit f5a1f83

Browse files
Closes #13368: Report installed plugins during server error (#13387)
* Introduce get_installed_plugins() utility * Extend 500 error template to list installed plugins * Move get_plugin_config() to extras.plugins.utils
1 parent f9648d8 commit f5a1f83

File tree

6 files changed

+48
-32
lines changed

6 files changed

+48
-32
lines changed

netbox/extras/plugins/__init__.py

-21
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
from importlib import import_module
33

44
from django.apps import AppConfig
5-
from django.conf import settings
65
from django.core.exceptions import ImproperlyConfigured
76
from django.utils.module_loading import import_string
87
from packaging import version
@@ -146,23 +145,3 @@ def validate(cls, user_config, netbox_version):
146145
for setting, value in cls.default_settings.items():
147146
if setting not in user_config:
148147
user_config[setting] = value
149-
150-
151-
#
152-
# Utilities
153-
#
154-
155-
def get_plugin_config(plugin_name, parameter, default=None):
156-
"""
157-
Return the value of the specified plugin configuration parameter.
158-
159-
Args:
160-
plugin_name: The name of the plugin
161-
parameter: The name of the configuration parameter
162-
default: The value to return if the parameter is not defined (default: None)
163-
"""
164-
try:
165-
plugin_config = settings.PLUGINS_CONFIG[plugin_name]
166-
return plugin_config.get(parameter, default)
167-
except KeyError:
168-
raise ImproperlyConfigured(f"Plugin {plugin_name} is not registered.")

netbox/extras/plugins/utils.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
from django.apps import apps
2+
from django.conf import settings
3+
from django.core.exceptions import ImproperlyConfigured
4+
5+
__all__ = (
6+
'get_installed_plugins',
7+
'get_plugin_config',
8+
)
9+
10+
11+
def get_installed_plugins():
12+
"""
13+
Return a dictionary mapping the names of installed plugins to their versions.
14+
"""
15+
plugins = {}
16+
for plugin_name in settings.PLUGINS:
17+
plugin_name = plugin_name.rsplit('.', 1)[-1]
18+
plugin_config = apps.get_app_config(plugin_name)
19+
plugins[plugin_name] = getattr(plugin_config, 'version', None)
20+
21+
return dict(sorted(plugins.items()))
22+
23+
24+
def get_plugin_config(plugin_name, parameter, default=None):
25+
"""
26+
Return the value of the specified plugin configuration parameter.
27+
28+
Args:
29+
plugin_name: The name of the plugin
30+
parameter: The name of the configuration parameter
31+
default: The value to return if the parameter is not defined (default: None)
32+
"""
33+
try:
34+
plugin_config = settings.PLUGINS_CONFIG[plugin_name]
35+
return plugin_config.get(parameter, default)
36+
except KeyError:
37+
raise ImproperlyConfigured(f"Plugin {plugin_name} is not registered.")

netbox/extras/tests/test_plugins.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
from django.test import Client, TestCase, override_settings
66
from django.urls import reverse
77

8-
from extras.plugins import PluginMenu, get_plugin_config
8+
from extras.plugins import PluginMenu
99
from extras.tests.dummy_plugin import config as dummy_config
10+
from extras.plugins.utils import get_plugin_config
1011
from netbox.graphql.schema import Query
1112
from netbox.registry import registry
1213

netbox/netbox/api/views.py

+2-9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from rest_framework.views import APIView
1212
from rq.worker import Worker
1313

14+
from extras.plugins.utils import get_installed_plugins
1415
from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired
1516

1617

@@ -61,19 +62,11 @@ def get(self, request):
6162
installed_apps[app_config.name] = version
6263
installed_apps = {k: v for k, v in sorted(installed_apps.items())}
6364

64-
# Gather installed plugins
65-
plugins = {}
66-
for plugin_name in settings.PLUGINS:
67-
plugin_name = plugin_name.rsplit('.', 1)[-1]
68-
plugin_config = apps.get_app_config(plugin_name)
69-
plugins[plugin_name] = getattr(plugin_config, 'version', None)
70-
plugins = {k: v for k, v in sorted(plugins.items())}
71-
7265
return Response({
7366
'django-version': DJANGO_VERSION,
7467
'installed-apps': installed_apps,
7568
'netbox-version': settings.VERSION,
76-
'plugins': plugins,
69+
'plugins': get_installed_plugins(),
7770
'python-version': platform.python_version(),
7871
'rq-workers-running': Worker.count(get_connection('default')),
7972
})

netbox/netbox/views/errors.py

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
from django.views.generic import View
1212
from sentry_sdk import capture_message
1313

14+
from extras.plugins.utils import get_installed_plugins
15+
1416
__all__ = (
1517
'handler_404',
1618
'handler_500',
@@ -53,4 +55,5 @@ def handler_500(request, template_name=ERROR_500_TEMPLATE_NAME):
5355
'exception': str(type_),
5456
'netbox_version': settings.VERSION,
5557
'python_version': platform.python_version(),
58+
'plugins': get_installed_plugins(),
5659
}))

netbox/templates/500.html

+4-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ <h5 class="card-header">
3030
{{ error }}
3131

3232
Python version: {{ python_version }}
33-
NetBox version: {{ netbox_version }}</pre>
33+
NetBox version: {{ netbox_version }}
34+
Plugins: {% for plugin, version in plugins.items %}
35+
{{ plugin }}: {{ version }}{% empty %}None installed{% endfor %}
36+
</pre>
3437
<p>
3538
If further assistance is required, please post to the <a href="https://github.com/netbox-community/netbox/discussions">NetBox discussion forum</a> on GitHub.
3639
</p>

0 commit comments

Comments
 (0)