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")
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
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)
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")