Exemple #1
0
class TrapReceiver():
    def __init__(self, conf={}):
        if conf is None or any(conf) == False:
            self.__conf = OpenClosProperty(appName=moduleName).getProperties()
        else:
            self.__conf = conf

        # default value
        self.target = DEFAULT_HOST
        self.port = DEFAULT_PORT

        # validate required parameter
        if 'snmpTrap' in self.__conf and 'openclos_trap_group' in self.__conf[
                'snmpTrap'] and 'target' in self.__conf['snmpTrap'][
                    'openclos_trap_group']:
            self.target = self.__conf['snmpTrap']['openclos_trap_group'][
                'target']
        else:
            logger.info(
                "snmpTrap:openclos_trap_group:target is missing from configuration. using %s"
                % (self.target))

        if 'snmpTrap' in self.__conf and 'openclos_trap_group' in self.__conf[
                'snmpTrap'] and 'port' in self.__conf['snmpTrap'][
                    'openclos_trap_group']:
            self.port = int(
                self.__conf['snmpTrap']['openclos_trap_group']['port'])
        else:
            logger.info(
                "snmpTrap:openclos_trap_group:port is missing from configuration. using %d"
                % (self.port))

        if 'snmpTrap' in self.__conf and 'threadCount' in self.__conf[
                'snmpTrap']:
            self.executor = concurrent.futures.ThreadPoolExecutor(
                max_workers=self.__conf['snmpTrap']['threadCount'])
        else:
            self.executor = concurrent.futures.ThreadPoolExecutor(
                max_workers=DEFAULT_MAX_THREADS)

        # event to stop from sleep
        self.stopEvent = Event()

        self.twoStageConfigurationCallback = util.getTwoStageConfigurationCallback(
            self.__conf)

    def threadFunction(self):
        self.transportDispatcher = AsynsockDispatcher()

        self.transportDispatcher.registerRecvCbFun(onTrap)

        # UDP/IPv4
        self.transportDispatcher.registerTransport(
            udp.domainName,
            udp.UdpSocketTransport().openServerMode((self.target, self.port)))

        self.transportDispatcher.jobStarted(1)

        try:
            # Dispatcher will never finish as job#1 never reaches zero
            self.transportDispatcher.runDispatcher()
        except Exception as exc:
            logger.error("Encounted error '%s' on trap receiver %s:%d" %
                         (exc, self.target, self.port))
            self.transportDispatcher.closeDispatcher()
            raise TrapDaemonError(
                "Trap receiver %s:%d" % (self.target, self.port), exc)
        else:
            self.transportDispatcher.closeDispatcher()

    def start(self):
        logger.info("Starting trap receiver...")
        self.thread = Thread(target=self.threadFunction, args=())
        self.thread.start()
        logger.info("Trap receiver started on %s:%d" %
                    (self.target, self.port))

    def stop(self):
        logger.info("Stopping trap receiver...")
        self.stopEvent.set()
        self.executor.shutdown()
        self.transportDispatcher.jobFinished(1)
        self.thread.join()
        logger.info("Trap receiver stopped")
Exemple #2
0
class SnmpServer(threading.Thread):
    def __init__(self, address):
        threading.Thread.__init__(self)
        self._address = address
        self._transportDispatcher = AsynsockDispatcher()
        self._transportDispatcher.registerRecvCbFun(self.onSnmpMessage)

    def run(self):
        self._transportDispatcher.registerTransport(
            udp.domainName,
            udp.UdpSocketTransport().openServerMode(self._address))
        getLogger().info("Now listening on %s:%s" % self._address)
        self._transportDispatcher.jobStarted(1)
        try:
            self._transportDispatcher.runDispatcher(timeout=1)
        except Exception as e:
            getLogger().error(u"Error while handling an SNMP message: %s" %
                              unicode(e))

    def stop(self):
        self._transportDispatcher.jobFinished(1)
        self._transportDispatcher.closeDispatcher()
        self.join()

    # Main handler, called when receiving an SNMP request
    def onSnmpMessage(self, transportDispatcher, transportDomain,
                      transportAddress, wholeMsg):
        while wholeMsg:
            msgVer = api.decodeMessageVersion(wholeMsg)
            if api.protoModules.has_key(msgVer):
                pMod = api.protoModules[msgVer]
            else:
                getLogger().error('Unsupported SNMP version %s' % msgVer)
                return
            reqMsg, wholeMsg = decoder.decode(
                wholeMsg,
                asn1Spec=pMod.Message(),
            )
            rspMsg = pMod.apiMessage.getResponse(reqMsg)
            rspPDU = pMod.apiMessage.getPDU(rspMsg)
            reqPDU = pMod.apiMessage.getPDU(reqMsg)
            varBinds = []
            errorIndex = -1

            # GET request
            if reqPDU.isSameTypeWith(pMod.GetRequestPDU()):
                getLogger().info("SNMP GET received...")
                for oid, val in pMod.apiPDU.getVarBinds(reqPDU):
                    getLogger().debug("Trying to GET %s... " %
                                      oidToString(oid))
                    if mibVariablesByOid.has_key(oid):
                        varBinds.append((oid, mibVariablesByOid[oid](msgVer)))
                    else:
                        # No such instance
                        pMod.apiPDU.setNoSuchInstanceError(rspPDU, errorIndex)
                        varBinds = pMod.apiPDU.getVarBinds(reqPDU)
                        break

            # GET-NEXT request
            elif reqPDU.isSameTypeWith(pMod.GetNextRequestPDU()):
                getLogger().info("SNMP GET-NEXT received...")
                # Produce response var-binds
                errorIndex = -1
                for oid, val in pMod.apiPDU.getVarBinds(reqPDU):
                    getLogger().debug("Trying to GET-NEXT %s... " %
                                      oidToString(oid))
                    errorIndex = errorIndex + 1
                    # Search next OID to report
                    nextIdx = bisect.bisect(mibVariables, oid)
                    if nextIdx == len(mibVariables):
                        # Out of MIB
                        pMod.apiPDU.setEndOfMibError(rspPDU, errorIndex)
                    else:
                        # Report value if OID is found
                        varBinds.append((mibVariables[nextIdx].oid,
                                         mibVariables[nextIdx](msgVer)))

            else:
                getLogger().error("Unsupported SNMP request received...")
                # Report unsupported request type
                pMod.apiPDU.setErrorStatus(
                    rspPDU, -1)  # we should use something different from -1

            pMod.apiPDU.setVarBinds(rspPDU, varBinds)
            transportDispatcher.sendMessage(encoder.encode(rspMsg),
                                            transportDomain, transportAddress)
        return wholeMsg
Exemple #3
0
class SNMPProcess(threading_tools.process_obj):
    def __init__(self, name, conf_dict, **kwargs):
        self.__snmp_name = name
        self.__log_name, self.__log_destination = (
            conf_dict["LOG_NAME"],
            conf_dict["LOG_DESTINATION"],
        )
        self.__verbose = conf_dict.get("VERBOSE", False)
        self.debug_zmq = conf_dict.get("DEBUG_ZMQ", False)
        threading_tools.process_obj.__init__(self, name, busy_loop=True)
        if kwargs.get("ignore_signals", False):
            signal.signal(signal.SIGTERM, signal.SIG_IGN)

    def process_init(self):
        self.__log_template = logging_tools.get_logger(
            self.__log_name,
            self.__log_destination,
            zmq=True,
            context=self.zmq_context)
        self.__return_proc_name = None
        self.register_func("fetch_snmp", self._fetch_snmp)
        self.register_func("register_return", self._register_return)
        self.register_func("trigger_timeout", self._trigger_timeout)
        self._init_dispatcher()
        self.__job_dict = {}
        self.__envelope_dict = {}
        self.__req_id_lut = {}

    def log(self, what, log_level=logging_tools.LOG_LEVEL_OK):
        self.__log_template.log(log_level, what)

    def _init_dispatcher(self):
        self.log("init snmp_session object")
        self.__disp = AsynsockDispatcher()
        self.__disp.registerTransport(
            udp.domainName,
            udp.UdpSocketTransport().openClientMode())
        self.__disp.registerRecvCbFun(self._recv_func)
        self.__disp.registerTimerCbFun(self._timer_func)
        self.v1_decoder = api.protoModules[api.protoVersion1]
        self.v2c_decoder = api.protoModules[api.protoVersion2c]

    def register_batch(self, cur_batch):
        if self.__verbose > 3:
            self.log("registered new batch {:d}".format(cur_batch.key))
        self.__job_dict[cur_batch.key] = cur_batch
        self.__disp.jobStarted(cur_batch.key)

    def unregister_batch(self, cur_batch):
        # ids we will no longer handle because of finish
        to_keys = [
            key for key, value in self.__req_id_lut.iteritems()
            if value == cur_batch
        ]
        if to_keys:
            for to_key in to_keys:
                del self.__req_id_lut[to_key]
            if self.__verbose > 3:
                cur_batch.log(
                    "removed {} for batch {}".format(
                        logging_tools.get_plural("request ID", len(to_keys)),
                        cur_batch,
                    ), )
        del self.__job_dict[cur_batch.key]
        del self.__envelope_dict[cur_batch.envelope]
        self.__disp.jobFinished(cur_batch.key)

    def loop(self):
        try:
            while self["run_flag"]:
                self.__disp.runDispatcher()
                self.step(blocking=self["run_flag"])
        except ValueConstraintError:
            self.log("caught ValueConstraintError, terminating process",
                     logging_tools.LOG_LEVEL_CRITICAL)
            _term_cause = "ValueConstraintError"
        except:
            exc_info = process_tools.exception_info()
            self.log("exception in dispatcher, terminating process",
                     logging_tools.LOG_LEVEL_CRITICAL)
            for log_line in exc_info.log_lines:
                self.log(" - {}".format(log_line),
                         logging_tools.LOG_LEVEL_CRITICAL)
            _term_cause = "internal error"
        else:
            self.log("no more jobs running")
            _term_cause = ""
        self.log("jobs pending: {:d}".format(len(self.__job_dict)))
        # close all jobs
        if _term_cause:
            self._terminate_jobs(error="{}, check logs".format(_term_cause))
        else:
            self._terminate_jobs()
        self.__disp.closeDispatcher()

    def _inject(self, cur_batch):
        try:
            next_tuple = cur_batch.iterator.next()
        except StopIteration:
            cur_batch.finish()
        else:
            self.send_next(cur_batch, next_tuple)

    def send_next(self, cur_batch, next_tuple):
        self.__req_id_lut[cur_batch.request_id] = cur_batch
        self.__disp.sendMessage(*next_tuple)

    def _register_return(self, proc_name, **kwargs):
        self.__return_proc_name = proc_name
        self.send_pool_message("hellox",
                               "hello2",
                               "hello3",
                               target=self.__return_proc_name)

    def _fetch_snmp(self, *scheme_data, **kwargs):
        new_batch = SNMPBatch(self,
                              *scheme_data,
                              verbose=self.__verbose,
                              **kwargs)
        self.__envelope_dict[new_batch.envelope] = new_batch
        self._inject(new_batch)

    def _trigger_timeout(self, *args, **kwargs):
        batch_id = args[0]
        if batch_id in self.__envelope_dict:
            self.log("triggering timeout for batch_id {}".format(batch_id),
                     logging_tools.LOG_LEVEL_WARN)
            self.__envelope_dict[batch_id].trigger_timeout()
        else:
            self.log("unknown batch_id {}".format(batch_id),
                     logging_tools.LOG_LEVEL_ERROR)

    def _timer_func(self, act_time):
        timed_out = [
            key for key, cur_job in self.__job_dict.iteritems()
            if cur_job.timer_func(act_time)
        ]
        for to_key in timed_out:
            self.__job_dict[to_key].finish()
        self.step()
        if self["exit_requested"]:
            self._terminate_jobs(error="exit requested")

    def _terminate_jobs(self, **kwargs):
        _stop_keys = set(self.__job_dict.keys())
        for _key in _stop_keys:
            if "error" in kwargs:
                self.__job_dict[_key].add_error(kwargs["error"])
            self.__job_dict[_key].finish()

    def _recv_func(self, disp, domain, address, whole_msg):
        while whole_msg:
            # rsp_msg, whole_msg = decoder.decode(whole_msg, asn1Spec=self.__p_mod.Message())
            try:
                rsp_msg, whole_msg = decoder.decode(
                    whole_msg, asn1Spec=self.v2c_decoder.Message())
            except:
                self.log(
                    "error decoding message from {}: {}".format(
                        address, process_tools.get_except_info()),
                    logging_tools.LOG_LEVEL_CRITICAL)
                # send meaningfull error message to client ? TODO, FIXME
                whole_msg = None
            else:
                # rsp_pdu = self.__p_mod.apiMessage.getPDU(rsp_msg)
                rsp_pdu = self.v2c_decoder.apiMessage.getPDU(rsp_msg)
                cur_id = self.v2c_decoder.apiPDU.getRequestID(rsp_pdu)
                if cur_id in self.__req_id_lut:
                    self.__req_id_lut[cur_id].feed_pdu(disp, domain, address,
                                                       rsp_pdu)
                else:
                    self.log("id {} in response not known".format(cur_id))
                if cur_id in self.__req_id_lut:
                    del self.__req_id_lut[cur_id]
        return whole_msg

    def loop_post(self):
        self.__log_template.close()

    def send_return(self, envelope, error_list, received, snmp):
        self.send_pool_message("snmp_finished",
                               envelope,
                               error_list,
                               received,
                               snmp,
                               target=self.__return_proc_name
                               or DEFAULT_RETURN_NAME)
Exemple #4
0
class TrapReceiver():
    def __init__(self, conf = {}):
        global logger
        if conf is None or any(conf) == False:
            self.__conf = util.loadConfig(appName = moduleName)
        else:
            self.__conf = conf

        logger = logging.getLogger(moduleName)
        # default value
        self.target = DEFAULT_HOST
        self.port = DEFAULT_PORT
        
        # validate required parameter
        if 'snmpTrap' in self.__conf and 'openclos_trap_group' in self.__conf['snmpTrap'] and 'target' in self.__conf['snmpTrap']['openclos_trap_group']:
            self.target = self.__conf['snmpTrap']['openclos_trap_group']['target']
        else:
            logger.info("snmpTrap:openclos_trap_group:target is missing from configuration. using %s" % (self.target))                

        if 'snmpTrap' in self.__conf and 'openclos_trap_group' in self.__conf['snmpTrap'] and 'port' in self.__conf['snmpTrap']['openclos_trap_group']:
            self.port = int(self.__conf['snmpTrap']['openclos_trap_group']['port'])
        else:
            logger.info("snmpTrap:openclos_trap_group:port is missing from configuration. using %d" % (self.port))                
            
        if 'snmpTrap' in self.__conf and 'threadCount' in self.__conf['snmpTrap']:
            self.executor = concurrent.futures.ThreadPoolExecutor(max_workers = self.__conf['snmpTrap']['threadCount'])
        else:
            self.executor = concurrent.futures.ThreadPoolExecutor(max_workers = DEFAULT_MAX_THREADS)

        # event to stop from sleep
        self.stopEvent = Event()
        
        self.twoStageConfigurationCallback = util.getTwoStageConfigurationCallback(self.__conf)
       
    def threadFunction(self):
        self.transportDispatcher = AsynsockDispatcher()

        self.transportDispatcher.registerRecvCbFun(onTrap)
        
        # UDP/IPv4
        self.transportDispatcher.registerTransport(
            udp.domainName, udp.UdpSocketTransport().openServerMode((self.target, self.port))
        )

        self.transportDispatcher.jobStarted(1)

        try:
            # Dispatcher will never finish as job#1 never reaches zero
            self.transportDispatcher.runDispatcher()
        except:
            self.transportDispatcher.closeDispatcher()
            raise
        else:
            self.transportDispatcher.closeDispatcher()

    def start(self):
        logger.info("Starting trap receiver...")
        self.thread = Thread(target=self.threadFunction, args=())
        self.thread.start()
        logger.info("Trap receiver started on %s:%d" % (self.target, self.port))

    def stop(self):
        logger.info("Stopping trap receiver...")
        self.stopEvent.set()
        self.executor.shutdown()
        self.transportDispatcher.jobFinished(1)  
        self.thread.join()
        logger.info("Trap receiver stopped")