mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-18 04:56:29 -06:00
Merge pull request #4392 from netbox-community/refactor-plugins-import
Refactor plugins import
This commit is contained in:
commit
e220c38b97
@ -2,13 +2,46 @@ import collections
|
|||||||
import importlib
|
import importlib
|
||||||
import inspect
|
import inspect
|
||||||
|
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.apps import AppConfig
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
|
|
||||||
from extras.registry import registry
|
from extras.registry import registry
|
||||||
from .signals import register_detail_page_content_classes, register_nav_menu_link_classes
|
from .signals import register_detail_page_content_classes, register_nav_menu_link_classes
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Plugin AppConfig class
|
||||||
|
#
|
||||||
|
|
||||||
|
class PluginConfig(AppConfig):
|
||||||
|
"""
|
||||||
|
Subclass of Django's built-in AppConfig class, to be used for NetBox plugins.
|
||||||
|
"""
|
||||||
|
# Plugin metadata
|
||||||
|
author = ''
|
||||||
|
description = ''
|
||||||
|
version = ''
|
||||||
|
|
||||||
|
# Root URL path under /plugins. If not set, the plugin's label will be used.
|
||||||
|
url_slug = None
|
||||||
|
|
||||||
|
# Minimum/maximum compatible versions of NetBox
|
||||||
|
min_version = None
|
||||||
|
max_version = None
|
||||||
|
|
||||||
|
# Default configuration parameters
|
||||||
|
default_settings = {}
|
||||||
|
|
||||||
|
# Mandatory configuration parameters
|
||||||
|
required_settings = []
|
||||||
|
|
||||||
|
# Middleware classes provided by the plugin
|
||||||
|
middleware = []
|
||||||
|
|
||||||
|
# Caching configuration
|
||||||
|
caching_config = {}
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Template content injection
|
# Template content injection
|
||||||
#
|
#
|
||||||
|
@ -640,71 +640,52 @@ if PAGINATE_COUNT not in PER_PAGE_DEFAULTS:
|
|||||||
|
|
||||||
PLUGINS = []
|
PLUGINS = []
|
||||||
if PLUGINS_ENABLED:
|
if PLUGINS_ENABLED:
|
||||||
for entry_point in iter_entry_points(group='netbox.plugin', name=None):
|
for entry_point in iter_entry_points(group='netbox_plugins', name=None):
|
||||||
plugin = entry_point.module_name
|
plugin = entry_point.module_name
|
||||||
|
app_config = entry_point.load()
|
||||||
|
|
||||||
PLUGINS.append(plugin)
|
PLUGINS.append(plugin)
|
||||||
INSTALLED_APPS.append(plugin)
|
INSTALLED_APPS.append(plugin)
|
||||||
|
|
||||||
# Import the app config and locate the inner meta class
|
# Check version constraints
|
||||||
try:
|
parsed_min_version = parse_version(app_config.min_version or VERSION)
|
||||||
module = importlib.import_module(plugin)
|
parsed_max_version = parse_version(app_config.max_version or VERSION)
|
||||||
default_app_config = getattr(module, 'default_app_config')
|
if app_config.min_version and app_config.max_version and parsed_min_version > parsed_max_version:
|
||||||
module, app_config = default_app_config.rsplit('.', 1)
|
raise ImproperlyConfigured(f"Plugin {plugin} specifies invalid version constraints!")
|
||||||
app_config = getattr(importlib.import_module(module), app_config)
|
if app_config.min_version and parsed_min_version > parse_version(VERSION):
|
||||||
except ImportError:
|
raise ImproperlyConfigured(f"Plugin {plugin} requires NetBox minimum version {app_config.min_version}!")
|
||||||
raise ImproperlyConfigured('Plugin config for {} could not be imported!'.format(plugin))
|
if app_config.max_version and parsed_max_version < parse_version(VERSION):
|
||||||
|
raise ImproperlyConfigured(f"Plugin {plugin} requires NetBox maximum version {app_config.max_version}!")
|
||||||
app_config_meta = getattr(app_config, 'NetBoxPluginMeta', None)
|
|
||||||
if not app_config_meta:
|
|
||||||
raise ImproperlyConfigured(
|
|
||||||
'The app config for plugin {} does not contain an inner meta class'.format(plugin)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check version contraints
|
|
||||||
min_version = getattr(app_config_meta, 'min_version', None)
|
|
||||||
max_version = getattr(app_config_meta, 'max_version', None)
|
|
||||||
parsed_min_version = parse_version(min_version or VERSION)
|
|
||||||
parsed_max_version = parse_version(max_version or VERSION)
|
|
||||||
if min_version and max_version and parsed_min_version > parsed_max_version:
|
|
||||||
raise ImproperlyConfigured('Plugin {} specifies invalid version contraints!'.format(plugin))
|
|
||||||
if min_version and parsed_min_version > parse_version(VERSION):
|
|
||||||
raise ImproperlyConfigured('Plugin {} requires NetBox minimum version {}!'.format(plugin, min_version))
|
|
||||||
if max_version and parsed_max_version < parse_version(VERSION):
|
|
||||||
raise ImproperlyConfigured('Plugin {} requires NetBox maximum version {}!'.format(plugin, max_version))
|
|
||||||
|
|
||||||
# Add middleware
|
# Add middleware
|
||||||
plugin_middleware = getattr(app_config_meta, 'middleware', [])
|
plugin_middleware = app_config.middleware
|
||||||
if plugin_middleware and isinstance(plugin_middleware, list):
|
if plugin_middleware and isinstance(plugin_middleware, list):
|
||||||
MIDDLEWARE.extend(plugin_middleware)
|
MIDDLEWARE.extend(plugin_middleware)
|
||||||
|
|
||||||
# Verify required configuration settings
|
# Verify required configuration settings
|
||||||
if plugin not in PLUGINS_CONFIG:
|
if plugin not in PLUGINS_CONFIG:
|
||||||
PLUGINS_CONFIG[plugin] = {}
|
PLUGINS_CONFIG[plugin] = {}
|
||||||
for setting in getattr(app_config_meta, 'required_settings', []):
|
for setting in app_config.required_settings:
|
||||||
if setting not in PLUGINS_CONFIG[plugin]:
|
if setting not in PLUGINS_CONFIG[plugin]:
|
||||||
raise ImproperlyConfigured(
|
raise ImproperlyConfigured(
|
||||||
"Plugin {} requires '{}' to be present in the PLUGINS_CONFIG section of configuration.py.".format(
|
f"Plugin {plugin} requires '{setting}' to be present in the PLUGINS_CONFIG section of "
|
||||||
plugin,
|
f"configuration.py."
|
||||||
setting
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set defined default setting values
|
# Set defined default setting values
|
||||||
for setting, value in getattr(app_config_meta, 'default_settings', {}).items():
|
for setting, value in app_config.default_settings.items():
|
||||||
if setting not in PLUGINS_CONFIG[plugin]:
|
if setting not in PLUGINS_CONFIG[plugin]:
|
||||||
PLUGINS_CONFIG[plugin][setting] = value
|
PLUGINS_CONFIG[plugin][setting] = value
|
||||||
|
|
||||||
# Apply cacheops config
|
# Apply cacheops config
|
||||||
plugin_cacheops = getattr(app_config_meta, 'caching_config', {})
|
plugin_cacheops = app_config.caching_config
|
||||||
if plugin_cacheops and isinstance(plugin_cacheops, dict):
|
if plugin_cacheops and isinstance(plugin_cacheops, dict):
|
||||||
for key in plugin_cacheops.keys():
|
for key in plugin_cacheops.keys():
|
||||||
# Validate config is only being set for the given plugin
|
# Validate config is only being set for the given plugin
|
||||||
try:
|
try:
|
||||||
app = key.split('.')[0]
|
app = key.split('.')[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
raise ImproperlyConfigured('Plugin {} caching_config is invalid!'.format(plugin))
|
raise ImproperlyConfigured(f"Plugin {plugin} caching_config is invalid!")
|
||||||
if app != plugin:
|
if app != plugin:
|
||||||
raise ImproperlyConfigured(
|
raise ImproperlyConfigured(f"Plugin {plugin} may not modify caching config for another app!")
|
||||||
'Plugin {} may not modify caching config for another app!'.format(plugin)
|
|
||||||
)
|
|
||||||
CACHEOPS.update(plugin_cacheops)
|
CACHEOPS.update(plugin_cacheops)
|
||||||
|
@ -8,6 +8,7 @@ from django.views.static import serve
|
|||||||
from drf_yasg import openapi
|
from drf_yasg import openapi
|
||||||
from drf_yasg.views import get_schema_view
|
from drf_yasg.views import get_schema_view
|
||||||
|
|
||||||
|
from extras.plugins import PluginConfig
|
||||||
from netbox.views import APIRootView, HomeView, StaticMediaFailureView, SearchView
|
from netbox.views import APIRootView, HomeView, StaticMediaFailureView, SearchView
|
||||||
from users.views import LoginView, LogoutView
|
from users.views import LoginView, LogoutView
|
||||||
from .admin import admin_site
|
from .admin import admin_site
|
||||||
@ -76,11 +77,11 @@ plugin_patterns = []
|
|||||||
plugin_api_patterns = []
|
plugin_api_patterns = []
|
||||||
for app in apps.get_app_configs():
|
for app in apps.get_app_configs():
|
||||||
# Loop over all apps look for installed plugins
|
# Loop over all apps look for installed plugins
|
||||||
if hasattr(app, 'NetBoxPluginMeta'):
|
if isinstance(app, PluginConfig):
|
||||||
# Check if the plugin specifies any URLs
|
# Check if the plugin specifies any URLs
|
||||||
if importlib.util.find_spec('{}.urls'.format(app.name)):
|
if importlib.util.find_spec('{}.urls'.format(app.name)):
|
||||||
urls = importlib.import_module('{}.urls'.format(app.name))
|
urls = importlib.import_module('{}.urls'.format(app.name))
|
||||||
url_slug = getattr(app.NetBoxPluginMeta, 'url_slug', app.label)
|
url_slug = getattr(app, 'url_slug') or app.label
|
||||||
if hasattr(urls, 'urlpatterns'):
|
if hasattr(urls, 'urlpatterns'):
|
||||||
# Mount URLs at `<url_slug>/<path>`
|
# Mount URLs at `<url_slug>/<path>`
|
||||||
plugin_patterns.append(
|
plugin_patterns.append(
|
||||||
@ -91,7 +92,7 @@ for app in apps.get_app_configs():
|
|||||||
if importlib.util.find_spec('{}.api.urls'.format(app.name)):
|
if importlib.util.find_spec('{}.api.urls'.format(app.name)):
|
||||||
urls = importlib.import_module('{}.api.urls'.format(app.name))
|
urls = importlib.import_module('{}.api.urls'.format(app.name))
|
||||||
if hasattr(urls, 'urlpatterns'):
|
if hasattr(urls, 'urlpatterns'):
|
||||||
url_slug = getattr(app.NetBoxPluginMeta, 'url_slug', app.label)
|
url_slug = getattr(app, 'url_slug') or app.label
|
||||||
# Mount URLs at `<url_slug>/<path>`
|
# Mount URLs at `<url_slug>/<path>`
|
||||||
plugin_api_patterns.append(
|
plugin_api_patterns.append(
|
||||||
path('{}/'.format(url_slug), include((urls.urlpatterns, app.label)))
|
path('{}/'.format(url_slug), include((urls.urlpatterns, app.label)))
|
||||||
|
Loading…
Reference in New Issue
Block a user