python自动化脚本_用python编写控制网络设备的自动化脚本4:接口

python自动化脚本_用python编写控制网络设备的自动化脚本4:接口_第1张图片

接口介绍(前言)

接口(interface)是网络设备用来处理各种连接媒介的抽象化的口,端口(port)是网络设备真实存在的物理意义上的口,端口一定是接口,接口不一定是端口。

接口是网络设备最重要的基础设施,从物理层到应用层的协议在接口中都有相关配置。可配置命令数量之多,仅次于全局配置模式。

注:由于本文章是涉及到网络工程和编程开发的跨专业文章,文章中会多次出现网络设备的接口和编程意义上的接口。为了区分,下面每当出现接口的地方会注明(网络)接口(编程)接口以表示哪个接口。

统一的(网络)接口结构

不同厂商的(网络)接口格式是大同小异的,看一下不同的(网络)接口可以知道(网络)接口格式都是类似于“(网络)接口类型 序号/序号/序号”的形式,中间的序号可能根据设备不同和(网络)接口类型不同会多一段少一段,有时候末尾还会跟子序号。

定义一个(网络)接口结构,让这个结构所储存的(网络)接口格式在任何网络设备使用,可以表示不同类型、不同序号的(网络)接口。

class S接口:
    "表示一个接口"
    def __init__(self, a类型: int, a名称: str, aa序号: tuple, a子序号 = 0):
        self.m类型 = int(a类型)
        self.m名称 = str(a名称)
        self.ma序号 = aa序号
        self.m子序号 = a子序号
    @staticmethod
    def fc标准(a类型, *a序号, a子序号 = 0):
        "(类型,*序号,子序号)"
        return S接口(a类型, "", a序号, a子序号)

这里的接口类型是一个枚举,用来统一不同网络设备的接口类型。在不同的设备中,同一种接口的名称可能不相同。比如思科设备的百兆以太网口名称是“FastEthernet”,华为/华三设备的百兆以太网口名称是“Ethernet”,中兴的百兆以太网口名称是“fei_”。所以有必要用统一的枚举值来表示这些同样类型不同名称的口,有了统一枚举值,等到具体设备要用的时候再转换成具体名称。

class E接口(enum.IntEnum):
    e空 = 0x00000000
    e管理 = 0x00000001
    e环回 = 0x00000100
    e十兆以太网 = 0x00000210 #10M=10'000'000
    e以太网 =  e十兆以太网
    e百兆以太网 = 0x00000220 #100M=100'000'000
    e快速以太网 =  e百兆以太网
    e吉以太网 = 0x00000230    #1G=1'000M=1'000'000'000
    e千兆以太网 = e吉以太网
    e串行 = 0x00000400
    e虚拟局域网 = 0x00000500
    e隧道 = 0x00000600

我在写接口类型枚举时考虑到了别名的情况。如:百兆以太网=快速以太网、吉以太网=千兆以太网。这些别名的值是一样的,所以最后转换成设备对应的接口名称的结果也是一样。

(网络)接口配置模式(编程)接口

(网络)接口配置模式(编程)接口说明这是一个可以对(网络)接口做配置的(编程)接口

class I接口配置模式(I接口配置模式基础):   #常见的接口配置
    def __init__(self, a, a接口):
        I接口配置模式基础.__init__(self, a, a接口)
    def fs开关(self, a开关):
        raise NotImplementedError()
    def fs描述(self, a描述, a操作 = E操作.e设置):
        raise NotImplementedError()
    def fs网络地址4(self, a地址, a操作 = E操作.e设置):
        raise NotImplementedError()

因为(网络)接口命令太多,这段代码只列举几个常用的。

这里有一个 I接口配置模式基础,它是所有(网络)接口配置模式(编程)接口的基类,提供了不同的(网络)接口配置模式(编程)接口都能使用的通用函数,比如进入命令。 I接口配置模式 只提供常用操作,更详细的操作分散在不同的(网络)接口配置模式(编程)接口中,所有的(网络)接口配置模式(编程)接口都要继承 I接口配置模式基础 以保证行为一致以及避免重复代码。

class I接口配置模式基础(I模式):   #所有接口配置模式接口的基类
    c模式名 = "接口配置模式"
    def __init__(self, a设备, a接口):
        I模式.__init__(self, a设备)
        self.m接口 = a接口
    def __eq__(self, a):
        if not isinstance(a, I接口配置模式基础):
            return False
        return self.m接口 == a.m接口
    #通用方法
    def fg模式参数(self):
        return (self.m接口,)
    def fg进入命令(self):
        return C命令("interface") + self.fg模式参数()
    def fg接口(self):
        return self.m接口

写完(编程)接口还要写如何创建对象。几乎所有的网络设备都是从全局配置模式进入(网络)接口配置模式,所以我习惯性地把创建(网络)接口配置模式对象的函数放在全局配置模式(编程)接口中。

class I全局配置模式(I模式):
    def f模式_接口配置(self, a接口, a操作 = E操作.e设置):
        raise NotImplementedError()

其中 a接口 可以是一个 S接口 值,也可以是字符串。如果传了字符串,还要解析成 S接口 值,以便于使用。具体解析过程见下面的解析(网络)接口字符串一节

统一(网络)接口类型值转换成具体(网络)接口名称

上面说到,不同设备,同一种(网络)接口的名称可能不同。生成一个具体设备的具体命令需要把(网络)接口类型值转换成一个准确的名称。这个很好实现,只要写个字典,根据类型值查字典即可。

我以思科设备的接口名称为范本写了一个接口名称字典。

ca接口名称 = {
      
    E接口.e空: "Null",
    E接口.e环回: "Loopback",
    E接口.e以太网: "Ethernet",
    E接口.e快速以太网: "FastEthernet",
    E接口.e吉以太网: "GigabitEthernet",
    E接口.e十吉以太网: "TenGigabitEthernet",
    E接口.e串行: "Serial",
    E接口.e虚拟局域网: "Vlan",
    E接口.e隧道: "Tunnel"
}

在 S接口 中添加相关函数:

class S接口:
    def __str__(self):
        if self.m名称:
            return self.m名称 + self.fg序号字符串()
        else:
            return self.ft字符串(ca接口名称)
    def fg序号字符串(self):
        "包含子序号"
        #转成字符串列表
        v列表 = list(self.ma序号)
        v子序号 = self.m子序号
        for i in range(len(v列表)):
            v = v列表[i]
            if type(v) == range:
                v列表[i] = str(v.start) + "-" + str(v.stop - 1)
            else:
                v列表[i] = str(v)
        s = '/'.join(v列表)
        if v子序号:
            s += '.' + str(v子序号)
        return s
    def fg名称(self, a字典 = None):
        "根据类型值查字典取名称"
        if a字典:
            return a字典[self.m类型]
        elif self.m名称:
            return self.m名称
        else:
            return ca接口名称[self.m类型]
    def ft字符串(self, a字典 = ca接口名称):
        return self.fg名称(a字典) + self.fg序号字符串()

细分的(网络)接口配置模式

接口介绍(前言)一节说到,接口配置模式命令非常多,且不同的(网络)接口类型有不同的命令,把所有命令放在一个(编程)接口中不现实,所以需要对(网络)接口配置模式(编程)接口细分成详细的子模式。

为了提高开发效率,降低进入子模式的频率,我把常用的、数量少的命令放在(网络)接口主模式中:

  • 描述
  • (网络)接口开关
  • 设置网络地址、物理地址
  • 设置以太网口的速率、双工模式
  • (网络)接口策略:访问控制列表、服务质量

然后把不常用的,或者只有特定场合才用得到的命令放在子模式:

  • 虚拟局域网
  • 各种动态路由协议
  • 端口安全
  • 等……

在(网络)接口配置模式(编程)接口添加创建详细的(网络)接口配置模式模式对象的入口

class I接口配置模式(I接口配置模式基础):
    def f模式_虚拟局域网(self):
        raise NotImplementedError()
    def f模式_端口安全(self):
        raise NotImplementedError()
    def f模式_生成树(self):
        raise NotImplementedError()

多种进入(网络)接口子模式的途径

(网络)接口配置模式按功能分成很多子模式,(网络)接口的命令跨越不同网络层次不同协议,因为功能太多导致(网络)接口的功能不可避免地跟其他模式交叉。

例如:在开放最短路径优先配置模式配置了一些路由常用命令之后,又要进(网络)接口配置模式配置一些(网络)接口独有命令,如果再从全局配置模式逐步创建开放最短路径优先(网络)接口配置模式对象会显得很繁琐:

v路由配置 = v全局配置.f模式_开放最短路径优先()
v路由配置.fs通告路由("1.1.1.1/24", a区域号 = 0)
v接口配置 = v全局配置.f模式_接口("f0/0")
v路由接口配置 = v接口配置.f模式_开放最短路径优先()
v路由接口配置.fs开销(100)

这段脚本放在思科设备中会变成以下命令:

router ospf 1
network 1.1.1.1 0.0.0.255 area 0
exit
interface FastEthernet0/0
ip ospf cost 100

为了避免这种繁琐的从头创建模式对象,我在(编程)接口设计中添加了从一个模式进入相关模式的函数。像上面的例子,可以直接从开放最短路径优先配置模式进入开放最短路径优先(网络)接口配置模式。

v路由配置 = v全局配置.f模式_开放最短路径优先()
v路由配置.fs通告路由("1.1.1.1/24", a区域号 = 0)
v路由接口配置 = v路由配置.f模式_接口("f0/0")
v路由接口配置.fs开销(100)

代码虽然少了一行,但还是能生成同样的命令。

这种设计可以在用户不需要记住进入顺序的情况下就能进入正确的模式。带来的副作用是命令作用范围不明确(思科的(网络)接口模式的“ip ospf cost xxx”命令作用于所有ospf进程)

我还设计了一种更快捷的方法可以直接进入深层次的(网络)接口配置模式:在全局配置模式调用模式函数进入相应模式时,直接在参数里传递一个(网络)接口就能直达相应的(网络)接口配置模式。调用过程如图所示。

python自动化脚本_用python编写控制网络设备的自动化脚本4:接口_第2张图片
快速进入开放最短路径优先接口配置模式

python自动化脚本_用python编写控制网络设备的自动化脚本4:接口_第3张图片
快速进入虚拟局域网接口配置模式

(网络)接口范围

对于交换机而言,(网络)接口是需要批量操作的。因为交换机有很多的物理端口,每一个口的配置基本上是一样的,一个个敲过去非常累。有的设备提供(网络)接口范围命令,可以批量配置(网络)接口。比如思科有“interface range xxx”(网络)接口范围命令,华为有端口组,新华三有(网络)接口范围,旧华三什么都没有。为了方便批量操作(网络)接口,以及保证统一性,需要使用(网络)接口范围直接在创建(网络)接口里填范围。

v接口 = S接口.fc标准(E接口.e快速以太网, 0, range(0, 2))

range类型仍然遵循Python的使用习惯(左闭右开)。如果把这个接口值传到 f模式_接口 中,在思科设备中进入(网络)接口配置模式会变成

interface range FastEthernet0/0-1

(网络)接口范围展开

对于直接支持或间接支持(网络)接口范围的设备而言,生成一个“interface range xxx”命令没什么问题。但是对于那些不支持(网络)接口范围的设备而言,设备本身没有提供批量操作的命令。我只能写一个生成器,把(网络)接口范围展开成一个个(网络)接口,然后在循环中不断地切换接口执行命令,给这些不支持(网络)接口范围的设备提供一种兼容措施。

class S接口:
    def fe接口(self, i = 0):
        if i == len(self.ma序号): #结束
            v指定序号 = self.m子序号
            if type(v指定序号) == range:
                for j in v指定序号:
                    v接口0 = S接口(self.m类型, self.m名称, self.ma序号, j)
                    yield v接口0
            else:
                v接口0 = self
                yield v接口0
        else:   #递归
            v指定序号 = self.ma序号[i]
            if type(v指定序号) == range:
                for j in v指定序号:
                    va新序号 = self.ma序号[:i] + (j,) + self.ma序号[i+1:]
                    v接口0 = S接口(self.m类型, self.m名称, va新序号, self.m子序号)
                    for v接口1 in v接口0.fe接口(i+1):
                        yield v接口1
            else:
                v接口0 = self
                for v接口1 in v接口0.fe接口(i+1):
                    yield v接口1

这个生成器可以写一段简单的测试代码验证正确性

def main():
    v接口0 = S接口.fc标准(E接口.e快速以太网, range(0, 2), range(0, 2), a子序号 = range(1, 5))
    for v接口1 in v接口0.fe接口():
        print(v接口1)
if __name__ == "__main__":
    main()

会打印:

FastEthernet0/0.1
FastEthernet0/0.2
FastEthernet0/0.3
FastEthernet0/0.4
FastEthernet0/1.1
FastEthernet0/1.2
FastEthernet0/1.3
FastEthernet0/1.4
FastEthernet1/0.1
FastEthernet1/0.2
FastEthernet1/0.3
FastEthernet1/0.4
FastEthernet1/1.1
FastEthernet1/1.2
FastEthernet1/1.3
FastEthernet1/1.4

(网络)接口自动展开

我写的接口范围的功能十分丰富,丰富到可以在任何一个序号写范围。然而并不是所有的网络设备都支持这么丰富的接口范围格式,还要根据设备支持程度确定是否在(网络)接口配置模式内部展开。

我在设计自动展开功能时,为了避免反复写多遍代码的情况,写了一个装饰器来判断和展开。

def fe接口模式展开(a接口模式):
    for v接口 in a接口模式.m接口.fe接口():
        v接口模式 = copy.copy(a接口模式)
        v接口模式.m模式栈 = a接口模式.m模式栈[:-1] + (v接口模式,)
        v接口模式.m接口 = v接口
        yield v接口模式
def A接口自动展开(af):
    def fi展开(self):
        if not self.m接口.fi范围():
            return False
        elif hasattr(self, "mi接口自动展开"):
            return bool(self.mi接口自动展开)
        else:
            return True
    def f包装(self, *a元组, **a字典):
        if fi展开(self):
            for v接口模式 in fe接口模式展开(self):
                af(v接口模式, *a元组, **a字典)
        else:
            return af(self, *a元组, **a字典)
    return f包装

fe接口模式展开 直接把一个带有接口范围的(网络)接口配置模式展开成带有单个接口的(网络)接口配置模式。A接口自动展开 则判断(网络)接口是否是(网络)接口范围,是否需要展开,然后选择展开/不展开。

装饰器不应用在(网络)接口配置模式(编程)接口,而是用在具体实现中。在需要执行命令的函数前加上这个装饰器。

class C接口配置(I接口配置模式):
    def __init__(self, a, a接口):
        设备.I接口配置模式.__init__(self, a, a接口)
    @A接口自动展开
    def fs开关(self, a开关):
        pass #省略
    @A接口自动展开
    def fs描述(self, a描述 = "", a操作 = E操作.e设置):
        pass #省略
    @A接口自动展开
    def fs网络地址4(self, a地址, a操作 = E操作.e设置):
        pass #省略
    @A接口自动展开
    def fs网络地址6(self, a地址, a操作 = E操作.e添加):
        pass #省略

判断设备是否支持接口范围的代码一般藏在接口配置模式实现的 __init__ 中。对于思科设备而言,可以用这么一个函数表示:

def f检查接口范围(self):
    v展开 = False
    if len(self.m接口.ma序号) > 1:
        for v序号 in self.m接口.ma序号[:-1]:
            if type(v序号) == range:
                v展开 = True
    self.mi范围 = type(self.m接口.ma序号[-1]) == range
    self.mi接口自动展开 = v展开

解析(网络)接口字符串 & (网络)接口缩写

为了方便起见,在创建(网络)接口模式时允许传递一个字符串,然后把这个字符串解析成具体的(网络)接口值。例如,对于思科设备,传入一个"f0/0"和传入 S接口.fc标准(E接口.e快速以太网, 0, 0) 是等价的。为了实现这个效果,需要写一个函数对字符串进行解析。

我定义了一个函数 S接口.fc字符串,它的功能是解析字符串,计算出相应的 S接口 值。这个函数的思路是:把字符串拆分成字母部分和数字部分,字母部分查(网络)接口名称字典,选择最接近的全称和对应的接口枚举值。数字部分很容易拆分成元祖。最后再创建接口值。

    @staticmethod
    def fc字符串(a字符串, a全称字典 = ca接口名称):
        v类型, v名称 = S接口.f解析_取全称(a字符串, a全称字典)
        v序号, v子序号 = S接口.f解析_取序号(a字符串)
        return S接口(v类型, v名称, v序号, v子序号)

思科的互联网操作系统(Internetwork Operating System)允许命令缩写,(网络)接口名称也可以缩写。为了支持这种缩写行为,我写了一个函数,根据缩写查找全称。原理是根据传进的名称缩写创建正则对象,让它匹配完整名称的前面部分,找到匹配的就返回。

    @staticmethod
    def f解析_取全称(a: str, a字典 = ca接口名称.items()):
        "提取接口字符串的名称部分,根据字典取全称"
        v类型 = type(a字典)
        if hasattr(a字典, "__iter__"):
            v列表 = a字典
        else:
            raise TypeError()
        v名称 = S接口.f解析_取名称(a)
        #找前面匹配, 无优先级版本见 cflw字符串.f找前面匹配
        v正则 = re.compile(r"^" + v名称, re.IGNORECASE)
        v目标 = None
        v优先级 = -1
        for k, v in a字典.items():    #k=E接口,v=字符串
            if type(v) != str:
                raise TypeError("元素类型必须是字符串")
            if a == v:  #完全相等
                return (k, v)
            elif re.search(v正则, v):
                v匹配优先级 = k // 0x10000
                if v匹配优先级 > v优先级:
                    v优先级 = v匹配优先级
                    v目标 = (k, v)
        if v目标:
            return v目标
        else:
            raise RuntimeError("未找到")

应用示例:批量划虚拟局域网

这个示例用华为模拟器做实验。
摆一台华为S5700,编写脚本做如下配置:

  • 每连续的4个口划同一个虚拟局域网,虚拟局域网号从10开始递增1。
  • 每个虚拟局域网(网络)接口设置地址10.0.x.1/24,其中x是虚拟局域网号。
import cflw网络连接 as 连接
import cflw网络地址 as 地址
import cflw网络设备 as 设备
import cflw网络设备_华为 as 华为
def main():
    v连接 = 连接.C网络终端("ensp.localhost", 2000)
    v设备 = 华为.f创建设备(v连接, 华为.E型号.s5700)
    v设备.fs回显(True)
    v用户 = v设备.f模式_用户()
    v用户.fs终端监视(False)
    v全局配置 = v用户.f模式_全局配置()
    v序号 = 10
    for i in range(1, 25, 4):
        v接口 = 设备.S接口.fc标准(设备.E接口.e千兆以太网, 0, 0, range(i, i+4))
        v接口配置0 = v全局配置.f模式_虚拟局域网(v接口)
        v接口配置0.fs链路类型(设备.E链路类型.e接入)
        v虚拟局域网 = v全局配置.f模式_虚拟局域网(v序号)
        v虚拟局域网.fs端口(v接口, a操作 = 设备.E操作.e添加)
        v虚拟接口 = 设备.S接口.fc标准(设备.E接口.e虚拟局域网, v序号)
        v接口配置1 = v全局配置.f模式_接口配置(v虚拟接口)
        v接口配置1.fs网络地址4(地址.S网络地址4.fc四段(10, 0, v序号, 1, 24))
        v序号 += 1
if __name__ == "__main__":
    main()

纯粹的按需求写脚本,不用人工计算哪个口划到虚拟局域网几,甚至不需要知道最后的虚拟局域网号是多少。如果是手敲命令还要不断计算哪些口划到虚拟局域网几。

运行脚本,打印了:(刷屏警告)



undo terminal monitor
Info: Current terminal monitor is off.
system-view
Enter system view, return user view with Ctrl+Z.
[Huawei]interface GigabitEthernet0/0/1
[Huawei-GigabitEthernet0/0/1]port link-type access
[Huawei-GigabitEthernet0/0/1]quit
[Huawei]interface GigabitEthernet0/0/2
[Huawei-GigabitEthernet0/0/2]port link-type access
[Huawei-GigabitEthernet0/0/2]quit
[Huawei]interface GigabitEthernet0/0/3
[Huawei-GigabitEthernet0/0/3]port link-type access
[Huawei-GigabitEthernet0/0/3]quit
[Huawei]interface GigabitEthernet0/0/4
[Huawei-GigabitEthernet0/0/4]port link-type access
[Huawei-GigabitEthernet0/0/4]quit
[Huawei]vlan 10
[Huawei-vlan10]port GigabitEthernet 0/0/1 to 0/0/4
[Huawei-vlan10]quit
[Huawei]interface Vlanif10
[Huawei-Vlanif10]ip address 10.0.10.1 24
[Huawei-Vlanif10]quit
[Huawei]interface GigabitEthernet0/0/5
[Huawei-GigabitEthernet0/0/5]port link-type access
[Huawei-GigabitEthernet0/0/5]quit
[Huawei]interface GigabitEthernet0/0/6
[Huawei-GigabitEthernet0/0/6]port link-type access
[Huawei-GigabitEthernet0/0/6]quit
[Huawei]interface GigabitEthernet0/0/7
[Huawei-GigabitEthernet0/0/7]port link-type access
[Huawei-GigabitEthernet0/0/7]quit
[Huawei]interface GigabitEthernet0/0/8
[Huawei-GigabitEthernet0/0/8]port link-type access
[Huawei-GigabitEthernet0/0/8]quit
[Huawei]vlan 11
[Huawei-vlan11]port GigabitEthernet 0/0/5 to 0/0/8
[Huawei-vlan11]quit
[Huawei]interface Vlanif11
[Huawei-Vlanif11]ip address 10.0.11.1 24
[Huawei-Vlanif11]quit
[Huawei]interface GigabitEthernet0/0/9
[Huawei-GigabitEthernet0/0/9]port link-type access
[Huawei-GigabitEthernet0/0/9]quit
[Huawei]interface GigabitEthernet0/0/10
[Huawei-GigabitEthernet0/0/10]port link-type access
[Huawei-GigabitEthernet0/0/10]quit
[Huawei]interface GigabitEthernet0/0/11
[Huawei-GigabitEthernet0/0/11]port link-type access
[Huawei-GigabitEthernet0/0/11]quit
[Huawei]interface GigabitEthernet0/0/12
[Huawei-GigabitEthernet0/0/12]port link-type access
[Huawei-GigabitEthernet0/0/12]quit
[Huawei]vlan 12
[Huawei-vlan12]port GigabitEthernet 0/0/9 to 0/0/12
[Huawei-vlan12]quit
[Huawei]interface Vlanif12
[Huawei-Vlanif12]ip address 10.0.12.1 24
[Huawei-Vlanif12]quit
[Huawei]interface GigabitEthernet0/0/13
[Huawei-GigabitEthernet0/0/13]port link-type access
[Huawei-GigabitEthernet0/0/13]quit
[Huawei]interface GigabitEthernet0/0/14
[Huawei-GigabitEthernet0/0/14]port link-type access
[Huawei-GigabitEthernet0/0/14]quit
[Huawei]interface GigabitEthernet0/0/15
[Huawei-GigabitEthernet0/0/15]port link-type access
[Huawei-GigabitEthernet0/0/15]quit
[Huawei]interface GigabitEthernet0/0/16
[Huawei-GigabitEthernet0/0/16]port link-type access
[Huawei-GigabitEthernet0/0/16]quit
[Huawei]vlan 13
[Huawei-vlan13]port GigabitEthernet 0/0/13 to 0/0/16
[Huawei-vlan13]quit
[Huawei]interface Vlanif13
[Huawei-Vlanif13]ip address 10.0.13.1 24
[Huawei-Vlanif13]quit
[Huawei]interface GigabitEthernet0/0/17
[Huawei-GigabitEthernet0/0/17]port link-type access
[Huawei-GigabitEthernet0/0/17]quit
[Huawei]interface GigabitEthernet0/0/18
[Huawei-GigabitEthernet0/0/18]port link-type access
[Huawei-GigabitEthernet0/0/18]quit
[Huawei]interface GigabitEthernet0/0/19
[Huawei-GigabitEthernet0/0/19]port link-type access
[Huawei-GigabitEthernet0/0/19]quit
[Huawei]interface GigabitEthernet0/0/20
[Huawei-GigabitEthernet0/0/20]port link-type access
[Huawei-GigabitEthernet0/0/20]quit
[Huawei]vlan 14
[Huawei-vlan14]port GigabitEthernet 0/0/17 to 0/0/20
[Huawei-vlan14]quit
[Huawei]interface Vlanif14
[Huawei-Vlanif14]ip address 10.0.14.1 24
[Huawei-Vlanif14]quit
[Huawei]interface GigabitEthernet0/0/21
[Huawei-GigabitEthernet0/0/21]port link-type access
[Huawei-GigabitEthernet0/0/21]quit
[Huawei]interface GigabitEthernet0/0/22
[Huawei-GigabitEthernet0/0/22]port link-type access
[Huawei-GigabitEthernet0/0/22]quit
[Huawei]interface GigabitEthernet0/0/23
[Huawei-GigabitEthernet0/0/23]port link-type access
[Huawei-GigabitEthernet0/0/23]quit
[Huawei]interface GigabitEthernet0/0/24
[Huawei-GigabitEthernet0/0/24]port link-type access
[Huawei-GigabitEthernet0/0/24]quit
[Huawei]vlan 15
[Huawei-vlan15]port GigabitEthernet 0/0/21 to 0/0/24
[Huawei-vlan15]quit
[Huawei]interface Vlanif15
[Huawei-Vlanif15]ip address 10.0.15.1 24
[Huawei-Vlanif15]

应用示例:关闭(划掉)备注不使用的(网络)接口

这个示例我拿一台闲置的路由器来做实验。路由器型号:中兴ZXR10 M6000-5S,一台价格几十万,单位里有2台,原本计划替换掉旧的路由器,但是上级一直没有指示,所以只能放在机房里浪费电。借此机会我把这价值几十万的路由器拿来做实验,反正没有业务,就算代码写错了把所有口都关了也没事,大不了再跑去机房把口子重新开起来。

先登录路由器看一下状态:

python自动化脚本_用python编写控制网络设备的自动化脚本4:接口_第4张图片
show version看版本

python自动化脚本_用python编写控制网络设备的自动化脚本4:接口_第5张图片
show interface brief看接口表

其实我本来是想写关闭不使用的(网络)接口,看了路由器的(网络)接口状态才想到路由器的端口默认是关闭的。于是我改变方案,改为备注不使用的(网络)接口。

代码思路是结合之前写的《乘风龙王:用python编写控制网络设备的自动化脚本2:显示》,查看接口表中接口的状态,然后做相应操作。

import cflw网络连接 as 连接
import cflw网络设备 as 设备
import cflw网络设备_中兴 as 中兴
def main():
    v连接 = 连接.C网络终端("*.*.*.*")
    v设备 = 中兴.f创建设备(v连接, 中兴.E型号.zxr10_m6000)
    v设备.fs回显(True)
    v用户模式 = v设备.f模式_用户()
    v用户模式.f登录("****", "****")
    v用户模式.f提升权限()
    v全局配置 = v用户模式.f模式_全局配置()
    for v行 in v用户模式.f显示_接口表():
        if not v行.m状态:
            v接口配置 = v全局配置.f模式_接口配置(v行.m接口)
            v接口配置.fs描述("123")
if __name__ == "__main__":
    main()

运行脚本,结束之后再看一下接口状态:

python自动化脚本_用python编写控制网络设备的自动化脚本4:接口_第6张图片

因为我拿一台价格昂贵的真机做实验,要是被别人看到我刷了一堆“123”会造成不良影响,所以做完实验还要再把这些“123”删掉。

修改脚本内容,在循环中判断描述内容然后删除描述。

    for v行 in v用户模式.f显示_接口表():
        if v行.m描述 == "123":
            v接口配置 = v全局配置.f模式_接口配置(v行.m接口)
            v接口配置.fs描述(a操作 = 设备.E操作.e删除)

看打印内容,可以看到脚本跳过了其他描述的(网络)接口(g0/4/1/1口),只删除描述为“123”的(网络)接口。

python自动化脚本_用python编写控制网络设备的自动化脚本4:接口_第7张图片

结尾

接口的内容简直是复杂到爆炸,感觉这部分内容比框架设计还要复杂,写起来真令人头大(@_@;)

接口作为一个网络设备的基础设备,为了实现特殊操作以及保证不同设备的兼容性,我写了一大堆代码来保证功能上的一致性。除了接口基本功能很复杂,还要跟其他模式配合,有时候不同(网络)接口模式(编程)接口可能在具体设备是同一模式,进入命令一样,这样可能存在同一个模式左右横跳的现象,我还要写一堆优化代码来避免这种无意义的切换。

我在写代码的过程中发现接口展开过程简直惨不忍睹。如果脚本里写的是一个接口范围执行操作A、B,那么接口展开之后变成先反复进入接口执行操作A,再反复进入接口执行操作B,同一个接口要进入2次。这部分内容有待优化,以后再说吧。

本文章的相关代码已发到Github,见:https://github.com/cflw/cflw_py

你可能感兴趣的:(python自动化脚本)