File Coverage

blib/lib/Net/Autoconfig/Device/HP.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             package Net::Autoconfig::Device::HP;
2              
3 1     1   29111 use 5.008008;
  1         4  
  1         43  
4 1     1   7 use strict;
  1         3  
  1         37  
5 1     1   5 use warnings;
  1         2  
  1         44  
6              
7 1     1   5 use base "Net::Autoconfig::Device";
  1         8  
  1         1256  
8             use Log::Log4perl qw(:levels);
9             use Expect;
10             use version; our $VERSION = version->new('v1.2.2');
11              
12             #################################################################################
13             ## Constants and Global Variables
14             #################################################################################
15              
16             use constant TRUE => 1;
17             use constant FALSE => 0;
18             use constant LONG_TIMEOUT => 30;
19             use constant MEDIUM_TIMEOUT => 15;
20             use constant SHORT_TIMEOUT => 5;
21              
22             ####################
23             # Expect Command Definitions
24             # These statements are strings, which need to be
25             # eval'ed within the methods to get their
26             # actual values. This provides a way to pre-declare
27             # common expect commands without having to copy-paste
28             # them into each and every method that uses them.
29             # This incurs a performance hit, but I think it's
30             # worth it.
31             #
32             # Yay!
33             ####################
34             my $expect_ssh_key_cmd = '[
35             -re => "continue connecting",
36             sub
37             {
38             $session->clear_accum();
39             $session->send("yes\n"); sleep(1);
40             }
41             ]';
42             my $expect_username_cmd = '[
43             -re => "name:",
44             sub
45             {
46             $session->clear_accum();
47             $session->send($self->username . "\n");
48             sleep(1);
49             }
50             ]';
51             my $expect_password_cmd = '[
52             -re => "word[.:.]",
53             sub
54             {
55             $session->clear_accum();
56             $session->send($self->password . "\n");
57             sleep(1);
58             }
59             ]';
60             my $expect_hp_continue_cmd = '[
61             #-re => "any key to continue",
62             -re => "continue",
63             sub
64             {
65             $session->clear_accum();
66             $session->send("\n");
67             sleep(1);
68             }
69             ]';
70             my $expect_exec_mode_cmd = '[
71             -re => ">",
72             sub
73             {
74             $session->clear_accum();
75             $session->send("\n");
76             sleep(1);
77             $connected_to_device = TRUE;
78             }
79             ]';
80             my $expect_priv_mode_cmd = '[
81             -re => "#",
82             sub
83             {
84             $session->clear_accum();
85             $session->send("\n");
86             sleep(1);
87             $self->admin_status(TRUE);
88             $connected_to_device = TRUE;
89             }
90             ]';
91             my $expect_enable_cmd = '[
92             -re => ">",
93             sub
94             {
95             $session->clear_accum();
96             $session->send("enable\n");
97             sleep(1);
98             }
99             ]';
100             my $expect_enable_passwd_cmd = '[
101             -re => "[Pp]assword:",
102             sub
103             {
104             $session->clear_accum();
105             $session->send($self->enable_password . "\n");
106             sleep(1);
107             }
108             ]';
109             my $expect_already_enabled_cmd = '[
110             -re => "#",
111             sub
112             {
113             $session->clear_accum();
114             $session->send("\n");
115             sleep(1);
116             $already_enabled = TRUE;
117             }
118             ]';
119             my $expect_disable_paging_cmd = '[
120             -re => "#",
121             sub
122             {
123             $session->clear_accum();
124             $session->send("terminal length 1000\n");
125             }
126             ]';
127             my $expect_timeout_cmd = '[
128             timeout =>
129             sub
130             {
131             $command_failed = TRUE;
132             }
133             ]';
134              
135             #################################################################################
136             # Methods
137             #################################################################################
138              
139             ############################################################
140             # Public Methods
141             ############################################################
142              
143             ########################################
144             # new
145             # public method
146             #
147             # create a new Net::Autoconfig::Device::HP object.
148             #
149             # If passed an array, it will assume those are key
150             # value pairs and assign them to the device.
151             #
152             # If no values are defined, then default ones are assigned.
153             #
154             # Returns:
155             # A Net::Autoconfig::Device::HP object
156             ########################################
157             sub new {
158             my $invocant = shift; # calling class
159             my $class = ref($invocant) || $invocant;
160             my $self = {
161             @_,
162             invalid_cmd_regex => '[iI]nvalid input:',
163             };
164             my $log = Log::Log4perl->get_logger('Net::Autoconfig');
165              
166             $log->debug("Creating new Net::Autoconfig::Device::HP");
167             return bless $self, $class;
168             }
169              
170              
171              
172             ########################################
173             # connect
174             # public method
175             #
176             # overloads the parent method.
177             # Takes into account the ecentricities of
178             # hp devices.'
179             ########################################
180             sub connect {
181             my $self = shift;
182             my $session; # a ref to the expect session
183             my $access_command; # the string to use to the telnet/ssh app.
184             my $result; # the value returned after executing an expect cmd
185             my @expect_commands; # the commands to run on the device
186             my $spawn_cmd; # command expect uses to connect to the device
187             my $log = Log::Log4perl->get_logger("Net::Autoconfig");
188              
189             # Expect success/failure flags
190             my $connected_to_device; # indicates a successful connection to the device
191             my $command_failed; # indicates a failed connection to the device
192              
193             # Do some sanity checking
194             if (not $self->hostname)
195             {
196             $log->warn("No hostname defined for this device.");
197             return "No hostname defined for this devince.";
198             }
199              
200             if (not $self->access_method)
201             {
202             $log->warn("Access method for " . $self->hostname . " not defined.");
203             return "Access method not defined.";
204             }
205            
206             if (not $self->access_cmd)
207             {
208             $log->warn("Access command for " . $self->hostname . " not defined.");
209             return "Access command not defined";
210             }
211              
212             # Setup the access command
213             if ($self->access_method =~ /^ssh$/)
214             {
215             # Force using ssh version 1 due to old firmware problems.
216             $spawn_cmd = join(" ", $self->access_cmd, "-l", $self->username, $self->hostname);
217             }
218             else
219             {
220             $spawn_cmd = join(" ", $self->access_cmd, $self->hostname);
221             }
222              
223             # Okay, let's get on with connecting to the device
224             $session = $self->session;
225             if (&_invalid_session($session))
226             {
227             $log->info("Connecting to " . $self->hostname);
228             $log->debug("Using command '" . $self->access_cmd . "'");
229             $log->debug("Spawning new expect session with: '$spawn_cmd'");
230             eval
231             {
232             $session = new Expect;
233             $session->raw_pty(TRUE);
234             $session->spawn($spawn_cmd);
235             };
236             if ($@)
237             {
238             $log->warn("Connecting to " . $self->hostname . " failed: $@");
239             return $@;
240             }
241             }
242             else
243             {
244             $log->info("Session for ". $self->hostname . " already exists.");
245             }
246              
247             # Enable dumping data to the screen.
248             if ($log->is_trace() || $log->is_debug() )
249             {
250             $session->log_stdout(TRUE);
251             }
252             else
253             {
254             $session->log_stdout(FALSE);
255             }
256              
257             ####################
258             # Setup Expect command array
259             #
260             # The commands are defined for the class, but they need
261             # to be eval'ed before we can use them.
262             ####################
263             # Setup the expect commands to do the initial login.
264             # Up to four commands may need to be run:
265             # accept the ssh key
266             # send the username
267             # send the password
268             # bypass the initial login screen
269             # verify connection (exec or priv exec mode)
270             ####################
271             push(@expect_commands, [
272             eval $expect_ssh_key_cmd,
273             eval $expect_username_cmd,
274             eval $expect_password_cmd,
275              
276             # Check to see if we already have access
277             eval $expect_exec_mode_cmd,
278             eval $expect_priv_mode_cmd,
279             ]);
280             push(@expect_commands, [
281             eval $expect_username_cmd,
282             eval $expect_password_cmd,
283             # Get past the initial login banner
284             eval $expect_hp_continue_cmd,
285             eval $expect_exec_mode_cmd,
286             eval $expect_priv_mode_cmd,
287             ]);
288             push(@expect_commands, [
289             eval $expect_password_cmd,
290             # Get past the initial login banner
291             eval $expect_hp_continue_cmd,
292             eval $expect_exec_mode_cmd,
293             eval $expect_priv_mode_cmd,
294             ]);
295             push(@expect_commands, [
296             eval $expect_hp_continue_cmd,
297             eval $expect_exec_mode_cmd,
298             eval $expect_priv_mode_cmd,
299             ]);
300             push(@expect_commands, [
301             eval $expect_exec_mode_cmd,
302             eval $expect_priv_mode_cmd,
303             ]);
304              
305             foreach my $command (@expect_commands)
306             {
307             $session->expect(MEDIUM_TIMEOUT, @$command, eval $expect_timeout_cmd);
308             if ($log->level == $TRACE)
309             {
310             $log->trace("Expect matching before: " . $session->before);
311             $log->trace("Expect matching match : " . $session->match);
312             $log->trace("Expect matching after : " . $session->after);
313             }
314             if ($connected_to_device)
315             {
316             $log->debug("Connected to device " . $self->hostname);
317             $self->session($session);
318             last;
319             }
320             elsif ($command_failed)
321             {
322             $log->warn("Failed to connect to device " . $self->hostname);
323             $log->debug("Failed on command: " , @$command);
324             $session->soft_close();
325             $self->session(undef);
326             last;
327             }
328             }
329              
330             return $connected_to_device ? undef : 'Failed to connect to device.';
331             }
332              
333             ########################################
334             # discover_dev_type
335             # public method
336             #
337             # overloads the parent method.
338             #
339             # Since this is already discovered,
340             # return what type of device it is.
341             ########################################
342             sub discover_dev_type {
343             my $self = shift;
344             return ref($self);
345             }
346              
347             ########################################
348             # get_admin_rights
349             # public method
350             #
351             # overloads the parent method.
352             # Takes into account the ecentricities of
353             # hp devices.
354             #
355             # Returns:
356             # success = undef
357             # failure = reason for failure (aka a true value)
358             ########################################
359             sub get_admin_rights {
360             my $self = shift;
361             my $session = $self->session;
362             my $password = $self->enable_password;
363             my $log = Log::Log4perl->get_logger("Net::Autoconfig");
364             my $command_failed; # indicates of the command failed.
365             my $already_enabled; # indicates if already in admin mode
366             my @expect_commands; # the commands to run on the device
367              
368             # Do some sanity checking
369             if (not $self->session)
370             {
371             $log->warn("No session defined for get admin rights.");
372             return "No session defined for get admin rights.";
373             }
374              
375             if ($self->admin_status)
376             {
377             $log->debug("Already have admin rights.");
378             return;
379             }
380              
381             ####################
382             # Setup Expect command array
383             #
384             # The commands are defined for the class, but they need
385             # to be eval'ed before we can use them.
386             ####################
387             # Setup the expect commands to get admin rights
388             # send "enable"
389             # send the enable password
390             # verify priv mode
391             ####################
392             push(@expect_commands, [
393             eval $expect_enable_cmd,
394             eval $expect_already_enabled_cmd,
395             ]);
396             push(@expect_commands, [
397             eval $expect_enable_passwd_cmd,
398             ]);
399             push(@expect_commands, [
400             eval $expect_priv_mode_cmd,
401             ]);
402              
403             foreach my $command (@expect_commands)
404             {
405             $self->session->expect(MEDIUM_TIMEOUT, @$command, eval $expect_timeout_cmd);
406             if ($command_failed)
407             {
408             $log->warn("Command failed.");
409             $log->debug("Failed command(s): " . @$command);
410             $self->admin_status(FALSE);
411             return "Enable command failed.";
412             }
413             elsif ($already_enabled)
414             {
415             $log->info("Already have admin privileges");
416             last;
417             }
418             }
419              
420             $self->admin_status(TRUE);
421             return;
422             }
423              
424             ########################################
425             # disable_paging
426             # public method
427             #
428             # Disable terminal paging (press -Enter-
429             # to continue) messages. They cause problems
430             # when using expect.
431             #
432             # Returns:
433             # success = undef
434             # failure = reason for failure
435             ########################################
436             sub disable_paging {
437             my $self = shift;
438             my $session; # the object's expect session
439             my $log = Log::Log4perl->get_logger("Net::Autoconfig");
440             my $command_failed; # a flag to indicate if the command failed
441             my @commands; # an array of commands to execute
442              
443             $session = $self->session;
444             if (&_invalid_session($session))
445             {
446             return "Failed - session not defined";
447             }
448              
449             $log->debug("Disabling paging");
450              
451             $session->expect(MEDIUM_TIMEOUT, eval $expect_disable_paging_cmd, eval $expect_timeout_cmd);
452             if ($command_failed)
453             {
454             $log->warn("Failed to disable paging. The rest of the configuration could fail.");
455             return "Failed - paging command timed out";
456             }
457              
458             $session->send("\n");
459              
460             $log->debug("Paging Disabled");
461              
462             return;
463             }
464              
465             ############################################################
466             # Private Methods
467             ############################################################
468              
469              
470             ########################################
471             # _invalid_session
472             # private method
473             #
474             # Determine if this is a valid session.
475             # We're using expect, so it has to be an
476             # expect object reference, and it has to
477             # be defined.
478             #
479             # Returns:
480             # true if invalid
481             # undef if valid
482             ########################################
483             sub _invalid_session {
484             my $session = shift;
485              
486             if (not defined $session)
487             {
488             return TRUE;
489             }
490             elsif (not ref($session))
491             {
492             return TRUE;
493             }
494             elsif (not ref($session) eq 'Expect')
495             {
496             return TRUE;
497             }
498             else
499             {
500             return;
501             }
502             }
503              
504             # Modules must return true.
505             TRUE;
506              
507              
508             __END__