pyagentx-0.4.1/0000755000076500000240000000000012544474101013604 5ustar rayedstaff00000000000000pyagentx-0.4.1/PKG-INFO0000644000076500000240000000223312544474101014701 0ustar rayedstaff00000000000000Metadata-Version: 1.1 Name: pyagentx Version: 0.4.1 Summary: AgentX package to extend SNMP with pure Python Home-page: https://github.com/rayed/pyagentx Author: Rayed Alrashed Author-email: rayed@rayed.com License: BSD Description: PyAgentX -------------------- pyagentx is a pure Python implementation of AgentX protocol (RFC 2741), it will allow you to extend SNMP agent (snmpd) by writing AgentX subagents, without modifying your original SNMP agent. The agent can support the following commands: - snmpget - snmpwalk - snmptable - snmpset Keywords: snmp network agentx Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: License :: OSI Approved :: BSD License Classifier: Environment :: No Input/Output (Daemon) Classifier: Topic :: System :: Monitoring Classifier: Topic :: System :: Networking Classifier: Programming Language :: Python Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: Intended Audience :: Telecommunications Industry pyagentx-0.4.1/pyagentx/0000755000076500000240000000000012544474101015443 5ustar rayedstaff00000000000000pyagentx-0.4.1/pyagentx/__init__.py0000644000076500000240000001020512540475623017560 0ustar rayedstaff00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- import logging from pyagentx.updater import Updater from pyagentx.agent import Agent from pyagentx.sethandler import SetHandler, SetHandlerError def setup_logging(debug=False): if debug: level = logging.DEBUG else: level = logging.INFO logger = logging.getLogger('pyagentx') logger.setLevel(level) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') ch = logging.StreamHandler() ch.setLevel(level) ch.setFormatter(formatter) logger.addHandler(ch) SOCKET_PATH = "/var/agentx/master" AGENTX_EMPTY_PDU = 1 AGENTX_OPEN_PDU = 1 AGENTX_CLOSE_PDU = 2 AGENTX_REGISTER_PDU = 3 AGENTX_UNREGISTER_PDU = 4 AGENTX_GET_PDU = 5 AGENTX_GETNEXT_PDU = 6 AGENTX_GETBULK_PDU = 7 AGENTX_TESTSET_PDU = 8 AGENTX_COMMITSET_PDU = 9 AGENTX_UNDOSET_PDU = 10 AGENTX_CLEANUPSET_PDU = 11 AGENTX_NOTIFY_PDU = 12 AGENTX_PING_PDU = 13 AGENTX_INDEXALLOCATE_PDU = 14 AGENTX_INDEXDEALLOCATE_PDU = 15 AGENTX_ADDAGENTCAPS_PDU = 16 AGENTX_REMOVEAGENTCAPS_PDU = 17 AGENTX_RESPONSE_PDU = 18 PDU_TYPE_NAME = {} PDU_TYPE_NAME[0] = "EMPTY_PDU" PDU_TYPE_NAME[1] = "OPEN_PDU" PDU_TYPE_NAME[2] = "CLOSE_PDU" PDU_TYPE_NAME[3] = "REGISTER_PDU" PDU_TYPE_NAME[4] = "UNREGISTER_PDU" PDU_TYPE_NAME[5] = "GET_PDU" PDU_TYPE_NAME[6] = "GETNEXT_PDU" PDU_TYPE_NAME[7] = "GETBULK_PDU" PDU_TYPE_NAME[8] = "TESTSET_PDU" PDU_TYPE_NAME[9] = "COMMITSET_PDU" PDU_TYPE_NAME[10] = "UNDOSET_PDU" PDU_TYPE_NAME[11] = "CLEANUPSET_PDU" PDU_TYPE_NAME[12] = "NOTIFY_PDU" PDU_TYPE_NAME[13] = "PING_PDU" PDU_TYPE_NAME[14] = "INDEXALLOCATE_PDU" PDU_TYPE_NAME[15] = "INDEXDEALLOCATE_PDU" PDU_TYPE_NAME[16] = "ADDAGENTCAPS_PDU" PDU_TYPE_NAME[17] = "REMOVEAGENTCAPS_PDU" PDU_TYPE_NAME[18] = "RESPONSE_PDU" TYPE_INTEGER = 2 TYPE_OCTETSTRING = 4 TYPE_NULL = 5 TYPE_OBJECTIDENTIFIER = 6 TYPE_IPADDRESS = 64 TYPE_COUNTER32 = 65 TYPE_GAUGE32 = 66 TYPE_TIMETICKS = 67 TYPE_OPAQUE = 68 TYPE_COUNTER64 = 70 TYPE_NOSUCHOBJECT = 128 TYPE_NOSUCHINSTANCE = 129 TYPE_ENDOFMIBVIEW = 130 TYPE_NAME = {} TYPE_NAME[2] = "INTEGER" TYPE_NAME[4] = "OCTETSTRING" TYPE_NAME[5] = "NULL" TYPE_NAME[6] = "OBJECTIDENTIFIER" TYPE_NAME[64] = "IPADDRESS" TYPE_NAME[65] = "COUNTER32" TYPE_NAME[66] = "GAUGE32" TYPE_NAME[67] = "TIMETICKS" TYPE_NAME[68] = "OPAQUE" TYPE_NAME[70] = "COUNTER64" TYPE_NAME[128] = "NOSUCHOBJECT" TYPE_NAME[129] = "NOSUCHINSTANCE" TYPE_NAME[130] = "ENDOFMIBVIEW" ERROR_NOAGENTXERROR = 0 ERROR_GENERR = 5 ERROR_NOACCESS = 6 ERROR_WRONGTYPE = 7 ERROR_WRONGLENGTH = 8 ERROR_WRONGENCODING = 9 ERROR_WRONGVALUE = 10 ERROR_NOCREATION = 11 ERROR_INCONSISTENTVALUE = 12 ERROR_RESOURCEUNAVAILABLE = 13 ERROR_COMMITFAILED = 14 ERROR_UNDOFAILED = 15 ERROR_NOTWRITABLE = 17 ERROR_INCONSISTENTNAME = 18 ERROR_OPENFAILED = 256 ERROR_NOTOPEN = 257 ERROR_INDEXWRONGTYPE = 258 ERROR_INDEXALREADYALLOCATED = 259 ERROR_INDEXNONEAVAILABLE = 260 ERROR_INDEXNOTALLOCATED = 261 ERROR_UNSUPPORTEDCONTEXT = 262 ERROR_DUPLICATEREGISTRATION = 263 ERROR_UNKNOWNREGISTRATION = 264 ERROR_UNKNOWNAGENTCAPS = 265 ERROR_PARSEERROR = 266 ERROR_REQUESTDENIED = 267 ERROR_PROCESSINGERROR = 268 ERROR_NAMES = {} ERROR_NAMES[0] = "NOAGENTXERROR" ERROR_NAMES[5] = "GENERR" ERROR_NAMES[6] = "NOACCESS" ERROR_NAMES[7] = "WRONGTYPE" ERROR_NAMES[8] = "WRONGLENGTH" ERROR_NAMES[9] = "WRONGENCODING" ERROR_NAMES[10] = "WRONGVALUE" ERROR_NAMES[11] = "NOCREATION" ERROR_NAMES[12] = "INCONSISTENTVALUE" ERROR_NAMES[13] = "RESOURCEUNAVAILABLE" ERROR_NAMES[14] = "ERROR_COMMITFAILED" ERROR_NAMES[15] = "ERROR_UNDOFAILED" ERROR_NAMES[17] = "NOTWRITABLE" ERROR_NAMES[18] = "INCONSISTENTNAME" ERROR_NAMES[256] = "OPENFAILED" ERROR_NAMES[257] = "NOTOPEN" ERROR_NAMES[258] = "INDEXWRONGTYPE" ERROR_NAMES[259] = "INDEXALREADYALLOCATED" ERROR_NAMES[260] = "INDEXNONEAVAILABLE" ERROR_NAMES[261] = "INDEXNOTALLOCATED" ERROR_NAMES[262] = "UNSUPPORTEDCONTEXT" ERROR_NAMES[263] = "DUPLICATEREGISTRATION" ERROR_NAMES[264] = "UNKNOWNREGISTRATION" ERROR_NAMES[265] = "UNKNOWNAGENTCAPS" ERROR_NAMES[266] = "PARSEERROR" ERROR_NAMES[267] = "REQUESTDENIED" ERROR_NAMES[268] = "PROCESSINGERROR" pyagentx-0.4.1/pyagentx/agent.py0000644000076500000240000000453212544473615017130 0ustar rayedstaff00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # -------------------------------------------- import logging class NullHandler(logging.Handler): def emit(self, record): pass logger = logging.getLogger('pyagentx.agent') logger.addHandler(NullHandler()) # -------------------------------------------- import time import Queue import pyagentx from pyagentx.updater import Updater from pyagentx.network import Network class AgentError(Exception): pass class Agent(object): def __init__(self): self._updater_list = [] self._sethandlers = {} self._threads = [] def register(self, oid, class_, freq=10): if Updater not in class_.__bases__: raise AgentError('Class given isn\'t an updater') # cleanup and test oid try: oid = oid.strip(' .') [int(i) for i in oid.split('.')] except ValueError: raise AgentError('OID isn\'t valid') self._updater_list.append({'oid':oid, 'class':class_, 'freq':freq}) def register_set(self, oid, class_): if pyagentx.SetHandler not in class_.__bases__: raise AgentError('Class given isn\'t a SetHandler') # cleanup and test oid try: oid = oid.strip(' .') [int(i) for i in oid.split('.')] except ValueError: raise AgentError('OID isn\'t valid') self._sethandlers[oid] = class_() def setup(self): # Override this pass def start(self): queue = Queue.Queue(maxsize=20) self.setup() # Start Updaters for u in self._updater_list: logger.debug('Starting updater [%s]' % u['oid']) t = u['class']() t.agent_setup(queue, u['oid'], u['freq']) t.start() self._threads.append(t) # Start Network oid_list = [u['oid'] for u in self._updater_list] t = Network(queue, oid_list, self._sethandlers) t.start() self._threads.append(t) # Do nothing ... just wait for someone to stop you while True: #logger.debug('Agent Sleeping ...') time.sleep(1) def stop(self): logger.debug('Stop threads') for t in self._threads: t.stop.set() logger.debug('Wait for updater') for t in self._threads: t.join() pyagentx-0.4.1/pyagentx/network.py0000644000076500000240000002125012542500367017510 0ustar rayedstaff00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # -------------------------------------------- import logging class NullHandler(logging.Handler): def emit(self, record): pass logger = logging.getLogger('pyagentx.network') logger.addHandler(NullHandler()) # -------------------------------------------- import socket import time import threading import Queue import pyagentx from pyagentx.pdu import PDU class Network(threading.Thread): def __init__(self, queue, oid_list, sethandlers): threading.Thread.__init__(self) self.stop = threading.Event() self._queue = queue self._oid_list = oid_list self._sethandlers = sethandlers self.session_id = 0 self.transaction_id = 0 self.debug = 1 # Data Related Variables self.data = {} self.data_idx = [] def _connect(self): while True: try: self.socket = socket.socket( socket.AF_UNIX, socket.SOCK_STREAM ) self.socket.connect(pyagentx.SOCKET_PATH) self.socket.settimeout(0.1) return except socket.error: logger.error("Failed to connect, sleeping and retrying later") time.sleep(2) def new_pdu(self, type): pdu = PDU(type) pdu.session_id = self.session_id pdu.transaction_id = self.transaction_id self.transaction_id += 1 return pdu def response_pdu(self, org_pdu): pdu = PDU(pyagentx.AGENTX_RESPONSE_PDU) pdu.session_id = org_pdu.session_id pdu.transaction_id = org_pdu.transaction_id pdu.packet_id = org_pdu.packet_id return pdu def send_pdu(self, pdu): if self.debug: pdu.dump() self.socket.send(pdu.encode()) def recv_pdu(self): buf = self.socket.recv(1024) if not buf: return None pdu = PDU() pdu.decode(buf) if self.debug: pdu.dump() return pdu # ========================================= def _get_updates(self): while True: try: item = self._queue.get_nowait() logger.debug('New update') update_oid = item['oid'] update_data = item['data'] # clear values with prefix oid for oid in self.data.keys(): if oid.startswith(update_oid): del(self.data[oid]) # insert updated value for row in update_data.values(): oid = "%s.%s" % (update_oid, row['name']) self.data[oid] = {'name': oid, 'type':row['type'], 'value':row['value']} # recalculate reverse index if data changed self.data_idx = sorted(self.data.keys(), key=lambda k: tuple(int(part) for part in k.split('.'))) except Queue.Empty: break def _get_next_oid(self, oid, endoid): if oid in self.data: # Exact match found #logger.debug('get_next_oid, exact match of %s' % oid) idx = self.data_idx.index(oid) if idx == (len(self.data_idx)-1): # Last Item in MIB, No match! return None return self.data_idx[idx+1] else: # No exact match, find prefix #logger.debug('get_next_oid, no exact match of %s' % oid) slist = oid.split('.') elist = endoid.split('.') for tmp_oid in self.data_idx: tlist = tmp_oid.split('.') for i in range(len(tlist)): try: sok = int(slist[i]) <= int(tlist[i]) eok = int(elist[i]) >= int(tlist[i]) if not ( sok and eok ): break except IndexError: pass if sok and eok: return tmp_oid return None # No match! def start(self): while True: try: self._start_network() except socket.error: logger.error("Network error, master disconnect?!") def _start_network(self): self._connect() logger.info("==== Open PDU ====") pdu = self.new_pdu(pyagentx.AGENTX_OPEN_PDU) self.send_pdu(pdu) pdu = self.recv_pdu() self.session_id = pdu.session_id logger.info("==== Ping PDU ====") pdu = self.new_pdu(pyagentx.AGENTX_PING_PDU) self.send_pdu(pdu) pdu = self.recv_pdu() logger.info("==== Register PDU ====") for oid in self._oid_list: logger.info("Registering: %s" % (oid)) pdu = self.new_pdu(pyagentx.AGENTX_REGISTER_PDU) pdu.oid = oid self.send_pdu(pdu) pdu = self.recv_pdu() logger.info("==== Waiting for PDU ====") while True: try: self._get_updates() request = self.recv_pdu() except socket.timeout: continue if not request: logger.error("Empty PDU, connection closed!") raise socket.error response = self.response_pdu(request) if request.type == pyagentx.AGENTX_GET_PDU: logger.info("Received GET PDU") for rvalue in request.range_list: oid = rvalue[0] logger.debug("OID: %s" % (oid)) if oid in self.data: logger.debug("OID Found") response.values.append(self.data[oid]) else: logger.debug("OID Not Found!") response.values.append({'type':pyagentx.TYPE_NOSUCHOBJECT, 'name':rvalue[0], 'value':0}) elif request.type == pyagentx.AGENTX_GETNEXT_PDU: logger.info("Received GET_NEXT PDU") for rvalue in request.range_list: oid = self._get_next_oid(rvalue[0],rvalue[1]) logger.debug("GET_NEXT: %s => %s" % (rvalue[0], oid)) if oid: response.values.append(self.data[oid]) else: response.values.append({'type':pyagentx.TYPE_ENDOFMIBVIEW, 'name':rvalue[0], 'value':0}) elif request.type == pyagentx.AGENTX_TESTSET_PDU: logger.info("Received TESTSET PDU") idx = 0 for row in request.values: idx += 1 oid = row['name'] type_ = pyagentx.TYPE_NAME.get(row['type'], 'Unknown type') value = row['data'] logger.info("Name: [%s] Type: [%s] Value: [%s]" % (oid, type_, value)) # Find matching sethandler matching_oid = '' for target_oid in self._sethandlers: if oid.startswith(target_oid): matching_oid = target_oid break if matching_oid == '': logger.debug('TestSet request failed: not writeable #%s' % idx) response.error = pyagentx.ERROR_NOTWRITABLE response.error_index = idx break try: self._sethandlers[matching_oid].network_test(request.session_id, request.transaction_id, oid, row['data']) except pyagentx.SetHandlerError: logger.debug('TestSet request failed: wrong value #%s' % idx) response.error = pyagentx.ERROR_WRONGVALUE response.error_index = idx break logger.debug('TestSet request passed') elif request.type == pyagentx.AGENTX_COMMITSET_PDU: for handler in self._sethandlers.values(): handler.network_commit(request.session_id, request.transaction_id) logger.info("Received COMMITSET PDU") elif request.type == pyagentx.AGENTX_UNDOSET_PDU: for handler in self._sethandlers.values(): handler.network_undo(request.session_id, request.transaction_id) logger.info("Received UNDOSET PDU") elif request.type == pyagentx.AGENTX_CLEANUPSET_PDU: for handler in self._sethandlers.values(): handler.network_cleanup(request.session_id, request.transaction_id) logger.info("Received CLEANUP PDU") self.send_pdu(response) pyagentx-0.4.1/pyagentx/pdu.py0000644000076500000240000002444012540253477016620 0ustar rayedstaff00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # -------------------------------------------- import logging class NullHandler(logging.Handler): def emit(self, record): pass logger = logging.getLogger('pyagentx.pdu') logger.addHandler(NullHandler()) # -------------------------------------------- import struct import pprint import pyagentx class PDU(object): def __init__(self, type=0): self.type = type self.session_id = 0 self.transaction_id = 0 self.packet_id = 0 self.error = pyagentx.ERROR_NOAGENTXERROR self.error_index = 0 self.decode_buf = '' self.state = {} self.values = [] def dump(self): name = pyagentx.PDU_TYPE_NAME[self.type] logger.debug('PDU DUMP: New PDU') logger.debug('PDU DUMP: Meta : [%s: %d %d %d]' % (name, self.session_id, self.transaction_id, self.packet_id)) if 'payload_length' in self.state: logger.debug('PDU DUMP: Length : %s' % self.state['payload_length']) if hasattr(self, 'response'): logger.debug('PDU DUMP: Response : %s' % self.response) if hasattr(self, 'values'): logger.debug('PDU DUMP: Values : %s' % pprint.pformat(self.values)) if hasattr(self, 'range_list'): logger.debug('PDU DUMP: Range list: %s' % pprint.pformat(self.range_list)) # ==================================================== # encode functions def encode_oid(self, oid, include=0): oid = oid.strip() oid = oid.split('.') oid = [int(i) for i in oid] if len(oid)>5 and oid[:4] == [1,3,6,1]: # prefix prefix = oid[4] oid = oid[5:] else: # no prefix prefix = 0 buf = struct.pack('BBBB', len(oid), prefix, include, 0) for i in range(len(oid)): buf += struct.pack('!L', oid[i]) return buf def encode_octet(self, octet): buf = struct.pack('!L', len(octet)) buf += str(octet) padding = ( 4 - ( len(octet) % 4 ) ) % 4 buf += chr(0)* padding return buf def encode_value(self, type, name, value): buf = struct.pack('!HH', type, 0) buf += self.encode_oid(name) if type in [pyagentx.TYPE_INTEGER]: buf += struct.pack('!l', value) elif type in [pyagentx.TYPE_COUNTER32, pyagentx.TYPE_GAUGE32, pyagentx.TYPE_TIMETICKS]: buf += struct.pack('!L', value) elif type in [pyagentx.TYPE_COUNTER64]: buf += struct.pack('!Q', value) elif type in [pyagentx.TYPE_OBJECTIDENTIFIER]: buf += self.encode_oid(value) elif type in [pyagentx.TYPE_IPADDRESS, pyagentx.TYPE_OPAQUE, pyagentx.TYPE_OCTETSTRING]: buf += self.encode_octet(value) elif type in [pyagentx.TYPE_NULL, pyagentx.TYPE_NOSUCHOBJECT, pyagentx.TYPE_NOSUCHINSTANCE, pyagentx.TYPE_ENDOFMIBVIEW]: # No data pass else: logger.error('Unknown Type:' % type) return buf def encode_header(self, pdu_type, payload_length=0, flags=0): flags = flags | 0x10 # Bit 5 = all ints in NETWORK_BYTE_ORDER buf = struct.pack('BBBB', 1, pdu_type, flags, 0) buf += struct.pack('!L', self.session_id) # sessionID buf += struct.pack('!L', self.transaction_id) # transactionID buf += struct.pack('!L', self.packet_id) # packetID buf += struct.pack('!L', payload_length) return buf def encode(self): buf = '' if self.type == pyagentx.AGENTX_OPEN_PDU: # timeout buf += struct.pack('!BBBB', 5, 0, 0, 0) # agent OID buf += struct.pack('!L', 0) # Agent Desc buf += self.encode_octet('MyAgent') elif self.type == pyagentx.AGENTX_PING_PDU: # No extra data pass elif self.type == pyagentx.AGENTX_REGISTER_PDU: range_subid = 0 timeout = 5 priority = 127 buf += struct.pack('BBBB', timeout, priority, range_subid, 0) # Sub Tree buf += self.encode_oid(self.oid) elif self.type == pyagentx.AGENTX_RESPONSE_PDU: buf += struct.pack('!LHH', 0, self.error, self.error_index) for value in self.values: buf += self.encode_value(value['type'], value['name'], value['value']) else: # Unsupported PDU type pass return self.encode_header(self.type, len(buf)) + buf # ==================================================== # decode functions def set_decode_buf(self, buf): self.decode_buf = buf def decode_oid(self): try: t = struct.unpack('!BBBB', self.decode_buf[:4]) self.decode_buf = self.decode_buf[4:] ret = { 'n_subid': t[0], 'prefix':t[1], 'include':t[2], 'reserved':t[3], } sub_ids = [] if ret['prefix']: sub_ids = [1,3,6,1] sub_ids.append(ret['prefix']) for i in range(ret['n_subid']): t = struct.unpack('!L', self.decode_buf[:4]) self.decode_buf = self.decode_buf[4:] sub_ids.append(t[0]) oid = '.'.join(str(i) for i in sub_ids) return oid, ret['include'] except Exception, e: logger.exception('Invalid packing OID header') logger.debug('%s' % pprint.pformat(self.decode_buf)) def decode_search_range(self): start_oid, include = self.decode_oid() if start_oid == []: return [], [], 0 end_oid, _ = self.decode_oid() return start_oid, end_oid, include def decode_search_range_list(self): range_list = [] while len(self.decode_buf): range_list.append(self.decode_search_range()) return range_list def decode_octet(self): try: t = struct.unpack('!L', self.decode_buf[:4]) l = t[0] self.decode_buf = self.decode_buf[4:] padding = 4 - (l%4) buf = self.decode_buf[:l] self.decode_buf = self.decode_buf[l+padding:] return buf except Exception, e: logger.exception('Invalid packing octet header') def decode_value(self): try: vtype,_ = struct.unpack('!HH', self.decode_buf[:4]) self.decode_buf = self.decode_buf[4:] except Exception, e: logger.exception('Invalid packing value header') oid,_ = self.decode_oid() if vtype in [pyagentx.TYPE_INTEGER, pyagentx.TYPE_COUNTER32, pyagentx.TYPE_GAUGE32, pyagentx.TYPE_TIMETICKS]: data = struct.unpack('!L', self.decode_buf[:4]) data = data[0] self.decode_buf = self.decode_buf[4:] elif vtype in [pyagentx.TYPE_COUNTER64]: data = struct.unpack('!Q', self.decode_buf[:8]) data = data[0] self.decode_buf = self.decode_buf[8:] elif vtype in [pyagentx.TYPE_OBJECTIDENTIFIER]: data,_ = self.decode_oid() elif vtype in [pyagentx.TYPE_IPADDRESS, pyagentx.TYPE_OPAQUE, pyagentx.TYPE_OCTETSTRING]: data = self.decode_octet() elif vtype in [pyagentx.TYPE_NULL, pyagentx.TYPE_NOSUCHOBJECT, pyagentx.TYPE_NOSUCHINSTANCE, pyagentx.TYPE_ENDOFMIBVIEW]: # No data data = None else: logger.error('Unknown Type: %s' % vtype) return {'type':vtype, 'name':oid, 'data':data} def decode_header(self): try: t = struct.unpack('!BBBBLLLL', self.decode_buf[:20]) self.decode_buf = self.decode_buf[20:] ret = { 'version': t[0], 'pdu_type':t[1], 'pdu_type_name': pyagentx.PDU_TYPE_NAME[t[1]], 'flags':t[2], 'reserved':t[3], 'session_id':t[4], 'transaction_id':t[5], 'packet_id':t[6], 'payload_length':t[7], } self.state = ret self.type = ret['pdu_type'] self.session_id = ret['session_id'] self.packet_id = ret['packet_id'] self.transaction_id = ret['transaction_id'] self.decode_buf = self.decode_buf[:ret['payload_length']] if ret['flags'] & 0x08: # content present context = self.decode_octet() logger.debug('Context: %s' % context) return ret except Exception, e: logger.exception('Invalid packing: %d' % len(self.decode_buf)) logger.debug('%s' % pprint.pformat(self.decode_buf)) def decode(self, buf): self.set_decode_buf(buf) ret = self.decode_header() if ret['pdu_type'] == pyagentx.AGENTX_RESPONSE_PDU: # Decode Response Header t = struct.unpack('!LHH', self.decode_buf[:8]) self.decode_buf = self.decode_buf[8:] self.response = { 'sysUpTime': t[0], 'error':t[1], 'error_name':pyagentx.ERROR_NAMES[t[1]], 'index':t[2], } # Decode VarBindList self.values = [] while len(self.decode_buf): self.values.append(self.decode_value()) elif ret['pdu_type'] == pyagentx.AGENTX_GET_PDU: self.range_list = self.decode_search_range_list() elif ret['pdu_type'] == pyagentx.AGENTX_GETNEXT_PDU: self.range_list = self.decode_search_range_list() elif ret['pdu_type'] == pyagentx.AGENTX_TESTSET_PDU: # Decode VarBindList self.values = [] while len(self.decode_buf): self.values.append(self.decode_value()) elif ret['pdu_type'] in [pyagentx.AGENTX_COMMITSET_PDU, pyagentx.AGENTX_UNDOSET_PDU, pyagentx.AGENTX_CLEANUPSET_PDU]: pass else: pdu_type_str = pyagentx.PDU_TYPE_NAME.get(ret['pdu_type'], 'Unknown:'+ str(ret['pdu_type'])) logger.error('Unsupported PDU type:'+ pdu_type_str) pyagentx-0.4.1/pyagentx/sethandler.py0000644000076500000240000000322712542500367020154 0ustar rayedstaff00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # -------------------------------------------- import logging class NullHandler(logging.Handler): def emit(self, record): pass logger = logging.getLogger('pyagentx.sethandler') logger.addHandler(NullHandler()) # -------------------------------------------- class SetHandlerError(Exception): pass class SetHandler(object): def __init__(self): self.transactions = {} def network_test(self, session_id, transaction_id, oid, data): tid = "%s_%s" % (session_id, transaction_id) if tid in self.transactions: del(self.transactions[tid]) try: self.test(oid, data) self.transactions[tid] = oid, data except SetHandler as e: logger.error('TestSet failed') raise e def network_commit(self, session_id, transaction_id): tid = "%s_%s" % (session_id, transaction_id) try: oid, data = self.transactions[tid] self.commit(oid, data) if tid in self.transactions: del(self.transactions[tid]) except: logger.error('CommitSet failed') def network_undo(self, session_id, transaction_id): tid = "%s_%s" % (session_id, transaction_id) if tid in self.transactions: del(self.transactions[tid]) def network_cleanup(self, session_id, transaction_id): tid = "%s_%s" % (session_id, transaction_id) if tid in self.transactions: del(self.transactions[tid]) # User override these def test(self, oid, data): pass def commit(self, oid, data): pass pyagentx-0.4.1/pyagentx/updater.py0000644000076500000240000000612712542500446017467 0ustar rayedstaff00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- # -------------------------------------------- import logging class NullHandler(logging.Handler): def emit(self, record): pass logger = logging.getLogger('pyagentx.updater') logger.addHandler(NullHandler()) # -------------------------------------------- import time import threading import Queue import pyagentx class Updater(threading.Thread): def agent_setup(self, queue, oid, freq): self.stop = threading.Event() self._queue = queue self._oid = oid self._freq = freq self._data = {} def run(self): start_time = 0 while True: if self.stop.is_set(): break now = time.time() if now - start_time > self._freq: logger.info('Updating : %s (%s)' % (self.__class__.__name__, self._oid)) start_time = now self._data = {} try: self.update() self._queue.put_nowait({'oid': self._oid, 'data':self._data}) except Queue.Full: logger.error('Queue full') except: logger.exception('Unhandled update exception') time.sleep(0.1) logger.info('Updater stopping') # Override this def update(self): pass def set_INTEGER(self, oid, value): logger.debug('Setting INTEGER %s = %s' % (oid, value)) self._data[oid] = {'name': oid, 'type':pyagentx.TYPE_INTEGER, 'value':value} def set_OCTETSTRING(self, oid, value): logger.debug('Setting OCTETSTRING %s = %s' % (oid, value)) self._data[oid] = {'name': oid, 'type':pyagentx.TYPE_OCTETSTRING, 'value':value} def set_OBJECTIDENTIFIER(self, oid, value): logger.debug('Setting OBJECTIDENTIFIER %s = %s' % (oid, value)) self._data[oid] = {'name': oid, 'type':pyagentx.TYPE_OBJECTIDENTIFIER, 'value':value} def set_IPADDRESS(self, oid, value): logger.debug('Setting IPADDRESS %s = %s' % (oid, value)) self._data[oid] = {'name': oid, 'type':pyagentx.TYPE_IPADDRESS, 'value':value} def set_COUNTER32(self, oid, value): logger.debug('Setting COUNTER32 %s = %s' % (oid, value)) self._data[oid] = {'name': oid, 'type':pyagentx.TYPE_COUNTER32, 'value':value} def set_GAUGE32(self, oid, value): logger.debug('Setting GAUGE32 %s = %s' % (oid, value)) self._data[oid] = {'name': oid, 'type':pyagentx.TYPE_GAUGE32, 'value':value} def set_TIMETICKS(self, oid, value): logger.debug('Setting TIMETICKS %s = %s' % (oid, value)) self._data[oid] = {'name': oid, 'type':pyagentx.TYPE_TIMETICKS, 'value':value} def set_OPAQUE(self, oid, value): logger.debug('Setting OPAQUE %s = %s' % (oid, value)) self._data[oid] = {'name': oid, 'type':pyagentx.TYPE_OPAQUE, 'value':value} def set_COUNTER64(self, oid, value): logger.debug('Setting COUNTER64 %s = %s' % (oid, value)) self._data[oid] = {'name': oid, 'type':pyagentx.TYPE_COUNTER64, 'value':value} pyagentx-0.4.1/pyagentx.egg-info/0000755000076500000240000000000012544474101017135 5ustar rayedstaff00000000000000pyagentx-0.4.1/pyagentx.egg-info/dependency_links.txt0000644000076500000240000000000112544474101023203 0ustar rayedstaff00000000000000 pyagentx-0.4.1/pyagentx.egg-info/PKG-INFO0000644000076500000240000000223312544474101020232 0ustar rayedstaff00000000000000Metadata-Version: 1.1 Name: pyagentx Version: 0.4.1 Summary: AgentX package to extend SNMP with pure Python Home-page: https://github.com/rayed/pyagentx Author: Rayed Alrashed Author-email: rayed@rayed.com License: BSD Description: PyAgentX -------------------- pyagentx is a pure Python implementation of AgentX protocol (RFC 2741), it will allow you to extend SNMP agent (snmpd) by writing AgentX subagents, without modifying your original SNMP agent. The agent can support the following commands: - snmpget - snmpwalk - snmptable - snmpset Keywords: snmp network agentx Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: License :: OSI Approved :: BSD License Classifier: Environment :: No Input/Output (Daemon) Classifier: Topic :: System :: Monitoring Classifier: Topic :: System :: Networking Classifier: Programming Language :: Python Classifier: Intended Audience :: Developers Classifier: Intended Audience :: Information Technology Classifier: Intended Audience :: System Administrators Classifier: Intended Audience :: Telecommunications Industry pyagentx-0.4.1/pyagentx.egg-info/SOURCES.txt0000644000076500000240000000037612544474101021027 0ustar rayedstaff00000000000000setup.py pyagentx/__init__.py pyagentx/agent.py pyagentx/network.py pyagentx/pdu.py pyagentx/sethandler.py pyagentx/updater.py pyagentx.egg-info/PKG-INFO pyagentx.egg-info/SOURCES.txt pyagentx.egg-info/dependency_links.txt pyagentx.egg-info/top_level.txtpyagentx-0.4.1/pyagentx.egg-info/top_level.txt0000644000076500000240000000001112544474101021657 0ustar rayedstaff00000000000000pyagentx pyagentx-0.4.1/setup.cfg0000644000076500000240000000007312544474101015425 0ustar rayedstaff00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 pyagentx-0.4.1/setup.py0000644000076500000240000000226712544474020015325 0ustar rayedstaff00000000000000from setuptools import setup setup( name = "pyagentx", version = "0.4.1", author = "Rayed Alrashed", author_email = "rayed@rayed.com", description = ("AgentX package to extend SNMP with pure Python"), license = "BSD", keywords = "snmp network agentx ", url = "https://github.com/rayed/pyagentx", packages=['pyagentx'], classifiers=[ "Development Status :: 4 - Beta", "License :: OSI Approved :: BSD License", "Environment :: No Input/Output (Daemon)", "Topic :: System :: Monitoring", "Topic :: System :: Networking", "Programming Language :: Python", "Intended Audience :: Developers", "Intended Audience :: Information Technology", "Intended Audience :: System Administrators", "Intended Audience :: Telecommunications Industry", ], long_description='''\ PyAgentX -------------------- pyagentx is a pure Python implementation of AgentX protocol (RFC 2741), it will allow you to extend SNMP agent (snmpd) by writing AgentX subagents, without modifying your original SNMP agent. The agent can support the following commands: - snmpget - snmpwalk - snmptable - snmpset ''', )