• 产品与解决方案
  • 行业解决方案
  • 服务
  • 支持
  • 合作伙伴
  • 新华三人才研学中心
  • 关于我们

01-基础配置指导

目录

08-自动配置

本章节下载 08-自动配置  (425.21 KB)

08-自动配置


1 自动配置

1.1  自动配置简介

自动配置功能是指设备在启动时自动获取并执行配置文件。网络管理员只需将配置文件保存在指定的存储介质上,启动设备,即可实现自动配置,从而简化了网络配置,大大降低了网络管理员的工作量,便于实现对设备的集中管理。

自动配置的实现方式如表1-1所示:

表1-1 自动配置实现方式

配置方式

配置文件保存位置

应用场景

服务器自动配置

文件服务器

网络规模较大,设备位置相对分散

 

设备空配置启动时,首先自动检查存储介质的根目录下是否存在autocfg.py、autocfg.tcl 或autocfg.cfg配置文件。如果存在,则直接执行此文件;如果不存在,则通过自动从文件服务器上获取并执行配置脚本文件或配置文件,实现自动配置功能。autocfg.py、autocfg.tcl和autocfg.cfg配置文件同时只能在设备上存在一个。

1.2  服务器自动配置

1.2.1  服务器自动配置简介

服务器自动配置是指在一个网络中存在文件服务器、DHCP服务器和DNS服务器的情况下,新加入或无配置文件的设备上电启动时,设备会自动运行DHCP Client服务,通过DHCP Server获取配置文件所在的URL地址或TFTP Server IP、TFTP Server name以及配置文件的文件名。最后从TFTP服务器下载配置文件进行配置加载并启动的过程。

服务器自动配置支持在IPv4和IPv6网络中实现,两种网络配置思路相同,本节仅以IPv4网络配置为例。

1.2.2  服务器自动配置典型组网

服务器自动配置的典型组网环境如图1-1所示。设备需要在DHCP服务器、文件服务器(TFTP服务器或HTTP服务器)和DNS服务器的配合下,实现服务器自动配置功能。

图1-1 服务器自动配置典型组网图

 

1.2.3  服务器自动配置任务简介

服务器自动配置任务如下:

(1)     配置文件服务器

(2)     准备配置文件或配置脚本

¡     准备配置文件

¡     准备配置脚本

(3)     配置DHCP服务器

(4)     (可选)配置DNS服务器

(5)     (可选)配置网关

(6)     准备获取配置文件

(7)     完成自动配置

1.2.4  配置文件服务器

设备可以通过HTTP或TFTP获取配置文件,管理员需要根据选用的方式在文件服务器上配置相应的HTTP服务或TFTP服务。

1.2.5  准备配置文件

1. 配置文件类型

配置文件包括特定配置文件、部分或全部公用配置文件以及缺省配置文件(device.cfg)三种类型,如表1-2所示。

表1-2 配置文件类型以及支持的文件服务器

配置文件类型

适用的设备

文件名要求

支持的文件服务器

特定配置文件

具有特定配置需求的设备

配置文件名.cfg

为了方便辨识文件名,尽量不要使用包含空格的配置文件名。

·     HTTP服务器

·     TFTP服务器

部分或全部共用配置文件

配置需求全部或者部分相同的设备

配置文件名.cfg

“配置文件名”可以是任意文件名。

·     HTTP服务器

·     TFTP服务器

缺省配置文件

其它设备

包含一般设备启动的公用配置信息

device.cfg

TFTP服务器

 

2. 配置文件准备过程

管理员可以根据网络中不同设备的需求和文件服务器类型选择配置:

(1)     在文件服务器上为每个具有特定配置需求的设备准备特定配置文件。

(2)     在文件服务器上以.cfg为后缀名为部分或全部具有相同配置的设备保存一个配置文件。

(3)     在TFTP服务器上保存名为device.cfg的缺省配置文件为既没有特定配置文件也没有部分或全部共用配置文件的设备提供缺省配置。

3. 在TFTP服务器上准备主机名文件

如果DHCP服务器未下发配置文件名,管理员还可以在TFTP服务器上创建主机名文件提供主机名和设备IP地址的对应关系,以保证执行自动配置的设备获取到配置文件。

按照如下方式配置:

(1)     创建主机名文件,文件名必须设置为“network.cfg”。

(2)     按照以下格式手工在文件中添加主机IP地址与主机名的映射关系,保证一行一条映射。

ip host host-name ip-address

例如,主机名文件中可以包括以下内容:

ip host host1 101.101.101.101

ip host host2 101.101.101.102

ip host client1 101.101.101.103

ip host client2 101.101.101.104

主机名必须与主机的配置文件名保持一致。

1.2.6  准备配置脚本

1. 功能简介

配置脚本可以实现自动更新版本、下发配置等功能。

目前设备支持的配置脚本包括Python脚本和Tcl脚本。Python脚本使用的文件后缀固定为py,Tcl脚本使用的文件后缀固定为tcl。关于Python脚本的详细介绍,请参见“基础配置指导”中的“Python”。关于Tcl脚本的详细介绍,请参见“基础配置指导”中的“Tcl”。

2. 配置限制和指导

使用Tcl脚本配置文件对设备进行自动配置时,若配置文件中的命令行错误(例如:命令行拼写错误、视图错误、设备不支持所配置的命令等),那么设备在执行到错误命令行时将直接中断自动配置操作。

使用配置脚本与使用配置文件有如下区别:

·     在文件服务器上只支持配置特定配置脚本和部分或全部共用配置脚本两种形式,不支持缺省配置脚本。

·     在文件服务器上不支持使用主机名文件提供主机名和IP地址的对应关系。

有关“特定配置”、“部分或全部共用配置”、“缺省配置”以及“主机名和IP地址的对应关系”请参见“1.2.5  准备配置文件

3. 配置脚本准备过程

管理员可以根据网络中不同设备的需求和文件服务器类型选择配置:

(1)     在文件服务器上为每个具有特定配置需求的设备准备特定配置脚本。

(2)     在文件服务器上以.tcl或.py为后缀名为部分或全部具有相同配置的设备保存一个配置文件。

1.2.7  配置DHCP服务器

1. 功能简介

DHCP服务器为执行服务器自动配置的设备分配IP地址,并向设备通告获取自动配置文件或配置脚本的途径。

DHCP服务器可以根据管理员需要的配置文件类型,进行相应的配置(下发配置脚本和下发配置文件实现一致,下面以下发配置文件为例):

·     如果管理员为每台设备分配特定配置文件,则需要在DHCP服务器上配置静态绑定关系,为每台设备分配特定的IP地址和配置文件名。由于一个地址池下只能配置一条配置文件名的命令,所以DHCP服务器上每一个地址池视图只能配置一个静态绑定关系。

·     如果管理员为局域网内的部分设备分配相同的配置文件,可以在DHCP服务器上为使用部分共用配置文件的设备配置静态绑定关系,并指定文件服务器和部分共用配置文件名。这时,这部分静态绑定关系需要在同一个DHCP地址池中配置。也可以使用动态分配IP地址的方式,管理员需要划分合适的动态地址段,为这部分设备分配IP地址,并指定文件服务器和部分共用配置文件名。

·     如果管理员为局域网内的所有设备分配相同的配置文件,则需要在DHCP服务器上配置动态分配IP地址的方式。为设备动态分配IP地址的同时,分配全部共用配置文件名。如果采用这种方式,全部共用配置文件中只能包含这些设备共有的配置,每个设备特有的配置还需要其他方式完成(如管理员使用Telnet登录到设备上手工配置)。

以上三种分配方式可以同时在一台DHCP服务器上配置。

2. 使用HTTP服务器下发配置文件或配置脚本

(1)     进入系统视图。

system-view

(2)     开启DHCP服务。

dhcp enable

缺省情况下,DHCP服务处于关闭状态。

(3)     创建DHCP地址池,并进入DHCP地址池视图。

dhcp server ip-pool pool-name

(4)     为客户端分配IP地址。请至少选择其中一项进行配置。

¡     配置DHCP地址池动态分配的主网段。

network network-address [ mask-length | mask mask ]

缺省情况下,未配置动态分配的主网段。

¡     配置静态地址绑定。

static-bind ip-address ip-address [ mask-length | mask mask ] { client-identifier client-identifier | hardware-address hardware-address [ ethernet | token-ring ] }

缺省情况下,未配置静态地址绑定。

多次执行本命令,可以配置多个静态地址绑定。同一地址只能绑定给一个客户端。若需修改绑定必须先解除绑定。

(5)     配置DHCP客户端使用的远程启动配置文件的HTTP形式URL。

bootfile-name url

缺省情况下,未配置DHCP客户端使用的远程启动配置文件的HTTP形式URL。

3. 使用TFTP服务器下发配置文件或配置脚本

(1)     进入系统视图。

system-view

(2)     开启DHCP服务。

dhcp enable

缺省情况下,DHCP服务处于关闭状态。

(3)     创建DHCP地址池,并进入DHCP地址池视图。

dhcp server ip-pool pool-name

(4)     为客户端分配IP地址。请至少选择其中一项进行配置。

¡     配置DHCP地址池动态分配的主网段。

network network-address [ mask-length | mask mask ]

缺省情况下,未配置动态分配的主网段。

¡     配置静态地址绑定。

static-bind ip-address ip-address [ mask-length | mask mask ] { client-identifier client-identifier | hardware-address hardware-address [ ethernet | token-ring ] }

缺省情况下,未配置静态地址绑定。

多次执行本命令,可以配置多个静态地址绑定。同一地址只能绑定给一个客户端。若需修改绑定必须先解除绑定。

(5)     指定TFTP服务器。请选择其中一项进行配置。

¡     配置DHCP客户端使用的TFTP服务器地址。

tftp-server ip-address ip-address

缺省情况下,未配置DHCP客户端使用的TFTP服务器地址。

¡     配置DHCP客户端使用的TFTP服务器名。

tftp-server domain-name domain-name

缺省情况下,未配置DHCP客户端使用的TFTP服务器名。

使用此方式指定TFTP服务器需要在网络中架设DNS服务器。

(6)     配置DHCP客户端使用的启动配置文件名。

bootfile-name bootfile-name

缺省情况下,未配置DHCP客户端使用的启动配置文件名。

1.2.8  配置DNS服务器

在使用服务器自动配置功能时,在如下两种情况时,管理员需要配置DNS服务器:

·     当TFTP服务器上不存在主机名文件时,执行服务器自动配置的设备可以通过DNS服务器将自己的IP地址解析为主机名,以便从TFTP服务器获取到配置文件;

·     如果设备从DHCP应答报文中获取到TFTP服务器的域名,设备还可以通过DNS服务器将TFTP服务器的域名解析为TFTP服务器的IP地址。

1.2.9  配置网关

如果DHCP服务器、文件服务器和DNS服务器与执行服务器自动配置的设备不在同一网段,则需要部署网关设备,使得各个服务器和设备之间路由可达,并在网关上配置DHCP中继功能。

如果DHCP应答报文中不包括TFTP服务器IP地址和域名信息,或TFTP服务器IP地址和域名信息不合法,设备将以广播方式向TFTP服务器发送请求消息。由于广播报文只能在本网段内传播,如果设备与TFTP服务器不在同一个网段,则需要在网关设备上配置UDP Helper功能,将广播报文转换成单播报文,转发给指定的TFTP服务器。有关UDP Helper功能的详细介绍,请参见“三层技术-IP业务配置指导”中的“UDP-helper”。

1.2.10  准备获取配置文件的接口

设备在进行自动配置时,系统按照如下规则选取符合条件的接口:

(1)     若有处于链路状态UP的管理以太网接口,则优先选取管理以太网接口。

(2)     若没有处于链路状态UP的管理以太网接口,有处于链路状态UP的二层以太网接口,则选取默认VLAN对应的VLAN接口。

1.2.11  完成自动配置

(1)     上电启动需要进行自动配置的设备。

设备进入服务器自动配置时:

¡     如果获取并执行配置文件成功,则整个服务器自动配置过程结束。

¡     如果获取不到自动配置文件,则本次自动配置尝试失败,设备将继续尝试自动配置。用户可以等待尝试次数达到上限,设备自动结束自动配置,或根据提示信息,使用<Ctrl+C>或<Ctrl+D>快捷键手工终止自动配置。自动配置失败并结束后,设备将以空配置启动。

(2)     在完成自动配置的设备上保存配置。

save

设备在文件服务器获取到的配置文件执行完成后,该文件将被删除。建议在配置文件执行完成后保存配置。本命令的详细介绍请参见“基础配置命令参考”中的“配置文件管理”。

1.3  自动配置典型配置举例

1.3.1  服务器自动配置举例(TFTP方式)

1. 组网需求

图1-2所示,某公司下属两个部门:市场部门和研发部门,两个部门通过不同的网关设备连入网络。要求连接终端主机的设备Switch D、Switch E、Switch F和Switch G执行自动配置功能,启动后自动获取并执行配置文件,以实现:

·     网络管理员能够通过Telnet方式登录、控制设备。

·     登录设备时需要进行认证,且登录不同部门的设备使用的用户名和密码不能相同,以提供一定的安全保证。

具体组网情况如下:

·     Switch A作为DHCP服务器,分别为市场部和研发部的主机分配IP地址和其他网络配置参数。

·     网关Switch B和Switch C作为DHCP中继设备。

·     一台运行TFTP管理软件的TFTP服务器上保存配置文件。

2. 组网图

图1-2 服务器自动配置组网图(TFTP方式)

3. 配置步骤

(1)     Switch A的配置

# 配置接口IP地址

<SwitchA> system-view

[SwitchA] vlan 2

[SwitchA-vlan2] port gigabitethernet 1/0/1

[SwitchA-vlan2] quit

[SwitchA] interface vlan-interface 2

[SwitchA-Vlan-interface2] ip address 192.168.1.42 24

[SwitchA-Vlan-interface2] quit

# 开启DHCP服务。

[SwitchA] dhcp enable

# 配置VLAN接口2工作在DHCP服务器模式。

[SwitchA] interface vlan-interface 2

[SwitchA-Vlan-interface2] dhcp select server

[SwitchA-Vlan-interface2] quit

# 配置DHCP地址池market,为市场部动态分配192.168.2.0/24网段的地址,并指定TFTP server地址、网关地址和配置文件名。

[SwitchA] dhcp server ip-pool market

[SwitchA-dhcp-pool-market] network 192.168.2.0 24

[SwitchA-dhcp-pool-market] tftp-server ip-address 192.168.1.40

[SwitchA-dhcp-pool-market] gateway-list 192.168.2.1

[SwitchA-dhcp-pool-market] bootfile-name market.cfg

[SwitchA-dhcp-pool-market] quit

# 配置DHCP地址池rd,为研发部动态分配192.168.3.0/24网段的地址,并指定TFTP server地址、网关地址和配置文件名。

[SwitchA] dhcp server ip-pool rd

[SwitchA-dhcp-pool-rd] network 192.168.3.0 24

[SwitchA-dhcp-pool-rd] tftp-server ip-address 192.168.1.40

[SwitchA-dhcp-pool-rd] gateway-list 192.168.3.1

[SwitchA-dhcp-pool-rd] bootfile-name rd.cfg

[SwitchA-dhcp-pool-rd] quit

# 配置到达DHCP中继的静态路由。

[SwitchA] ip route-static 192.168.2.0 24 192.168.1.41

[SwitchA] ip route-static 192.168.3.0 24 192.168.1.43

[SwitchA] quit

(2)     Switch B的配置

# 配置接口的IP地址

<SwitchB> system-view

[SwitchB] vlan 2

[SwitchB-vlan2] port gigabitethernet 1/0/3

[SwitchB-vlan2] quit

[SwitchB] interface vlan-interface 2

[SwitchB-Vlan-interface2] ip address 192.168.1.41 24

[SwitchB-Vlan-interface2] quit

[SwitchB] vlan 3

[SwitchB-vlan3] port gigabitethernet 1/0/1

[SwitchB-vlan3] port gigabitethernet 1/0/2

[SwitchB-vlan3] quit

[SwitchB] interface vlan-interface 3

[SwitchB-Vlan-interface3] ip address 192.168.2.1 24

[SwitchB-Vlan-interface3] quit

# 开启DHCP服务。

[SwitchB] dhcp enable

# 配置VLAN接口3工作在DHCP中继模式。

[SwitchB] interface vlan-interface 3

[SwitchB-Vlan-interface3] dhcp select relay

# 配置DHCP服务器的地址。

[SwitchB-Vlan-interface3] dhcp relay server-address 192.168.1.42

(3)     Switch C的配置

# 配置接口的IP地址

<SwitchC> system-view

[SwitchC] vlan 2

[SwitchC-vlan2] port gigabitethernet 1/0/3

[SwitchC-vlan2] quit

[SwitchC] interface vlan-interface 2

[SwitchC-Vlan-interface2] ip address 192.168.1.43 24

[SwitchC-Vlan-interface2] quit

[SwitchC] vlan 3

[SwitchC-vlan3] port gigabitethernet 1/0/1

[SwitchC-vlan3] port gigabitethernet 1/0/2

[SwitchC-vlan3] quit

[SwitchC] interface vlan-interface 3

[SwitchC-Vlan-interface3] ip address 192.168.3.1 24

[SwitchC-Vlan-interface3] quit

# 开启DHCP服务。

[SwitchC] dhcp enable

# 配置VLAN接口3工作在DHCP中继模式。

[SwitchC] interface vlan-interface 3

[SwitchC-Vlan-interface3] dhcp select relay

# 配置DHCP服务器的地址。

[SwitchC-Vlan-interface3] dhcp relay server-address 192.168.1.42

(4)     TFTP服务器配置

在TFTP server创建配置文件market.cfg,文件内容如下:

#

 sysname Market

#

 telnet server enable

#

vlan 3

#

local-user market

 password simple build22345

 service-type telnet

 quit

#

interface Vlan-interface3

 ip address dhcp-alloc

 quit

#

interface gigabitethernet 1/0/1

 port access vlan 3

 quit

#

user-interface vty 0 63

 authentication-mode scheme

 user-role network-admin

#

return

在TFTP服务器创建配置文件rd.cfg,文件内容如下:

#

 sysname RD

#

 telnet server enable

#

vlan 3

#

local-user rd

 password simple create22345

 service-type telnet

 quit

#

interface Vlan-interface3

 ip address dhcp-alloc

 quit

#

interface gigabitethernet 1/0/1

 port access vlan 3

 quit

#

user-interface vty 0 63

 authentication-mode scheme

 user-role network-admin

#

return

# 启动TFTP管理软件,并指定TFTP的工作路径为保存上述配置文件的路径。

# 以Windows XP系统的主机为例,需保证TFTP服务器与DHCP中继之间路由可达。

4. 验证配置

(1)     Switch D、Switch E、Switch F和Switch G在没有配置文件的情况下启动。启动成功后,在Switch A上查看地址池中的地址绑定信息。

<SwitchA> display dhcp server ip-in-use

IP address       Client-identifier/    Lease expiration      Type

                 Hardware address

192.168.2.2      3030-3066-2e65-3233-  May 6 05:21:25 2013   Auto(C)

                 642e-3561-6633-2d56-

                 6c61-6e2d-696e-7465-

                 7266-6163-6533

192.168.2.3      3030-3066-2e65-3230-  May 6 05:22:50 2013   Auto(C)

                 302e-3232-3033-2d56-

                 6c61-6e2d-696e-7465-

                 7266-6163-6533

192.168.3.2      3030-6530-2e66-6330-  May 6 05:23:15 2013   Auto(C)

                 302e-3335-3131-2d56-

                 6c61-6e2d-696e-7465-

                 7266-6163-6531

192.168.3.3      3030-6530-2e66-6330-  May 6 05:24:10 2013   Auto(C)

                 302e-3335-3135-2d56-

                 6c61-6e2d-696e-7465-

                 7266-6163-6532

(2)     在Switch A上执行如下命令:

<SwitchA> telnet 192.168.2.2

(3)     输入用户名market、密码build22345后,可以登录Switch D或Switch E。

1.3.2  服务器自动配置举例(HTTP Tcl方式)

1. 组网需求

图1-3所示,Switch A启动后自动从HTTP服务器获取Tcl脚本启动配置文件,并执行该文件,以实现:

·     网络管理员能够通过Telnet方式登录、控制设备。

·     登录设备时需要进行认证,以提供一定的安全保证。

2. 组网图

图1-3 服务器自动配置组网图(HTTP Tcl方式)

3. 配置步骤

(1)     配置DHCP服务器

# 开启DHCP服务,创建名称为1的DHCP地址池,配置地址池动态分配IP地址的网段为192.168.1.0/24。

<DeviceA> system-view

[DeviceA] dhcp enable

[DeviceA] dhcp server ip-pool 1

[DeviceA-dhcp-pool-1] network 192.168.1.0 24

# 配置DHCP客户端远程启动配置文件为HTTP形式的URL。

[DeviceA-dhcp-pool-1] bootfile-name http://192.168.1.40/device.tcl

(2)     配置HTTP服务器,保证Switch A可以从HTTP服务器成功下载配置文件device.tcl。

# 在HTTP服务器创建配置文件device.tcl,文件内容如下:

system-view

telnet server enable

local-user user

password simple hello22345

service-type telnet

quit

user-interface vty 0 63

authentication-mode scheme

user-role network-admin

quit

 

interface vlan-interface 1

ip address dhcp-alloc

return

# 启动HTTP管理软件,开启HTTP服务(配置过程略)。

4. 验证配置

(1)     Switch A在没有配置文件的情况下启动。启动成功后,在Device A上查看地址池中的地址绑定信息。

<DeviceA> display dhcp server ip-in-use

IP address       Client identifier/    Lease expiration      Type

                 Hardware address

192.168.1.2      0030-3030-632e-3239-  Dec 12 17:41:15 2013  Auto(C)

                 3035-2e36-3736-622d-

                 4574-6830-2f30-2f32

(2)     在Device A上执行如下命令:

<SwitchA> telnet 192.168.1.2

(3)     输入用户名user、密码hello22345后,用户可以登录Switch A。

1.3.3  服务器自动配置举例(HTTP Python方式)

1. 组网需求

图1-4所示,Switch A启动后自动从HTTP服务器获取Python脚本启动配置文件,并执行该文件,以实现:

·     网络管理员能够通过Telnet方式登录、控制设备。

·     登录设备时需要进行认证,以提供一定的安全保证。

2. 组网图

图1-4 服务器自动配置组网图(HTTP Python方式)

3. 配置步骤

(1)     配置DHCP服务器

# 开启DHCP服务,创建名称为1的DHCP地址池,配置地址池动态分配IP地址的网段为192.168.1.0/24。

<DeviceA> system-view

[DeviceA] dhcp enable

[DeviceA] dhcp server ip-pool 1

[DeviceA-dhcp-pool-1] network 192.168.1.0 24

# 配置DHCP客户端远程启动配置文件为HTTP形式的URL。

[DeviceA-dhcp-pool-1] bootfile-name http://192.168.1.40/device.py

(2)     配置HTTP服务器,保证Switch A可以从HTTP服务器成功下载配置文件device.py。

# 在HTTP服务器创建配置文件device.py,文件内容如下:

#!usr/bin/python

 

import comware

comware.CLI(‘system-view ;telnet server enable ;local-user user ;password simple hello22345 ;service-type telnet ;quit ;user-interface vty 0 63 ;authentication-mode scheme ;user-role network-admin ;quit ;interface vlan-interface 1 ; ip address dhcp-alloc ;return’)

# 启动HTTP管理软件,开启HTTP服务(配置过程略)。

4. 验证配置

(1)     Switch A在没有配置文件的情况下启动。启动成功后,在Device A上查看地址池中的地址绑定信息。

<DeviceA> display dhcp server ip-in-use

IP address       Client identifier/    Lease expiration      Type

                 Hardware address

192.168.1.2      0030-3030-632e-3239-  Dec 12 17:41:15 2013  Auto(C)

                 3035-2e36-3736-622d-

                 4574-6830-2f30-2f32

(2)     在Device A上执行如下命令:

<DeviceA> telnet 192.168.1.2

(3)     输入用户名user、密码hello22345后,用户可以登录Switch A。

1.3.4  服务器自动配置实现IRF零配置举例

1. 组网需求

图1-5所示,Switch A和Switch B通过管理以太网口分别与HTTP服务器和Device A相连。Device A上开启DHCP服务。为网络中的设备动态分配192.168.1.0/24网段的IP地址。

现要求通过自动配置实现Switch A和Switch B根据脚本自动执行IRF配置的相关命令。然后再连接Switch A和Switch B之间的线缆,完成IRF的建立。

2. 组网图

图1-5 服务器自动配置实现IRF零配置组网图

 

3. 配置步骤

(1)     配置设备接口地址,保证设备间路由可达。

配置HTTP服务器。启动HTTP管理软件,开启HTTP服务(配置过程略)。针对IRF零配置,HTTP服务器上需要配置Python脚本文件、配置文件、sn.txt和软件启动包等文件。以下是关于各文件的介绍:

·     Python脚本文件:Python脚本是设备进行IRF零配置操作的主要文件,需要管理员自行准备并保存在HTTP服务器上。Python脚本需要完成的操作:

¡     设备判断flash是否存在足够的存储空间(可选);

¡     设备从HTTP服务器下载配置文件;

¡     设备从HTTP服务器下载启动软件包(可选);

¡     设备从HTTP服务器下载sn.txt文件;

¡     配置设备下次启动时使用的启动软件包(可选);

¡     解析sn.txt文件并修改设备的IRF成员编号;

¡     配置设备下次启动时使用的配置文件;

¡     设备重新启动。

Python脚本的具体内容如下(Python脚本中标注有简单的中文注释,使用时请将中文注释删除):

#!usr/bin/python

 

import comware

from time import strftime,gmtime,sleep

import signal

import os

import string

import commands

import hashlib

 

#python_config_file_mode

#'python_static'

#python_serial_number

#U can use 2 modes to obtain the config file

#- 'python_static'

#- 'python_serial_number'

python_config_file_mode = "python_serial_number"

 

#配置本次软件升级设备flash所需的最小剩余空间,单位为KB

#Required space to copy config kickstart and system image in KB

required_space = 500000

 

#配置HTTP服务器的相关参数:用户名、密码、HTTP服务器IP地址、VPN实例名称、登录的超时时间

#transfer information

username = ""

password = ""

hostname = "192.168.1.40"

protocol = "http"

vrf = ""

config_timeout = 120

irf_timeout = 120

image_timeout = 2100

 

#HTTP服务器的下载路径

#Server File Path

server_path = ""

 

#下载到本地设备时,存放到Flash根目录下

#Loacl File path

local_path = "flash:/"

 

#下载到设备之后的配置文件名

#Local config name

config_local_name = "startup.cfg"

 

#HTTP服务器上的配置文件名

#Server config name

config_server_name = "startup.cfg"

 

#下载到本地的启动软件包

#Local boot name

boot_local_name = "xxxx.ipe"

 

#HTTP服务器上的启动软件包

#Server boot name

boot_server_name = "xxxx.ipe"

 

#下载到本地的SN文件名

#Local irf name

irf_local_name = "sn.txt"

 

#HTTP服务器上的sn文件名

#Server irf name

irf_server_name = "sn.txt"

 

#设备本地上记录升级日志的log文件名

python_log_name = ""

 

#在设备上记录升级日志的方法

#Write Log File

def write2Log(info):

  global python_log_name, local_path

  if python_log_name == "":

    try:

      python_log_name = "%s%s_python_%s_script.log" %(local_path, strftime("%Y%m%d%H%M%S", gmtime()), os.getpid())

    except Exception as inst:

      print inst

  fd = open(python_log_name, "a")

  fd.write(info)

  fd.flush()

  fd.close()

 

#获取设备的chassis号和slot号,与前面定义的local_path变量,共同计算出文件本地的存放路径

# get path according to the Chassis and Slot

def getPath(chassisID, slotID):

  global local_path

  path = ""

  obj = comware.get_self_slot()

  if (obj[0] == chassisID) and (obj[1] == slotID):

    return local_path

  if chassisID != -1:

    path = "chassis%d#" % chassisID

  if slotID != -1:

    path = "%sslot%d#%s" %(path, slotID, local_path)

  return path

 

#删除下载到本地的文件

#Remove File

def removeFile(filename):

  try:

    os.remove(filename)

  except os.error:

    pass

 

#计算该设备需要删除的文件数量

#Cleanup one device temp files

def cleanDeviceFiles(str, oDevNode):

  global config_local_name, boot_local_name, irf_local_name

  sFilePath = getPath(oDevNode[0], oDevNode[1])

  if str == "error":

    removeFile("%s%s" %(sFilePath, config_local_name))

  removeFile("%s%s" %(sFilePath, boot_local_name))

  removeFile("%s%s" %(sFilePath, irf_local_name))

  removeFile("%s%s.md5" %(sFilePath, config_local_name))

  removeFile("%s%s.md5" %(sFilePath, boot_local_name))

  removeFile("%s%s.md5" %(sFilePath, irf_local_name))

  write2Log("\ndelete %s all files\n" %sFilePath)

  print "\ndelete %s all files" %sFilePath

 

#Cleanup files

def cleanupFiles(str):

  aSlotRange = []

  if ("get_standby_slot" in dir(comware)):

    aSlotRange = aSlotRange + comware.get_standby_slot()

    

  aSlotRange.append(comware.get_self_slot())

  i = 0

  while i < len(aSlotRange):

    if(aSlotRange[i] != None):

      cleanDeviceFiles(str, aSlotRange[i])

    i = i + 1

 

#计算设备flash上的剩余空间大小

#Verify if free space is available to download config, boot-loader image

def verifyfreespace(path):

  global required_space

  try:

    s = os.statvfs(path)

    freespace = (s.f_bavail * s.f_frsize) /1024

    write2Log("\nthe %s free space is %s" %(path, freespace))

    print "\n####the %s free space is %s####" %(path, freespace)

    if required_space > freespace:

      write2Log("\nthe %s space is not enough" % path)

      print "\n####the %s space is not enough####" % path

      return False

  except Exception as inst:

    write2Log("\nverify %s free space exception: %s" % (path, inst))

    print "\n####verify %s free space exception: %s####" % (path, inst)

    return False

  return True

 

#判断设备上的剩余空间是否充足

#verify device freespace

def verifyDeviceFree(obj):

  path = getPath(obj[0], obj[1])

  if True != verifyfreespace(path):

    return False

  return True

 

#check all mpu free space

def verifyAllFreeSpace():

  aSlotRange = []

  if ("get_standby_slot" in dir(comware)):

    aSlotRange = aSlotRange + comware.get_standby_slot()

    

  aSlotRange.append(comware.get_self_slot())

  bAllEnough = True

  i = 0

  while i < len(aSlotRange):

    if(aSlotRange[i] != None) and (True != verifyDeviceFree(aSlotRange[i])):

      bAllEnough = False

    i = i + 1

  return bAllEnough

 

def doExit(str):

  if str == "success":

    write2Log("\nThe script is running success!")

    print "\n#### The script is running success! ####"

    cleanupFiles("success")

    comd = "reboot force"

    comware.CLI(comd, False)

    exit(0)

  if str == "error":

    write2Log("\nThe script is running failed!")

    print "\n#### The script is running failed! ####"

    cleanupFiles("error")

    exit(1)

  else:

    exit(0)

 

#获取软件升级时chassis号和slot号参数

#get Chassis and Slot

def getChassisSlot(style):

  if style == "master":

    obj = comware.get_self_slot()

  if len(obj) <= 0:

    write2Log("\nget %s chassis and slot failed" % style)

    print "\n####get %s chassis and slot failed####" % style

    return None

  return obj

 

#获取启动软件包发生错误返回的信息

#signal terminal handler function

def sig_handler_no_exit(signum, function):

  write2Log("\nSIGTERM Handler while configuring boot-loader variables")

  print "\n####SIGTERM Handler while configuring boot-loader variables####"

 

#软件升级过程发生错误时返回的信息

#signal terminal handler

def sigterm_handler(signum, function):

  write2Log("\nSIGTERM Handler")

  print "\n####SIGTERM Handler####"

  cleanupFiles("error")

  doExit("error")

 

#从HTTP服务器上下载文件

#transfer file

def doCopyFile(src = "", des = "", login_timeout = 10):

  global username, password, hostname, protocol, vrf

  print "INFO: Starting Copy of %s" % src

  try:

    removeFile(des)

    obj = comware.Transfer(protocol, hostname, src, des, vrf, login_timeout, username, password)

    if obj.get_error() != None:

      write2Log("\ncopy %s failed: %s" % (src, obj.get_error()))

      print "\n####copy %s failed: %s####" % (src, obj.get_error())

      return False

  except Exception as inst:

    write2Log("\ncopy %s exception: %s" % (src, inst))

    print "\n####copy %s exception: %s####" % (src, inst)

    return False

  write2Log("\ncopy file %s to %s success" % (src, des))

  print "INFO: Completed Copy of %s" % src

  return True

 

#Get MD5SUM from md5ConfigFile

def getMD5SumGiven(keyword, filename):

  try:

    file = open(filename, "r")

    line = file.readline()

    while "" != line:

      if not string.find(line, keyword, 0, len(keyword)):

        line = line.split("=")

        line = line[1]

        line = line.strip()

        file.close()

        return line

      line = file.readline()

    file.close()

  except Exception as inst:

    write2Log("\nget %s md5 exception: %s" % (filename, inst))

    print "\n####get %s md5 exception: %s####" % (filename, inst)

  return ""

 

#verify MD5SUM of the file

def verifyMD5sumofFile(md5sumgiven, filename):

  if md5sumgiven == "":

    write2Log("\nverify %s md5 error: the %s md5 file is error" %(filename, filename))

    print "\n####verify %s md5 error: the %s md5 file is error####" %(filename, filename)

    return False

  try:

    m = hashlib.md5()

    f = open(filename, 'rb')

    buffer = 8192

    while 1:

      chunk = f.read(buffer)

      if not chunk:

        break

      m.update(chunk)

    f.close()

    md5calculated = m.hexdigest()

  except Exception as inst:

    write2Log("\nverify %s md5 exception: %s" % (filename, inst))

    print "\n####verify %s md5 exception: %s####" % (filename, inst)

    return False

  if md5sumgiven == md5calculated:

    return True

  write2Log("\nverify %s md5 error: md5sumgiven is %s filemd5 is %s" %(filename, md5sumgiven, md5calculated))

  print "\n####verify %s md5 error: md5sumgiven is %s filemd5 is %s####" %(filename, md5sumgiven, md5calculated)

  return False

 

#Check MD5 file

def checkFile(src, dest):

  src = "%s.md5" % src

  destmd5 = "%s.md5" % dest

  bFlag = doCopyFile(src, destmd5, 120)

  if (True == bFlag) and (True == verifyMD5sumofFile(getMD5SumGiven("md5sum", destmd5), dest)):

    write2Log("\ncheckFile success: %s" % destmd5)

    print "\n####checkFile success: %s####" % destmd5

    return True

  elif (True != bFlag):

    write2Log("\n%s is not exist! Don't verify the MD5 file!" % destmd5)

    print "INFO: %s is not exist! Don't verify the MD5 file!" % destmd5

    return True

  return False

 

#Get config file according to the mode

def getCfgFileName():

  global config_server_name

  if (python_config_file_mode == "python_serial_number") and (os.environ.has_key('DEV_SERIAL')):

    config_server_name = "%s.cfg" % os.environ['DEV_SERIAL']

    return config_server_name

  else:

    return config_server_name

 

#copy file to all standby slot

def syncFileToStandby(sSrcFile, sFileName):

  try:

    aSlotRange = []

    if ("get_standby_slot" in dir(comware)):

      aSlotRange = aSlotRange + comware.get_standby_slot()

        

    i = 0

    while i < len(aSlotRange):

      if(aSlotRange[i] != None):

        sDestFile = "%s%s" %(getPath(aSlotRange[i][0], aSlotRange[i][1]), sFileName)

        removeFile(sDestFile)

        open(sDestFile,"wb").write(open(sSrcFile,"rb").read())

        write2Log("\nsync file to standby %s" % (sDestFile))

        print "\n####sync file to standby %s####" % (sDestFile)

      i = i + 1

  except Exception as inst:

    write2Log("\nsync file to standby %s exception: %s" % (sSrcFile, inst))

    print "\n####sync file to standby %s exception: %s####" % (sSrcFile, inst)

 

#根据脚本开始处定义的全局变量,下载启动软件包、配置文件、sn文件等

#Procedure to copy config file using global information

def copyAndCheckFile(src, dest, timeout):

  global server_path, local_path

  srcTmp = "%s%s" % (server_path, src)

  sDestFile = "%s%s" % (local_path, dest)

  if (True == doCopyFile(srcTmp, sDestFile, timeout)) and (True == checkFile(srcTmp, sDestFile)):

    syncFileToStandby(sDestFile, dest)

    return True

  else:

    srcTmp = "%sdefault_%s" %(server_path, src)

    if (True == doCopyFile(srcTmp, sDestFile, timeout)) and (True == checkFile(srcTmp, sDestFile)):

      syncFileToStandby(dest)

      return True

  return False

 

# split the Chassis and Slot

def splitChassisSlot(chassisID, slotID):

  chassis_slot = ""

  if chassisID != -1:

    chassis_slot = " chassis %d"  % chassisID

  if slotID != -1:

    chassis_slot = "%s slot %d" %(chassis_slot, slotID)

  return chassis_slot

 

#从HTTP服务器上下载启动软件包

def copyBootImage():

  global image_timeout, local_path, boot_server_name, boot_local_name

  src = "%s" % boot_server_name

  return copyAndCheckFile(src, boot_local_name, image_timeout)

 

#从HTTP服务器上下载配置文件

def copyCfgFile():

  global config_timeout, local_path, config_local_name

  src = "%s" % getCfgFileName()

  return copyAndCheckFile(src, config_local_name, config_timeout)

 

#从HTTP服务器上下载sn.txt文件

def copyIrfStack():

  global irf_timeout, local_path, irf_local_name, irf_server_name

  src = "%s" % irf_server_name

  return copyAndCheckFile(src, irf_local_name, config_timeout)

 

#执行boot-loader命令,为设备指定下次主用启动文件

# Procedure to Install Boot Image

def installBoot(chassis_slot, sFile, style):

  result = None

  write2Log("\ninstall%s%s begin" %(chassis_slot, style))

  print "INFO: Install%s%s Start, Please Wait..." %(chassis_slot, style)

  comd = "boot-loader file %s%s%s" % (sFile, chassis_slot, style)

  try:

    result = comware.CLI(comd, False)

    if result == None:

      write2Log("\nboot-loader file %s%s%s failed" % (sFile, chassis_slot, style))

      print "\n####boot-loader file %s%s%s failed####" % (sFile, chassis_slot, style)

      return False

  except Exception as inst:

    write2Log("\nboot-loader %s exception: %s" % (sFile, inst))

    print "\n####boot-loader %s exception: %s####" % (sFile, inst)

    return False

  return True

 

#Procedure to install boot image

def installBootImage():

  global boot_local_name

  aSlotRange = [comware.get_self_slot()]

  if ("get_standby_slot" in dir(comware)):

    aSlotRange = aSlotRange + comware.get_standby_slot()

  bInstallOk = True

  i = 0

  while i < len(aSlotRange):

    sFile = "%s%s" %(getPath(aSlotRange[0][0], aSlotRange[0][1]), boot_local_name)

    if False == installBoot(splitChassisSlot(aSlotRange[i][0], aSlotRange[i][1]), sFile, " main"):

      bInstallOk = False

    i = i + 1

  return bInstallOk

 

#执行startup saved-configuration命令为设备指定下次启动配置文件

def startupCfg():

  global local_path, config_local_name

  result = None

  dest = "%s%s" %(local_path, config_local_name)

  write2Log("\nstartup saved-configuration %s begin" %dest)

  print "INFO: Startup Saved-configuration Start"

  comd = "startup saved-configuration %s main" % dest

  try:

    result = comware.CLI(comd, False)

    if result == None:

      write2Log("\nstartup saved-configuration %s failed" % dest)

      print "\n####startup saved-configuration %s failed####" % dest

      return False

  except Exception as inst:

    write2Log("\nstartup %s exception: %s" % (dest, inst))

    print "\n####startup %s exception: %s####" % (dest, inst)

    return False

  write2Log("\nstartup saved-configuration %s success" % dest)

  print "INFO: Completed Startup Saved-configuration"

  return True

 

def getIrfCfg(line, num):

  line = line.split()

  number = None

  if 3 == len(line):

    number = line[num]

  else :

    number = None

  return number

 

def getMemberID():

  aMemId = comware.get_self_slot()

  memId = None

  if aMemId[0] == -1 :

    memId = aMemId[1]

  else :

    memId = aMemId[0]

  return memId

 

def getNewMemberID():

  global irf_local_name, local_path, env

  filename = "%s%s" %(local_path, irf_local_name)

  serNum = os.environ['DEV_SERIAL']

  print "\n####Test Chassis SN or Slot SN %s" % serNum

  reNum = None

  try:

    file = open(filename, "r")

    line = file.readline()

    while "" != line:

      if (serNum == getIrfCfg(line, 0)):

        file.close()

        reNum = getIrfCfg(line, 2)

        return reNum

      line = file.readline()

    file.close()

  except Exception as inst:

    write2Log("\nget renumberID exception: %s" % inst)

    print "\n####get renumberID exception: %s####" % inst

  write2Log("\nget %s renumberID failed" % filename)

  print "\n#### get %s renumberID failed ####" % filename

  return reNum

 

#判断设备是否是处于已经建立IRF

def isIrfDevice():

  try:

    result = comware.CLI("display irf", False)

    if result == None:

      return False

  except Exception as inst:

    return False

  return True

 

#解析sn.txt文件并使用renumber修改设备的IRF成员编号

def getIrfComd():

  comd = None

  newMemberID = getNewMemberID()

  aMemId = comware.get_self_slot()

  if None == newMemberID:

    return None

  if False == isIrfDevice():

    comd = "system-view ; irf member %s ; chassis convert mode irf" % newMemberID

  else:

    comd = "system-view ; irf member %s renumber %s" % (getMemberID(), newMemberID)

  return comd

 

def stackIrfCfg():

  global env

  if (not os.environ.has_key('DEV_SERIAL')):

    write2Log("\nenviron variable 'DEV_SERIAL' is not found!")

    print "\n####environ variable 'DEV_SERIAL' is not found!####"

    return False

  comd = getIrfComd()

  if None == comd:

    return False

  result = None

  write2Log("\nstartup stack irf begin")

  print "INFO: Startup stack irf Start"

  try:

    result = comware.CLI(comd, False)

    if result == None:

      write2Log("\nstartup stack irf failed: %s" % comd)

      print "\n####startup stack irf failed: %s####" %comd

      return False

  except Exception as inst:

    write2Log("\nstartup stack irf exception: %s command: %s" % (inst, comd))

    print "\n####startup stack irf exception: %s command: %s####" % (inst, comd)

    return False

  write2Log("\nstartup stack irf success")

  print "INFO: Completed Startup Stack Irf"

  return True

 

#check if all standby slots are ready

def ifAllStandbyReady():

  if (("get_slot_range" in dir(comware)) == False):

    return True

    

  aSlotRange = comware.get_slot_range()

  bAllReady = True

  for i in range(aSlotRange["MinSlot"], aSlotRange["MaxSlot"]):

    oSlotInfo =  comware.get_slot_info(i)

    if (oSlotInfo != None) and (oSlotInfo["Role"] == "Standby") and (oSlotInfo["Status"] == "Fail"):

      bAllReady = False

      write2Log("\nSlot %s is not ready!" %i)

      print "\n####Slot %s is not ready!####" %i

  return bAllReady

 

#if have any standby slot was not ready sleep for waiting

def waitStandbyReady():

  while ifAllStandbyReady() == False:

    sleep(10)

 

#python main

 

#when download file user can stop script

waitStandbyReady()

signal.signal(signal.SIGTERM, sigterm_handler)

 

if (True == verifyAllFreeSpace()) and (True == copyBootImage()) and (True == copyCfgFile()) and (True == copyIrfStack()):

  #after download file user can not stop script

  signal.signal(signal.SIGTERM, sig_handler_no_exit)

  if (True == installBootImage()) and (True == startupCfg()) and (True == stackIrfCfg()):

    doExit("success")

doExit("error")

·     配置文件:配置文件包含了所有设备进行IRF的相关命令,管理员可以在已经成功创建IRF的设备上,将配置文件导出并修改然后保存在HTTP服务器上,供需要创建类似拓扑IRF的设备下载使用。

·     sn.txt文件:每个设备都有唯一的设备序列号,sn.txt文件根据设备的序列号来指定设备在IRF组中的成员编码。设备通过运行Python脚本来解析sn.txt文件,然后修改设备的IRF成员编号,并根据自身的成员编号来完成相应的IRF配置。

·     软件启动包:软件启动包是设备启动、运行的必备软件,需保存在HTTP服务器上。如果现有设备(包括主设备和从设备)的启动软件包全部一致且不需要升级软件版本,可不需要准备该文件。

(2)     在Device A上配置DHCP服务器

# 开启DHCP服务,创建名称为1的DHCP地址池,配置地址池动态分配IP地址的网段为192.168.1.0/24。

<DeviceA> system-view

[DeviceA] dhcp enable

[DeviceA] dhcp server ip-pool 1

[DeviceA-dhcp-pool-1] network 192.168.1.0 24

# 配置DHCP客户端远程启动配置文件为HTTP形式的URL。

[DeviceA-dhcp-pool-1] bootfile-name http://192.168.1.40/device.py

[DeviceA-dhcp-pool-1] quit

# 配置接口GigabitEthernet1/0/1工作在DHCP服务器模式。

[DeviceA] interface gigabitethernet 1/0/1

[DeviceA-GigabitEthernet1/0/1] dhcp select server

[DeviceA-GigabitEthernet1/0/1] quit

(3)     设备根据DHCP服务器获取到Python脚本文件,执行Python脚本下载配置文件和软件启动包;解析sn.txt文件生成IRF成员编号。然后,所有设备会执行重启操作。

(4)     设备重启完毕后,连接Switch A和Switch B之间的线缆,连接好线缆后设备将进行IRF选举,选举失败的一台设备会再次重启。当设备自动重启后,Switch A和Switch B成功组成IRF。

4. 验证配置

下面以Switch A为例验证设备是否成功组成IRF,Switch B和Switch A类似,不再赘述。

# 显示IRF中所有成员设备的相关信息。

<Switch A> display irf

MemberID  Slot  Role    Priority  CPU-Mac         Description

   1      1     Standby 1         00e0-fc0f-8c02  ---

 *+2      1     Master  30        00e0-fc0f-8c14  ---

--------------------------------------------------

 * indicates the device is the master.

 + indicates the device through which the user logs in.

 

 The Bridge MAC of the IRF is: 000c-1000-1111

 Auto upgrade                : yes

 Mac persistent              : always

 Domain ID                   : 0

以上显示信息表明IRF已经成功建立。

 

不同款型规格的资料略有差异, 详细信息请向具体销售和400咨询。H3C保留在没有任何通知或提示的情况下对资料内容进行修改的权利!

新华三官网
联系我们