jenkins-bot has submitted this change and it was merged.

Change subject: Load plug-in data sinks from preconfigured location
......................................................................


Load plug-in data sinks from preconfigured location

This patch allows EventLogging to be extended using plug-ins. Plug-ins are
Python scripts that register data readers/writers using the @reads and @writes
decorators provided in eventlogging.factory. If these Python scripts are placed
in /usr/lib/eventlogging (overrideable by setting EVENTLOGGING_PLUGIN_DIR in
the environment), they will be auto-loaded by eventlogging-consumer, unless
'--no-plugins' is specified on the command line.

Change-Id: Ia5f9d9979e740ef903be2611fb482e1849aec16d
---
M server/bin/eventlogging-consumer
M server/eventlogging/handlers.py
A server/tests/plugins/mock.py
M server/tests/test_handlers.py
4 files changed, 55 insertions(+), 2 deletions(-)

Approvals:
  Ori.livneh: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/server/bin/eventlogging-consumer b/server/bin/eventlogging-consumer
index 3e527d7..e58abf4 100755
--- a/server/bin/eventlogging-consumer
+++ b/server/bin/eventlogging-consumer
@@ -13,7 +13,8 @@
     output-uri     URI of output stream
 
   optional arguments:
-    -h, --help  show this help message and exit
+    -h, --help     show this help message and exit
+    --no-plugins   run without loading plug-ins
 
   :copyright: (c) 2012 by Ori Livneh <[email protected]>
   :license: GNU General Public Licence 2.0 or later
@@ -36,8 +37,14 @@
                              fromfile_prefix_chars='@')
 ap.add_argument('input', help='URI of raw input stream')
 ap.add_argument('output', help='URI of output stream', default='stdout://')
+ap.add_argument('--no-plugins', help='run without loading plug-ins',
+                action='store_false', dest='load_plugins')
+ap.set_defaults(load_plugins=True)
 args = ap.parse_args()
 
+if args.load_plugins:
+    eventlogging.load_plugins()
+
 log.info('Driving %s -> %s..', args.input, args.output)
 while 1:
     try:
diff --git a/server/eventlogging/handlers.py b/server/eventlogging/handlers.py
index e974225..8717da6 100644
--- a/server/eventlogging/handlers.py
+++ b/server/eventlogging/handlers.py
@@ -11,10 +11,13 @@
 
 """
 import datetime
+import glob
+import imp
 import io
 import json
 import logging
 import logging.handlers
+import os
 import socket
 import sys
 
@@ -27,6 +30,23 @@
 from .jrm import store_sql_event
 
 
+__all__ = ('load_plugins',)
+
+#: EventLogging will attempt to load the configuration file specified in the
+#: 'EVENTLOGGING_PLUGIN_DIR' environment variable if it is defined. If it is
+#: not defined, EventLogging will default to the value specified below.
+DEFAULT_PLUGIN_DIR = '/usr/lib/eventlogging'
+
+
+def load_plugins(path=None):
+    """Load EventLogging plug-ins from `path`. Plug-in module names are mangled
+    to prevent clobbering modules in the Python module search path."""
+    if path is None:
+        path = os.environ.get('EVENTLOGGING_PLUGIN_DIR', DEFAULT_PLUGIN_DIR)
+    for plugin in glob.glob(os.path.join(path, '*.py')):
+        imp.load_source('__eventlogging_plugin_%x__' % hash(plugin), plugin)
+
+
 # Mappers
 
 @mapper
diff --git a/server/tests/plugins/mock.py b/server/tests/plugins/mock.py
new file mode 100644
index 0000000..92c5656
--- /dev/null
+++ b/server/tests/plugins/mock.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+from eventlogging.factory import reads
+
+
+@reads('mock')
+def mock_writer():
+    """A mock EventLogging writer used for testing the plug-in auto-loader."""
+    while 1:
+        yield 'value generated by plug-in'
diff --git a/server/tests/test_handlers.py b/server/tests/test_handlers.py
index 8f95a25..dc16752 100644
--- a/server/tests/test_handlers.py
+++ b/server/tests/test_handlers.py
@@ -3,14 +3,16 @@
   eventlogging unit tests
   ~~~~~~~~~~~~~~~~~~~~~~~
 
-  This module contains tests for :module:`eventlogging.jrm`.
+  This module contains tests for :module:`eventlogging.handlers`.
 
 """
 from __future__ import unicode_literals
 
+import os
 import unittest
 
 import eventlogging
+import eventlogging.handlers
 import eventlogging.factory
 
 
@@ -48,3 +50,18 @@
         """``get_reader`` returns the right generator for the URI scheme."""
         reader = eventlogging.get_reader('test://localhost/?value=secret')
         self.assertEqual(next(reader), 'secret')
+
+
+class PluginTestCase(unittest.TestCase):
+    """Test case for the plug-in loader."""
+
+    def setUp(self):
+        """Determine path to mock plugin directory."""
+        script_path = os.path.dirname(os.path.abspath(__file__))
+        self.plugin_path = os.path.join(script_path, 'plugins')
+
+    def test_load_plugins(self):
+        """`get_plugins` loads plug-ins from an arbitrary path."""
+        eventlogging.handlers.load_plugins(self.plugin_path)
+        reader = eventlogging.get_reader('mock://localhost')
+        self.assertEqual(next(reader), 'value generated by plug-in')

-- 
To view, visit https://gerrit.wikimedia.org/r/74303
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ia5f9d9979e740ef903be2611fb482e1849aec16d
Gerrit-PatchSet: 2
Gerrit-Project: mediawiki/extensions/EventLogging
Gerrit-Branch: master
Gerrit-Owner: Ori.livneh <[email protected]>
Gerrit-Reviewer: Mattflaschen <[email protected]>
Gerrit-Reviewer: Ori.livneh <[email protected]>
Gerrit-Reviewer: Spage <[email protected]>
Gerrit-Reviewer: Yuvipanda <[email protected]>
Gerrit-Reviewer: jenkins-bot

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to