Change DataSources to be called Plugins
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 7 May 2015 11:32:12 +0000 (11:32 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 7 May 2015 11:32:52 +0000 (11:32 +0000)
src/collecty/daemon.py
src/collecty/plugins/__init__.py
src/collecty/plugins/base.py
src/collecty/plugins/cpu.py
src/collecty/plugins/entropy.py
src/collecty/plugins/interface.py
src/collecty/plugins/latency.py
src/collecty/plugins/loadavg.py
src/collecty/plugins/memory.py

index 8f31021..a66fa10 100644 (file)
@@ -38,41 +38,37 @@ class Collecty(object):
                if debug:
                        log.setLevel(logging.DEBUG)
 
-               self.data_sources = []
+               self.plugins = []
 
                # Indicates whether this process should be running or not.
                self.running = True
                self.timer = plugins.Timer(self.SUBMIT_INTERVAL, heartbeat=2)
 
-               # Add all automatic data sources.
-               self.add_autocreate_data_sources()
+               # Add all plugins
+               for plugin in plugins.get():
+                       self.add_plugin(plugin)
 
-               log.info(_("Collecty successfully initialized."))
+               log.info(_("Collecty successfully initialized with %s plugins") \
+                       % len(self.plugins))
 
-       def add_autocreate_data_sources(self):
-               for data_source in plugins.data_sources:
-                       if not hasattr(data_source, "autocreate"):
-                               continue
+       def add_plugin(self, plugin_class):
+               # Try initialising a new plugin. If that fails, we will log the
+               # error and try to go on.
+               try:
+                       plugin = plugin_class(self)
+               except:
+                       log.critical(_("Plugin %s could not be initialised") % plugin_class, exc_info=True)
+                       return
 
-                       ret = data_source.autocreate(self)
-                       if not ret:
-                               continue
-
-                       if not type(ret) == type([]):
-                               ret = [ret,]
-
-                       log.debug(_("Data source '%(name)s' registered %(number)s instance(s).") % \
-                               { "name" : data_source.name, "number" : len(ret) })
-
-                       self.data_sources += ret
+               self.plugins.append(plugin)
 
        def run(self):
                # Register signal handlers.
                self.register_signal_handler()
 
                # Start all data source threads.
-               for ds in self.data_sources:
-                       ds.start()
+               for p in self.plugins:
+                       p.start()
 
                # Regularly submit all data to disk.
                while self.running:
@@ -80,11 +76,11 @@ class Collecty(object):
                                self.submit_all()
 
                # Wait until all instances are finished.
-               while self.data_sources:
-                       for ds in self.data_sources[:]:
-                               if not ds.isAlive():
-                                       log.debug(_("%s is not alive anymore. Removing.") % ds)
-                                       self.data_sources.remove(ds)
+               while self.plugins:
+                       for p in self.plugins[:]:
+                               if not p.isAlive():
+                                       log.debug(_("%s is not alive anymore. Removing.") % p)
+                                       self.plugins.remove(p)
 
                        # Wait a bit.
                        time.sleep(0.1)
@@ -96,8 +92,8 @@ class Collecty(object):
                        Submit all data right now.
                """
                log.debug(_("Submitting all data in memory"))
-               for ds in self.data_sources:
-                       ds._submit()
+               for p in self.plugins:
+                       p._submit()
 
                # Schedule the next submit.
                self.timer.reset()
@@ -110,8 +106,8 @@ class Collecty(object):
                        self.timer.cancel()
 
                # Propagating shutdown to all threads.
-               for ds in self.data_sources:
-                       ds.shutdown()
+               for p in self.plugins:
+                       p.shutdown()
 
        def register_signal_handler(self):
                for s in (signal.SIGTERM, signal.SIGINT, signal.SIGUSR1):
index 172c9e1..2524ed4 100644 (file)
 #                                                                             #
 ###############################################################################
 
-from base import Timer
+from base import Timer, get
 
+import base
 import cpu
 import entropy
 import interface
 import latency
 import loadavg
 import memory
-
-data_sources = [
-       cpu.DataSourceCPU,
-       entropy.DataSourceEntropy,
-       interface.DataSourceInterface,
-       latency.DataSourceLatency,
-       loadavg.DataSourceLoadAvg,
-       memory.DataSourceMemory,
-]
-
-# Generate graph templates list.
-graph_templates = []
-for ds in data_sources:
-       graph_templates += ds.templates
index 8f67a3c..82b0982 100644 (file)
@@ -31,6 +31,14 @@ import time
 from ..constants import *
 from ..i18n import _
 
+_plugins = {}
+
+def get():
+       """
+               Returns a list with all automatically registered plugins.
+       """
+       return _plugins.values()
+
 class Timer(object):
        def __init__(self, timeout, heartbeat=1):
                self.timeout = timeout
@@ -63,7 +71,7 @@ class Timer(object):
                return self.elapsed > self.timeout
 
 
-class DataSource(threading.Thread):
+class Plugin(threading.Thread):
        # The name of this plugin.
        name = None
 
@@ -85,6 +93,22 @@ class DataSource(threading.Thread):
        # The default interval of this plugin.
        default_interval = 60
 
+       # Automatically register all providers.
+       class __metaclass__(type):
+               def __init__(plugin, name, bases, dict):
+                       type.__init__(plugin, name, bases, dict)
+
+                       # The main class from which is inherited is not registered
+                       # as a plugin.
+                       if name == "Plugin":
+                               return
+
+                       if not all((plugin.name, plugin.description)):
+                               raise RuntimeError(_("Plugin is not properly configured: %s") \
+                                       % plugin)
+
+                       _plugins[plugin.name] = plugin
+
        def __init__(self, collecty, **kwargs):
                threading.Thread.__init__(self, name=self.description)
                self.daemon = True
index 3ba1079..1d26dcb 100644 (file)
@@ -102,7 +102,7 @@ class GraphTemplateCPU(base.GraphTemplate):
        ]
 
 
-class DataSourceCPU(base.DataSource):
+class ProcessorPlugin(base.Plugin):
        name = "cpu"
        description = "CPU Usage Data Source"
 
index 1bf5f5f..7966e8b 100644 (file)
@@ -53,7 +53,7 @@ class GraphTemplateEntropy(base.GraphTemplate):
        ]
 
 
-class DataSourceEntropy(base.DataSource):
+class EntropyPlugin(base.Plugin):
        name = "entropy"
        description = "Entropy Data Source"
 
index 1e9703a..fbf715a 100644 (file)
@@ -197,7 +197,7 @@ class GraphTemplateInterfaceErrors(base.GraphTemplate):
                ]
 
 
-class DataSourceInterface(base.DataSource):
+class InterfacePlugin(base.Plugin):
        name = "interface"
        description = "Interface Statistics Data Source"
 
index 9b55bb9..b269221 100644 (file)
@@ -82,7 +82,7 @@ class GraphTemplateLatency(base.GraphTemplate):
                ]
 
 
-class DataSourceLatency(base.DataSource):
+class LatencyPlugin(base.Plugin):
        name = "latency"
        description = "Latency (ICMP ping) Data Source"
 
index 6e4a54d..c14145f 100644 (file)
@@ -69,7 +69,7 @@ class GraphTemplateLoadAvg(base.GraphTemplate):
        ]
 
 
-class DataSourceLoadAvg(base.DataSource):
+class LoadAvgPlugin(base.Plugin):
        name = "loadavg"
        description = "Load Average Data Source"
 
index ae90968..e66e223 100644 (file)
@@ -87,7 +87,7 @@ class GraphTemplateMemory(base.GraphTemplate):
        ]
 
 
-class DataSourceMemory(base.DataSource):
+class MemoryPlugin(base.Plugin):
        name = "memory"
        description = "Memory Usage Data Source"