Rumah >pembangunan bahagian belakang >Tutorial Python >使用IPython下的Net-SNMP来管理类UNIX系统的教程
引言
对于简单网络管理协议 (SNMP),大多数系统管理员都具有一定的使用经验,或者至少听说过它。如果您正在一个数据中心工作,那么您每天都可能采用某种方式与 SNMP 进行交互。有许多给人印象深刻的、同等规模的网络管理系统 (NMS) 或者网络监视系统使用了 SNMP 监视,但本文并不打算介绍这些系统。本文主要涉及的是通过 Python? 语言来研究 SNMP,并亲自编写相关的代码。
一位朋友最近告诉我,有时候遇到的情况就像:只是希望沿着街道一路走到奶奶家,而不需要乘坐像 Saturn V 火箭一样飞快。有许多任务,如果利用或者配置大规模的 NMS,就好像是一个 Saturn V 火箭,在填满液氧罐之前,先尝试一下使用 Python,那么您将得到更好的服务。了解如何编写灵活的 Python 代码与 SNMP 进行交互,这可能是系统管理员可以获得的、最有趣且最高效的技能之一。尽管 SNMP 的设置和使用非常复杂,但本文中所讨论的内容将使它变得非常有趣。
安装和配置 Net-SNMP
要学习本文中的内容,您需要在您的 *nix 计算机中安装最新的 Python(即 Python 2.3 或者更高版本)。在撰写本文时,Python 2.5.1 是 Python 的最新版本。您还需要 IPython,以便以交互的方式使用带 Python 绑定的 Net-SNMP 库。Net-SNMP 团队对各种操作系统中的支持进行了详细测试,具体包括 AIX?、HP-UX?、GNU/Linux? 分发版(如 Red Hat)、Windows?,甚至 OS X?。
安装 IPython 是一项非常简单的工作。一个很好的选择是使用 Easy Install 来管理 Python 包。通过运行 ez_setup.py 脚本,您可以很容易地安装任何 Python 包。例如,您只需要键入以下命令:
easy_install ipython
其他可选的安装方式包括,使用您最喜欢的包管理系统、或者只需下载 IPython 并键入以下命令:
python setup.py install
请注意,干线 (trunk) 指的是版本控制系统中的根路径,其中保存了最近的代码副本。此外,干线还常常表示一个子版本和版本控制系统。有关更详细的内容,请参见参考资料部分中的子版本链接。
要学习本文中的内容,您需要确保您的客户端计算机、或者运行所有代码的计算机都安装了 NET-SNMP Version 5.4.x 或者更高版本,因为从这个源代码版本开始,包括了 Python 绑定。在大多数情况下,绑定的安装需要对源文件进行编译;然而,也可以使用 Red Hat Package Managers (RPM)。如果你有兴趣和时间,那么可以从 Net-SNMP Web 站点查看一下它的最新版本。
有许多编译选项可供使用,但主要的任务是对 NET-SNMP 进行正确编译,然后运行 Python 目录中的、独立的 Python 安装程序。另一个需要注意的问题是,当您进行编译并运行 ./configure 的时候,它将运行本地计算机(正在编译代理的计算机)的配置脚本。您不应该使用该配置脚本,对于本文而言,您只需要创建一个简单的配置脚本。
对 /etc/snmp/snmpd.conf 中所存储的配置文件进行备份,并构建下面这个非常基本的配置:
syslocation "My Local Machine" syscontact me@localhost.com rocommunity public
保存它,并重新启动 snmpd 守护进程。在大多数 *nix 系统中,可以使用 /etc/init.d/snmpd restart 来完成这项工作。
除非在不得已的情况下,否则最好不要对处于活动开发阶段的版本进行编译,因为这样做,您将需要自己动手修复有问题的代码。在 CentOS 5 或者 Red Hat Enterprise Linux 5 (RHEL 5) 中,您可以下载最新的、稳定的源文件 RPM(在撰写本文之时,是 5.4.1 版本)。请注意,您还需要使用 Python 源文件来构建绑定。因此,如果您正在使用一台基于 Red Hat 的计算机,那么请确保为特定的 *nix 操作系统安装了 python-dev(或者其等价物)和 Python Header 文件。如果您在从源文件构建 RPM 的过程中,需要任何帮助的话,请参考官方的 Red Hat 文档。从源文件构建包可能是一个非常复杂的主题,并且已经超出了本文的范围。如果您在使用 Python 绑定的时候遇到了麻烦,那么您应该在 Net-SNMP 邮件列表中请求帮助。
对代码进行分析
还等什么呢?假设您已经安装了 Python 绑定和 IPython。现在,您已经做好了使用 IPython 的准备,并开始相关的工作。尽管在某些时候,您可能还需要浏览 IPython 文档。Jeff Rush 是当前的 Python Advocacy Coordinator,他为 IPython 提供了一些非常好的屏幕录像内容。好的,让我们开始进行编码。
让我们进行一次简单的查询,以便通过使用计算机的对象标识符 (OID) 值 sysDescr 来标识一台计算机。通过键入 ipython 启动 IPython,然后执行这个交互式会话:
清单 1. IPython 示例
In [1]: import netsnmp In [2]: oid = netsnmp.Varbind('sysDescr') In [3]: result = netsnmp.snmpwalk(oid, ...: Version = 2, ...: DestHost="localhost", ...: Community="public") In [4]: result = netsnmp.snmpwalk(oid, Version = 2, DestHost="localhost", Community="public") In [16]: result Out[16]: ('Linux localhost 2.6.18-8.1.14.el5 #1 SMP Thu Sep 27 18:58:54 EDT 2007 i686',)
请注意,您所得到的 result 值与这里所显示的 result 值是不同的。如果您已经遵循了上面清单 1 中所显示的配置,那么所有其他的内容都应该是可用的。如果您对 SNMP 比较熟悉,那么您可能马上就能够明白这些内容的实际作用。
使用 IPython 来测试 SNMP 代码片段的好处之一是,它就好像是一个普通的 Shell,并且许多基本的、交互式 Shell 的概念“都可以起作用”,但需要说明的是,它们是以 python 方式进行工作的。编写 SNMP 代码可能是一项非常单调乏味的活动,但是通过 IPython 来使用 Net-SNMP 库将使其变得非常有趣。
正如您所看到的,要将结果转换为 Python 数据类型,这项任务是非常简单的。这就是为什么 IPython 和 Net-SNMP 可以很好地在一起工作的原因。现在,对于编写自定义脚本来说,只需要以交互方式分析 OID 的组合以进行查询。在理想的情况下,需要运行一个大规模的、易于配置的 NMS 设置脚本,自动地将新的计算机集成到网络中。
当然,并不存在这种理想的情况,您需要了解如何将一些好的 SNMP 代码组合到一起,对于一名系统管理员来说,这是非常有用的。下面给出一个示例情况,假设您刚刚将一个高速 DDR 转换为正在运行 Ubuntu Linux 的 2 TB RAID 0 服务器,因为您必须在一个小时的时间内解决问题,所以您不得不这样做。
现在,您遇到了很大的麻烦,并且您只有几分钟的时间来监视具体的问题,以了解是否需要开始发送简历、或者是否应该开始准备讲话并请求升职。让我们使用 IPython 中的编辑功能来编写脚本,并将它保存到文件中,然后在不离开 IPython 的情况下,在一个会话中运行它: ed snmpinput.py
清单 2. IPython 模块的创建
import netsnmp class snmpSessionBaseClass(object): """A Base Class For a SNMP Session""" def __init__(self, oid="sysDescr", Version=2, DestHost="localhost", Community="public"): self.oid = oid self.Version = Version self.DestHost = DestHost self.Community = Community def query(self): """Creates SNMP query session""" try: result = netsnmp.snmpwalk(self.oid, Version = self.Version, DestHost = self.DestHost, Community = self.Community) except: import sys print sys.exc_info() result = None return result
对 IPython 进行自定义以使用正确的编辑器
通过编辑 $HOME/.ipython/ipythonrc,您可以对 Ipython 进行自定义。首先需要进行自定义的内容之一是 %edit 命令,可以通过键入 ed 来调用该命令。在缺省情况下,它被设置为使用 vi,但是您可以更改它,以便使用其他编辑器,包括 Emacs。关于如何更改您的环境,本文给出了相应的指导。您还可以使用下面的命令来启动 Ipython,以便以硬编码的形式指定使用某个特定的编辑器: ipython -editor=vim。
继续执行,将下面的代码剪切并粘贴到您刚刚创建的文件中。当保存这个文件时,IPython 将自动地运行它,并将该类放置到您环境中相应的模块中。如果您键入 who,那么您将看到与以下所示类似的内容:
In [2]: who netsnmp snmpSessionBaseClass
这项操作的功能非常强大,因为您可以获得使用您最喜欢的文本编辑器(也许是 Vim 或者 Emacs)的所有优点,然后在交互的 IPython Shell 会话中立即使用这些代码。请注意,如果您已经编写了一个模块,那么您还可以简单地键入并运行它,以获得相同的结果。执行和运行 IPython 中的模块,这就相当于运行其中的代码,并将其放入到 IPython 环境中。
以迭代的方式进行编码
现在通过使用 IPython,可以将 Python Shell、UNIX Shell 和您最喜欢的文本编辑器的最佳特性组合到一起。在与像 SNMP 库这样非常复杂的对象进行交互时,您需要使用可以获得的所有帮助,而在这个示例中,真正地展示了 IPython 的强大功能。
您可以动态地编写一些模块,并且您可以在稍后对其进行测试和使用。IPython 可以与任何编程风格很好地融合在一起,包括测试驱动的开发 (TDD) 或者测试增强的开发 (TED)。为了证明这种便利性,让我们转到您刚刚编写的模块。
既然已经有一个面向对象的 SNMP 接口,那么您就可以开始向本地计算机进行询问:
清单 3. IPython 迭代式编码
In [1]: run snmpinput In [2]: who netsnmp snmpSessionBaseClass In [3]: s = snmpSessionBaseClass() In [4]: s.query() Out[4]: ('Linux localhost 2.6.18-8.1.14.el5 #1 SMP Thu Sep 27 18:58:54 EDT 2007 i686',) In [5]: result = s.query() In [6]: len(result) Out[6]: 1
通过使用这个模块获得相关的结果,这是非常容易的,但是您基本上只是在运行一个硬编码脚本,因此需要更改 OID 对象的值,以遍历系统子树:
清单 4. 更改 OID 对象的值
In [7]: s.oid Out[7]: 'sysDescr' In [8]: s.oid = ".1.3.6.1.2.1.1" In [9]: result = s.query() In [10]: print result ('Linux localhost 2.6.18-8.1.14.el5 #1 SMP Thu Sep 27 18:58:54 EDT 2007 i686', '.1.3.6.1.4.1.8072.3.2.10', '121219', 'me@localhost.com', 'localhost', '"My Local Machine"', '0', '.1.3.6.1.6.3.10.3.1.1', '.1.3.6.1.6.3.11.3.1.1', '.1.3.6.1.6.3.15.2.1.1', '.1.3.6.1.6.3.1', '.1.3.6.1.2.1.49', '.1.3.6.1.2.1.4', '.1.3.6.1.2.1.50', '.1.3.6.1.6.3.16.2.2.1', 'The SNMP Management Architecture MIB.', 'The MIB for Message Processing and Dispatching.', 'The management information definitions for the SNMP User-based Security Model.', 'The MIB module for SNMPv2 entities', 'The MIB module for managing TCP implementations', 'The MIB module for managing IP and ICMP implementations', 'The MIB module for managing UDP implementations', 'View-based Access Control Model for SNMP.', '0', '0', '0', '0', '0', '0', '0', '0')
正如您可以看到的,要使用这个模块并开始分析整个网络(一次一台计算机),这项任务是非常容易的。请仔细地进行分析,并确定需要在网络中进行查询的内容。这是 IPython 的另一个有趣的特性,有必要对其进行深入研究。IPython 具有一个令人难以置信的特性,即允许您将 Python 代码片段作为后台进程来运行。幸运的是,进行这项操作非常简单。让我们再次运行相同的查询,但这一次将其作为后台进程运行(请参见清单 5)。
清单 5. IPython 迭代式编码示例——后台进程
In [11]: bg s.query() Starting job # 0 in a separate thread. In [12]: jobs[0].status Out[12]: 'Completed' In [16]: jobs[0].result Out[16]: ('Linux localhost 2.6.18-8.1.14.el5 #1 SMP Thu Sep 27 18:58:54 EDT 2007 i686', '.1.3.6.1.4.1.8072.3.2.10', '121219', 'me@localhost.com', 'localhost', '"My Local Machine"', '0', '.1.3.6.1.6.3.10.3.1.1', '.1.3.6.1.6.3.11.3.1.1', '.1.3.6.1.6.3.15.2.1.1', '.1.3.6.1.6.3.1', '.1.3.6.1.2.1.49', '.1.3.6.1.2.1.4', '.1.3.6.1.2.1.50', '.1.3.6.1.6.3.16.2.2.1', 'The SNMP Management Architecture MIB.', 'The MIB for Message Processing and Dispatching.', 'The management information definitions for the SNMP User-based Security Model.', 'The MIB module for SNMPv2 entities', 'The MIB module for managing TCP implementations', 'The MIB module for managing IP and ICMP implementations', 'The MIB module for managing UDP implementations', 'View-based Access Control Model for SNMP.', '0', '0', '0', '0', '0', '0', '0', '0')
令人激动的是,IPython 中的后台线程是一种非常有价值的功能,但它只能与支持异步线程的库一起工作。不幸的是,Net-SNMP 是同步的。如果您对这一点感兴趣,那么可以通过将 s.oid 值更改为 .iso 来进行测试。在查询完成之前,您应该可以注意到,IPython 解释器发生了“阻塞”或者“挂起”。尽管只是一个警告,但对整个 .iso 树的 SNMP 遍历可能会花费较长的时间,因此您可能会接受我的观点。
当然,还有另一种解决方案。您可以使用 Python 所提供的众多处理库中的其中一个,为这个阻塞的进程派生新的进程。Python Cheese Shop 提供了一些第三方库。如果您正在使用 easy_install,那么要安装一个包(如 Parallel Python)并使用 Net-SNMP 来测试这个库,将是相当简单的,因此这将由您来决定。
easy_install http://www.parallelpython.com/downloads/pp/pp-1.5.zip
这里要展示的最后一个特性是,在 IPython Shell 中运行单元测试。在对模块进行更改时,需要频繁地运行单元测试,而这也是非常容易的。您需要添加一个标记以运行 run -e,这样一来,您就可以在 IPython Shell 中避免回溯到单元测试模块。您可以在本文所附带的源文件中下载这个单元测试。
请注意,IPython 0.8.2 还有一个新的文档测试特性,它允许您在 IPython 中生成文档测试。文档测试是 Python 的一个很好的特性,因为与其他特性一起,它提供了一种为 API 创建可测试文档的方法。下面给出了一个示例,以说明如何在 IPython 中为我们的模块运行 doctest:
清单 6.以 doctest 模式运行 IPython
In [5]: %doctest_mode *** Pasting of code with ">>>" or "..." has been enabled. Exception reporting mode: Plain Doctest mode is: ON >>> from snmpinput import snmpSessionBaseClass >>> s = snmpSessionBaseClass() >>> s.query() ('Linux devmws2.racemi.com 2.6.9-55.0.2.EL #1 Tue Jun 26 14:08:18 EDT 2007 i686',)
因为 doctest 模式将不加分析地执行 Python 语句,所以您必须小心,不要在 doctest 中使用可能更改的值,就像上面所给出的值。如果您在模块的 docstring 中粘贴了数行代码,那么您可以通过使用下面的方法来测试您的 API 文档:
def _test(): import doctest doctest.testmod() if __name__ == "__main__": _test()
总结
在本文中,您已经了解了协同使用 Net-SNMP 和 IPython 将成为一种功能强大的组合。本文介绍了下面几个主要概念:
SNMP 非常复杂,它几乎使人们不敢想象编写任何有意义的代码,但是,我们希望本文所介绍的技术能够激发某些新的观点。如果您很好奇,想知道 SNMP 的 Python 实现究竟到了什么程度,那么可以研究一下 Zenoss,下载一个虚拟机,并对它进行测试。还有一个 API,您可以利用它来编写脚本,因此您可以将这里所学到的内容和全面的 Python NMS 相结合。当然,也适用于任何其他 NMS。