網絡管理:網絡設備的批量化操作


新浪微博: @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.h3c and
#                 sw-backup.cmd.cisco
#  <uid>          uid for telnet
#  <pwd>          pwd for telnet
#
#
# Depends:        <cmd-prefix>.cmd.h3c
#                 <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.h3c 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.h3c 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.h3c 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.h3c 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 "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批量操作,具體實現本文不再贅述。


希望本文能夠對有需要的朋友有所幫助,程序代碼可以任意使用。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章