您好,登录后才能下订单哦!
新浪微博: @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> <cmd-prefix> <uid> <pwd> # # <ip> ip for telnet # <cmd-prefix> For example, sw-backup is cmd-prefix of sw-backup.cmd.h4c and # sw-backup.cmd.cisco # <uid> uid for telnet # <pwd> pwd for telnet # # # Depends: <cmd-prefix>.cmd.h4c # <cmd-prefix>.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 <ip> <cmd-prefix> <uid> <pwd>" puts " ^^" puts " <ip> ip for telnet" puts " <cmd-prefix> For example, sw-backup is cmd-prefix of sw-backup.cmd.h4c and" puts " sw-backup.cmd.cisco" puts " <uid> uid for telnet" puts " <pwd> pwd for telnet" puts "" exit 1 } # Arg 2 set cmd_prefix [lindex $argv 1] if { $cmd_prefix == "" } { puts "" puts "Statement: command <ip> <cmd-prefix> <uid> <pwd>" puts " ^^^^^^^^^^" puts " <ip> ip for telnet" puts " <cmd-prefix> For example, sw-backup is cmd-prefix of sw-backup.cmd.h4c and" puts " sw-backup.cmd.cisco" puts " <uid> uid for telnet" puts " <pwd> pwd for telnet" puts "" exit 1 } # Arg 3 set uid [lindex $argv 2] if { $uid == "" } { #set uid "backup" puts "" puts "Statement: command <ip> <cmd-prefix> <uid> <pwd>" puts " ^^^" puts " <ip> ip for telnet" puts " <cmd-prefix> For example, sw-backup is cmd-prefix of sw-backup.cmd.h4c and" puts " sw-backup.cmd.cisco" puts " <uid> uid for telnet" puts " <pwd> pwd for telnet" puts "" exit 1 } # Arg 4 set pwd [lindex $argv 3] if { $pwd == "" } { #set pwd "M2dpSF6rSU" puts "" puts "Statement: command <ip> <cmd-prefix> <uid> <pwd>" puts " ^^^" puts " <ip> ip for telnet" puts " <cmd-prefix> For example, sw-backup is cmd-prefix of sw-backup.cmd.h4c and" puts " sw-backup.cmd.cisco" puts " <uid> uid for telnet" puts " <pwd> pwd for telnet" puts "" exit 1 } #___ start telnet ___ spawn $cmd_telnet "$ip" sleep 1 expect "H3C" { set vendor "h4c" } 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, h4c) _____ 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" } h4c { # vendor: h4c set timeout_h4c 10 set timeout $timeout_h4c #___ 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_h4c } 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.h4c
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.h4c
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批量操作,具体实现本文不再赘述。
希望本文能够对有需要的朋友有所帮助,程序代码可以任意使用。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。