Skip to content
This repository has been archived by the owner on Jul 10, 2024. It is now read-only.

Latest commit

 

History

History
183 lines (154 loc) · 9.06 KB

README.md

File metadata and controls

183 lines (154 loc) · 9.06 KB

netsnmptable

A Python C Extension package to query SNMP tables and table subsets based on the Net-SNMP libraries.

Goals

The project aims to bring SNMP table query functionality for Python.

  • Based on the native Net-SNMP libraries
  • High-level Python interface
  • Resulting data structures behave like tables, in the sense that a cell is addressable by row and column
  • Table structure can be defined from MIB
  • Indexes are selectable to some extent, to save bandwidth and memory when you want to only retrieve a small portion of a large table
  • Include a unit test solution that does not depend on external services
  • Focus on table functions only, don't re-implement other manager functionality
  • Eventually find a parent-project that will integrate this package. Implementation concepts and coding conventions from the parent project can be adapted.

Current state and future

The API is currently not yet stable. Implementation works and is tested on following targets

  • Linux x86_64
  • Debian Wheezy, python 2.7.3, netsnmp 5.4.3
  • Ubuntu Wily, python 2.7.9, netsnmp 5.7.3

IMO it would be good to eventually integrate the table functions into a more complete, all-in-one Python SNMP Client package. If you are the maintainer of such a package and like the idea, please let me know.

I currently do monkey patching of the original Net-SNMP Python Bindings to fake that integration, but are looking forward for better options.

How to build and install

Prerequisites:

  • C compiler toolchain
  • Python 2
  • Net-SNMP libraries and headers

Download and extract the source package, then

~/netsnmptable$ python setup.py build
~/netsnmptable$ sudo python setup.py install

License

This software is released under the LGPLv3 license.

Some re-used code is copyrighted. See the LICENSE file for full license text and the original copyright notices.

Examples

Here are some examples how to use netsnmptable.

Example 1: Print out the Host Resources Storage Table###

import netsnmp
import netsnmptable

# create a table object
session = netsnmp.Session(Version=2, DestHost='localhost', Community='public')
table = session.table_from_mib('HOST-RESOURCES-MIB::hrStorageTable')

# go and get the table...
tbldict = table.get_entries()
if (netsnmp_session.ErrorNum):
    print("Can't query HOST-RESOURCES-MIB:hrStorageTable.")
    exit(-1)

print("{:10s} {:25s} {:10s} {:10s} {:10s}".format("Index", "Description", "Units", "Size", "Used"))
row_keys = sorted(list(tbldict.keys()))
for row_key in row_keys:
    row = tbldict[row_key]
    cell_list = [element.val if element else "" for element in
                 [row.get('hrStorageIndex'), row.get('hrStorageDescr'),
                  row.get('hrStorageAllocationUnits'), row.get('hrStorageSize'),
                  row.get('hrStorageUsed')]]
    print("{:10s} {:25s} {:10s} {:10s} {:10s}".format(*cell_list))

Results in

Index      Description               Units      Size       Used      
1          Physical memory           1024       2054128    233540    
3          Virtual memory            1024       3099628    361064    
6          Memory buffers            1024       2054128    14564     
7          Cached memory             1024       82232      82232     
8          Shared memory             1024       0                    
10         Swap space                1024       1045500    127524    
31         /dev                      4096       2560       0         
32         /                         4096       10063200   2495552   
33         /sys/fs/fuse/connections  4096       0          0         
34         /run/vmblock-fuse         512        0          0         
35         /media/sources            4096       121833215  92355036  
36         /media/sandboxes          4096       121833215  92355036  
37         /media/cdrom0             2048       32876      32876    

Example 2: Query a multi-indexed table

Tables with more than one index are no problem. The row key tuple just gets more elements.

Let's setup following table in snmpd.conf:

table MYTABLETEST::testTable 
#                               idx1          idx2            aValue  anotherValue
add_row MYTABLETEST::testTable "OuterIdx_1"   "InnerIdx_1"     1       2
add_row MYTABLETEST::testTable "OuterIdx_1"   "InnerIdx_2"     3       4
add_row MYTABLETEST::testTable "OuterIdx_2"   "InnerIdx_1"     5       6
add_row MYTABLETEST::testTable "OuterIdx_2"   "InnerIdx_2"     7       8
add_row MYTABLETEST::testTable "OuterIdx_3"   "InnerIdx_1"     9      10
add_row MYTABLETEST::testTable "OuterIdx_3"   "InnerIdx_2"    11      12

Now query it with

import netsnmp
import netsnmptable
import pprint
from types import MethodType

def varbind_to_repr(self):
    return self.type + ":" + self.val
netsnmp.Varbind.__repr__ = MethodType(varbind_to_repr, None, netsnmp.Varbind)

session = netsnmp.Session(Version=2, DestHost='localhost', Community='public')
table = session.table_from_mib('MYTABLETEST::testTable')
tbldict = table.get_entries()
pprint.pprint(tbldict)

This gives

{('OuterIdx_1', 'InnerIdx_1'): {'aValue': INTEGER32:1,
                                'anotherValue': INTEGER32:2},
 ('OuterIdx_1', 'InnerIdx_2'): {'aValue': INTEGER32:3,
                                'anotherValue': INTEGER32:4},
 ('OuterIdx_2', 'InnerIdx_1'): {'aValue': INTEGER32:5,
                                'anotherValue': INTEGER32:6},
 ('OuterIdx_2', 'InnerIdx_2'): {'aValue': INTEGER32:7,
                                'anotherValue': INTEGER32:8},
 ('OuterIdx_3', 'InnerIdx_1'): {'aValue': INTEGER32:9,
                                'anotherValue': INTEGER32:10},
 ('OuterIdx_3', 'InnerIdx_2'): {'aValue': INTEGER32:11,
                                'anotherValue': INTEGER32:12}}

Example 3: Query a multi-indexed table with only selected index values

Say we want to fetch from the same table, but only entries for "OuterIdx_2".

session = netsnmp.Session(Version=2, DestHost='localhost', Community='public')
table = session.table_from_mib('MYTABLETEST::testTable')
tbldict = table.get_entries(iid = netsnmptable.str_to_varlen_iid("OuterIdx_2"))
pprint.pprint(tbldict)

Results in

{('OuterIdx_2', 'InnerIdx_1'): {'aValue': INTEGER32:5,
                                'anotherValue': INTEGER32:6},
 ('OuterIdx_2', 'InnerIdx_2'): {'aValue': INTEGER32:7,
                                'anotherValue': INTEGER32:8}}

Development Resources

Credits

Thanks to Pieter Hollants [email protected] for python-netsnmpagent. The tests.testagent package is heavily based on it.

Related work

Other people also tackle the hassle of dealing with SNMP in Python and found interesting approaches. Below is an incomplete and unordered list.

Libraries

  • easysnmp - "Pythonic SNMP library based on the official Net-SNMP bindings". Very nice approach to improve the original by sophisticated tests and more pythonic interface and design.
  • PySNMP - Pure Python SNMP library, to act in Agent/Manager/Proxy role.
  • snimpy - Library on top of PySNMP. "Snimpy is aimed at being the more Pythonic possible. You should forget that you are doing SNMP requests."
  • Net::SNMP - Object oriented Perl interface to Net-SNMP with table handling.
  • Multi-core SNMP Works around lacking asynchronous support in original Python Bindings by using a process pool.

Table handling

  • HNMP - PySNMP based package, to "ease the pain of retrieving and processing data from SNMP-capable devices". Let's you define table structures manually, rather than parsing them from MIB, because "Depending on MIB files would make the calling piece of code harder to distribute".
  • A Munin Plugin, get's table via netsnmp.snmpwalk and converts it to a dictionary.