diff --git a/docs/configuration/miscellaneous.md b/docs/configuration/miscellaneous.md index 576eb8739..b983acd80 100644 --- a/docs/configuration/miscellaneous.md +++ b/docs/configuration/miscellaneous.md @@ -106,6 +106,15 @@ By default, NetBox will prevent the creation of duplicate prefixes and IP addres --- +## EVENTS_PIPELINE + + +Default: `['extras.events.process_event_queue',]` + +NetBox will call dotted paths to the functions listed here for events (create, update, delete) on models as well as when custom EventRules are fired. + +--- + ## FILE_UPLOAD_MAX_MEMORY_SIZE Default: `2621440` (2.5 MB) diff --git a/docs/plugins/development/index.md b/docs/plugins/development/index.md index f3f9a3e4f..8a83ab71b 100644 --- a/docs/plugins/development/index.md +++ b/docs/plugins/development/index.md @@ -114,6 +114,7 @@ NetBox looks for the `config` variable within a plugin's `__init__.py` to load i | `max_version` | Maximum version of NetBox with which the plugin is compatible | | `middleware` | A list of middleware classes to append after NetBox's build-in middleware | | `queues` | A list of custom background task queues to create | +| `events_pipeline` | A list of handlers to add to [`EVENTS_PIPELINE`](./miscellaneous.md#events_pipeline), identified by dotted paths | | `search_extensions` | The dotted path to the list of search index classes (default: `search.indexes`) | | `data_backends` | The dotted path to the list of data source backend classes (default: `data_backends.backends`) | | `template_extensions` | The dotted path to the list of template extension classes (default: `template_content.template_extensions`) | diff --git a/netbox/netbox/plugins/__init__.py b/netbox/netbox/plugins/__init__.py index e2f0f22fc..69881a251 100644 --- a/netbox/netbox/plugins/__init__.py +++ b/netbox/netbox/plugins/__init__.py @@ -78,6 +78,7 @@ class PluginConfig(AppConfig): menu_items = None template_extensions = None user_preferences = None + events_pipeline = [] def _load_resource(self, name): # Import from the configured path, if defined. diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 2b057b9ab..0682e713d 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -110,9 +110,9 @@ DEFAULT_PERMISSIONS = getattr(configuration, 'DEFAULT_PERMISSIONS', { DEVELOPER = getattr(configuration, 'DEVELOPER', False) DOCS_ROOT = getattr(configuration, 'DOCS_ROOT', os.path.join(os.path.dirname(BASE_DIR), 'docs')) EMAIL = getattr(configuration, 'EMAIL', {}) -EVENTS_PIPELINE = getattr(configuration, 'EVENTS_PIPELINE', ( +EVENTS_PIPELINE = getattr(configuration, 'EVENTS_PIPELINE', [ 'extras.events.process_event_queue', -)) +]) EXEMPT_VIEW_PERMISSIONS = getattr(configuration, 'EXEMPT_VIEW_PERMISSIONS', []) FIELD_CHOICES = getattr(configuration, 'FIELD_CHOICES', {}) FILE_UPLOAD_MAX_MEMORY_SIZE = getattr(configuration, 'FILE_UPLOAD_MAX_MEMORY_SIZE', 2621440) @@ -787,6 +787,10 @@ STRAWBERRY_DJANGO = { PLUGIN_CATALOG_URL = 'https://api.netbox.oss.netboxlabs.com/v1/plugins' +EVENTS_PIPELINE = list(EVENTS_PIPELINE) +if 'extras.events.process_event_queue' not in EVENTS_PIPELINE: + EVENTS_PIPELINE.insert(0, 'extras.events.process_event_queue') + # Register any configured plugins for plugin_name in PLUGINS: try: @@ -857,6 +861,13 @@ for plugin_name in PLUGINS: f"{plugin_name}.{queue}": RQ_PARAMS for queue in plugin_config.queues }) + events_pipeline = plugin_config.events_pipeline + if events_pipeline: + if type(events_pipeline) in (list, tuple): + EVENTS_PIPELINE.extend(events_pipeline) + else: + raise ImproperlyConfigured(f"events_pipline in plugin: {plugin_name} must be a list or tuple") + # UNSUPPORTED FUNCTIONALITY: Import any local overrides. try: from .local_settings import * diff --git a/netbox/netbox/tests/dummy_plugin/__init__.py b/netbox/netbox/tests/dummy_plugin/__init__.py index 3ade8f9df..6ab62d638 100644 --- a/netbox/netbox/tests/dummy_plugin/__init__.py +++ b/netbox/netbox/tests/dummy_plugin/__init__.py @@ -17,6 +17,9 @@ class DummyPluginConfig(PluginConfig): 'testing-medium', 'testing-high' ] + events_pipeline = [ + 'netbox.tests.dummy_plugin.events.process_events_queue' + ] config = DummyPluginConfig diff --git a/netbox/netbox/tests/dummy_plugin/events.py b/netbox/netbox/tests/dummy_plugin/events.py new file mode 100644 index 000000000..934594643 --- /dev/null +++ b/netbox/netbox/tests/dummy_plugin/events.py @@ -0,0 +1,2 @@ +def process_events_queue(events): + pass diff --git a/netbox/netbox/tests/test_plugins.py b/netbox/netbox/tests/test_plugins.py index ba44378c5..16778667d 100644 --- a/netbox/netbox/tests/test_plugins.py +++ b/netbox/netbox/tests/test_plugins.py @@ -203,3 +203,10 @@ class PluginTest(TestCase): self.assertEqual(get_plugin_config(plugin, 'foo'), 123) self.assertEqual(get_plugin_config(plugin, 'bar'), None) self.assertEqual(get_plugin_config(plugin, 'bar', default=456), 456) + + + def test_events_pipeline(self): + """ + Check that events pipeline is registered. + """ + self.assertIn('netbox.tests.dummy_plugin.events.process_events_queue', settings.EVENTS_PIPELINE)