网络管理:网络设备的批量化操作
新浪微博: @wandering
博客地址: dayong.info
在深入进行网络工作一段时间后,开始着手解决AAA、NTP、SYSLOG基础服务(简称:基础服务)的可用性和线上设备相关配置的正确性问题。
前期,一边优化、重构基础服务,一边修正线上配置。但这个项目是个系统工程,无法在短期内完成,因此即要保持战果让已修正的配置不再出错,还希望新增加的设备可以直接进行正确配置。另外,如何保证其他工程师也正确配置设备,也是需要解决的问题,毕竟工作最终是需要多个团队共同协作的。
因此,自动检查线上所有重要交换机和路由器的网管服务、Spanning-Tree、VTP Mode等重要配置是否正确,成了必须优先解决的问题。
最直接的方法就是直接检查相应配置,这符合网络管理人员的思维和操作习惯。因此,决定优先解决多台设备的批量执行命令需求。
本人一直对程序设计有这样的观点,不能解决问题的程序不是好程序,因此程序首先要实现功能,其次才是程序的效能。只有在规模、需求达到相当程度后才有必要对效率、性能追求极致。对非专业开发人员来说更是要注意精力、时间的分配,20%的投入获得80%的回报其投入产出比是相当可观的,再多花80%的精力去提升最多20%的性能是必须慎重对待的。因此,决定采用模拟人机交互方式实现网络设备的批量化操作。
程序实现基本逻辑是:
1)自动登录交换机、路由器批量执行命令,将结果输出。
2)对输出结果进行二次处理,实现不同目标。
这样,基本可以解决大部分网络管理需要,其主要优点是简单,会操作交换机/路由器的人就可以使用。但是,此方法最大的问题是效率,因为本质上只是由程序模仿手工操作,需要考虑cli可以接受的操作频率等问题。曾考虑过SNMP、TCL-Script、NET-CONF等方法,但考虑到自己的能力及精力分配、跨厂商平台兼容性问题最终放弃。
网上可以查到的模拟人工命令交互操作的方法有2个:perl、expect
首先考虑的是perl,因为有perl编程基础,有其他同事写好的相似功能脚本,但最终放弃。因为perl的switch模块不支持Cisco的Nexus平台内容输出,其解决方法非常复杂,要修改switch模块的源代码,这样会产生自己的分支,管理维护成本太高,不利于程序的持续开发和推广 。
最后,选择expect,其原理是执行命令,根据不同输出反馈采取不同操作,重复这个过程。
关于expect的学习使用,不在本文的关注范围。
以下最新版本的代码:
#!/usr/local/bin/expect
#
# Statement: sw-telnet.exp
#
# ip for telnet
# For example, sw-backup is cmd-prefix of sw-backup.cmd.h3c and
# sw-backup.cmd.cisco
# uid for telnet
# pwd for telnet
#
#
# Depends: .cmd.h3c
# .cmd.cisco
#
#
# Last modified: 2012/05/24
#
#
set path_cmd "/aaa/bin"
set cmd_telnet "telnet"
set timeout_default 10
set timeout $timeout_default
set vendor "cisco"
# Arg 1
set ip [lindex $argv 0]
if { $ip == "" } {
puts ""
puts "Statement: command "
puts " ^^"
puts " ip for telnet"
puts " For example, sw-backup is cmd-prefix of sw-backup.cmd.h3c and"
puts " sw-backup.cmd.cisco"
puts " uid for telnet"
puts " pwd for telnet"
puts ""
exit 1
}
# Arg 2
set cmd_prefix [lindex $argv 1]
if { $cmd_prefix == "" } {
puts ""
puts "Statement: command "
puts " ^^^^^^^^^^"
puts " ip for telnet"
puts " For example, sw-backup is cmd-prefix of sw-backup.cmd.h3c and"
puts " sw-backup.cmd.cisco"
puts " uid for telnet"
puts " pwd for telnet"
puts ""
exit 1
}
# Arg 3
set uid [lindex $argv 2]
if { $uid == "" } {
#set uid "backup"
puts ""
puts "Statement: command "
puts " ^^^"
puts " ip for telnet"
puts " For example, sw-backup is cmd-prefix of sw-backup.cmd.h3c and"
puts " sw-backup.cmd.cisco"
puts " uid for telnet"
puts " pwd for telnet"
puts ""
exit 1
}
# Arg 4
set pwd [lindex $argv 3]
if { $pwd == "" } {
#set pwd "M2dpSF6rSU"
puts ""
puts "Statement: command "
puts " ^^^"
puts " ip for telnet"
puts " For example, sw-backup is cmd-prefix of sw-backup.cmd.h3c and"
puts " sw-backup.cmd.cisco"
puts " uid for telnet"
puts " pwd for telnet"
puts ""
exit 1
}
#___ start telnet ___
spawn $cmd_telnet "$ip"
sleep 1
expect "H3C" { set vendor "h3c" }
expect -re "Username:|Login:|login:" {
send "$uid\r"
sleep 1
}
expect "Password:" {
send "$pwd\r"
sleep 1
}
#_____ login failed _____
expect {
"Access denied" { exit }
"Connection refused" { exit }
"Login failed" { exit }
"Login incorrect" { exit }
"Login invalid" { exit }
"Password incorrect." { exit }
"timeout expired!" { exit }
}
#_____ Command sets selection by vendor (cisco, h3c) _____
switch -- $vendor cisco { # vendor: cisco
set timeout_cisco 60
set timeout $timeout_cisco
#___ get commands __
set file [ open "$path_cmd/$cmd_prefix.cmd.$vendor" "r" ]
set cmd_count 0
while 1 {
if { [gets $file line] == -1 } break
incr cmd_count
set cmd_list($cmd_count) $line
}
close $file
expect -re ".*# *$"
send "term len 0\r\n\n\n"
set i 1
while { $i <= $cmd_count } {
expect -re ".*# *$"
send "$cmd_list($i)\r\n\n\n"
incr i
sleep 1
}
expect -re ".*# *$"
send "exit\r"
} h3c { # vendor: h3c
set timeout_h3c 10
set timeout $timeout_h3c
#___ get commands __
set file [ open "$path_cmd/$cmd_prefix.cmd.$vendor" "r" ]
set cmd_count 0
while 1 {
if { [gets $file line] == -1 } break
incr cmd_count
set cmd_list($cmd_count) $line
}
close $file
set i 1
while { $i <= $cmd_count } {
expect -re "<.*>$"
send "$cmd_list($i)\r\r\r\r"
expect -re "\- More \-+$" {
set timeout 3
set more "yes"
while {$more == "yes"} {
#puts "___ more ___\r"
send " "
expect -re "<.*>$" {
#puts "___ there's no more ___"
set more "no"
}
}
set timeout $timeout_h3c
}
incr i
sleep 1
}
expect -re "<.*>$"
send "quit\r"
} default { # vendor: unkown
puts "\nError: Unkown Vendor!\n"
exit
}
expect eof
puts "\nVendor: $vendor"
puts "Command list:"
set i 1
while { $i <= $cmd_count } {
puts "$i) $cmd_list($i)"
incr i
}
puts ""
exit
*注:脚本目前只支持Cisco和H3C两个主流平台。
*注:注意设置程序运行路径变量 path_cmd 。
举例,假设需要对设备1.2.3.4做以下操作:
1)备份running-config
2)查看cpu状态
首先,需要建立4个文件,脚本会自动判断Cisco或H3C设备类型执行相应命令集:
1)backup.cmd.cisco
dir show ver show inv show run
2)backup.cmd.h3c
dir disp verion disp device manuinfo disp curr
3)version.cmd.cisco
show process cpu sort | exclude 0.00% show process cpu history
4)version.cmd.h3c
display cpu-usage
其次,写crontab:
0 3 * * * /aaa/bin/sw-telnet.exp 1.2.3.4 backup test_uid test_pwd > /bak/1.2.3.4_show-run_$(date +"%Y%m%d") */10 * * * * /aaa/bin/sw-telnet.exp 1.2.3.4 version test_uid test_pwd >> /bak/1.2.3.4_show-ver_$(date +"%Y%m%d")
OK,这样就实现了对1.2.3.4的自动抓取running-config和记录cpu状态。
在此代码基础上,完成了以下工作:
对全网重要设备抓取running-config,并实现关键配置检查报警对某产品相关服务器接入交换机端口进行流量监控、报警(公司监控不能查看port-channel属性)对某IDC核心交换机的mac地址表监控,增减幅度超过5%报警
自动批量执行命令脚本是核心代码,可以通过其它程序调用实现更复杂的功能,例如对多个IP批量操作,具体实现本文不再赘述。
希望本文能够对有需要的朋友有所帮助,程序代码可以任意使用。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
暂时没有评论,来抢沙发吧~