3
require File.dirname(__FILE__) + '/../../../../spec_helper'
5
require 'puppet/util/network_device/cisco/device'
7
describe Puppet::Util::NetworkDevice::Cisco::Device do
9
@transport = stub_everything 'transport', :is_a? => true, :command => ""
10
@cisco = Puppet::Util::NetworkDevice::Cisco::Device.new("telnet://user:password@localhost:23/")
11
@cisco.transport = @transport
14
describe "when creating the device" do
15
it "should find the enable password from the url" do
16
cisco = Puppet::Util::NetworkDevice::Cisco::Device.new("telnet://user:password@localhost:23/?enable=enable_password")
17
cisco.enable_password.should == "enable_password"
20
it "should find the enable password from the options" do
21
cisco = Puppet::Util::NetworkDevice::Cisco::Device.new("telnet://user:password@localhost:23/?enable=enable_password", :enable_password => "mypass")
22
cisco.enable_password.should == "mypass"
26
describe "when connecting to the physical device" do
27
it "should connect to the transport" do
28
@transport.expects(:connect)
32
it "should attempt to login" do
33
@cisco.expects(:login)
37
it "should tell the device to not page" do
38
@transport.expects(:command).with("terminal length 0")
42
it "should enter the enable password if returned prompt is not privileged" do
43
@transport.stubs(:command).yields("Switch>").returns("")
44
@cisco.expects(:enable)
48
it "should find device capabilities" do
49
@cisco.expects(:find_capabilities)
53
it "should execute given command" do
54
@transport.expects(:command).with("mycommand")
55
@cisco.command("mycommand")
58
it "should yield to the command block if one is provided" do
59
@transport.expects(:command).with("mycommand")
61
c.command("mycommand")
65
it "should close the device transport" do
66
@transport.expects(:close)
70
describe "when login in" do
71
it "should not login if transport handles login" do
72
@transport.expects(:handles_login?).returns(true)
73
@transport.expects(:command).never
74
@transport.expects(:expect).never
78
it "should send username if one has been provided" do
79
@transport.expects(:command).with("user", :prompt => /^Password:/)
83
it "should send password after the username" do
84
@transport.expects(:command).with("user", :prompt => /^Password:/)
85
@transport.expects(:command).with("password")
89
it "should expect the Password: prompt if no user was sent" do
91
@transport.expects(:expect).with(/^Password:/)
92
@transport.expects(:command).with("password")
97
describe "when entering enable password" do
98
it "should raise an error if no enable password has been set" do
99
@cisco.enable_password = nil
100
lambda{ @cisco.enable }.should raise_error
103
it "should send the enable command and expect an enable prompt" do
104
@cisco.enable_password = 'mypass'
105
@transport.expects(:command).with("enable", :prompt => /^Password:/)
109
it "should send the enable password" do
110
@cisco.enable_password = 'mypass'
111
@transport.stubs(:command).with("enable", :prompt => /^Password:/)
112
@transport.expects(:command).with("mypass")
118
describe "when finding network device capabilities" do
119
it "should try to execute sh vlan brief" do
120
@transport.expects(:command).with("sh vlan brief").returns("")
121
@cisco.find_capabilities
124
it "should detect errors" do
125
@transport.stubs(:command).with("sh vlan brief").returns(<<eos)
127
% Ambiguous command: "sh vlan brief"
131
@cisco.find_capabilities
132
@cisco.should_not be_support_vlan_brief
138
"Fa 0/1" => "FastEthernet0/1",
139
"Fa0/1" => "FastEthernet0/1",
140
"FastEth 0/1" => "FastEthernet0/1",
141
"Gi1" => "GigEthernet1",
143
"Ethernet 0/0/1" => "Ethernet0/0/1",
145
"ATM 0/1.1" => "ATM0/1.1",
147
}.each do |input,expected|
148
it "should canonicalize #{input} to #{expected}", :'fails_on_ruby_1.9.2' => true do
149
@cisco.canonalize_ifname(input).should == expected
153
describe "when updating device vlans" do
154
describe "when removing a vlan" do
155
it "should issue the no vlan command" do
156
@transport.expects(:command).with("no vlan 200")
157
@cisco.update_vlan("200", {:ensure => :present, :name => "200"}, { :ensure=> :absent})
161
describe "when updating a vlan" do
162
it "should issue the vlan command to enter global vlan modifications" do
163
@transport.expects(:command).with("vlan 200")
164
@cisco.update_vlan("200", {:ensure => :present, :name => "200"}, { :ensure=> :present, :name => "200"})
167
it "should issue the name command to modify the vlan description" do
168
@transport.expects(:command).with("name myvlan")
169
@cisco.update_vlan("200", {:ensure => :present, :name => "200"}, { :ensure=> :present, :name => "200", :description => "myvlan"})
174
describe "when parsing interface" do
176
it "should parse interface output" do
177
@cisco.expects(:parse_interface).returns({ :ensure => :present })
179
@cisco.interface("FastEthernet0/1").should == { :ensure => :present }
182
it "should parse trunking and merge results" do
183
@cisco.stubs(:parse_interface).returns({ :ensure => :present })
184
@cisco.expects(:parse_trunking).returns({ :native_vlan => "100" })
186
@cisco.interface("FastEthernet0/1").should == { :ensure => :present, :native_vlan => "100" }
189
it "should return an absent interface if parse_interface returns nothing" do
190
@cisco.stubs(:parse_interface).returns({})
192
@cisco.interface("FastEthernet0/1").should == { :ensure => :absent }
195
it "should parse ip address information and merge results" do
196
@cisco.stubs(:parse_interface).returns({ :ensure => :present })
197
@cisco.expects(:parse_interface_config).returns({ :ipaddress => [24,IPAddr.new('192.168.0.24'), nil] })
199
@cisco.interface("FastEthernet0/1").should == { :ensure => :present, :ipaddress => [24,IPAddr.new('192.168.0.24'), nil] }
202
it "should parse the sh interface command" do
203
@transport.stubs(:command).with("sh interface FastEthernet0/1").returns(<<eos)
204
Switch#sh interfaces FastEthernet 0/1
205
FastEthernet0/1 is down, line protocol is down
206
Hardware is Fast Ethernet, address is 00d0.bbe2.19c1 (bia 00d0.bbe2.19c1)
207
MTU 1500 bytes, BW 100000 Kbit, DLY 100 usec,
208
reliability 255/255, txload 1/255, rxload 1/255
209
Encapsulation ARPA, loopback not set
211
Auto-duplex , Auto Speed , 100BaseTX/FX
212
ARP type: ARPA, ARP Timeout 04:00:00
213
Last input never, output 5d04h, output hang never
214
Last clearing of "show interface" counters never
215
Queueing strategy: fifo
216
Output queue 0/40, 0 drops; input queue 0/75, 0 drops
217
5 minute input rate 0 bits/sec, 0 packets/sec
218
5 minute output rate 0 bits/sec, 0 packets/sec
219
580 packets input, 54861 bytes
220
Received 6 broadcasts, 0 runts, 0 giants, 0 throttles
221
0 input errors, 0 CRC, 0 frame, 0 overrun, 0 ignored
222
0 watchdog, 1 multicast
223
0 input packets with dribble condition detected
224
845 packets output, 80359 bytes, 0 underruns
225
0 output errors, 0 collisions, 1 interface resets
226
0 babbles, 0 late collision, 0 deferred
227
0 lost carrier, 0 no carrier
228
0 output buffer failures, 0 output buffers swapped out
232
@cisco.parse_interface("FastEthernet0/1").should == { :ensure => :absent, :duplex => :auto, :speed => :auto }
235
it "should be able to parse the sh vlan brief command output", :'fails_on_ruby_1.9.2' => true do
236
@cisco.stubs(:support_vlan_brief?).returns(true)
237
@transport.stubs(:command).with("sh vlan brief").returns(<<eos)
239
VLAN Name Status Ports
240
---- -------------------------------- --------- -------------------------------
241
1 default active Fa0/3, Fa0/4, Fa0/5, Fa0/6,
242
Fa0/7, Fa0/8, Fa0/9, Fa0/10,
243
Fa0/11, Fa0/12, Fa0/13, Fa0/14,
244
Fa0/15, Fa0/16, Fa0/17, Fa0/18,
247
100 management active Fa0/1, Fa0/2
251
@cisco.parse_vlans.should == {"100"=>{:status=>"active", :interfaces=>["FastEthernet0/1", "FastEthernet0/2"], :description=>"management", :name=>"100"}, "1"=>{:status=>"active", :interfaces=>["FastEthernet0/3", "FastEthernet0/4", "FastEthernet0/5", "FastEthernet0/6", "FastEthernet0/7", "FastEthernet0/8", "FastEthernet0/9", "FastEthernet0/10", "FastEthernet0/11", "FastEthernet0/12", "FastEthernet0/13", "FastEthernet0/14", "FastEthernet0/15", "FastEthernet0/16", "FastEthernet0/17", "FastEthernet0/18", "FastEthernet0/23", "FastEthernet0/24"], :description=>"default", :name=>"1"}, "10"=>{:status=>"active", :interfaces=>[], :description=>"VLAN0010", :name=>"10"}}
254
it "should parse trunk switchport information" do
255
@transport.stubs(:command).with("sh interface FastEthernet0/21 switchport").returns(<<eos)
256
Switch#sh interfaces FastEthernet 0/21 switchport
259
Administrative mode: trunk
260
Operational Mode: trunk
261
Administrative Trunking Encapsulation: dot1q
262
Operational Trunking Encapsulation: dot1q
263
Negotiation of Trunking: Disabled
264
Access Mode VLAN: 0 ((Inactive))
265
Trunking Native Mode VLAN: 1 (default)
266
Trunking VLANs Enabled: ALL
267
Trunking VLANs Active: 1,10,100
268
Pruning VLANs Enabled: 2-1001
270
Priority for untagged frames: 0
271
Override vlan tag priority: FALSE
273
Appliance trust: none
278
@cisco.parse_trunking("FastEthernet0/21").should == { :mode => :trunk, :encapsulation => :dot1q, :allowed_trunk_vlans=>:all, }
281
it "should parse trunk switchport information with allowed vlans" do
282
@transport.stubs(:command).with("sh interface GigabitEthernet 0/1 switchport").returns(<<eos)
283
c2960#sh interfaces GigabitEthernet 0/1 switchport
286
Administrative Mode: trunk
287
Operational Mode: trunk
288
Administrative Trunking Encapsulation: dot1q
289
Operational Trunking Encapsulation: dot1q
290
Negotiation of Trunking: On
291
Access Mode VLAN: 1 (default)
292
Trunking Native Mode VLAN: 1 (default)
293
Administrative Native VLAN tagging: enabled
295
Administrative private-vlan host-association: none
296
Administrative private-vlan mapping: none
297
Administrative private-vlan trunk native VLAN: none
298
Administrative private-vlan trunk Native VLAN tagging: enabled
299
Administrative private-vlan trunk encapsulation: dot1q
300
Administrative private-vlan trunk normal VLANs: none
301
Administrative private-vlan trunk associations: none
302
Administrative private-vlan trunk mappings: none
303
Operational private-vlan: none
304
Trunking VLANs Enabled: 1,99
305
Pruning VLANs Enabled: 2-1001
306
Capture Mode Disabled
307
Capture VLANs Allowed: ALL
310
Unknown unicast blocked: disabled
311
Unknown multicast blocked: disabled
312
Appliance trust: none
316
@cisco.parse_trunking("GigabitEthernet 0/1").should == { :mode => :trunk, :encapsulation => :dot1q, :allowed_trunk_vlans=>"1,99", }
319
it "should parse access switchport information" do
320
@transport.stubs(:command).with("sh interface FastEthernet0/1 switchport").returns(<<eos)
321
Switch#sh interfaces FastEthernet 0/1 switchport
324
Administrative mode: static access
325
Operational Mode: static access
326
Administrative Trunking Encapsulation: isl
327
Operational Trunking Encapsulation: isl
328
Negotiation of Trunking: Disabled
329
Access Mode VLAN: 100 (SHDSL)
330
Trunking Native Mode VLAN: 1 (default)
331
Trunking VLANs Enabled: NONE
332
Pruning VLANs Enabled: NONE
334
Priority for untagged frames: 0
335
Override vlan tag priority: FALSE
337
Appliance trust: none
342
@cisco.parse_trunking("FastEthernet0/1").should == { :mode => :access, :native_vlan => "100" }
345
it "should parse ip addresses" do
346
@transport.stubs(:command).with("sh running-config interface Vlan 1 | begin interface").returns(<<eos)
347
router#sh running-config interface Vlan 1 | begin interface
349
description $ETH-SW-LAUNCH$$INTF-INFO-HWIC 4ESW$$FW_INSIDE$
350
ip address 192.168.0.24 255.255.255.0 secondary
351
ip address 192.168.0.1 255.255.255.0
352
ip access-group 100 in
355
ip nbar protocol-discovery
356
ip dns view-group dow
358
ip virtual-reassembly
360
ipv6 address 2001:7A8:71C1::/64 eui-64
362
ipv6 traffic-filter DENY-ACL6 out
364
ipv6 nd prefix 2001:7A8:71C1::/64
365
ipv6 nd ra interval 60
366
ipv6 nd ra lifetime 180
367
ipv6 verify unicast reverse-path
368
ipv6 inspect STD6 out
373
@cisco.parse_interface_config("Vlan 1").should == {:ipaddress=>[[24, IPAddr.new('192.168.0.24'), 'secondary'],
374
[24, IPAddr.new('192.168.0.1'), nil],
375
[64, IPAddr.new('2001:07a8:71c1::'), "eui-64"]]}
378
it "should parse etherchannel membership" do
379
@transport.stubs(:command).with("sh running-config interface Gi0/17 | begin interface").returns(<<eos)
380
c2960#sh running-config interface Gi0/17 | begin interface
381
interface GigabitEthernet0/17
382
description member of Po1
383
switchport mode access
384
channel-protocol lacp
385
channel-group 1 mode passive
386
spanning-tree portfast
387
spanning-tree bpduguard enable
392
@cisco.parse_interface_config("Gi0/17").should == {:etherchannel=>"1"}
396
describe "when finding device facts" do
397
it "should delegate to the cisco facts entity" do
399
Puppet::Util::NetworkDevice::Cisco::Facts.expects(:new).returns(facts)
401
facts.expects(:retrieve).returns(:facts)
403
@cisco.facts.should == :facts