Skip incompatible plugins during startup and remove from PLUGINS

This commit is contained in:
Brian Tiemann 2025-01-29 18:22:22 -05:00
parent 41923b0cf8
commit 588fa9d9ab
3 changed files with 25 additions and 7 deletions

View File

@ -1,2 +1,9 @@
from django.core.exceptions import ImproperlyConfigured
class SyncError(Exception): class SyncError(Exception):
pass pass
class IncompatiblePluginError(ImproperlyConfigured):
pass

View File

@ -6,6 +6,7 @@ from django.core.exceptions import ImproperlyConfigured
from django.utils.module_loading import import_string from django.utils.module_loading import import_string
from packaging import version from packaging import version
from core.exceptions import IncompatiblePluginError
from netbox.registry import registry from netbox.registry import registry
from netbox.search import register_search from netbox.search import register_search
from netbox.utils import register_data_backend from netbox.utils import register_data_backend
@ -138,14 +139,14 @@ class PluginConfig(AppConfig):
if cls.min_version is not None: if cls.min_version is not None:
min_version = version.parse(cls.min_version) min_version = version.parse(cls.min_version)
if current_version < min_version: if current_version < min_version:
raise ImproperlyConfigured( raise IncompatiblePluginError(
f"Plugin {cls.__module__} requires NetBox minimum version {cls.min_version} (current: " f"Plugin {cls.__module__} requires NetBox minimum version {cls.min_version} (current: "
f"{netbox_version})." f"{netbox_version})."
) )
if cls.max_version is not None: if cls.max_version is not None:
max_version = version.parse(cls.max_version) max_version = version.parse(cls.max_version)
if current_version > max_version: if current_version > max_version:
raise ImproperlyConfigured( raise IncompatiblePluginError(
f"Plugin {cls.__module__} requires NetBox maximum version {cls.max_version} (current: " f"Plugin {cls.__module__} requires NetBox maximum version {cls.max_version} (current: "
f"{netbox_version})." f"{netbox_version})."
) )

View File

@ -11,6 +11,7 @@ from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.core.validators import URLValidator from django.core.validators import URLValidator
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from core.exceptions import IncompatiblePluginError
from netbox.config import PARAMS as CONFIG_PARAMS from netbox.config import PARAMS as CONFIG_PARAMS
from netbox.constants import RQ_QUEUE_DEFAULT, RQ_QUEUE_HIGH, RQ_QUEUE_LOW from netbox.constants import RQ_QUEUE_DEFAULT, RQ_QUEUE_HIGH, RQ_QUEUE_LOW
from netbox.plugins import PluginConfig from netbox.plugins import PluginConfig
@ -789,6 +790,7 @@ if 'extras.events.process_event_queue' not in EVENTS_PIPELINE:
EVENTS_PIPELINE.insert(0, 'extras.events.process_event_queue') EVENTS_PIPELINE.insert(0, 'extras.events.process_event_queue')
# Register any configured plugins # Register any configured plugins
incompatible_plugins = []
for plugin_name in PLUGINS: for plugin_name in PLUGINS:
try: try:
# Import the plugin module # Import the plugin module
@ -810,6 +812,16 @@ for plugin_name in PLUGINS:
f"__init__.py file and point to the PluginConfig subclass." f"__init__.py file and point to the PluginConfig subclass."
) )
# Validate version compatibility and user-provided configuration settings and assign defaults
if plugin_name not in PLUGINS_CONFIG:
PLUGINS_CONFIG[plugin_name] = {}
try:
plugin_config.validate(PLUGINS_CONFIG[plugin_name], RELEASE.version)
except IncompatiblePluginError as e:
print(f'Unable to load plugin {plugin_name}: {e}')
incompatible_plugins.append(plugin_name)
continue
plugin_module = "{}.{}".format(plugin_config.__module__, plugin_config.__name__) # type: ignore plugin_module = "{}.{}".format(plugin_config.__module__, plugin_config.__name__) # type: ignore
# Gather additional apps to load alongside this plugin # Gather additional apps to load alongside this plugin
@ -839,11 +851,6 @@ for plugin_name in PLUGINS:
sorted_apps = reversed(list(dict.fromkeys(reversed(INSTALLED_APPS)))) sorted_apps = reversed(list(dict.fromkeys(reversed(INSTALLED_APPS))))
INSTALLED_APPS = list(sorted_apps) INSTALLED_APPS = list(sorted_apps)
# Validate user-provided configuration settings and assign defaults
if plugin_name not in PLUGINS_CONFIG:
PLUGINS_CONFIG[plugin_name] = {}
plugin_config.validate(PLUGINS_CONFIG[plugin_name], RELEASE.version)
# Add middleware # Add middleware
plugin_middleware = plugin_config.middleware plugin_middleware = plugin_config.middleware
if plugin_middleware and type(plugin_middleware) in (list, tuple): if plugin_middleware and type(plugin_middleware) in (list, tuple):
@ -865,6 +872,9 @@ for plugin_name in PLUGINS:
else: else:
raise ImproperlyConfigured(f"events_pipline in plugin: {plugin_name} must be a list or tuple") raise ImproperlyConfigured(f"events_pipline in plugin: {plugin_name} must be a list or tuple")
[PLUGINS.remove(x) for x in incompatible_plugins]
# UNSUPPORTED FUNCTIONALITY: Import any local overrides. # UNSUPPORTED FUNCTIONALITY: Import any local overrides.
try: try:
from .local_settings import * from .local_settings import *