Example #1
0
    def resultContext(self, template, instance=None, **context):
        """Creates a dict containg relevant contextual information about a 
           result.  You can override this method and tailor it to your liking.
           We typically use this to pass verbose structured data to a master
           DroneD controller (not provided with DroneD core) so that it may
           quickly make decisions based on the result of it's previous command
           and control activities.

           IF you set 'error' in the **context this will raise a server error
           at the remote end. This can be good or bad depending on your outlook
           on exceptions.  Consider this your only warning.

           return dict
        """
        if 'application' not in context:
            context['application'] = self.action
        failure = context.pop('error', False)
        if isinstance(failure, Failure):
            if 'description' not in context:
                context['description'] = '[%s] %s: %s' % \
                        (self.action, getException(failure), failure.getErrorMessage())
            if 'code' not in context:
                context['code'] = -2
            context['error'] = True
            context['stacktrace'] = failure.getTraceback()
            self.log('Result context during exception\n%(stacktrace)s' %
                     context)
            return context  #failed so bad we need to shortcut out
        else:
            context['error'] = bool(failure)
        if instance:  #this was made for AppManager's
            if hasattr(instance, 'version'):
                context['version'] = instance.version
            if hasattr(instance, 'label'):
                context['label'] = instance.label
            if hasattr(instance, 'running'):
                context['running'] = instance.running
        try:  #fail-safe in case someone is a bonehead
            context['description'] = template % context
        except:
            failure = Failure()
            context['description'] = '[%s] %s: %s' % \
                    (self.action, getException(failure), failure.getErrorMessage())
            context['stacktrace'] = failure.getTraceback()
            if 'code' not in context:
                context['code'] = -2
        #be nice to blaster api and the remote client
        context.update({'code': context.get('code', 0)})
        return context
Example #2
0
    def resultContext(self, template, instance=None, **context):
        """Creates a dict containg relevant contextual information about a 
           result.  You can override this method and tailor it to your liking.
           We typically use this to pass verbose structured data to a master
           DroneD controller (not provided with DroneD core) so that it may
           quickly make decisions based on the result of it's previous command
           and control activities.

           IF you set 'error' in the **context this will raise a server error
           at the remote end. This can be good or bad depending on your outlook
           on exceptions.  Consider this your only warning.

           return dict
        """
        if 'application' not in context:
            context['application'] = self.action
        failure = context.pop('error', False)
        if isinstance(failure, Failure):
            if 'description' not in context:
                context['description'] = '[%s] %s: %s' % \
                        (self.action, getException(failure), failure.getErrorMessage())
            if 'code' not in context:
                context['code'] = -2
            context['error'] = True
            context['stacktrace'] = failure.getTraceback()
            self.log('Result context during exception\n%(stacktrace)s' % context)
            return context #failed so bad we need to shortcut out
        else:
            context['error'] = bool(failure)
        if instance: #this was made for AppManager's
            if hasattr(instance, 'version'):
                context['version'] = instance.version
            if hasattr(instance, 'label'):
                context['label'] = instance.label
            if hasattr(instance, 'running'):
                context['running'] = instance.running
        try: #fail-safe in case someone is a bonehead
            context['description'] = template % context
        except:
            failure = Failure()
            context['description'] = '[%s] %s: %s' % \
                    (self.action, getException(failure), failure.getErrorMessage())
            context['stacktrace'] = failure.getTraceback()
            if 'code' not in context:
                context['code'] = -2
        #be nice to blaster api and the remote client
        context.update({'code' : context.get('code',0) })
        return context
Example #3
0
 def _start_stop_common(self, label, action):
     result = {}
     try:
         function = getattr(self.model, action)
         d = defer.maybeDeferred(function, label)
         wfd = defer.waitForDeferred(d)
         yield wfd
         result = wfd.getResult()
         #take this time to update the instance
         if isinstance(result, dict):
             thisInst = self.model.getInstance(label)
             thisInst.updateInfo(result)
     except:
         failure = Failure()
         if failure.check(DroneCommandFailed):
             result = failure.value.resultContext
         else:
             #log the error, allowing for debugging
             self.debugReport()
             #be nice and return something to the end user
             template = "%s: %s" % (getException(failure),
                                    failure.getErrorMessage())
             context = {'error': failure, 'code': -2}
             result = self.resultContext(template, None, **context)
         #finally wrap the failure into a known type
         result = Failure(DroneCommandFailed(result))
     #AppInstances need a moment to be updated
     d = defer.Deferred()
     config.reactor.callLater(1.0, d.callback, None)
     wfd = defer.waitForDeferred(d)
     yield wfd
     wfd.getResult()
     yield result
Example #4
0
    def __call__(self, argstr):
        args = argstr.split()
        resultContext = None
        if not args:  #return command usage
            methods = {}
            for name, args, doc in self.exposedMethodInfo:
                methods[name] = {'args': args, 'doc': doc}
            resultContext = dict(description=self.__doc__, methods=methods)
            yield resultContext
        else:
            method = args.pop(0)
            try:
                wfd = defer.waitForDeferred(self.invoke(method, args))
                yield wfd
                resultContext = wfd.getResult()
            except:
                failure = Failure()
                if failure.check(DroneCommandFailed):
                    resultContext = failure.value.resultContext
                else:
                    #be nice and return something to the end user
                    template = "[%(application)s] "
                    template += "%s: %s" % (getException(failure),
                                            failure.getErrorMessage())
                    context = {
                        'error': True,
                        'code': -2,
                        'stacktrace': failure.getTraceback()
                    }
                    resultContext = self.resultContext(template, None,
                                                       **context)

            yield resultContext
Example #5
0
 def __call__(self, argstr):
     args = argstr.split()
     resultContext = None
     if not args: #return command usage
         methods = {}
         for name,args,doc in self.exposedMethodInfo:
             methods[name] = {'args' : args, 'doc' : doc}
         resultContext = dict(description=self.__doc__, methods=methods)
         yield resultContext
     else:
         method = args.pop(0)
         try:
             wfd = defer.waitForDeferred(
                     self.invoke(method,args)
             )
             yield wfd
             resultContext = wfd.getResult()
         except:
             failure = Failure()
             if failure.check(DroneCommandFailed):
                 resultContext = failure.value.resultContext
             else:
                 #be nice and return something to the end user
                 template = "[%(application)s] "
                 template += "%s: %s" % (getException(failure), failure.getErrorMessage())
                 context = {'error': True, 'code': -2, 'stacktrace': failure.getTraceback()}
                 resultContext = self.resultContext(template, None, 
                     **context
                 )
                 
         yield resultContext
Example #6
0
 def decorator(*args, **kwargs):
     try: return func(*args, **kwargs)
     except:
         failure = Failure()
         msg = getException(failure)
         msg += ': ' + failure.getErrorMessage()
         return NoResource(msg)
Example #7
0
 def _start_stop_common(self, label, action):
     result = {}
     try:
         function = getattr(self.model, action)
         d = defer.maybeDeferred(function, label)
         wfd = defer.waitForDeferred(d)
         yield wfd
         result = wfd.getResult()
         #take this time to update the instance
         if isinstance(result, dict):
             thisInst = self.model.getInstance(label)
             thisInst.updateInfo(result) 
     except:
         failure = Failure()
         if failure.check(DroneCommandFailed):
             result = failure.value.resultContext
         else:
             #log the error, allowing for debugging
             self.debugReport()
             #be nice and return something to the end user
             template = "%s: %s" % (getException(failure), failure.getErrorMessage())
             context = {'error':failure,'code':-2}
             result = self.resultContext(template, None, **context)
         #finally wrap the failure into a known type
         result = Failure(DroneCommandFailed(result))
     #AppInstances need a moment to be updated
     d = defer.Deferred()
     reactor.callLater(1.0, d.callback, None)
     wfd = defer.waitForDeferred(d)
     yield wfd
     wfd.getResult()
     yield result
Example #8
0
    def invoke(self, name, args):
        """Invoke Exposed Methods
           @param name (str) - name of method to invoke
           @param args (tuple) - arguments to pass to invoked method

           @return (defer.Deferred)
        """
        if name not in self.exposedMethods:
            return defer.fail(
                DroneCommandFailed(
                    self.resultContext(
                        "[%(application)s] Unknown method '%(method)s'",
                        method=name,
                        error='unknown method')))
        try:
            #our own form of maybeDeferred
            d = self.exposedMethods[name](*args)
            if isinstance(d, defer.Deferred):
                action = Action(' '.join([str(i) for i in \
                        (self.action, name) + tuple(args)]), d)
                return action.deferred
            elif isinstance(d, DroneCommandFailed):
                return defer.fail(d)
            elif isinstance(d, dict):
                return defer.succeed(d)
            elif isinstance(d, type(None)):
                #this just feels dirty
                return defer.succeed(d)
            elif isinstance(d, Failure):
                d.raiseException()  #sigh
            #probably from a triggerred Event callback
            elif type(d) == types.InstanceType:
                return defer.succeed(None)
            return defer.fail(FormatError("Result is not formatted correctly you " + \
                 "must return self.resultContext or DroneCommandFailed." + \
                 "\nResult: <%s>" % (str(d),)))
        except:
            failure = Failure()
            if failure.check(DroneCommandFailed):
                template = "[%(application)s] %(description)s"
                context = failure.value.resultContext
                if not 'description' in context:
                    context['description'] = failure.getErrorMessage()
            else:
                template = "[%(application)s] " + "%s: %s" % (
                    getException(failure), failure.getErrorMessage())
                context = {
                    'error': True,
                    'code': -2,
                    'stacktrace': failure.getTraceback()
                }
            return defer.fail(
                DroneCommandFailed(
                    self.resultContext(template, None, **context)))
Example #9
0
 def handleDeferreds(labels):
     """Remember last yield is the return value, don't use return"""
     results = {}
     descriptions = []
     ret = {}
     code = 0
     for l in labels:
         try:
             d = defer.maybeDeferred(func, l, *args[1:], **kwargs)
             wfd = defer.waitForDeferred(d)
             yield wfd
             ret = wfd.getResult()
         except:
             failure = Failure()
             des = "%s: %s" % \
                     (getException(failure),failure.getErrorMessage())
             if failure.check(DroneCommandFailed):
                 result[l] = failure.value.resultContext
                 if 'description' not in result[l]:
                     result[l]['description'] = des
                 result[l]['stacktrace'] = failure.getTraceback()
                 result[l]['error'] = True
                 if 'code' not in result[l]:
                     result[l]['code'] = 1
             else:
                 ret = {
                     'description': des,
                     'code': 1,
                     'error': True,
                     'stacktrace': failure.getTraceback()
                 }
         if not ret:  #NoneType detection
             ret = {'description': str(ret), 'code': 0}
         if 'code' in ret:
             code += abs(ret['code'])
         results[l] = ret
         try:
             descriptions.append(results[l]['description'])
         except:
             self.debugReport()
     results['code'] = code
     try:
         results['description'] = '\n'.join(descriptions)
     except:
         results['description'] = None
     if len(labels) == 0:
         Label = labels[0]
     else:
         Label = None
     ret = self.resultContext('%(description)s',
                              label=Label,
                              **results)
     yield ret
Example #10
0
 def handleDeferreds(labels):
     """Remember last yield is the return value, don't use return"""
     results = {}
     descriptions = []
     ret = {}
     code = 0
     for l in labels:
         try:
             d = defer.maybeDeferred(func, l, *args[1:], **kwargs)
             wfd = defer.waitForDeferred(d)
             yield wfd
             ret = wfd.getResult()
         except:
             failure = Failure()
             des = "%s: %s" % \
                     (getException(failure),failure.getErrorMessage())
             if failure.check(DroneCommandFailed):
                 result[l] = failure.value.resultContext
                 if 'description' not in result[l]:
                     result[l]['description'] = des
                 result[l]['stacktrace'] = failure.getTraceback()
                 result[l]['error'] = True
                 if 'code' not in result[l]:
                     result[l]['code'] = 1
             else:
                 ret = {
                     'description': des,
                     'code': 1,
                     'error': True,
                     'stacktrace': failure.getTraceback()
                 }
         if not ret: #NoneType detection
             ret = {'description' : str(ret), 'code' : 0}
         if 'code' in ret:
             code += abs(ret['code'])
         results[l] = ret
         try:
             descriptions.append(results[l]['description'])
         except:
            self.debugReport()
     results['code'] = code
     try:
         results['description'] = '\n'.join(descriptions)
     except:
         results['description'] = None
     if len(labels) == 0:
         Label = labels[0]
     else:
         Label = None
     ret = self.resultContext('%(description)s',label=Label,**results) 
     yield ret
Example #11
0
    def invoke(self, name, args):
        """Invoke Exposed Methods
           @param name (str) - name of method to invoke
           @param args (tuple) - arguments to pass to invoked method

           @return (defer.Deferred)
        """
        if name not in self.exposedMethods:
            return defer.fail(DroneCommandFailed(self.resultContext(
                "[%(application)s] Unknown method '%(method)s'", method=name, 
                error='unknown method'))
            )
        try:
            #our own form of maybeDeferred
            d = self.exposedMethods[name](*args)
            if isinstance(d, defer.Deferred):
                action = Action(' '.join([str(i) for i in \
                        (self.action, name) + tuple(args)]), d)
                return action.deferred
            elif isinstance(d, DroneCommandFailed):
                return defer.fail(d)
            elif isinstance(d, dict):
                return defer.succeed(d)
            elif isinstance(d, type(None)):
                #this just feels dirty
                return defer.succeed(d)
            elif isinstance(d, Failure):
                d.raiseException() #sigh
            #probably from a triggerred Event callback
            elif type(d) == types.InstanceType:
                return defer.succeed(None)
            return defer.fail(FormatError("Result is not formatted correctly you " + \
                 "must return self.resultContext or DroneCommandFailed." + \
                 "\nResult: <%s>" % (str(d),)))
        except:
            failure = Failure()
            if failure.check(DroneCommandFailed):
                template = "[%(application)s] %(description)s"
                context = failure.value.resultContext
                if not 'description' in context:
                    context['description'] = failure.getErrorMessage()
            else:
                template = "[%(application)s] " + "%s: %s" % (getException(failure),
                        failure.getErrorMessage())
                context = {'error': True, 'code':-2, 'stacktrace': failure.getTraceback()}
            return defer.fail(DroneCommandFailed(self.resultContext(template, 
                None, **context))
            )
Example #12
0
    def _killInstance(self, result, instanceRef):
        """Last resort to stop your process"""
        bagOfTricks = [
            (lambda: os.kill(instanceRef.process.pid, signal.SIGTERM),
             'forcefully'),
            (lambda: os.kill(instanceRef.process.pid, signal.SIGKILL),
             'viciously'),
        ]
        #trap the failure and set a default message
        if isinstance(result, Failure):
            result.trap(Exception)
            result = 'Not Running'

        #give the protocol handler and OS a moment to do their thing
        d = defer.Deferred()
        config.reactor.callLater(0.2, d.callback, None)
        wfd = defer.waitForDeferred(d)
        yield wfd
        wfd.getResult()

        if instanceRef.running:
            pid = instanceRef.process.pid
            #ninja's need tricks too
            for kung, fu in bagOfTricks:
                d = defer.Deferred()
                try:
                    self.log("Trying to shutdown %d %s" % (pid, fu))
                    kung()
                    x = defer.Deferred()
                    #wait for the OS to reap the PID
                    config.reactor.callLater(5.0, x.callback, None)
                    wfd = defer.waitForDeferred(x)
                    yield wfd
                    wfd.getResult()
                    #check for the pid
                    if instanceRef.running:
                        self.log("Failed to shutdown process %s" % (fu, ))
                    else:
                        result = "process %d %s shutdown" % (pid, fu)
                except Exception, exc:
                    self.log("%s while trying to %s shutdown process %d: %s" % \
                          (getException(), fu, pid, exc))

                if not instanceRef.running: break
                config.reactor.callLater(10, d.callback, None)
                wfd = defer.waitForDeferred(d)
                yield wfd
                wfd.getResult()
Example #13
0
    def _killInstance(self, result, instanceRef):
        """Last resort to stop your process"""
        bagOfTricks = [
            (lambda: os.kill(instanceRef.process.pid, signal.SIGTERM),'forcefully'),
            (lambda: os.kill(instanceRef.process.pid, signal.SIGKILL),'viciously'),
        ]
        #trap the failure and set a default message
        if isinstance(result, Failure):
            result.trap(Exception)
            result = 'Not Running'

        #give the protocol handler and OS a moment to do their thing
        d = defer.Deferred()
        reactor.callLater(0.2, d.callback, None)
        wfd = defer.waitForDeferred(d)
        yield wfd
        wfd.getResult()
                
        if instanceRef.running:
            pid = instanceRef.process.pid
            #ninja's need tricks too
            for kung, fu in bagOfTricks:
                d = defer.Deferred()
                try:
                    self.log("Trying to shutdown %d %s" % (pid,fu))
                    kung()
                    x = defer.Deferred()
                    #wait for the OS to reap the PID
                    reactor.callLater(5.0, x.callback, None)
                    wfd = defer.waitForDeferred(x)
                    yield wfd
                    wfd.getResult()
                    #check for the pid
                    if instanceRef.running:
                        self.log("Failed to shutdown process %s" % (fu,))
                    else:
                        result = "process %d %s shutdown" % (pid, fu)
                except Exception, exc:
                    self.log("%s while trying to %s shutdown process %d: %s" % \
                          (getException(), fu, pid, exc))

                if not instanceRef.running: break
                reactor.callLater(10, d.callback, None)
                wfd = defer.waitForDeferred(d)
                yield wfd
                wfd.getResult() 
Example #14
0
    def startInstance(self, label):
        """Starts an application instance by label

           @param label: (string)

           @fires Event('instance-started')

           return defer.Deferred()
        """
        template = '[%(application)s,%(label)s] %(description)s'
        context = {'description': 'Failed to Start', 'code': 254}
        result = {}
        thisInst = None
        try:
            if self.model.getInstance(label).running:
                context.update(self.model.statusInstance(label))
                raise DroneCommandFailed(context)

            d = self._start_stop_common(label, 'startInstance')
            wfd = defer.waitForDeferred(d)
            yield wfd
            result = wfd.getResult()

            d = self.statusInstance(label)
            wfd = defer.waitForDeferred(d)
            yield wfd
            result.update(wfd.getResult())
            #refresh the instance as it can change
            thisInst = self.model.getInstance(label)
            if isinstance(result, dict):
                context.update(result)
            elif isinstance(result, DroneCommandFailed):
                context.update(result.resultContext)
            if thisInst.running:
                Event('instance-started').fire(instance=thisInst)
                context['code'] = 0
                raise AssertionError('ignore')
            raise DroneCommandFailed(context)
        except AssertionError:
            #update the instance model
            wfd = defer.waitForDeferred(self.statusInstance(label))
            yield wfd
            result = wfd.getResult()
        except:
            thisInst = self.model.getInstance(label)
            failure = Failure()
            if failure.check(DroneCommandFailed):
                template = '%(description)s'
                context = failure.value.resultContext
            else:
                #log the error, allowing for debugging
                self.debugReport()
                #be nice and return something to the end user
                temp = "%s: %s" % (getException(failure),
                                   failure.getErrorMessage())
                context = {'error': failure, 'code': 253, 'description': temp}
            result = self.resultContext(template, thisInst, **context)
        try:
            thisInst = self.model.getInstance(label)
            thisInst.shouldBeRunning = True
        except:
            pass
        yield result
Example #15
0
    def stopInstance(self, label):
        """Stops an application instance by label

           @param label: (string)

           @fires Event('instance-stopped')

           return defer.Deferred()
        """
        result = {}
        template = '[%(application)s,%(label)s] %(description)s'
        context = {'code': 254}
        thisInst = None
        try:
            thisInst = self.model.getInstance(label)
            thisInst.shouldBeRunning = False
            if not thisInst.running:
                context.update(self.model.statusInstance(label))
                raise DroneCommandFailed(context)
            pid = thisInst.process.pid 
            self.log("Trying to shutdown %d gracefully" % (pid,))

            def failed(result):
                """attempting to be consistant"""
                self.log("Failed to shutdown process gracefully")
                return result

            def success(result):
                """attempting to be consistant"""
                self.log("process %d gracefully shutdown" % (pid,))
                return result

            d = self._start_stop_common(label, 'stopInstance')
            d.addCallback(success)
            d.addErrback(failed)
            d.addErrback(self._killInstance, thisInst)
            wfd = defer.waitForDeferred(d)
            yield wfd
            #refresh the instance as it can change
            thisInst = self.model.getInstance(label)
            result = wfd.getResult()
            if isinstance(result, dict):
                context.update(result)
            elif isinstance(result, DroneCommandFailed):
                context.update(result.resultContext)
            if not thisInst.running:
                context['code'] = 0
                Event('instance-stopped').fire(instance=thisInst)
                raise AssertionError('ignore me')
            raise DroneCommandFailed(context)
        except AssertionError:
            #update the instance model
            wfd = defer.waitForDeferred(self.statusInstance(label))
            yield wfd
            result = wfd.getResult()
            result['code'] = context['code']
        except:
            failure = Failure()
            if failure.check(DroneCommandFailed):
                context = failure.value.resultContext
                template = '%(description)s'
            else:
                temp = "%s: %s" % (getException(failure), failure.getErrorMessage())
                context = {'error': failure, 'code': 253, 'description': temp}
            result = self.resultContext(template, thisInst, **context)
        try:
            thisInst = self.model.getInstance(label)
            thisInst.shouldBeRunning = False
        except: pass
        yield result
Example #16
0
    def startInstance(self, label):
        """Starts an application instance by label

           @param label: (string)

           @fires Event('instance-started')

           return defer.Deferred()
        """
        template = '[%(application)s,%(label)s] %(description)s'
        context = {
            'description': 'Failed to Start',
            'code': 254
        }
        result = {}
        thisInst = None
        try:
            if self.model.getInstance(label).running:
                context.update(self.model.statusInstance(label))
                raise DroneCommandFailed(context)

            d = self._start_stop_common(label, 'startInstance')
            wfd = defer.waitForDeferred(d)
            yield wfd
            result = wfd.getResult()

            d = self.statusInstance(label)
            wfd = defer.waitForDeferred(d)
            yield wfd
            result.update(wfd.getResult())
            #refresh the instance as it can change
            thisInst = self.model.getInstance(label)
            if isinstance(result, dict):
                context.update(result)
            elif isinstance(result, DroneCommandFailed):
                context.update(result.resultContext)
            if thisInst.running:
                Event('instance-started').fire(instance=thisInst)
                context['code'] = 0
                raise AssertionError('ignore')
            raise DroneCommandFailed(context)
        except AssertionError:
            #update the instance model
            wfd = defer.waitForDeferred(self.statusInstance(label))
            yield wfd
            result = wfd.getResult()
        except:
            thisInst = self.model.getInstance(label)
            failure = Failure()
            if failure.check(DroneCommandFailed):
                template = '%(description)s'
                context = failure.value.resultContext
            else:
                #log the error, allowing for debugging
                self.debugReport()
                #be nice and return something to the end user
                temp = "%s: %s" % (getException(failure), failure.getErrorMessage())
                context = {'error': failure, 'code': 253, 'description': temp}
            result = self.resultContext(template, thisInst, **context)
        try:
            thisInst = self.model.getInstance(label)
            thisInst.shouldBeRunning = True
        except: pass
        yield result
Example #17
0
    def stopInstance(self, label):
        """Stops an application instance by label

           @param label: (string)

           @fires Event('instance-stopped')

           return defer.Deferred()
        """
        result = {}
        template = '[%(application)s,%(label)s] %(description)s'
        context = {'code': 254}
        thisInst = None
        try:
            thisInst = self.model.getInstance(label)
            thisInst.shouldBeRunning = False
            if not thisInst.running:
                context.update(self.model.statusInstance(label))
                raise DroneCommandFailed(context)
            pid = thisInst.process.pid
            self.log("Trying to shutdown %d gracefully" % (pid, ))

            def failed(result):
                """attempting to be consistant"""
                self.log("Failed to shutdown process gracefully")
                return result

            def success(result):
                """attempting to be consistant"""
                self.log("process %d gracefully shutdown" % (pid, ))
                return result

            d = self._start_stop_common(label, 'stopInstance')
            d.addCallback(success)
            d.addErrback(failed)
            d.addErrback(self._killInstance, thisInst)
            wfd = defer.waitForDeferred(d)
            yield wfd
            #refresh the instance as it can change
            thisInst = self.model.getInstance(label)
            result = wfd.getResult()
            if isinstance(result, dict):
                context.update(result)
            elif isinstance(result, DroneCommandFailed):
                context.update(result.resultContext)
            if not thisInst.running:
                context['code'] = 0
                Event('instance-stopped').fire(instance=thisInst)
                raise AssertionError('ignore me')
            raise DroneCommandFailed(context)
        except AssertionError:
            #update the instance model
            wfd = defer.waitForDeferred(self.statusInstance(label))
            yield wfd
            result = wfd.getResult()
            result['code'] = context['code']
        except:
            failure = Failure()
            if failure.check(DroneCommandFailed):
                context = failure.value.resultContext
                template = '%(description)s'
            else:
                temp = "%s: %s" % (getException(failure),
                                   failure.getErrorMessage())
                context = {'error': failure, 'code': 253, 'description': temp}
            result = self.resultContext(template, thisInst, **context)
        try:
            thisInst = self.model.getInstance(label)
            thisInst.shouldBeRunning = False
        except:
            pass
        yield result