Ejemplo n.º 1
0
class SMAgentXMPP(Client):
    def __init__(self, config):
        """
        XMPP agent class.
        """
        log.info("Starting Agent...")
        
        log.info("Loading Commands...")
        self.command_runner = CommandRunner(config['Plugins'])

        log.info("Setting up Certificate")
        self.verify = ECVerify()

        log.info("Setting up Memory checker")
        self.running_commands = 0
        self.memory_checker = LoopingCall(self._check_memory, self.running_commands)
        self.memory_checker.start(_CHECK_RAM_INTERVAL)

        log.debug("Loading XMPP...")
        Client.__init__(
            self,
            config['XMPP'],
            [('/iq', self.__onIq), ],
            resource='ecm_agent-%d' % AGENT_VERSION_PROTOCOL)
            
    def __onIq(self, msg):
        """
        A new IQ message has been received and we should process it.
        """
        log.debug('__onIq')
        mem_clean('__onIq [start]')
        self.running_commands += 1

        log.debug("q Message received: \n%s" % msg.toXml())
        log.debug("Message type: %s" % msg['type'])

        if msg['type'] == 'set':
            message = IqMessage(msg)

            if hasattr(message, 'command') and hasattr(message, 'from_'):
                log.debug('online contacts: %s' % self._online_contacts)

                if message.from_ not in self._online_contacts:
                    log.warn('IQ sender not in roster (%s), dropping message' % message.from_)
                else:
                    self._processCommand(message)
            else:
                log.warn('Unknown ecm_message received: Full XML:\n%s' % (msg.toXml()))
                
            del message
            
        else:
            log.warn('Unknown IQ type received: Full XML:\n%s' % (msg.toXml()))

        del msg
        mem_clean('__onIq [end]')

    def _processCommand(self, message):
        if not self.verify.signature(message):
            result = (_E_UNVERIFIED_COMMAND, '', 'Bad signature', 0)
            self._onCallFinished(result, message)
            return

        flush_callback = self._flush
        message.command_name = message.command.replace('.', '_')

        mem_clean('run_command [start]')
        d = self.command_runner.run_command(message, flush_callback)
        
        # Clean message
        message.command_args = {}

        if d:
            d.addCallbacks(self._onCallFinished, self._onCallFailed,
                           callbackKeywords={'message': message},
                           errbackKeywords={'message': message},
            )
            del message
            mem_clean('run_command [end]')
            return d

        else:
            log.info("Command Ignored: Unknown command: %s" % message.command)
            result = (_E_RUNNING_COMMAND, '', "Unknown command: %s" % message.command, 0)
            self._onCallFinished(result, message)

        del message
        mem_clean('run_command [end]')
        return
        
    def _onCallFinished(self, result, message):
        mem_clean('agent._onCallFinished')
        log.debug('Call Finished')
        self._send(result, message)
        self.running_commands -= 1

    def _onCallFailed(self, failure, *argv, **kwargs):
        log.error("onCallFailed")
        log.debug(failure)
        if 'message' in kwargs:
            message = kwargs['message']
            result = (2, '', failure, 0)
            self._onCallFinished(result, message)

    def _flush(self, result, message):
        log.debug('Flush Message')
        self._send(result, message)

    def _send(self, result, message):
        log.debug('Send Response')
        mem_clean('agent._send')
        message.toResult(*result)

        del result
        mem_clean('agent._send')
        self.send(message.toEtree())

    def _check_memory(self, running_commands):
        rss, vms = mem_usage()
        log.info("Running commands: %i" % running_commands)
        log.info("Current Memory usage: rss=%sMB | vms=%sMB" % (rss, vms))

        if not running_commands and rss > _CHECK_RAM_MAX_RSS_MB:
            log.critical("Max allowed RSS memory exceeded: %s MB, exiting."
                         % _CHECK_RAM_MAX_RSS_MB)
            reactor.stop()
Ejemplo n.º 2
0
class SMAgentXMPP(Client):
    def __init__(self, config):
        """
        XMPP agent class.
        """
        log.info("Starting Agent...")

        log.info("Loading Commands...")
        self.command_runner = CommandRunner(config['Plugins'])

        log.info("Setting up Certificate")
        self.verify = ECVerify()

        log.info("Setting up Memory checker")

        self.running_commands = {}
        self.num_running_commands = 0
        self.timestamp = 0

        self.memory_checker = LoopingCall(self._check_memory, self.running_commands)
        self.memory_checker.start(_CHECK_RAM_INTERVAL)
        
        self.keepalive = LoopingCall(self._reconnect)

        log.debug("Loading XMPP...")
        Client.__init__(
            self,
            config['XMPP'],
            [("/iq[@type='set']", self.__onIq), ],
            resource='ecm_agent-%d' % AGENT_VERSION_PROTOCOL)

    def _reconnect(self):
        """ 
        Disconnect the current reactor to try to connect again
        """
        log.info("No data received in %ss: Trying to reconnect" % KEEPALIVED_TIMEOUT)
        reactor.disconnectAll()	
            
    def __onIq(self, msg):
        """
        A new IQ message has been received and we should process it.
        """
        log.debug('__onIq')

        log.debug("q Message received: \n%s" % msg.toXml())
        log.debug("Message type: %s" % msg['type'])

        if self.keepalive.running:
            log.debug("Stop keepalived")
            self.keepalive.stop()
        
        log.debug("Starting keepalived")
        self.keepalive.start(KEEPALIVED_TIMEOUT, now=False)

        self.timestamp = time()

        message = IqMessage(msg)
        recv_command = message.command.replace('.', '_')

        if recv_command in self.running_commands:
            if self.timestamp > self.running_commands[recv_command]:
                del self.running_commands[recv_command]
                self.num_running_commands -= 1
                log.debug("Deleted %s from running_commands dict as should have been completed" % (recv_command))

        if recv_command not in self.running_commands:
            log.debug('recieved new command: %s with message: %s' % (message.command, message))

            if hasattr(message, 'command') and hasattr(message, 'from_'):
                log.debug('online contacts: %s' % self._online_contacts)

                if message.from_ not in self._online_contacts:
                    log.warn('IQ sender not in roster (%s), dropping message' % message.from_)
                else:
                    self.running_commands[recv_command] = self.timestamp + int(message.command_args['timeout'])
                    self.num_running_commands += 1
                    log.debug("Running commands: names: %s numbers: %i" % (self.running_commands, self.num_running_commands))
                    self._processCommand(message)

        else:
            log.debug("already running given command %s" %recv_command)
            result = (_E_RUNNING_COMMAND, '', 'another command is running', 0)
            self._send(result, message)

        del msg
        del message

    def _processCommand(self, message):
        if not self.verify.signature(message):
            result = (_E_UNVERIFIED_COMMAND, '', 'Bad signature', 0)
            self._onCallFinished(result, message)
            return

        flush_callback = self._flush
        message.command_name = message.command.replace('.', '_')

        d = self.command_runner.run_command(message, flush_callback)
        
        # Clean message
        message.command_args = {}

        if d:
            d.addCallbacks(self._onCallFinished, self._onCallFailed,
                           callbackKeywords={'message': message},
                           errbackKeywords={'message': message},
            )
            del message
            return d

        else:
            log.info("Command Ignored: Unknown command: %s" % message.command)
            result = (_E_RUNNING_COMMAND, '', "Unknown command: %s" % message.command, 0)
            self._onCallFinished(result, message)

        del message
        return
        
    def _onCallFinished(self, result, message):
        log.debug('Call Finished')
        self._send(result, message)
        del self.running_commands[message.command_name]
        self.num_running_commands -= 1
        log.debug('command finished %s' %message.command_name)

    def _onCallFailed(self, failure, *argv, **kwargs):
        log.error("onCallFailed")
        log.info(failure)

        if 'message' in kwargs:
            message = kwargs['message']
            result = (2, '', failure, 0)
            del self.running_commands[message.command_name]
            self.num_running_commands -= 1
            self._onCallFinished(result, message)

    def _flush(self, result, message):
        log.debug('Flush Message')
        self._send(result, message)

    def _send(self, result, message):
        log.debug('Send Response')
        message.toResult(*result)

        del result

        self.send(message.toEtree())

    def _check_memory(self, num_running_commands):
        rss = mem_clean('periodic memory clean')
        if not num_running_commands and rss > _CHECK_RAM_MAX_RSS_MB:
            log.critical("Max allowed RSS memory exceeded: %s MB, exiting."
                         % _CHECK_RAM_MAX_RSS_MB)
            reactor.stop()
        del rss