構建異步Net-SNMP 引擎

為Net-SNMP 異步生成Python 綁定。默認情況下,Net-SNMP 將阻塞每一個Python 調用。使用多進程庫可以非常簡單地將Net-SNMP 庫轉換為完全異步的操作。

在開始之前,需要檢查是否安裝了一些必備的內容,以便使用Python 2.6 多進程庫和Net-SNMP 綁定:

1. 下載Python 2.6並針對所使用的操作系統進行編譯:Python 2.6下載
2. 調整shell路徑,這樣在輸入python時就會啟動Python 2.6。例如,如果將Python編譯到/usr/local/bin/, 您就需要預先處理$PATH變量,從而確保它位於一個較舊的Python版本之前。
3. 下載並安裝設置工具:設置工具
4. 下載Net-SNMP,除了使用其他操作系統所需的標記(參見相應的README文件)外,另外使用一個“--with-python-modules”標記進行配置。 ./configure --with-python-modules

按如下所示編譯Net-SNMP:

-------------------------------------------------- -------
            Net-SNMP configuration summary:
-------------------------------------------------- -------

  SNMP Versions Supported: 1 2c 3
  Net-SNMP Version: 5.4.2.1
  Building for: darwin9
  Network transport support: Callback Unix TCP UDP
  SNMPv3 Security Modules: usm
  Agent MIB code: default_modules => snmpv3mibs mibII ucd_snmp notification 
notification-log-mib target agent_mibs agentx disman/event disman/schedule utilities
  Embedded Perl support: enabled
  SNMP Perl modules: building -- embeddable
  SNMP Python modules: building for /usr/local/bin//python
  Authentication support: MD5 SHA1
  Encryption support: DES AES
]]
Net-SNMP 的多進程包裝器

'''
Created on 2012/8/1

@author: 10001045
'''
#!/usr/bin/env python2.7
"""
This is a multiprocessing wrapper for Net-SNMP.
This makes a synchronous API asynchronous by combining
it with Python2.7
"""

import netsnmp
from multiprocessing import Process, Queue, current_process

class HostRecord():
    """This creates a host record"""
    def __init__(self,
                 hostname = None,
                 query = None):
        self.hostname = hostname
        self.query = query
        
class SnmpSession():
    """A SNMP Session"""
    def __init__(self,
                oid = "sysDescr",
                Version = 2,
                DestHost = "localhost",
                Community = "public",
                Verbose = True,
                ):
        self.oid = oid
        self.Version = Version
        self.DestHost = DestHost
        self.Community = Community
        self.Verbose = Verbose
        self.var = netsnmp.Varbind(oid, 0)
        self.hostrec = HostRecord()
        self.hostrec.hostname = self.DestHost
        
    def query(self):
        """ creates SNMP query
            Fills out a Host Object and returns result
        """
        
        try:
            result = netsnmp.snmpget(self.var,
                                     Version = self.Version,
                                     DestHost = self.DestHost,
                                     Community = self.Community)
            self.hostrec.query = result
        except Exception, err:
            if self.Verbose:
                print err
            self.hostrec.query = None
        finally:
            return self.hostrec

def make_query(host):
    """This does the actual snmp query
    This is a bit fancy as it accepts both instances
    of SnmpSession and host/ip addresses. This
    allows a user to customize mass queries with
    subsets of different hostnames and community strings
    """
    if isinstance(host,SnmpSession):
        return host.query()
    else:
        s = SnmpSession(DestHost=host)
        return s.query()
    
# Function run by worker processes
def worker(input, output):
    for func in iter(input.get, 'STOP'):
        result = make_query(func)
        output.put(result)
        
def main():
    """Runs everything"""
    #clients
    hosts = ["localhost", "localhost"]
    NUMBER_OF_PROCESSES = len(hosts)
    
    # Create queues
    task_queue = Queue()
    done_queue = Queue()
    
    #submit tasks
    for host in hosts:
        task_queue.put(host)
        
     #Start worker processes
    for i in range(NUMBER_OF_PROCESSES):
        Process(target=worker, args=(task_queue, done_queue)).start()
        
    # Get and print results
    print 'Unordered results:'
    for i in range(len(hosts)):
        print '\t', done_queue.get().query
        
     # Tell child processes to stop
    for i in range(NUMBER_OF_PROCESSES):
        task_queue.put('STOP')
        print "Stopping Process #%s" % i
        
if __name__ == "__main__":
    main()
這裡有兩個類,一個HostRecord 類和一個SnmpSession 類。SnmpSession 類包含一個使用Net-SNMP 的SNMP 庫實際執行查詢的方法。由於調用一般都會進行阻塞,因此需要導入多進程庫並使用Process 運行它。此外,傳入一個task_queue 和一個done_queue,這樣可以同步並保護進出進程池的數據。如果對線程比較熟悉的話,將會注意到這種方式非常類似於線程API 使用的方法。

需要特別關註一下主函數中#clients部分的主機列表。注意,可以對50或100台或更多主機運行異步SNMP查詢,具體取決於當前使用的硬件。NUMBER_OF_PROCESSES變量的設置非常簡單,只是被設置為主機列表中的主機數。最終,最後兩個部分在處理過程中從隊列獲取結果,然後將一個“STOP”消息放到隊列中,表示可以終止進程

如果在對Net-SNMP 進行監聽的OS X 機器上運行代碼,那麼將會得到如下所示的非阻塞輸出:


mac% time python multisnmp.py
Unordered results:
     ('Darwin mac.local 9.6.0 Darwin Kernel Version 9.6.0: Mon Nov 24 17:37:00 PST 2008;
root:xnu-1228.9.59~1/RELEASE_I386 i386',)
     ('Darwin mac.local 9.6.0 Darwin Kernel Version 9.6.0: Mon Nov 24 17:37:00 PST 2008;
root:xnu-1228.9.59~1/RELEASE_I386 i386',)
Stopping Process #0
Stopping Process #1
python multisnmp.py 0.18s user 0.08s system 107% cpu 0.236 total
配置O​​S X 的SNMPD
如果希望配置OS X 的SNMP Daemon 以針對本文進行測試,那麼需要執行下面的操作。首先,在shell 中使用三個命令重寫配置文件:

 $ sudo cp /etc/snmp/snmpd.conf /etc/snmp/snmpd.conf.bak.testing
 $ sudo echo "rocommunity public" > /etc/snmp/snmpd.conf 
 $ sudo snmpd
         

留言

這個網誌中的熱門文章

Json概述以及python對json的相關操作

Docker容器日誌查看與清理

利用 Keepalived 提供 VIP