Skip to content

Instantly share code, notes, and snippets.

@momchilov
Last active December 20, 2015 20:59
Show Gist options
  • Save momchilov/7b3c5b09eaacc153f43d to your computer and use it in GitHub Desktop.
Save momchilov/7b3c5b09eaacc153f43d to your computer and use it in GitHub Desktop.
switch backup through telnet management interface
#!/usr/bin/env ruby
require 'rubygems'
require 'net/telnet'
require 'mac_vendor'
has_errors = false
# loading mac database
mac_vendor = MacVendor.new :use_local => true
File.open('switch_ips').read.each_line do |switch_ip|
next if switch_ip =~ /^\s*$/
ip_addr=switch_ip.strip
port_num = 23
uname = "admin"
# pass="lan#{ip_addr[/(\d){1,3}$/]}"
pass="digest"
dir_name="configs/#{Time.now.strftime("%Y-%m")}/#{ip_addr}/"
file_name="#{ip_addr}-#{Time.now.strftime("%Y-%m-%d")}-config"
telnet_prompt=/^(.*)#\z/i # dlink prompt
telnet_uname=/(user[ ]?name):/i
telnet_pass=/(password):/i
telnet_dlink_failed=/fail/i
switch_mac=`(ping -c1 #{ip_addr} > /dev/null 2>&1 ) && /usr/sbin/arp -e #{ip_addr} | tail -n1 | awk '{ print $3 }'`.strip
if not switch_mac.match(/^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$/i)
print "[error] #{ip_addr}: Couldn't get MAC address.\n"; has_errors = true; next
end
# initializing the variables
vendor_match=Hash.new
switch_vendor=""
mac_vendor_result = mac_vendor.lookup(switch_mac)[:name]
# vendor-specific initial settings
case mac_vendor_result
when /d-link/i
switch_vendor="d-link"
telnet_prompt=/^(.*)#\z/i
when /zyxel/i
switch_vendor="zyxel"
telnet_prompt=/^(.*)#\s/i
when /dell/i
switch_vendor= "dell"
telnet_prompt=/^(.*)#\s/i
else
print "[error] #{ip_addr}: No match found for the switch vendor.\n"; has_errors = true; next
end
begin
host = Net::Telnet::new(
"Host" => ip_addr, # default: "localhost"
"Port" => port_num, # default: 23
"Binmode" => false, # default: false
#"Output_log" => "output_log", # default: nil (no output)
#"Dump_log" => "dump_log", # default: nil (no output)
"Prompt" => telnet_prompt, # default: /[$%#>] \z/n
"Telnetmode" => true, # default: true
#"Telnetmode" => false, # default: true
"Timeout" => 10, # default: 10
# if ignore timeout then set "Timeout" to false.
"Waittime" => 0 # default: 0
# proxy is Net::Telnet or IO object
)
host.waitfor(telnet_uname)
host.puts(uname)
host.waitfor(telnet_pass)
rescue Timeout::Error
print "[error] #{ip_addr} timed out.\n"; has_errors=true; next
end
login_failed = false
host.cmd(pass) do |output|
# LOGIN DETECTION:
# d-link displays a failure message
# zyxel asks for password if login fails
if output.match(telnet_dlink_failed) or output.match(telnet_pass) or output.match(telnet_uname)
print "[error] #{ip_addr}: Login failed\n" ; login_failed = true; has_errors = true; break
end
end
next if login_failed
# init response variable
resp = ""
# switch vendor-specific instructions
case switch_vendor
when "d-link"
host.cmd("show config current_config\na") { |line| resp += line }
resp = resp.split("\n")[4..-4].join("\n").gsub(/(\^M)*/, '')
when "zyxel"
host.cmd("show running-config") { |line| resp += line }
resp = resp.split("\n")[5..-2].join("\n").gsub(/(\^M)*/, '')
when "dell"
host.cmd("enable")
host.cmd("show startup-config") do |line|
unless line.match(/More\:\s\<space\>/)
resp += line
else
host.puts("\s")
end
end
resp = resp.split("\n")[1..-2].join("\n").gsub(/(\^M)*/, '')
end
`mkdir -p #{dir_name}`
File.open(dir_name + file_name, 'w') {|f| f.write(resp.chomp) }
print "[downloaded] Switch configuration for: #{ip_addr}. Device vendor: #{switch_vendor.capitalize}.\n";
end
exit 1 if has_errors
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment