Python中的SNMP模块

Python中的SNMP模块

SNMP ,简称 简单网络管理协议 ,是SDN的必备工具,也是控制软件中设备的最佳选择。即使不考虑这一点,应用程序访问也是SNMP的主要目的。毫无疑问,所有监控系统都利用SNMP来监视和控制服务器和网络设备。在脚本中具备SNMP的强大功能将是令人惊叹的。因此,在本教程中,我们将讨论Python编程语言中SNMP的应用。

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

理解SNMP

SNMP ,也称为 简单网络管理协议 ,是管理服务器和远程设备(代理)之间进行通信的标准方式。SNMP的目标是使管理者能够理解(甚至更改)代理上的数据。例如,管理者可以检查哪些接口正常运行,哪些接口已经下线,或者更改远程设备的主机名。

Python中的SNMP模块

我们的脚本使得一个在管理站点上运行的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 的用法。

此外,我们将了解Python中 PySNMP 的不同功能。本教程的主要目标是创建一个简单的Python程序,以简化我们的工作。在程序中,我们将拥有所需的所有SNMP操作。

那么,让我们开始吧。

准备环境

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

语法:

$ pip install pysnmp

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

验证安装

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

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

示例:

# importing the required module
import pysnmp

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

语法:

$ python .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(OID)的列表,之后是会话认证的一组凭据。我们还可以指定一个不同的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。它简单地根据 count 变量循环处理多次的处理程序。如果有任何错误引发,流程将停止,并返回 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方法,以特定的原因停止迭代。在用户指定的计数高于我们实际拥有的对象数量的情况下,我们只需停止并返回目前为止所得到的结果。这就是这个结构的目的。

为什么需要返回一个字典列表?在每个获取操作中,我们可以获取各种对象ID。因此,每个字典将由对象ID作为键和MIB中OID的值作为该键的值组成。在需要在单个获取中使用多个OID的情况下,我们将返回一个具有多个键的字典。但为什么还需要一个列表?使用获取操作,我们只能检索数据一次。然而,正如我们将在获取批量中看到的那样,我们可能需要在各个实例上多次获取类似的详细信息。让我们用一个示例来更好地理解。假设我们需要检查所有接口上的错误:信息始终是错误的;然而,我们有不同的实例(每个接口一个)。我们可以使用列表来可视化它,其中每个数据元素都是表示实例的字典。

注意:fetch()函数依赖于我们必须创建的另一个函数:cast()。此函数将从PySNMP接收到的数据转换为int、float或string。

让我们考虑以下相同的代码片段:

示例:

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() 函数以及其他函数都有一个特殊的credentials变量,其中包含了身份验证对象。如果我们使用SNMPv2c或SNMPv3,这个对象会有所不同。

在SNMPv2c(或更低版本)的情况下,我们需要指定community。我们可以使用以下方式进行设置:

语法:

hlapi.CommunityData('JAVATPOINT')

相反,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('JAVATPOINT')))

输出:

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

解释:

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

注意:这里我们不是获取一个字典列表,而是仅一个字典。这是故意的, get() 函数始终如此。通常情况下,我们知道函数只执行一次,它不能创建多个实例。因此,我们返回从fetch()获取的第一个元素。

理解Python SNMP Get Bulk

get_bulk() 方法检索同一对象ID的多个实例,比如每个接口的实例。当我们在处理表格时,比如接口一的路由表时,这个函数变得可支持。它非常简单,并且类似于 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() 函数告诉代码从另一个OID中检索计数变量。因此,我们可以指定一个对象ID,而不是指定一个数字。函数将为该对象进行get操作,并将其用作计数。

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

示例:

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() 和返回 get_bulk() 函数指定了 count 变量。

使用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('JAVATPOINT'),
    '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=

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程