canonalize_ifname(interface)
click to toggle source
def canonalize_ifname(interface)
IF.each do |k,ifnames|
if found = ifnames.find { |ifname| interface =~ /^#{ifname}\s*\d/ }
found = /^#{found}(.+)\Z/.match(interface)
return "#{k.to_s}#{found[1]}".gsub(/\s+/,'')
end
end
interface
end
command(cmd = nil) { |self| ... }
click to toggle source
def command(cmd = nil)
connect
out = execute(cmd) if cmd
yield self if block_given?
disconnect
out
end
connect()
click to toggle source
def connect
transport.connect
login
transport.command("terminal length 0") do |out|
enable if out =~ />\s?\z/
end
find_capabilities
end
disconnect()
click to toggle source
def disconnect
transport.close
end
enable()
click to toggle source
def enable
raise "Can't issue \"enable\" to enter privileged, no enable password set" unless enable_password
transport.command("enable", :prompt => /^Password:/)
transport.command(enable_password)
end
execute(cmd)
click to toggle source
def execute(cmd)
transport.command(cmd)
end
facts()
click to toggle source
def facts
@facts ||= Puppet::Util::NetworkDevice::Cisco::Facts.new(transport)
facts = {}
command do |ng|
facts = @facts.retrieve
end
facts
end
find_capabilities()
click to toggle source
def find_capabilities
out = execute("sh vlan brief")
lines = out.split("\n")
lines.shift; lines.pop
@support_vlan_brief = ! (lines.first =~ /^%/)
end
interface(name)
click to toggle source
def interface(name)
ifname = canonalize_ifname(name)
interface = parse_interface(ifname)
return { :ensure => :absent } if interface.empty?
interface.merge!(parse_trunking(ifname))
interface.merge!(parse_interface_config(ifname))
end
login()
click to toggle source
def login
return if transport.handles_login?
if @url.user != ''
transport.command(@url.user, :prompt => /^Password:/)
else
transport.expect(/^Password:/)
end
transport.command(@url.password)
end
new_interface(name)
click to toggle source
def new_interface(name)
Puppet::Util::NetworkDevice::Cisco::Interface.new(canonalize_ifname(name), transport)
end
parse_enable(query)
click to toggle source
def parse_enable(query)
if query
params = CGI.parse(query)
params['enable'].first unless params['enable'].empty?
end
end
parse_interface(name)
click to toggle source
def parse_interface(name)
resource = {}
out = execute("sh interface #{name}")
lines = out.split("\n")
lines.shift; lines.pop
lines.each do |l|
if l =~ /#{name} is (.+), line protocol is /
resource[:ensure] = ($1 == 'up' ? :present : :absent);
end
if l =~ /Auto Speed \(.+\),/ or l =~ /Auto Speed ,/ or l =~ /Auto-speed/
resource[:speed] = :auto
end
if l =~ /, (.+)Mb\/s/
resource[:speed] = $1
end
if l =~ /\s+Auto-duplex \((.{4})\),/
resource[:duplex] = :auto
end
if l =~ /\s+(.+)-duplex/
resource[:duplex] = $1 == "Auto" ? :auto : $1.downcase.to_sym
end
if l =~ /Description: (.+)/
resource[:description] = $1
end
end
resource
end
parse_interface_config(name)
click to toggle source
def parse_interface_config(name)
resource = Hash.new { |hash, key| hash[key] = Array.new ; }
out = execute("sh running-config interface #{name} | begin interface")
lines = out.split("\n")
lines.shift; lines.pop
lines.each do |l|
if l =~ /ip address (#{IP}) (#{IP})\s+secondary\s*$/
resource[:ipaddress] << [prefix_length(IPAddr.new($2)), IPAddr.new($1), 'secondary']
end
if l =~ /ip address (#{IP}) (#{IP})\s*$/
resource[:ipaddress] << [prefix_length(IPAddr.new($2)), IPAddr.new($1), nil]
end
if l =~ /ipv6 address (#{IP})\/(\d+) (eui-64|link-local)/
resource[:ipaddress] << [$2.to_i, IPAddr.new($1), $3]
end
if l =~ /channel-group\s+(\d+)/
resource[:etherchannel] = $1
end
end
resource
end
parse_trunking(interface)
click to toggle source
def parse_trunking(interface)
trunking = {}
out = execute("sh interface #{interface} switchport")
lines = out.split("\n")
lines.shift; lines.pop
lines.each do |l|
case l
when /^Administrative mode:\s+(.*)$/
case $1
when "trunk"
trunking[:mode] = :trunk
when "static access"
trunking[:mode] = :access
else
raise "Unknown switchport mode: #{$1} for #{interface}"
end
when /^Administrative Trunking Encapsulation:\s+(.*)$/
case $1
when "dot1q","isl"
trunking[:encapsulation] = $1.to_sym if trunking[:mode] == :trunk
else
raise "Unknown switchport encapsulation: #{$1} for #{interface}"
end
when /^Access Mode VLAN:\s+(.*) \(\(Inactive\)\)$/
when /^Access Mode VLAN:\s+(.*) \(.*\)$/
trunking[:native_vlan] = $1 if trunking[:mode] == :access
when /^Trunking VLANs Enabled:\s+(.*)$/
next if trunking[:mode] == :access
vlans = $1
trunking[:allowed_trunk_vlans] = case vlans
when /all/
:all
when /none/
:none
else
vlans
end
end
end
trunking
end
parse_vlans()
click to toggle source
def parse_vlans
vlans = {}
out = execute(support_vlan_brief? ? "sh vlan brief" : "sh vlan-switch brief")
lines = out.split("\n")
lines.shift; lines.shift; lines.shift; lines.pop
vlan = nil
lines.each do |l|
case l
when /^(\d+)\s+(\w+)\s+(\w+)\s+([a-zA-Z0-9,\/. ]+)\s*$/
vlan = { :name => $1, :description => $2, :status => $3, :interfaces => [] }
if $4.strip.length > 0
vlan[:interfaces] = $4.strip.split(/\s*,\s*/).map{ |ifn| canonalize_ifname(ifn) }
end
vlans[vlan[:name]] = vlan
when /^\s+([a-zA-Z0-9,\/. ]+)\s*$/
raise "invalid sh vlan summary output" unless vlan
if $1.strip.length > 0
vlan[:interfaces] += $1.strip.split(/\s*,\s*/).map{ |ifn| canonalize_ifname(ifn) }
end
else
end
end
vlans
end
support_vlan_brief?()
click to toggle source
def support_vlan_brief?
!! @support_vlan_brief
end
update_vlan(id, is = {}, should = {})
click to toggle source
def update_vlan(id, is = {}, should = {})
if should[:ensure] == :absent
Puppet.info "Removing #{id} from device vlan"
execute("conf t")
execute("no vlan #{id}")
execute("exit")
return
end
execute("conf t")
execute("vlan #{id}")
[is.keys, should.keys].flatten.uniq.each do |property|
Puppet.debug("trying property: #{property}: #{should[property]}")
next if property != :description
execute("name #{should[property]}")
end
execute("exit")
execute("exit")
end