SNMP,即Simple Network Management Protocol,是SDN的必要工具,也是控制软件中的设备的最佳选项。即使不考虑这一点,SNMP的主要目的是应用程序访问。毫无疑问,所有监控系统都使用SNMP来监视和控制服务器和网络设备。在脚本中具备SNMP的强大功能将会非常有用。因此,在本教程中,我们将讨论如何在Python编程语言中使用SNMP。

但在开始之前,让我们先了解一下SNMP。

了解SNMP

SNMP(Simple Network Management Protocol),也称为简单网络管理协议,是管理服务器和远程设备(代理)之间通信的标准方式。SNMP的目标是使管理者能够了解(甚至更改)代理上的数据。例如,管理者可以检查哪些接口处于活动状态,哪些接口已停用,或更改远程设备的主机名。

349.png

我们的脚本能够在管理站上运行Python程序,以控制执行SNMP代理的远程设备。

SNMP代理准备了管理者可以在特殊表(MIB)中读取或更改的大部分信息。MIB是一种树状结构,其中树中的每个节点都有一个编号。例如,1.3.6.1.2.1.1代表系统的描述。如果您想知道这些数字是从哪里来的,那就是整个树结构!每个数字都关联一个名称。因此,我们可以将其翻译成更具说明性的iso.org.dod.internet.mgmt.mib-2.system.sysDescr

现在,让我们使用Python的PySNMP模块来了解如何在Python编程语言中使用SNMP。

了解PySNMP模块

PySNMP是Python的一个开源模块。与telnet或HTTP不同,Python本身不原生实现SNMP。毕竟,只有网络和系统工程师才需要在工厂中雇佣Python开发人员。PySNMP在覆盖Python本机功能的不足方面做得很好。总的来说,PySNMP模块允许我们使用任何版本的SNMP,无论是作为代理还是管理者。创建代理意味着我们正在构建一个应用程序或设备。然而,我们只会讨论如何使用PySNMP来管理远程设备。

此外,我们将了解PySNMP在Python中的不同功能。本教程的主要目标是创建一个可以为我们简化事情的快速Python程序。在程序中,我们将包含我们需要的所有SNMP操作。

那么,让我们开始吧。

准备环境

首先,我们需要安装PySNMP模块。我们可以使用pip安装程序来安装所需的模块,使用以下命令:

命令:

$ pip install pysnmp 

该模块将根据Python和pip的版本安装在系统中。

验证安装

为了验证模块是否已正确安装在系统中,我们可以尝试导入模块并执行程序。

安装完成后,创建一个新的Python文件,然后在文件中键入以下语法。

示例:

# importing the required module  
import pysnmp 

现在,保存文件并在命令提示符中使用以下命令运行文件。

命令:

$ python <file-name>.py  

如果程序运行而没有引发任何导入错误,那么模块已正确安装。否则,建议重新安装模块并查看其官方文档。

了解Python SNMP Get操作

SNMP的Get操作允许我们检索MIB中单个对象的值。我们还可以使用它来获取单个对象的列表。我们可以编写如下的get()函数:

示例:

# importing the required module  
from pysnmp import hlapi  
  
# defining the get() function  
def get(  
    target,  
    oids,  
    credentials,  
    port = 161,  
    engine = hlapi.SnmpEngine(),  
    context = hlapi.ContextData()  
    ):  
    handler = hlapi.getCmd(  
        engine,  
        credentials,  
        hlapi.UdpTransportTarget((target, port)),  
        context,  
        *construct_object_types(oids)  
    )  
    return fetch(handler, 1)[0]  

解释:

在上面的代码片段中,我们可以看到PySNMP的高级API的使用。我们定义了一个名为get()的简单函数,首先需要目标(IP或远程设备名称)。然后,它需要我们需要获取的对象ID(oids)的列表以及会话身份验证的一组凭据。如果需要,我们还可以指定不同的UDP端口,使用现有的SNMP引擎或自定义上下文。我们可能需要在相同设备上的所有操作上使用相同的引擎,这可以节省资源。但是,对于简单的代码段,这不是必需的,所以我们可以忽略引擎和上下文。

该函数生成了SNMP会话的处理程序,并从中获取数据。为了执行此操作,它依赖于我们必须创建的两种方法:construct_object_typesfetch

构建对象类型

正如我们之前讨论过的,更多的功能意味着更多的复杂性。因此,hlapi.getCmd()函数需要一些特殊的hlapi.ObjectType对象,而不是简单的字符串OID列表。因此,construct_object_type函数是根据PySNMP的需求创建的。如果没有时间,我们可以将其简单地复制并粘贴到代码中。但这应该是一个非常简单的函数,让我们来看看:

示例:

def construct_object_types(listOfOids):  
    objectTypes = []  
    for oid in listOfOids:  
        objectTypes.append(hlapi.ObjectType(hlapi.ObjectIdentity(oid)))  
    return objectTypes  

解释:

在上面的代码片段中,我们定义了一个函数,该函数返回一个列表,可以通过在get()方法中使用与操作数一样的方式来扩展它。

获取数据

fetch()函数是Python SMP教程的杰作。总的来说,我们编写它以便在其他基于PySNMP的函数上可以重复使用它,例如get-bulk。它只是在处理程序上多次循环,次数取决于计数变量。如果出现任何错误,流程将停止,并返回RuntimeError消息。在其他情况下,它会将数据存储在字典列表中。

示例:

def fetch(handler, count):  
    res = []  
    for i in range(count):  
        try:  
            error_indication, error_status, error_index, var_binds = next(handler)  
            if not error_indication and not error_status:  
                items = {}  
                for var_bind in var_binds:  
                    items[str(var_bind[0])] = cast(var_bind[1])  
                res.append(items)  
            else:  
                raise RuntimeError('Got SNMP error: {0}'.format(error_indication))  
        except StopIteration:  
            break  
    return res  

解释:

在上面的代码片段中,我们构建了try-except方法以停止特定原因的迭代。如果用户指定的计数高于我们实际拥有的对象数量,我们只需停止并返回到目前为止获取的内容。这是构建的目的。

为什么需要返回一个字典列表呢?在每个get操作中,我们可以获取多个对象ID。因此,每个字典将包含对象ID作为键,MIB中OID的值作为该键的值。在需要一次获取多个OID的情况下,我们将返回包含多个键的字典。但是列表有什么用呢?使用get操作,我们只能一次检索数据。但是,正如我们将在get-bulk中看到的那样,我们可能需要在不同实例上多次获取相同的数据。为了更好地理解,让我们考虑一个示例。假设我们需要检查所有接口上的错误:信息总是错误,但我们有不同的实例(每个接口一个)。我们可以使用一个列表来表示,其中每个数据元素都是表示一个实例的字典。

注意: fetch()函数依赖于另一个我们必须创建的函数:cast()。此函数将从PySNMP接收的数据转换为整数、浮点数或字符串。

让我们看一下以下示例来了解:

示例:

def cast(val):  
    try:  
        return int(val)  
    except (ValueError, TypeError):  
        try:  
            return float(val)  
        except (ValueError, TypeError):  
            try:  
                return str(val)  
            except (ValueError, TypeError):  
                pass  
    return val  

解释:

在上面的代码片段中,我们定义了一个函数,该函数使用try-except方法检查是否引发任何错误。

提供凭据

PySNMP 库的身份验证系统强大且非常直观。没有必要在其上再写一层额外的代码,所以我们可以直接使用它。get() 函数以及其他函数都在凭据变量中有一个特殊的身份验证对象。如果使用 SNMPv2c 或 SNMPv3,这个对象会有所不同。

对于 SNMPv2c(或更低版本),我们需要指定社区。我们可以使用以下的 CommunityData 对象来实现:

语法:

hlapi.CommunityData('javatiku')  

而 SNMPv3 较为复杂。这是因为它使用一个用户带有两个密码和两个协议:一个用于身份验证,另一个用于加密。因此,我们需要指定用户名、身份验证密码、身份验证协议、加密密码和加密协议。我们可以使用 UsmUserData 类来实现。

让我们通过以下示例更好地理解。

示例:

hlapi.UsmUserData(  
    'testuser',  
    authKey = 'authenticationkey',  
    privKey = 'encryptionkey',  
    authProtocol = hlapi.usmHMACSHAAuthProtocol,  
    privProtocol = hlapi.usmAesCfb128Protocol  
    )  

解释:

在上面的代码片段中,我们使用了 UsmUserData 类并输入了所需的详细信息。这比它看起来简单,我们只需了解远程设备的协议。不过,一些人可能需要参考完整的 UsmUserData 官方文档。

获取主机名

现在,让我们测试 get() 函数。我们将使用它来检索设备的主机名,其对象为 1.3.6.1.2.1.1.5.0。我们可以简单地编写以下代码片段:

示例:

print(get('10.0.0.1', ['1.3.6.1.2.1.1.5.0'], hlapi.CommunityData('javatiku')))  

输出:

{'1.3.6.1.2.1.1.5.0': 'R1.sdn.local'}

解释:

在上面的代码片段中,我们打印了 get() 函数获取设备主机名的结果。

注意:这里我们不会得到一个字典列表,而只是一个字典。这是有意的,get() 函数在所有情况下都会表现得像这样。通常情况下,我们知道该函数只会执行一次,它无法创建多个实例。因此,我们返回了从 fetch() 获取的第一个元素。

理解Python SNMP Get Bulk

get_bulk() 方法用于检索相同对象标识的多个实例,比如每个接口的一个实例。当我们处理表格时,如接口一的路由表时,这个函数变得非常有用。它非常直观,与 get() 方法类似。但是它需要一些额外的详细信息:从哪个对象开始以及我们需要获取多少个实例。我们在 start_fromcount 中提供这些信息。

让我们考虑以下代码片段以了解 get_bulk() 函数的工作原理。

示例:

def get_bulk(  
    target,  
    oids,  
    credentials,  
    count,  
    start_from = 0,  
    port = 161,  
    engine = hlapi.SnmpEngine(),  
    context = hlapi.ContextData()):  
    handler = hlapi.bulkCmd(  
        engine,  
        credentials,  
        hlapi.UdpTransportTarget(( target, port )),  
        context,  
        start_from, count,  
        *construct_object_types( oids )  
    )  
    return fetch(handler, count)  

解释:

在上面的代码片段中,我们定义了 get_bulk() 函数,其中指定了处理程序。最后,我们返回了 fetch() 函数。因此,我们期望得到一个字典列表,因此我们不需要像使用 get() 函数那样提取第一个字典。

理解Python SNMP Get Bulk Auto

get_bulk_auto() 函数是 get_bulk() 函数的改进版本。假设我们想使用 get_bulk() 遍历设备接口。我们如何知道接口的数量?这变得必要,因为 SNMP 需要知道要迭代多少次。我们无法提前知道这一点,但我们可以使用 SNMP 作为选项来查找这些信息。

我们可以使用 get_bulk_auto() 函数告诉代码从另一个对象标识中检索计数变量。因此,我们可以指定一个对象标识,而不是指定一个数字。函数将获取该对象并将其用作 count

让我们考虑以下示例以更好地理解。

示例:

def get_bulk_auto(  
    target,  
    oids,  
    credentials,  
    count_oid,  
    start_from = 0,  
    port = 161,  
    engine = hlapi.SnmpEngine(),  
    context = hlapi.ContextData()):  
    count = get(  
        target,  
        [count_oid],   
        credentials,   
        port,  
        engine,  
        context  
        )[count_oid]  
    return get_bulk(target, oids, credentials, count, start_from, port, engine, context)  

解释:

在上面的代码片段中,我们定义了 get_bulk_auto() 函数,并使用 get() 指定了 count 变量,然后返回了 get_bulk() 函数。

使用Python SNMP Get Bulk和Get Bulk Auto

让我们考虑执行以下代码片段。

示例:

ele = get_bulk_auto(  
    '10.0.0.1',  
    ['1.3.6.1.2.1.2.2.1.2 ', '1.3.6.1.2.1.31.1.1.1.18'],  
    hlapi.CommunityData('javatiku'),  
    '1.3.6.1.2.1.2.1.0')  
for i in ele:  
    for x, y in i.items():  
        print("{0} = {1}".format(x, y))  
    print('')  

输出:

1.3.6.1.2.1.2.2.1.2.1=FastEthernet1/0
1.3.6.1.2.1.31.1.1.1.18.1=
1.3.6.1.2.1.2.2.1.2.2=FastEthernet0/0
1.3.6.1.2.1.31.1.1.1.18.2=
1.3.6.1.2.1.2.2.1.2.3=FastEthernet0/1
1.3.6.1.2.1.31.1.1.1.18.3=Test Desc
1.3.6.1.2.1.2.2.1.2.4=Serial2/0
1.3.6.1.2.1.31.1.1.1.18.4=
1.3.6.1.2.1.2.2.1.2.5=Serial2/1
1.3.6.1.2.1.31.1.1.1.18.5=
1.3.6.1.2.1.2.2.1.2.6=Serial2/2
1.3.6.1.2.1.31.1.1.1.18.6=
1.3.6.1.2.1.2.2.1.2.7=Serial2/3
1.3.6.1.2.1.31.1.1.1.18.7=
1.3.6.1.2.1.2.2.1.2.9=Null0
1.3.6.1.2.1.31.1.1.1.18.9=

标签: Tkinter教程, Tkinter安装, Tkinter库, Tkinter入门, Tkinter学习, Tkinter入门教程, Tkinter, Tkinter进阶, Tkinter指南, Tkinter学习指南, Tkinter进阶教程, Tkinter编程