diff --git a/secop/modules.py b/secop/modules.py index 5623d93..7b488a9 100644 --- a/secop/modules.py +++ b/secop/modules.py @@ -280,6 +280,7 @@ class Module(HasAccessibles): # reference to the dispatcher (used for sending async updates) DISPATCHER = None + attachedModules = None def __init__(self, name, logger, cfgdict, srv): # remember the dispatcher object (for the async callbacks) @@ -649,11 +650,11 @@ class Module(HasAccessibles): self.log.info('recovered after %d calls to doPoll (%r)', error_count, last_error) last_error = None except Exception as e: - if type(e) != last_error: + if repr(e) != last_error: error_count = 0 self.log.error('error in doPoll: %r', e) error_count += 1 - last_error = e + last_error = repr(e) now = time.time() # find ONE due slow poll and call it loop = True @@ -803,14 +804,15 @@ class Attached(Property): assign a module name to this property in the cfg file, and the server will create an attribute with this module """ - module = None - - def __init__(self, description='attached module'): + def __init__(self, basecls=Module, description='attached module'): + self.basecls = basecls super().__init__(description, StringType(), mandatory=False) def __get__(self, obj, owner): if obj is None: return self - if self.module is None: - self.module = obj.DISPATCHER.get_module(super().__get__(obj, owner)) - return self.module + if obj.attachedModules is None: + # return the name of the module (called from Server on startup) + return super().__get__(obj, owner) + # return the module (called after startup) + return obj.attachedModules[self.name] diff --git a/secop/server.py b/secop/server.py index d6253f8..4199061 100644 --- a/secop/server.py +++ b/secop/server.py @@ -30,10 +30,11 @@ import sys import traceback from collections import OrderedDict -from secop.errors import ConfigError +from secop.errors import ConfigError, SECoPError from secop.lib import formatException, get_class, generalConfig from secop.lib.multievent import MultiEvent from secop.params import PREDEFINED_ACCESSIBLES +from secop.modules import Attached try: from daemon import DaemonContext @@ -275,6 +276,23 @@ class Server: missing_super.add('%s was not called, probably missing super call' % modobj.earlyInit.__qualname__) + # handle attached modules + for modname, modobj in self.modules.items(): + attached_modules = {} + for propname, propobj in modobj.propertyDict.items(): + if isinstance(propobj, Attached): + try: + attname = getattr(modobj, propname) + attobj = self.dispatcher.get_module(attname) + if isinstance(attobj, propobj.basecls): + attached_modules[propname] = attobj + else: + errors.append('attached module %s=%r must inherit from %r' + % (propname, attname, propobj.basecls.__qualname__)) + except SECoPError as e: + errors.append('module %s, attached %s: %s' % (modname, propname, str(e))) + modobj.attachedModules = attached_modules + # call init on each module after registering all for modname, modobj in self.modules.items(): try: @@ -287,18 +305,17 @@ class Server: failure_traceback = traceback.format_exc() errors.append('error initializing %s: %r' % (modname, e)) - if self._testonly: - return - start_events = MultiEvent(default_timeout=30) - for modname, modobj in self.modules.items(): - # startModule must return either a timeout value or None (default 30 sec) - start_events.name = 'module %s' % modname - modobj.startModule(start_events) - if not modobj.startModuleDone: - missing_super.add('%s was not called, probably missing super call' - % modobj.startModule.__qualname__) + if not self._testonly: + start_events = MultiEvent(default_timeout=30) + for modname, modobj in self.modules.items(): + # startModule must return either a timeout value or None (default 30 sec) + start_events.name = 'module %s' % modname + modobj.startModule(start_events) + if not modobj.startModuleDone: + missing_super.add('%s was not called, probably missing super call' + % modobj.startModule.__qualname__) + errors.extend(missing_super) - errors.extend(missing_super) if errors: for errtxt in errors: for line in errtxt.split('\n'): @@ -310,6 +327,8 @@ class Server: sys.stderr.write(failure_traceback) sys.exit(1) + if self._testonly: + return self.log.info('waiting for modules being started') start_events.name = None if not start_events.wait(): diff --git a/test/test_attach.py b/test/test_attach.py index 9c6c69c..76aa4b8 100644 --- a/test/test_attach.py +++ b/test/test_attach.py @@ -75,4 +75,6 @@ def test_attach(): assert m.propertyValues['att'] == 'a' srv.dispatcher.register_module(a, 'a') srv.dispatcher.register_module(m, 'm') + assert m.att == 'a' + m.attachedModules = {'att': a} assert m.att == a