Example #1
0
 def stop(self):
     """This is used by service binding to stop"""
     try:
         if not self.running:
             raise AssertionError('not running')
         self._task.stop()
         #clear the event dictionary and delete events
         while self.events:
             name, appevent = self.events.popitem()
             if appevent.loop and appevent.loop.running:
                 appevent.loop.stop()
             ApplicationEvent.delete(appevent)
     except:
         self.debugReport()
     #remove this appmanager's actions
     AdminAction.delete(self.action)
Example #2
0
 def stop(self):
     """This is used by service binding to stop"""
     try:
         if not self.running:
             raise AssertionError('not running')
         self._task.stop()
         #clear the event dictionary and delete events
         while self.events:
             name, appevent = self.events.popitem()
             if appevent.loop and appevent.loop.running:
                 appevent.loop.stop()
             ApplicationEvent.delete(appevent)
     except:
         self.debugReport()
     #remove this appmanager's actions
     AdminAction.delete(self.action)
Example #3
0
    def setup_actions(self):
	self.action = AdminAction('systemstats')
	self.action.expose("stop_collect", self.stop_collect, (), "stops collecting metrics")
	self.action.expose("start_collect", self.start_collect, (), "starts collecting metrics")
	self.action.expose("stop_output", self.stop_output, (), "stops output of metrics")
	self.action.expose("start_output", self.start_output, (), "starts output of metrics")
	adoc = "sets log level of this service. valid values are info,error,debug [info default]"
	self.action.expose("set_log_level", self.set_log_level,("level",),adoc)
	self.action.buildDoc()
Example #4
0
    def __init__(self):
        if 'services' in sys.modules:
            e = "Instantiate ServiceManager before the services module!"
            raise AssertionError(e)
        self.SERVICE_STATE = {}
        self._parent = None
        drone.log('Loading Services')
        import services
        mask = ('loadAll', )  #mask as private
        #truely become service module
        for var, val in vars(services).items():
            if var.startswith('_'): continue
            if var in mask: continue
            setattr(self, var, val)  #bind the module globals to self
        services.loadAll()  #load all services before replacing module
        sys.modules['services'] = self  #replace the services module

        from droned.models.action import AdminAction
        #droneblaster action hooks
        self._action = AdminAction('service')
        self._action.expose('start', self._startService, ('name', ),
                            'starts the service')
        self._action.expose('stop', self._stopService, ('name', ),
                            'stops the service')
        self._action.expose('disable', self._disableService, ('name', ),
                            'prevent the service from starting')
        self._action.expose('enable', self._enableService, ('name', ),
                            'allow the service to start')
        self._action.expose('status', self._statusService, ('name', ),
                            'status of the service')
        self._action.expose('list', lambda: \
                self._action.resultContext('\n'.join([ i for i in \
                    self.EXPORTED_SERVICES.keys() ]), None),
            (), 'list all services'
        )
        self._action.buildDoc()  #finalize the admin action
Example #5
0
    def __init__(self):
        if 'services' in sys.modules:
            e = "Instantiate ServiceManager before the services module!"
            raise AssertionError(e)
        self.SERVICE_STATE = {}
        self._parent = None
        drone.log('Loading Services')
        import services
        mask = ('loadAll',) #mask as private
        #truely become service module
        for var, val in vars(services).items():
            if var.startswith('_'): continue
            if var in mask: continue
            setattr(self, var, val) #bind the module globals to self
        services.loadAll() #load all services before replacing module
        sys.modules['services'] = self #replace the services module

        from droned.models.action import AdminAction
        #droneblaster action hooks
        self._action = AdminAction('service')
        self._action.expose('start', self._startService, ('name',),
            'starts the service'
        )
        self._action.expose('stop', self._stopService, ('name',),
            'stops the service'
        )
        self._action.expose('disable', self._disableService, ('name',),
            'prevent the service from starting'
        )
        self._action.expose('enable', self._enableService, ('name',),
            'allow the service to start'
        )
        self._action.expose('status', self._statusService, ('name',),
            'status of the service'
        )
        self._action.expose('list', lambda: \
                self._action.resultContext('\n'.join([ i for i in \
                    self.EXPORTED_SERVICES.keys() ]), None),
            (), 'list all services'
        )
        self._action.buildDoc() #finalize the admin action
Example #6
0
class SystemStats(Service):
    writing = defer.succeed(None)
    
    def stop_collect(self,*args):
	log("disabling all metric collection")
	for h in self.handlers:
	    h[1].disable_collect()
	
    def start_collect(self,*args):
	log("enabling metic collection")
	for h in self.handlers:
	    h[1].enable_collect()
	
    def stop_output(self,*args):
	log("disabling all metric outputs")
	for h in self.handlers:
	    h[1].disable_output()
	
    def start_output(self,*args):
	log("enabling all metric outputs")
	for h in self.handlers:
	    h[1].enable_output()
    
    def set_log_level(self,level):
	log("adjusting to %s log level" % level)
	for h in self.handlers:
	    h[1].set_log_level(level)
    
    def setup_actions(self):
	self.action = AdminAction('systemstats')
	self.action.expose("stop_collect", self.stop_collect, (), "stops collecting metrics")
	self.action.expose("start_collect", self.start_collect, (), "starts collecting metrics")
	self.action.expose("stop_output", self.stop_output, (), "stops output of metrics")
	self.action.expose("start_output", self.start_output, (), "starts output of metrics")
	adoc = "sets log level of this service. valid values are info,error,debug [info default]"
	self.action.expose("set_log_level", self.set_log_level,("level",),adoc)
	self.action.buildDoc()
	    
    
    def startService(self):
	self.handlers = []
	stat_handlers = StatBlockLoader.load()
	for STAT in SERVICECONFIG.STATS:
            STAT_BLOCK = STAT['STAT']
            try:
                for sh in stat_handlers:
                    if sh.TYPE == STAT_BLOCK['TYPE']:
                        inst = sh(STAT_BLOCK)
                        self.handlers.append((STAT_BLOCK,inst))
            except:
                f = Failure()
                err("Error while initializing systemstats service.")
        self.setup_actions()
        Service.startService(self)
            
    def stopService(self):
        Service.stopService(self)
Example #7
0
class ServiceManager(Entity):
    """ServiceManager Provides an Interface to get to any
       methods a service may provide.
       
       After the ServiceManager has been instantiated you can
       access services from any python package in the DroneD
       framework simply by placing ```import services``` in
       your code.
    """
    parentService = property(lambda s: s._parent)
    serializable = False #would not be discovered in this file anyway
    def __init__(self):
        if 'services' in sys.modules:
            e = "Instantiate ServiceManager before the services module!"
            raise AssertionError(e)
        self.SERVICE_STATE = {}
        self._parent = None
        drone.log('Loading Services')
        import services
        mask = ('loadAll',) #mask as private
        #truely become service module
        for var, val in vars(services).items():
            if var.startswith('_'): continue
            if var in mask: continue
            setattr(self, var, val) #bind the module globals to self
        services.loadAll() #load all services before replacing module
        sys.modules['services'] = self #replace the services module

        from droned.models.action import AdminAction
        #droneblaster action hooks
        self._action = AdminAction('service')
        self._action.expose('start', self._startService, ('name',),
            'starts the service'
        )
        self._action.expose('stop', self._stopService, ('name',),
            'stops the service'
        )
        self._action.expose('disable', self._disableService, ('name',),
            'prevent the service from starting'
        )
        self._action.expose('enable', self._enableService, ('name',),
            'allow the service to start'
        )
        self._action.expose('status', self._statusService, ('name',),
            'status of the service'
        )
        self._action.expose('list', lambda: \
                self._action.resultContext('\n'.join([ i for i in \
                    self.EXPORTED_SERVICES.keys() ]), None),
            (), 'list all services'
        )
        self._action.buildDoc() #finalize the admin action

    def _installServices(self, parentService):
        """Install Services for DroneD to run

           @param parentService (instance service.Application)
           @return None
        """
        drone.log('Installing Services')
        self._parent = parentService
        dead = set() #track objects that blow up on setup
        for name,obj in self.EXPORTED_SERVICES.items():
            try:
                #decorate start and stop methods for eventing
                obj.start = self._startDecorator(obj.start, name)
                obj.stop = self._stopDecorator(obj.stop, name)
                obj.install(self.parentService) #set the twisted parent service
                obj.parentService = self.parentService #make sure it's set
            except:
                err(Failure(), 'Exception while installing %s' % (name,))
                dead.add(name)

        drone.log('Evaluating Services Startup')
        #start up services that should run after everything is setup
        for name,obj in self.EXPORTED_SERVICES.items():
            if name in dead: continue
            #make sure we have a notion of dis/enabled
            if name not in self.SERVICE_STATE:
                self.SERVICE_STATE[name] = name in config.AUTOSTART_SERVICES
            #service is not in autostart and is not marked to start
            if name not in config.AUTOSTART_SERVICES:
                if not self.SERVICE_STATE[name]:
                    continue
            #service is marked as down even though it is in AUTO_START
            elif not self.SERVICE_STATE[name]: continue
            try:
                self.SERVICE_STATE[name] = True #be safe
                self._startService(name)
            except: #logging is not setup yet use twisted's err facility
                err(Failure(), 'Exception while registering %s' % (name,))

    def _statusService(self, name):
        """used by the AdminAction handler"""
        status = self.getService(name).running() and 'running and' or \
                'stopped and'
        status += self.SERVICE_STATE.get(name, False) and ' enabled' or \
                ' disabled'
        return self._result(status, name)

    def _startService(self, name):
        """used by the AdminAction handler"""
        obj = self.getService(name)
        if not obj.running():
            result = obj.start()
            if isinstance(result, Failure): return result
        return self._result('running', name)

    def _stopService(self, name):
        """used by the AdminAction handler"""
        obj = self.getService(name)
        if obj.running():
            result = obj.stop()
            if isinstance(result, Failure): return result
        return self._result('stopped', name)

    def _enableService(self, name):
        """used by the AdminAction handler"""
        self.SERVICE_STATE[name] = True #mark service as runnable
        return self._result('enabled', name)

    def _disableService(self, name):
        """used by the AdminAction handler"""
        self.SERVICE_STATE[name] = False #mark service as unrunnable
        return self._result('disabled', name)

    def _result(self, description, name):
        template = '[%(application)s] %(description)s'
        context = {'application': name, 'description': description}
        return self._action.resultContext(template, None, **context)

    def _startDecorator(self, func, name):
        """decorate the service start method for eventing"""
        log = droned.logging.logWithContext(type=name)
        obj = self.getService(name)
        def newfunc():
            try:
                if not self.SERVICE_STATE[name]:
                    raise AssertionError('%s is disabled' % (name,))
                if not obj.running():
                    log('Starting Service')
                    func() #don't really care about the return
                    if not obj.running():
                        raise AssertionError("%s not running" % (name,))
                    Event('service-started').fire(service=obj)
                    log('Started Service')
            except: return Failure()
            return True
        return newfunc

    def _stopDecorator(self, func, name):
        """decorate the service stop method for eventing"""
        log = droned.logging.logWithContext(type=name)
        obj = self.getService(name)
        def newfunc():
            try:
                if obj.running():
                    log('Stopping Service')
                    func() #we don't really care about the return
                    if obj.running():
                        raise AssertionError("%s is still running" % (name,))
                    Event('service-stopped').fire(service=obj)
                    log('Stopped Service')
            except: return Failure()
            return True
        return newfunc

    def _stopAll(self):
        for name in self.EXPORTED_SERVICES.keys():
            self._stopService(name)

    def __getattr__(self, param): #compatibility hack
        try: return self.EXPORTED_SERVICES[param]
        except KeyError:
            return object.__getattr__(self, param)
Example #8
0
class AppManager(Entity):
    """This is a generic application container service.  It's sole
       purpose is to provide an abstraction to the application plugin.
       Think of this as an application service container.
    """
    implements(IDroneModelAppManager)
    serializable = True
    #global container lock
    globalLock = defer.DeferredLock()
    running = property(lambda s: hasattr(s, '_task') and s._task.running)
    model = property(lambda s: IDroneDApplication(s))  #late plugin lookup
    action = property(lambda s: AdminAction(s.name))
    invoke = property(lambda s: s.action.invoke)
    resultContext = property(lambda s: s.action.resultContext)
    exposedMethodInfo = property(lambda s: s.action.exposedMethodInfo)
    exposedMethods = property(lambda s: s.action.exposedMethods)
    instances = property(lambda s: App(s.name).localappinstances)
    labels = property(lambda s: (i.label for i in s.instances))
    #whether or not the application service should discover apps for us
    discover = property(lambda s: not all([i.running for i in s.instances]))

    def __init__(self, name):
        self.name = name
        #this is for user defined storage
        self.applicationContext = {}
        #allow the models to block methods from registering
        self.blockedMethods = set()
        #create a local lock
        self.busy = defer.DeferredLock()
        #track events
        self.events = {}

    def log(self, message, label=None):
        """route logging messages to the application log and allow for custom 
           labeling to be applied
           @param message: (string)
           @param label: (string) or (None)

           @return None
        """
        info = self.name
        if label: info += ',%(label)s' % locals()
        logWithContext(type=info, route='application')(message)

    def __getstate__(self):
        """used to serialize the application model"""
        return {
            'name': self.name,
            'applicationContext': self.applicationContext
        }

    @staticmethod
    def construct(state):
        """rebuild the model with context

           @param state: (dict)

           return AppManger(state['name'])
        """
        manager = AppManager(state['name'])
        manager.applicationContext = state['applicationContext']
        return manager

    def start(self):
        """This is used by service binding to start"""
        if self.running:
            raise AssertionError('already running')

        #not only is this a safety, but makes sure the model is bound
        #donot ever remove this, otherwise first run won't automatically
        #create appinstances or any other models.
        #should be self, but make sure we avoid a race
        if self.model.service != AppManager(self.name):
            raise InvalidPlugin('Plugin for %s is invalid' % (self.name, ))

        self.action.log = self.log  #override default logging
        #create default exposed methods, the model can override any of these
        self.expose('add',
                    self.addInstance, ('instance', ),
                    "Configure the specified instance",
                    BUSYLOCK=True)
        self.expose('remove',
                    self.removeInstance, ('instance', ),
                    "Unconfigure the specified instance",
                    BUSYLOCK=True)
        self.expose('start',
                    self.startInstance, ('instance', ),
                    "Start the instance",
                    BUSYLOCK=True,
                    INSTANCED=True)
        self.expose('stop',
                    self.stopInstance, ('instance', ),
                    "Stop the instance",
                    BUSYLOCK=True,
                    INSTANCED=True)
        self.expose('status',
                    self.statusInstance, ('instance', ),
                    "Status the instance",
                    INSTANCED=True)
        self.expose('enable',
                    self.enableInstance, ('instance', ),
                    "Enable the instance",
                    INSTANCED=True)
        self.expose('disable',
                    self.disableInstance, ('instance', ),
                    "Disable the instance",
                    INSTANCED=True)
        self.expose('debug', self.debug, ('bool', ),
                    "Turn application container debugging on or off")
        self.expose(
            'labels',
            lambda: self.resultContext('\n'.join(sorted(self.labels)), None, **
                                       {'labels': sorted(self.labels)}), (),
            "lists all application instance labels")

        #build our documentation
        self.rebuildHelpDoc()

        #check conditional events
        self._task = LoopingCall(self.conditionalEvents)
        self._task.start(1.0)

    def conditionalEvents(self):
        """check the status of conditional events"""
        if self.busy.locked:
            return  #skip conditional event processing while busy
        for appevent in self.events.values():
            if not appevent.condition: continue
            appevent.occurred()

    def registerEvent(self, name, callback, **kwargs):
        """Interface to Register Service Events"""
        #the self parameter will help ensure this event is unique to the service
        self.events[name] = ApplicationEvent(self.name, name, callback,
                                             **kwargs)

    def triggerEvent(self, name, data=None, delay=0.0):
        """Interface to trigger an out of band service event"""
        assert name in self.events, "No such event '%s'" % (name, )
        return self.events[name].trigger(data, delay)

    def disableEvent(self, name):
        """Interface to disable a previously registered service event"""
        assert name in self.events, "No such event '%s'" % (name, )
        self.events[name].event.disable()

    def enableEvent(self, name):
        """Interface to enable a previously disabled registered service event
        """
        assert name in self.events, "No such event '%s'" % (name, )
        self.events[name].event.enable()

    def stop(self):
        """This is used by service binding to stop"""
        try:
            if not self.running:
                raise AssertionError('not running')
            self._task.stop()
            #clear the event dictionary and delete events
            while self.events:
                name, appevent = self.events.popitem()
                if appevent.loop and appevent.loop.running:
                    appevent.loop.stop()
                ApplicationEvent.delete(appevent)
        except:
            self.debugReport()
        #remove this appmanager's actions
        AdminAction.delete(self.action)

    ###########################################################################
    # This part of the class exposes the Model API to outside world
    ###########################################################################

    @synchronizedDeferred(globalLock)
    def unexpose(self, name, blacklist=True):
        """Removes an exposed method, probably not a good idea to expose"""
        #add method to blocked list
        if blacklist:
            self.blockedMethods.add(name)
        if name in self.exposedMethods:
            del self.exposedMethods[name]
            info = None
            found = False
            for info in self.exposedMethodInfo:
                (n, a, d) = info
                if n == name:
                    found == True
                    break
            if info and found:
                self.exposedMethodInfo.remove(info)

    def rebuildHelpDoc(self):
        """rebuild exposed method documentation"""
        self.action.buildDoc()

    @synchronizedDeferred(globalLock)
    def expose(self, name, method, args, doc, **kwargs):
        """Wraps the models exposed methods for gremlin and make methods
           available via blaster protocol for action invocation.

           expose(self, name, method, methodSignature, description, **kwargs)

             name: (string)         - This is the action parameter to expose
             method: (callable)     - This is the function name to call
             args: (tuple)          - layout for parsing args
             description: (string)  - Help Documentation to expose

             kwargs:
                 INSTANCED: (bool)  - sets the instanceOperator decorator for
                                      administrator's ease of use.
                 BUSYLOCK: (bool)   - sets the synchronizedDeferred decorator
                                      for this AppManager.
                 GLOBALLOCK: (bool) - sets the synchronizedDeferred decorator
                                      for synchronizing all AppManagers.
        """
        if name in self.blockedMethods:
            return  #method was blocked by the model, probably
        #allow models to override the defaults and print a warning
        if name in self.exposedMethods:
            self.log('Warning method "%s" is already exposed' % (name, ))
            return
        #These decorators must be applied in a specific order of precedence
        requireInstance = kwargs.pop('INSTANCED', False)
        requireBusyLock = kwargs.pop('BUSYLOCK', False)
        requireGlobalLock = kwargs.pop('GLOBALLOCK', False)

        #applying decorators at runtime
        if requireBusyLock or requireGlobalLock or requireInstance:
            #ordering is critical
            if requireInstance:
                #this bizarre decorator is used b/c we need instance info.
                method = self.instanceOperation(method)
            if requireBusyLock:
                sync = synchronizedDeferred(self.busy)
                method = sync(method)
            if requireGlobalLock:
                sync = synchronizedDeferred(self.globalLock)
                method = sync(method)

        self.exposedMethodInfo.append((name, args, doc))
        self.exposedMethods[name] = method

    ###########################################################################
    # This part of the class is for Generic actions that all apps perform
    ###########################################################################
#FIXME is this really needed?

    def debug(self, var):
        """Enable or Disable application model debugging.  You should extend
           this if you know how to enable application debugging in your custom
           'application model'.

           returns deferred - already called
        """
        #assume blaster which is string based, sent the message
        var = str(var)  #for safety
        a = var.lower()
        context = {'code': 0}
        template = '[%(application)s] Debug '
        try:
            if a == 'true':
                self.model.debug = True
                defer.setDebugging(True)
                template += 'Enabled'
            elif a == 'false':
                self.model.debug = False
                defer.setDebugging(False)
                template += 'Disabled'
            else:
                raise TypeError('input must be a bool, True/False')
        except Exception, exc:
            template += str(exc)
            context['code'] = 1
        return defer.succeed(self.resultContext(template, None, **context))
Example #9
0
class ServiceManager(Entity):
    """ServiceManager Provides an Interface to get to any
       methods a service may provide.
       
       After the ServiceManager has been instantiated you can
       access services from any python package in the DroneD
       framework simply by placing ```import services``` in
       your code.
    """
    parentService = property(lambda s: s._parent)
    serializable = False  #would not be discovered in this file anyway

    def __init__(self):
        if 'services' in sys.modules:
            e = "Instantiate ServiceManager before the services module!"
            raise AssertionError(e)
        self.SERVICE_STATE = {}
        self._parent = None
        drone.log('Loading Services')
        import services
        mask = ('loadAll', )  #mask as private
        #truely become service module
        for var, val in vars(services).items():
            if var.startswith('_'): continue
            if var in mask: continue
            setattr(self, var, val)  #bind the module globals to self
        services.loadAll()  #load all services before replacing module
        sys.modules['services'] = self  #replace the services module

        from droned.models.action import AdminAction
        #droneblaster action hooks
        self._action = AdminAction('service')
        self._action.expose('start', self._startService, ('name', ),
                            'starts the service')
        self._action.expose('stop', self._stopService, ('name', ),
                            'stops the service')
        self._action.expose('disable', self._disableService, ('name', ),
                            'prevent the service from starting')
        self._action.expose('enable', self._enableService, ('name', ),
                            'allow the service to start')
        self._action.expose('status', self._statusService, ('name', ),
                            'status of the service')
        self._action.expose('list', lambda: \
                self._action.resultContext('\n'.join([ i for i in \
                    self.EXPORTED_SERVICES.keys() ]), None),
            (), 'list all services'
        )
        self._action.buildDoc()  #finalize the admin action

    def _installServices(self, parentService):
        """Install Services for DroneD to run

           @param parentService (instance service.Application)
           @return None
        """
        drone.log('Installing Services')
        self._parent = parentService
        dead = set()  #track objects that blow up on setup
        for name, obj in self.EXPORTED_SERVICES.items():
            try:
                #decorate start and stop methods for eventing
                obj.start = self._startDecorator(obj.start, name)
                obj.stop = self._stopDecorator(obj.stop, name)
                obj.install(
                    self.parentService)  #set the twisted parent service
                obj.parentService = self.parentService  #make sure it's set
            except:
                err(Failure(), 'Exception while installing %s' % (name, ))
                dead.add(name)

        drone.log('Evaluating Services Startup')
        #start up services that should run after everything is setup
        for name, obj in self.EXPORTED_SERVICES.items():
            if name in dead: continue
            #make sure we have a notion of dis/enabled
            if name not in self.SERVICE_STATE:
                self.SERVICE_STATE[name] = name in config.AUTOSTART_SERVICES
            #service is not in autostart and is not marked to start
            if name not in config.AUTOSTART_SERVICES:
                if not self.SERVICE_STATE[name]:
                    continue
            #service is marked as down even though it is in AUTO_START
            elif not self.SERVICE_STATE[name]:
                continue
            try:
                self.SERVICE_STATE[name] = True  #be safe
                self._startService(name)
            except:  #logging is not setup yet use twisted's err facility
                err(Failure(), 'Exception while registering %s' % (name, ))

    def _statusService(self, name):
        """used by the AdminAction handler"""
        status = self.getService(name).running() and 'running and' or \
                'stopped and'
        status += self.SERVICE_STATE.get(name, False) and ' enabled' or \
                ' disabled'
        return self._result(status, name)

    def _startService(self, name):
        """used by the AdminAction handler"""
        obj = self.getService(name)
        if not obj.running():
            result = obj.start()
            if isinstance(result, Failure): return result
        return self._result('running', name)

    def _stopService(self, name):
        """used by the AdminAction handler"""
        obj = self.getService(name)
        if obj.running():
            result = obj.stop()
            if isinstance(result, Failure): return result
        return self._result('stopped', name)

    def _enableService(self, name):
        """used by the AdminAction handler"""
        self.SERVICE_STATE[name] = True  #mark service as runnable
        return self._result('enabled', name)

    def _disableService(self, name):
        """used by the AdminAction handler"""
        self.SERVICE_STATE[name] = False  #mark service as unrunnable
        return self._result('disabled', name)

    def _result(self, description, name):
        template = '[%(application)s] %(description)s'
        context = {'application': name, 'description': description}
        return self._action.resultContext(template, None, **context)

    def _startDecorator(self, func, name):
        """decorate the service start method for eventing"""
        log = droned.logging.logWithContext(type=name)
        obj = self.getService(name)

        def newfunc():
            try:
                if not self.SERVICE_STATE[name]:
                    raise AssertionError('%s is disabled' % (name, ))
                if not obj.running():
                    log('Starting Service')
                    func()  #don't really care about the return
                    if not obj.running():
                        raise AssertionError("%s not running" % (name, ))
                    Event('service-started').fire(service=obj)
                    log('Started Service')
            except:
                return Failure()
            return True

        return newfunc

    def _stopDecorator(self, func, name):
        """decorate the service stop method for eventing"""
        log = droned.logging.logWithContext(type=name)
        obj = self.getService(name)

        def newfunc():
            try:
                if obj.running():
                    log('Stopping Service')
                    func()  #we don't really care about the return
                    if obj.running():
                        raise AssertionError("%s is still running" % (name, ))
                    Event('service-stopped').fire(service=obj)
                    log('Stopped Service')
            except:
                return Failure()
            return True

        return newfunc

    def _stopAll(self):
        for name in self.EXPORTED_SERVICES.keys():
            self._stopService(name)

    def __getattr__(self, param):  #compatibility hack
        try:
            return self.EXPORTED_SERVICES[param]
        except KeyError:
            return object.__getattr__(self, param)