소스 검색

Merge pull request #4392 from netbox-community/refactor-plugins-import

Refactor plugins import
John Anderson 5 년 전
부모
커밋
e220c38b97
3개의 변경된 파일58개의 추가작업 그리고 43개의 파일을 삭제
  1. 34 1
      netbox/extras/plugins/__init__.py
  2. 20 39
      netbox/netbox/settings.py
  3. 4 3
      netbox/netbox/urls.py

+ 34 - 1
netbox/extras/plugins/__init__.py

@@ -2,13 +2,46 @@ import collections
 import importlib
 import inspect
 
-from django.core.exceptions import ImproperlyConfigured
+from django.apps import AppConfig
 from django.template.loader import get_template
 
 from extras.registry import registry
 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
 #

+ 20 - 39
netbox/netbox/settings.py

@@ -640,71 +640,52 @@ if PAGINATE_COUNT not in PER_PAGE_DEFAULTS:
 
 PLUGINS = []
 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
+        app_config = entry_point.load()
+
         PLUGINS.append(plugin)
         INSTALLED_APPS.append(plugin)
 
-        # Import the app config and locate the inner meta class
-        try:
-            module = importlib.import_module(plugin)
-            default_app_config = getattr(module, 'default_app_config')
-            module, app_config = default_app_config.rsplit('.', 1)
-            app_config = getattr(importlib.import_module(module), app_config)
-        except ImportError:
-            raise ImproperlyConfigured('Plugin config for {} could not be imported!'.format(plugin))
-
-        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))
+        # Check version constraints
+        parsed_min_version = parse_version(app_config.min_version or VERSION)
+        parsed_max_version = parse_version(app_config.max_version or VERSION)
+        if app_config.min_version and app_config.max_version and parsed_min_version > parsed_max_version:
+            raise ImproperlyConfigured(f"Plugin {plugin} specifies invalid version constraints!")
+        if app_config.min_version and parsed_min_version > parse_version(VERSION):
+            raise ImproperlyConfigured(f"Plugin {plugin} requires NetBox minimum version {app_config.min_version}!")
+        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}!")
 
         # Add middleware
-        plugin_middleware = getattr(app_config_meta, 'middleware', [])
+        plugin_middleware = app_config.middleware
         if plugin_middleware and isinstance(plugin_middleware, list):
             MIDDLEWARE.extend(plugin_middleware)
 
         # Verify required configuration settings
         if plugin not in PLUGINS_CONFIG:
             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]:
                 raise ImproperlyConfigured(
-                    "Plugin {} requires '{}' to be present in the PLUGINS_CONFIG section of configuration.py.".format(
-                        plugin,
-                        setting
-                    )
+                    f"Plugin {plugin} requires '{setting}' to be present in the PLUGINS_CONFIG section of "
+                    f"configuration.py."
                 )
 
         # 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]:
                 PLUGINS_CONFIG[plugin][setting] = value
 
         # 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):
             for key in plugin_cacheops.keys():
                 # Validate config is only being set for the given plugin
                 try:
                     app = key.split('.')[0]
                 except IndexError:
-                    raise ImproperlyConfigured('Plugin {} caching_config is invalid!'.format(plugin))
+                    raise ImproperlyConfigured(f"Plugin {plugin} caching_config is invalid!")
                 if app != plugin:
-                    raise ImproperlyConfigured(
-                        'Plugin {} may not modify caching config for another app!'.format(plugin)
-                    )
+                    raise ImproperlyConfigured(f"Plugin {plugin} may not modify caching config for another app!")
         CACHEOPS.update(plugin_cacheops)

+ 4 - 3
netbox/netbox/urls.py

@@ -8,6 +8,7 @@ from django.views.static import serve
 from drf_yasg import openapi
 from drf_yasg.views import get_schema_view
 
+from extras.plugins import PluginConfig
 from netbox.views import APIRootView, HomeView, StaticMediaFailureView, SearchView
 from users.views import LoginView, LogoutView
 from .admin import admin_site
@@ -76,11 +77,11 @@ plugin_patterns = []
 plugin_api_patterns = []
 for app in apps.get_app_configs():
     # Loop over all apps look for installed plugins
-    if hasattr(app, 'NetBoxPluginMeta'):
+    if isinstance(app, PluginConfig):
         # Check if the plugin specifies any URLs
         if importlib.util.find_spec('{}.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'):
                 # Mount URLs at `<url_slug>/<path>`
                 plugin_patterns.append(
@@ -91,7 +92,7 @@ for app in apps.get_app_configs():
             if importlib.util.find_spec('{}.api.urls'.format(app.name)):
                 urls = importlib.import_module('{}.api.urls'.format(app.name))
                 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>`
                     plugin_api_patterns.append(
                         path('{}/'.format(url_slug), include((urls.urlpatterns, app.label)))