File Coverage

blib/lib/Net/Autoconfig/Device.pm
Criterion Covered Total %
statement 72 798 9.0
branch 0 366 0.0
condition 0 40 0.0
subroutine 24 73 32.8
pod 32 37 86.4
total 128 1314 9.7


line stmt bran cond sub pod time code
1             package Net::Autoconfig::Device;
2              
3 6     6   33015 use 5.008008;
  6         22  
  6         300  
4 6     6   33 use strict;
  6         11  
  6         192  
5 6     6   30 use warnings;
  6         11  
  6         209  
6              
7 6     6   32 use base "Net::Autoconfig";
  6         12  
  6         5578  
8 2     2   11 use Log::Log4perl qw(:levels);
  2         18  
  2         28  
9 2     2   30557 use Net::SNMP;
  2         388663  
  2         414  
10 2     2   8532 use Expect;
  2         275252  
  2         570  
11 2     2   13415 use Net::Ping;
  2         182445  
  2         226  
12 2     2   5241 use Data::Dumper;
  2         53956  
  2         239  
13 2     2   5762 use version; our $VERSION = version->new('v1.4.6');
  2         11474  
  2         19  
14              
15             #################################################################################
16             ## Constants and Global Variables
17             #################################################################################
18              
19 2     2   8987 use constant TRUE => 1;
  2         5  
  2         208  
20 2     2   17 use constant FALSE => 0;
  2         4  
  2         87  
21 2     2   11 use constant LONG_TIMEOUT => 30;
  2         4  
  2         80  
22 2     2   10 use constant MEDIUM_TIMEOUT => 15;
  2         4  
  2         77  
23 2     2   10 use constant SHORT_TIMEOUT => 5;
  2         4  
  2         117  
24              
25 2     2   10 use constant SSH_CMD => "/usr/bin/ssh";
  2         4  
  2         104  
26 2     2   10 use constant TELNET_CMD => "/usr/bin/telnet";
  2         4  
  2         90  
27              
28             # Default device parameters
29 2     2   13 use constant DEFAULT_INVALID_CMD_REGEX => '[iI]nvalid input';
  2         4  
  2         90  
30 2     2   9 use constant DEFAULT_SNMP_VERSION => "2c";
  2         6  
  2         81  
31 2     2   10 use constant DEFAULT_ACCESS_METHOD => "ssh";
  2         5  
  2         263  
32              
33             ####################
34             # device => matching regex tables
35             ####################
36 2         1654 use constant SPECIFIC_DEVICE_MODEL_REGEX => {
37             hp2512 => 'Switch 2512',
38             hp2524 => 'Switch 2524',
39             hp2626 => 'Switch 2626\s',
40             hp2650 => 'Switch 2650\s',
41             hp2626pwr => 'Switch 2626-PWR',
42             hp2650pwr => 'Switch 2650-PWR',
43             hp2824 => 'Switch 2824',
44             hp2848 => 'Switch 2848',
45             'hp2810-24g' => 'Switch 2810-24',
46             'hp2810-48g' => 'Switch 2810-48',
47             'hp2900-24g' => 'Switch 2900-24',
48             'hp2900-48g' => 'Switch 2900-48',
49             'hp3500-24g' => 'Switch 3500-24',
50             'hp3500-48g' => 'Switch 3500-48',
51             hp4104 => 'Switch 4104',
52             hp4108 => 'Switch 4108',
53             hp4208 => 'Switch 4208',
54             hp6108 => 'Switch 6108',
55             hub224 => 'J2603A/B',
56             hub48 => 'J2603A ',
57             c3550 => 'C3550',
58             c3560 => 'C3560-',
59             c3560g => 'C3560G-',
60             c3560e => 'C3560E-',
61             c3750 => 'C3750-',
62             c3750g => 'C3750G-',
63             c3750e => 'C3750E-',
64             c2960 => 'C2960-',
65             c2960g => 'C2960G-',
66 2     2   12 };
  2         3  
67              
68 2         324 use constant GENERIC_DEVICE_MODEL_REGEX => {
69             hp1600 => 'Switch 16',
70             hp2500 => 'Switch 25',
71             hp2600 => 'Switch 26',
72             hp2800 => 'Switch 28(2|4)',
73             hp2810 => 'Switch 2810',
74             hp2900 => 'Switch 29',
75             hp3500 => 'Switch 35',
76             hp4100 => 'Switch 41',
77             hp4200 => 'Switch 42',
78             hp6100 => 'Switch 61',
79             hp4000 => 'Switch 40',
80             hp8000 => 'Switch 80',
81             hp224 => '1991-1994',
82             hub => 'J2603A',
83             c3xxx => 'C3(5|6|7)',
84             c29xx => 'C29(5|6)',
85 2     2   18 };
  2         3  
86              
87 2         223 use constant ALL_TYPES_MODEL_HASH => {
88             hp1600 => 'hp_switch',
89             hp2600 => 'hp_switch',
90             hp2500 => 'hp_switch',
91             hp2800 => 'hp_switch',
92             hp2810 => 'hp_switch',
93             hp2900 => 'hp_switch',
94             hp3500 => 'hp_switch',
95             hp4100 => 'hp_switch',
96             hp4200 => 'hp_switch',
97             hp6100 => 'hp_switch',
98             hp4000 => 'hp_switch',
99             hp8000 => 'hp_switch',
100             hp224 => 'hp_switch',
101             hub => 'hp_hub',
102             c3xxx => 'cisco_switch',
103             c29xx => 'cisco_switch',
104 2     2   31 };
  2         9  
105              
106 2         42473 use constant VENDORS_REGEX => {
107             'Switch 16' => 'HP',
108             'Switch 26' => 'HP',
109             'Switch 25' => 'HP',
110             'Switch 28(2|4)' => 'HP',
111             'Switch 2810' => 'HP',
112             'Switch 29' => 'HP',
113             'Switch 35' => 'HP',
114             'Switch 41' => 'HP',
115             'Switch 42' => 'HP',
116             'Switch 61' => 'HP',
117             'Switch 40' => 'HP4000',
118             'Switch 80' => 'HP4000',
119             '1991-1994' => 'HPHub',
120             'J2603A' => 'HPHub',
121             '(?i:cisco|C\d{4})' => 'Cisco',
122 2     2   12 };
  2         4  
123              
124             ####################
125             # Expect Commands
126             ####################
127              
128             ####################
129             # Expect Command Definitions
130             # These statements are strings, which need to be
131             # evaled within the methods to get their
132             # actual values. This provides a way to pre-declare
133             # common expect commands without having to copy-paste
134             # them into each and every method that uses them.
135             # This incurs a performance hit, but I think its
136             # worth it.
137             #
138             # Define package variables for the variables.
139             # Do this for the following reasons:
140             # 1) I want to use a separate eval function to do some
141             # error checking.
142             # 2) Eval'ing the statements is useless without the
143             # correct variable references.
144             # 3) If a global (our) variable is locally scoped (local),
145             # if the eval func. is called from that block, then
146             # it will have the right values. However, all other
147             # methods/functions will have the global value.
148             # 4) Maybe I should change the way I eval these things.
149             #
150             ####################
151              
152             our $connected_to_device;
153             our $command_failed;
154              
155             my $expect_show_version_cmd = '[
156             -re => "#",
157             sub
158             {
159             $session->clear_accum();
160             $session->send("show version\n");
161             $log->trace($self->hostname . " - Expect CMD - Show Version");
162             sleep(1);
163             }
164             ]';
165             my $expect_ssh_key_cmd = '[
166             -re => "continue connecting",
167             sub
168             {
169             $log->trace($self->hostname . " - Expect Cmd - SSH unknown key command.");
170             $session->clear_accum();
171             $session->send("yes\n");
172             sleep(1);
173             }
174             ]';
175             my $expect_username_cmd = '[
176             -re => "name:",
177             sub
178             {
179             $session->clear_accum();
180             $session->send($self->username . "\n");
181             $log->trace($self->hostname . " - Expect CMD - Sending device username");
182             sleep(1);
183             }
184             ]';
185             my $expect_password_cmd = '[
186             -re => "word:",
187             sub
188             {
189             $session->clear_accum();
190             $session->send($self->password . "\n");
191             $log->trace($self->hostname . " - Expect CMD - Sending device password");
192             sleep(1);
193             }
194             ]';
195             # Expect console login cmd. Make sure we're using the correct
196             # password.
197             my $expect_console_login_cmd = '[
198             -re => "word:",
199             sub
200             {
201             $log->trace($self->hostname . " - Expect Cmd - Sending console password.");
202             $session->clear_accum();
203             $session->send($self->console_password . "\n");
204             sleep(1);
205             }
206             ]';
207             my $expect_hp_continue_cmd = '[
208             -re => "any key to continue",
209             sub
210             {
211             $session->clear_accum();
212             $session->send("\n");
213             $log->trace($self->hostname . " - Expect CMD - Sending HP continue command");
214             sleep(1);
215             }
216             ]';
217             # Find the prompt, and preserve the accumulator
218             my $expect_exec_mode_cmd = '[
219             -re => ">",
220             sub
221             {
222             my $accumulated;
223             $accumulated = $session->clear_accum();
224             $session->set_accum( $session->before.
225             $session->match.
226             $session->after.
227             $accumulated
228             );
229             #$session->send("\n");
230             $log->trace($self->hostname . " - Expect CMD - Got device exec mode");
231             sleep(1);
232             $connected_to_device = TRUE;
233             }
234             ]';
235             # Find the prompt, and preserve the accumulator
236             my $expect_priv_mode_cmd = '[
237             -re => "#",
238             sub
239             {
240             my $accumulated;
241             $accumulated = $session->clear_accum();
242             $session->set_accum( $session->before.
243             $session->match.
244             $session->after.
245             $accumulated
246             );
247             #$session->clear_accum();
248             #$session->send("\n");
249             $log->trace($self->hostname . " - Expect CMD - Got device admin mode");
250             sleep(1);
251             $self->admin_status(TRUE);
252             $connected_to_device = TRUE;
253             }
254             ]';
255             my $expect_enable_cmd = '[
256             -re => ">",
257             sub
258             {
259             $session->clear_accum();
260             $session->send("enable\n");
261             $log->trace($self->hostname . " - Expect CMD - Sending device enable command");
262             sleep(1);
263             }
264             ]';
265             my $expect_enable_passwd_cmd = '[
266             -re => "[Pp]assword:",
267             sub
268             {
269             $session->clear_accum();
270             $session->send($self->enable_password . "\n");
271             $log->trace($self->hostname . " - Expect CMD - Sending device enable password");
272             sleep(1);
273             }
274             ]';
275             #my $expect_already_enabled_cmd = '[
276             # -re => "#",
277             # sub
278             # {
279             # $session->clear_accum();
280             # $session->send("\n");
281             # sleep(1);
282             # $already_enabled = TRUE;
283             # }
284             # ]';
285             my $expect_initial_console_prompt_cmd = '[
286             -re => "how and erase",
287             sub
288             {
289             $log->trace($self->hostname . " - Expect Cmd - Initial Console Prompt (Buffered) Command.");
290             $session->clear_accum();
291             sleep(3);
292             $session->send("I\n");
293             sleep(1);
294             $session->send("\r\n\r\n");
295             sleep(1);
296             $log->debug($self->hostname , " - Connected via inital console prompt cmd");
297             $connected_to_device = TRUE;
298             }
299             ]';
300              
301             # Match and don't destroy the accumulated data.
302             my $expect_get_priv_console_output = '[
303             -re => "#",
304             sub
305             {
306             #$session->clear_accum();
307             #$session->send("\n");
308             my $accumulated;
309             $accumulated = $session->clear_accum();
310             $session->set_accum( $session->before.
311             $session->match.
312             $session->after.
313             $accumulated,
314             );
315             $log->trace($self->hostname " - Expect CMD - Got admin console output");
316             sleep(1);
317             }
318             ]';
319             # Compromise - set the length to 512
320             # Cisco disable paging = set length to 0
321             # HP disable paging = set length to 1000
322             my $expect_disable_paging_cmd = '[
323             -re => "#",
324             sub
325             {
326             $session->clear_accum();
327             $session->send("terminal length 512\n");
328             $log->trace($self->hostname . " - Expect CMD - Disabling paging");
329             sleep(1);
330             }
331             ]';
332             my $expect_initial_config_dialog = '[
333             -re => "initial configuration",
334             sub
335             {
336             $session->clear_accum();
337             $session->send("no\n");
338             $log->trace($self->hostname . " - Expect CMD - Bypassing initial config dialog");
339             sleep(1);
340             }
341             ]';
342             my $expect_timeout_cmd = '[
343             timeout =>
344             sub
345             {
346             $session->clear_accum();
347             $log->info($self->hostname . " - Expect CMD - Timeout");
348             $command_failed = TRUE;
349             }
350             ]';
351              
352             #################################################################################
353             # Methods
354             #################################################################################
355              
356             ############################################################
357             # Public Methods
358             ############################################################
359              
360             ########################################
361             # new
362             # public method
363             #
364             # create a new Net::Autoconfig::Device object.
365             #
366             # If passed an array, it will assume those are key
367             # value pairs and assign them to the device.
368             #
369             # If no values are defined, then default ones are assigned.
370             #
371             # Returns:
372             # A Net::Autoconfig::Device object
373             #
374             # Publis variable descriptions
375             # See the POD below
376             # Private/Internal Variables
377             # session
378             # - Expect ref or undef
379             # - contains a ref to the expect session
380             # connected
381             # - TRUE or FALSE
382             # - indicates if a successful connection was made
383             # admin_rights_status
384             # - TRUE or FALSE
385             # - Indicates if admin rights have been established
386             ########################################
387             sub new {
388 0     0 1   my $invocant = shift; # calling class
389 0   0       my $class = ref($invocant) || $invocant;
390 0           my $self = {
391             hostname => "",
392             model => "",
393             vendor => "",
394             auto_discover => TRUE,
395             admin_rights_status => FALSE,
396             console_username => "",
397             console_password => "",
398             console_hostane => "",
399             console_tty => "",
400             username => "",
401             password => "",
402             enable_password => "",
403             session => undef,
404             connected => FALSE,
405             snmp_community => "",
406             snmp_version => DEFAULT_SNMP_VERSION,
407             access_method => DEFAULT_ACCESS_METHOD,
408             access_cmd => SSH_CMD,
409             invalid_cmd_regex => DEFAULT_INVALID_CMD_REGEX,
410             @_,
411             };
412 0           my $log = Log::Log4perl->get_logger($class);
413 0           my $hostname;
414 0           bless $self, $class;
415              
416 0           $log->debug("Creating new device object");
417              
418 0           $hostname = $self->hostname;
419              
420 0 0         if ($log->is_trace())
421             {
422 0           $log->trace(Dumper($self));
423             }
424              
425             # Check to see if it's using a console server
426 0 0         if ($self->hostname =~ /(.*)\@(.*)/)
427             {
428 0           $log->debug("$hostname - Setting Provision mode");
429 0           $log->debug("$hostname - using console server $2, tty/line $1");
430 0           $self->provision(TRUE);
431 0           $self->set('auto_discover', FALSE);
432 0           $self->console_hostname($2);
433 0           $self->console_tty($1);
434              
435 0 0         if ( not $self->console_username )
436             {
437 0           $log->info("$hostname - Console username not set, using access username.");
438 0           $self->console_username($self->username);
439 0           $log->trace("$hostname - console username = " . $self->console_username);
440             }
441              
442 0 0         if ( not $self->console_password)
443             {
444 0           $log->info("$hostname - Console password not set, using access password.");
445 0           $self->console_password($self->password);
446             }
447             }
448              
449 0 0         return $self->get('auto_discover') ? $self->auto_discover : $self;
450             }
451              
452             ########################################
453             # auto_discover
454             # public method
455             #
456             # Try to determine the make and model of the device.
457             # If it's possible, return a more specific device.
458             # Else, return itself (the old device)
459             ########################################
460             sub auto_discover {
461 0     0 0   my $self = shift;
462 0   0       my $vendor = $self->vendor || "";
463 0   0       my $model = $self->model || "";
464 0   0       my $snmp_community = $self->snmp_community || "";
465 0   0       my $snmp_version = $self->snmp_version || "2c";
466 0   0       my $session = $self->session || "";
467 0           my $log = Log::Log4perl->get_logger( ref($self) );
468 0           my $device_type; # The name of the module for that device.
469              
470 0           $log->debug($self->hostname . " - auto-discovering device.");
471              
472 0           $device_type = $self->lookup_model();
473              
474 0 0         if (not $device_type)
475             {
476 0           $log->info($self->hostname . " - using default device class");
477             }
478              
479             # Unset "auto_discover" so it doesn't try to recurse to infinity
480 0           $self->set('auto_discover', FALSE);
481              
482             # Make a new object of the returned device type.
483             # If we didn't get one, return the same object.
484 0 0         if ($device_type)
485             {
486 0           eval "require $device_type;";
487 0 0         if ($@)
488             {
489 0           $log->warn($self->hostname
490             . " - Failed - unable to load module: $device_type");
491 0           return;
492             }
493 0           $self = $device_type->new( $self->get() );
494             }
495              
496 0           return $self;
497             }
498              
499              
500              
501             ########################################
502             # get
503             #
504             # return a value for a given attribute,
505             # or return all attributes as a hash or hash ref
506             # if no value is passed.
507             ########################################
508             sub get {
509 0     0 1   my $self = shift;
510 0           my @attribs = @_;
511 0           my $ref = ref($self);
512 0           my %data;
513              
514 0 0         if (not @attribs)
    0          
515             {
516 0           %data = %{ $self };
  0            
517             }
518             elsif (scalar(@attribs) == 1)
519             {
520 0           return $self->{$attribs[0]};
521             }
522             else
523             {
524 0           foreach my $attrib (@attribs)
525             {
526 0           $data{$attrib} = $self->{$attrib};
527             }
528             }
529 0 0         return wantarray ? %data : \%data;
530             }
531              
532              
533             ########################################
534             #set()
535             #
536             # Set the value of an attribute. If the attribute does not
537             # yet exist, create it.
538             #
539             # Returns undef for success
540             # Returns TRUE for failure
541             ############################################################
542             sub set {
543 0     0 1   my $self = shift;
544 0           my %attribs = @_;
545 0           my $log = Log::Log4perl->get_logger( ref($self) );
546              
547 0 0         if ($self->hostname)
548             {
549 0           $log->trace($self->hostname . " - setting attribute(s)");
550             }
551             else
552             {
553 0           $log->trace("hostname not defined - setting attribute(s)");
554             }
555              
556 0           foreach my $key ( keys %attribs )
557             {
558 0   0       $self->{$key} = $attribs{$key} || '';
559             }
560              
561 0           return;
562             }
563              
564              
565             ########################################
566             # Below are a set of accessor/mutator methods.
567             # They return or set values for the attribute specified
568             ########################################
569             sub model {
570 0     0 1   my $self = shift;
571 0           my $model = shift;
572 0 0         defined $model and $self->{'model'} = $model;
573 0 0         return defined $model ? [] : $self->{'model'};
574             }
575             sub vendor {
576 0     0 1   my $self = shift;
577 0           my $vendor = shift;
578 0 0         defined $vendor and $self->{'vendor'} = $vendor;
579 0 0         return defined $vendor ? undef : $self->{'vendor'};
580             }
581             sub hostname {
582 0     0 1   my $self = shift;
583 0           my $hostname = shift;
584 0 0         defined $hostname and $self->{'hostname'} = $hostname;
585 0 0         return defined $hostname ? undef : $self->{'hostname'};
586             }
587             sub username {
588 0     0 1   my $self = shift;
589 0           my $username = shift;
590 0 0         defined $username and $self->{'username'} = scalar $username;
591 0 0         return defined $username ? undef : $self->{'username'};
592             }
593             sub password {
594 0     0 1   my $self = shift;
595 0           my $password = shift;
596 0 0         defined $password and $self->{'password'} = scalar $password;
597 0 0         return defined $password ? undef : $self->{'password'};
598             }
599             sub provision {
600 0     0 1   my $self = shift;
601 0           my $provision = shift;
602 0 0         defined $provision and $self->{'provision'} = scalar $provision;
603 0 0         return defined $provision ? undef : $self->{'provision'};
604             }
605             sub admin_status {
606 0     0 1   my $self = shift;
607 0           my $admin_status = shift;
608 0 0         defined $admin_status and $self->{'admin_status'} = scalar $admin_status;
609 0 0         return defined $admin_status ? undef : $self->{'admin_status'};
610             }
611             sub console_username {
612 0     0 1   my $self = shift;
613 0           my $console_username = shift;
614 0 0         defined $console_username and $self->{'console_username'} = scalar $console_username;
615 0 0         return defined $console_username ? undef : $self->{'console_username'};
616             }
617             sub console_password {
618 0     0 1   my $self = shift;
619 0           my $console_password = shift;
620 0 0         defined $console_password and $self->{'console_password'} = scalar $console_password;
621 0 0         return defined $console_password ? undef : $self->{'console_password'};
622             }
623             sub console_hostname {
624 0     0 1   my $self = shift;
625 0           my $console_hostname = shift;
626 0 0         defined $console_hostname and $self->{'console_hostname'} = scalar $console_hostname;
627 0 0         return defined $console_hostname ? undef : $self->{'console_hostname'};
628             }
629             sub console_tty {
630 0     0 1   my $self = shift;
631 0           my $console_tty = shift;
632 0 0         defined $console_tty and $self->{'console_tty'} = scalar $console_tty;
633 0 0         return defined $console_tty ? undef : $self->{'console_tty'};
634             }
635             ###
636             sub enable_password {
637 0     0 1   my $self = shift;
638 0           my $enable_password = shift;
639 0 0         defined $enable_password and $self->{'enable_password'} = scalar $enable_password;
640 0 0         return defined $enable_password ? undef : $self->{'enable_password'};
641             }
642             sub snmp_community {
643 0     0 1   my $self = shift;
644 0           my $snmp_community = shift;
645 0 0         defined $snmp_community and $self->{'snmp_community'} = scalar $snmp_community;
646 0 0         return defined $snmp_community ? undef : $self->{'snmp_community'};
647             }
648             # The same things as snmp_community, but easier to type
649             # I.e. I didn't use snmp_community in some other code and this
650             # was easer to change than the other code.
651             sub community {
652 0     0 0   my $self = shift;
653 0           my $snmp_community = shift;
654 0 0         defined $snmp_community and $self->{'snmp_community'} = scalar $snmp_community;
655 0 0         return defined $snmp_community ? undef : $self->{'snmp_community'};
656             }
657             sub snmp_version {
658 0     0 1   my $self = shift;
659 0           my $snmp_version = shift;
660 0 0         defined $snmp_version and $self->{'snmp_version'} = scalar $snmp_version;
661 0 0         return defined $snmp_version ? undef : $self->{'snmp_version'};
662             }
663             sub session {
664 0     0 1   my $self = shift;
665 0           my $session = shift;
666 0 0         defined $session and $self->{'session'} = scalar $session;
667 0 0         return defined $session ? undef : $self->{'session'};
668             }
669             sub paging_disabled {
670 0     0 0   my $self = shift;
671 0           my $paging_disabled = shift;
672 0 0         defined $paging_disabled and $self->{'paging_disabled'} = scalar $paging_disabled;
673 0 0         return defined $paging_disabled ? undef : $self->{'paging_disabled'};
674             }
675              
676              
677             ########################################
678             # access_method
679             # public method
680             #
681             # Set the access method to either ssh,
682             # telnet or something user defined.
683             # OR
684             # Get the access method if undef is passed
685             ########################################
686             sub access_method {
687 0     0 1   my $self = shift;
688 0           my $access_method = shift;
689              
690 0 0         $access_method or $access_method = "";
691              
692 0 0         if ($access_method =~ /ssh/i)
    0          
    0          
693             {
694 0           $self->{'access_method'} = "ssh";
695             }
696             elsif ($access_method =~ /telnet/i)
697             {
698 0           $self->{'access_method'} = "telnet";
699             }
700             elsif ($access_method)
701             {
702 0           $self->{'access_method'} = "user_defined";
703             }
704              
705 0 0         return $access_method ? undef : $self->{'access_method'};
706             }
707              
708             ########################################
709             # access_cmd
710             # public method
711             #
712             # Get the command to connect to the device.
713             # ssh and telnet are defined. Anything else must
714             # have an absolute path or else it's ignored.
715             #
716             # Also set the access_method. This can be
717             # overwritten.
718             #
719             # Specifying "ssh" or "telnet", without the
720             # absoluate path, will use the default
721             # ssh and telnet locations.
722             ########################################
723             sub access_cmd {
724 0     0 1   my $self = shift;
725 0           my $access_cmd = shift;
726 0           my $log = Log::Log4perl->get_logger( ref($self) );
727              
728 0 0         $access_cmd or $access_cmd = "";
729              
730 0 0         if ($access_cmd =~ /^ssh$/i)
    0          
    0          
    0          
731             {
732 0           $self->{'access_cmd'} = SSH_CMD;
733             }
734             elsif ($access_cmd =~ /^telnet$/i)
735             {
736 0           $self->{'access_cmd'} = TELNET_CMD;
737             }
738             elsif ($access_cmd =~ /^\/.+/)
739             {
740 0           $self->{'access_cmd'} = $access_cmd;
741             }
742             elsif ($access_cmd)
743             {
744 0           $log->warn($self->hostname . ": Access command, '$access_cmd', specified but not recognized.");
745             }
746              
747 0 0         if ($access_cmd =~ /ssh/i)
    0          
    0          
748             {
749 0           $self->access_method('ssh');
750             }
751             elsif ($access_cmd =~ /telnet/i)
752             {
753 0           $self->access_method('telnet');
754             }
755             elsif ($access_cmd)
756             {
757 0           $self->access_method('user_Defined');
758             }
759              
760 0 0         return $access_cmd ? undef : $self->{'access_cmd'};
761             }
762              
763             ########################################
764             # invalid_regex
765             # public
766             #
767             # Either get or set the regex that
768             # determines if a command was invalid
769             # or was not recognized by the device.
770             ########################################
771             sub invalid_cmd_regex {
772 0     0 0   my $self = shift;
773 0           my $regex = shift;
774 0 0         defined $regex and $self->{'invalid_cmd_regex'} = $regex;
775 0 0         return defined $regex ? undef : $self->{'invalid_cmd_regex'};
776             }
777              
778             ########################################
779             # connect
780             # public method
781             #
782             # Connect to a generic device using parameters
783             # specified in the device object, i.e.
784             # hostname, username and password.
785             #
786             # This expects to be overridden by a sub class
787             # E.g. Net::Autoconfig::Device::Cisco.
788             ########################################
789             sub connect {
790 0     0 1   my $self = shift;
791 0           my $session; # a ref to the expect session
792             my $access_command; # the string to use to the telnet/ssh app.
793 0           my $result; # the value returned after executing an expect cmd
794 0           my @expect_commands; # the commands to run on the device
795 0           my $spawn_cmd; # command expect uses to connect to the device
796 0           my $log = Log::Log4perl->get_logger( ref($self) );
797              
798 0           $log->debug($self->hostname . " - using default connect method.");
799              
800             # Expect success/failure flags
801 0           local $connected_to_device; # indicates a successful connection to the device
802 0           local $command_failed; # indicates a failed connection to the device
803              
804             # Do some sanity checking
805 0 0         if (not $self->hostname)
806             {
807 0           $log->warn("No hostname defined for this device.");
808 0           return "No hostname defined for this devince.";
809             }
810              
811 0 0         if (not $self->access_method)
812             {
813 0           $log->warn($self->hostname . " - access method not defined.");
814 0           return "Access method not defined.";
815             }
816            
817 0 0         if (not $self->access_cmd)
818             {
819 0           $log->warn($self->hostname . " - access command not defined.");
820 0           return "Access command not defined";
821             }
822              
823 0 0         if (not $self->username)
824             {
825 0           $log->warn($self->hostname . " - No username defined.");
826 0           return "No username defined.";
827             }
828              
829             # Setup the access command
830 0 0         if ($self->access_method =~ /^ssh$/)
831             {
832 0           $spawn_cmd = join(" ", $self->access_cmd,
833             "-l", $self->username, $self->hostname);
834             }
835             else
836             {
837 0           $spawn_cmd = join(" ", $self->access_cmd, $self->hostname);
838             }
839              
840             # Okay, let's get on with connecting to the device
841 0           $session = $self->session;
842 0 0         if (&_invalid_session($session))
843             {
844 0           $log->info($self->hostname . " - initiating connection");
845 0           $log->debug($self->hostname . " - using command '"
846             . $self->access_cmd . "'");
847 0           $log->debug($self->hostname
848             . " - spawning new expect session with: '$spawn_cmd'");
849              
850 0 0         if (&_host_not_reachable($self->hostname))
851             {
852 0           return "Failed " . $self->hostname . " not reachable via ping.";
853             }
854              
855             eval
856 0           {
857 0           $session = new Expect;
858 0           $session->raw_pty(TRUE);
859 0           $session->spawn($spawn_cmd);
860             };
861 0 0         if ($@)
862             {
863 0           $log->warn($self->hostname . " Failed - connection failed: $@");
864 0           return $@;
865             }
866             }
867             else
868             {
869 0           $log->info($self->hostname . " - session already exists.");
870             }
871              
872             # Enable dumping data to the screen.
873 0 0 0       if ($log->is_trace() || $log->is_debug() )
874             {
875 0           $session->log_stdout(TRUE);
876             }
877             else
878             {
879 0           $session->log_stdout(FALSE);
880             }
881              
882             ####################
883             # Setup Expect command array
884             #
885             # The commands are defined for the class, but they need
886             # to be eval'ed before we can use them.
887             ####################
888             # Setup the expect commands to do the initial login.
889             # Up to four commands may need to be run:
890             # accept the ssh key
891             # send the username
892             # send the password
893             # hp->bypass initial login screen
894             # verify connection (exec or priv exec mode)
895             ####################
896 0           push(@expect_commands, [
897             eval $expect_ssh_key_cmd,
898             eval $expect_username_cmd,
899             eval $expect_password_cmd,
900              
901             # Used for initial configuration of cisco devices
902             eval $expect_initial_config_dialog,
903              
904             # Check to see if we already have access
905             eval $expect_exec_mode_cmd,
906             eval $expect_priv_mode_cmd,
907             ]);
908             # Handle some HP weirdness
909 0           push(@expect_commands, [
910             eval $expect_username_cmd,
911             eval $expect_password_cmd,
912             # Get past the initial login banner
913             eval $expect_hp_continue_cmd,
914             eval $expect_exec_mode_cmd,
915             eval $expect_priv_mode_cmd,
916             ]);
917 0           push(@expect_commands, [
918             eval $expect_password_cmd,
919             # Get past the initial login banner
920             eval $expect_hp_continue_cmd,
921             eval $expect_exec_mode_cmd,
922             eval $expect_priv_mode_cmd,
923             ]);
924 0           push(@expect_commands, [
925             # Get past the initial login banner
926             eval $expect_hp_continue_cmd,
927             eval $expect_exec_mode_cmd,
928             eval $expect_priv_mode_cmd,
929             ]);
930 0           push(@expect_commands, [
931             eval $expect_exec_mode_cmd,
932             eval $expect_priv_mode_cmd,
933             ]);
934              
935 0           foreach my $command (@expect_commands)
936             {
937 0           $session->expect(MEDIUM_TIMEOUT, @$command, eval $expect_timeout_cmd);
938 0 0         if ($log->level == $TRACE)
939             {
940 0           $log->trace("Expect matching before: " . $session->before);
941 0           $log->trace("Expect matching match : " . $session->match);
942 0           $log->trace("Expect matching after : " . $session->after);
943             }
944              
945 0 0         if ($connected_to_device)
    0          
946             {
947 0           $log->debug("Connected to device " . $self->hostname);
948 0           $self->session($session);
949 0           last;
950             }
951             elsif ($command_failed)
952             {
953 0           $self->error_end_session("Failed to connect to device " . $self->hostname);
954 0           $log->debug("Failed on command: " , Dumper($command));
955 0           last;
956             }
957             }
958              
959 0 0         return $connected_to_device ? undef : 'Failed to connect to device.';
960             }
961              
962             ########################################
963             # console_connect
964             # public method
965             #
966             # Connect to a console server for a given
967             # hostname. Assumes various characterisitics about
968             # the hostname and username + password
969             #
970             # After connecting to the console server,
971             # this then calls the normal connect method.
972             #
973             # At this point in time, this returns undef.
974             ########################################
975             sub console_connect {
976 0     0 1   my $self = shift;
977 0           my $hostname; # hostname of the console server
978             my $tty; # console port name
979 0           my $username; # console username
980 0           my $session; # a ref to the expect session
981 0           my $access_command; # the string to use to the telnet/ssh app.
982 0           my $result; # the value returned after executing an expect cmd
983 0           my @expect_commands; # the commands to run on the device
984 0           my $spawn_cmd; # command expect uses to connect to the device
985 0           my $log = Log::Log4perl->get_logger( ref($self) );
986              
987 0           $log->debug("Using default console connect method.");
988              
989             # Expect success/failure flags
990 0           local $connected_to_device; # indicates a successful connection to the device
991 0           local $command_failed; # indicates a failed connection to the device
992              
993             # if ($self->_connected)
994             # {
995             # $log->info($self->hostname . " - connection already established.");
996             # return "Connection already established.";
997             # }
998              
999             # Do some sanity checking
1000 0 0         if (not $self->hostname)
1001             {
1002 0           $log->warn("No hostname defined for this device.");
1003 0           return "No hostname defined for this devince.";
1004             }
1005              
1006 0 0         if (not $self->provision)
1007             {
1008 0           $log->warn($self->hostname
1009             . "Device not configured for provisioning"
1010             . " (console server) proceeding anyway.");
1011             }
1012              
1013 0 0         if (not $self->access_method)
1014             {
1015 0           $log->warn("Access method for " . $self->hostname . " not defined.");
1016 0           return "Access method not defined.";
1017             }
1018            
1019 0 0         if (not $self->access_cmd)
1020             {
1021 0           $log->warn("Access command for " . $self->hostname . " not defined.");
1022 0           return "Access command not defined";
1023             }
1024              
1025 0 0         if (not $self->console_username)
1026             {
1027 0           $log->warn("Failed - No console user defined.");
1028 0           return "No console user defined.";
1029             }
1030              
1031 0 0         if (not $self->username)
1032             {
1033 0           $log->warn("Failed - No normal username defined.");
1034             }
1035              
1036 0           $hostname = $self->console_hostname;
1037 0           $username = $self->console_username;
1038 0           $tty = $self->console_tty;
1039              
1040             # this could read (not $tty or not $hostname)
1041 0 0 0       if (not $tty or not $username)
1042             {
1043 0           $log->warn($self->hostname
1044             . ' - Failed - Invalid tty@console hostname.');
1045 0           return 'Failed - Invalid tty@console hostname.';
1046             }
1047              
1048 0           $username = join(":", $username, $tty);
1049              
1050             # Setup the access command
1051 0 0         if ($self->access_method =~ /^ssh$/)
1052             {
1053 0           $spawn_cmd = join(" ", $self->access_cmd, "-l", $username, $hostname);
1054             }
1055             else
1056             {
1057 0           $spawn_cmd = join(" ", $self->access_cmd, $hostname);
1058             }
1059              
1060             # Okay, let's get on with connecting to the device
1061 0           $session = $self->session;
1062 0 0         if (&_invalid_session($session))
1063             {
1064 0           $log->info($self->hostname . " - Connecting to console server.");
1065 0           $log->debug($self->hostname
1066             . " - Using command '" . $self->access_cmd . "'");
1067 0           $log->debug($self->hostname
1068             . " - Spawning new expect session with: '$spawn_cmd'");
1069              
1070 0 0         if (&_host_not_reachable($hostname))
1071             {
1072 0           $log->warn($self->hostname . " - Failed"
1073             . " - '$hostname' not reachable via ping.");
1074 0           return "Failed $hostname not reachable via ping.";
1075             }
1076              
1077             eval
1078 0           {
1079 0           $session = new Expect;
1080 0           $session->raw_pty(TRUE);
1081 0           $session->spawn($spawn_cmd);
1082             };
1083 0 0         if ($@)
1084             {
1085 0           $log->warn($self->hostname . " - Failed"
1086             . " - Connecting to $hostname failed: $@");
1087 0           return $@;
1088             }
1089 0           $self->session($session);
1090             }
1091             else
1092             {
1093 0           $log->info($self->hostname . " - Session for already exists.");
1094             }
1095              
1096              
1097             # Enable dumping data to the screen.
1098 0 0 0       if ($log->is_trace() || $log->is_debug() )
1099             {
1100 0           $session->log_stdout(TRUE);
1101             }
1102             else
1103             {
1104 0           $session->log_stdout(FALSE);
1105             }
1106              
1107             ####################
1108             # Setup Expect command array
1109             #
1110             # The commands are defined for the class, but they need
1111             # to be eval'ed before we can use them.
1112             ####################
1113             # Setup the expect commands to login to the console server.
1114             # This method only connects to the server, not the device.
1115             # Therefore, if we see the login prompt for the device, preserve
1116             # the output so the connect() method sees it too.
1117             #
1118             # Up to seven things may happen:
1119             # 1) send the password
1120             # 2) Bypass the "what to do with data buffer" from the console
1121             # 3) see and preserve a username prompt
1122             # 4) see and preserve a password prompt
1123             # 5) see an exec mode prompt
1124             # 6) see a priv mode prompt
1125             # 7) bypass HP "continue" screen
1126             ####################
1127 0           push(@expect_commands, [
1128             _eval($expect_console_login_cmd, $self),
1129             _eval( $expect_ssh_key_cmd, $self),
1130             ]);
1131 0           push(@expect_commands, [
1132             _eval($expect_console_login_cmd, $self),
1133             _eval($expect_initial_console_prompt_cmd, $self),
1134             ]);
1135 0           push(@expect_commands, [
1136             _eval($expect_initial_console_prompt_cmd, $self),
1137             ]);
1138              
1139             # There are two cases when connecting to a console server:
1140             # 1) the console server has a buffer and you need to clear it
1141             # 2) the console server has _no_ buffer and it gives you a blank
1142             # prompt.
1143              
1144 0           foreach my $command (@expect_commands)
1145             {
1146 0           $session->expect(MEDIUM_TIMEOUT, @$command, eval $expect_timeout_cmd);
1147 0 0         if ($log->level == $TRACE)
1148             {
1149 0           $log->trace("Expect matching before: " . $session->before);
1150 0           $log->trace("Expect matching match : " . $session->match);
1151 0           $log->trace("Expect matching after : " . $session->after);
1152 0           $log->trace("Expect command: " . Dumper($command));
1153             }
1154 0 0         if ($connected_to_device)
    0          
1155             {
1156 0           $log->debug($self->hostname . " - Console Buffered - Connected to device ");
1157 0           last;
1158             }
1159             elsif ($command_failed)
1160             {
1161             ### $self->error_end_session("Failed - Unable to connect to device");
1162             ### $log->debug($self->hostname . " - Failed - on command: "
1163             ### . Dumper($command));
1164 0           $log->debug($self->hostname . " - Console Connect Problem - Command timed out");
1165 0           last;
1166             }
1167             }
1168              
1169             # It may not have failed/timed out. It could have connected and had
1170             # an empty buffer.
1171 0 0         if ($command_failed)
1172             {
1173             # Check to see if we connected to the device
1174 0           $command_failed = FALSE;
1175 0           my $expect_command = [
1176             _eval($expect_initial_config_dialog, $self),
1177             _eval($expect_exec_mode_cmd, $self),
1178             _eval($expect_priv_mode_cmd, $self),
1179             _eval($expect_username_cmd, $self),
1180             _eval($expect_password_cmd, $self),
1181             _eval($expect_initial_console_prompt_cmd, $self),
1182             ];
1183              
1184 0           $session->clear_accum();
1185 0           $session->send("\r\n\r\n");
1186 0           sleep(1);
1187 0           $session->expect( MEDIUM_TIMEOUT,
1188             @$expect_command,
1189             _eval($expect_timeout_cmd, $self)
1190             );
1191 0 0         if ($command_failed)
    0          
1192             {
1193 0           $self->error_end_session("Failed - Unable to connect to device");
1194             }
1195             elsif ($connected_to_device)
1196             {
1197 0           $log->debug($self->hostname
1198             . " - Console Not Buffered - Connected to device ");
1199 0           $self->session($session);
1200             }
1201             else
1202             {
1203 0           $log->error($self->hostname . " - Undefined Console State");
1204             }
1205             }
1206              
1207 0 0         return $connected_to_device ? undef : 'Failed to connect to device.';
1208             }
1209              
1210             ########################################
1211             # configure
1212             # public method
1213             #
1214             # This can be overwritten in submodules
1215             # if necessary.
1216             # E.g. Net::Autoconfig::Device::Cisco.
1217             #
1218             # Configure a device using the
1219             # specified template.
1220             #
1221             # Template data should be in the form of
1222             # a hash:
1223             # $template_data = {
1224             # {cmds} = [ {cmd 1}, {cmd 2}, {cmd 3} ]
1225             # {default} = { default data }
1226             #
1227             # Returns
1228             # success = undef
1229             # failure = Failure message.
1230             ########################################
1231             sub configure {
1232 0     0 1   my $self = shift;
1233 0           my $template_data = shift;
1234 0           my $session; # the object's expect session
1235             my $error_cmd; # expect cmd to see if a cmd was invalid
1236 0           my $error_flag; # indicates if the command was invalid
1237 0           my $log = Log::Log4perl->get_logger( ref($self) );
1238 0           my $last_cmd; # record keeping for error reporting
1239              
1240 0           $log->trace("Using the default configure method!");
1241              
1242              
1243             # Let's do some sanity checking
1244 0 0         if (not $template_data)
1245             {
1246 0           $log->warn("Failed - No template data");
1247 0           return "Failed - No template data";
1248             }
1249              
1250 0 0         if (&_invalid_session($self->session))
1251             {
1252 0   0       my $hostname = $self->hostname || "no hostname";
1253 0           $log->warn("Failed - No session for " . $hostname);
1254 0           return "Failed - No session for " . $hostname;
1255             }
1256              
1257 0 0         if (not $self->admin_status)
1258             {
1259 0   0       my $hostname = $self->hostname || "no hostname";
1260 0           $log->warn("Failed - do not have admin access to device.");
1261 0           return "Failed - do not have admin access to device.";
1262             }
1263            
1264 0 0         if (not exists $template_data->{default})
1265             {
1266 0           $template_data->{default} = {};
1267             }
1268 0           $session = $self->session;
1269              
1270             # Each cmd is a hash ref
1271             # Join it with the default data. The cmd data
1272             # will overwrite the default data. Yay!
1273 0           COMMAND:
1274 0           foreach my $cmd (@{ $template_data->{cmds} })
1275             {
1276 0           my $expect_cmd; # the command to run on the CLI
1277             my $error_cmd; # the cmd that detects an error/invalid command
1278 0           my $command_failed; # a flag to indicate if the command failed
1279 0           my $timeout_cmd; # what to do if there's a timeout
1280              
1281             # This is a perfance hit for each command. Does it matter?
1282 0 0         if ($cmd->{required} )
1283             {
1284 0           $timeout_cmd = eval $expect_timeout_cmd;
1285             }
1286             else
1287             {
1288 0           undef $timeout_cmd;
1289             }
1290              
1291 0           $log->trace("Command: Regex :" . $cmd->{regex});
1292 0           $log->trace("Command: Cmd :" . $cmd->{cmd});
1293 0           $log->trace("Command: Timeout :" . $cmd->{timeout});
1294 0           $log->trace("Command: Required:" . $cmd->{required});
1295              
1296 0           VARIABLE_INTERPOLATION:
1297             {
1298 0           my $old_cmd = $cmd->{cmd};
1299 0           my $new_cmd = $old_cmd;
1300             # matches $variable_name; not \$variable_name
1301             # "-" counts as a word boundry, which is good for things like "range $a-$b"
1302             FIND_VARIABLE:
1303 0           while ($old_cmd =~ /[^\\]\$(\w+)/g)
1304             {
1305 0           my $replacement = $self->get($1);
1306 0 0         if (defined $replacement)
1307             {
1308 0           $log->trace("Replacing '$1' with '$replacement' for cmd "
1309             . "'$old_cmd' for device " . $self->hostname);
1310 0           $new_cmd =~ s/\$$1/$replacement/;
1311             }
1312             else
1313             {
1314 0 0         if ($cmd->{required})
1315             {
1316 0           my $message = "'$1' not defined for required command "
1317             . "'$old_cmd' for " . $self->hostname;
1318 0           $self->error_end_session($message);
1319 0           return "Command failed.";
1320             }
1321             else
1322             {
1323 0           $log->info("Skipping... ". "'$1' not defined for optinal command "
1324             . "'$old_cmd' for " . $self->hostname);
1325 0           next COMMAND;
1326             }
1327             }
1328             }
1329             # Since we escape the $s, remove the
1330             # escape characters.
1331 0           $new_cmd =~ s/\\\$/\$/g;
1332 0 0         if (not $new_cmd eq $old_cmd)
1333             {
1334 0           $cmd->{cmd} = $new_cmd;
1335             }
1336              
1337             #Re-insert command characters
1338             # i.e. tabs and newlines
1339 0           $cmd->{cmd} =~ s/\\t/\t/g;
1340 0           $cmd->{cmd} =~ s/\\n/\n/g;
1341 0           $log->trace("\$cmd->{cmd} after replacing tabs and newlines '"
1342             . $cmd->{cmd} . "'");
1343             }
1344              
1345              
1346             $error_cmd = [
1347             -re => $self->invalid_cmd_regex,
1348             sub
1349             {
1350 0     0     $log->warn("Invalid command entered! '$last_cmd'");
1351 0           $command_failed = TRUE;
1352             }
1353 0           ];
1354              
1355             $expect_cmd = [
1356             -re => $cmd->{regex},
1357             sub
1358             {
1359 0     0     $session->clear_accum();
1360 0           $session->send($cmd->{cmd} . "\n");
1361             }
1362 0           ];
1363              
1364              
1365             # Okay, send the command
1366 0 0         if ($cmd->{cmd} =~ /wait/i)
1367             {
1368 0           $session->expect($cmd->{timeout}, [ -re => "BOGUS REGEX" ] );
1369             }
1370             else
1371             {
1372 0           $session->expect($cmd->{timeout}, $error_cmd, $expect_cmd, $timeout_cmd);
1373             }
1374              
1375 0           $last_cmd = $cmd->{cmd};
1376              
1377 0 0         if ($command_failed)
1378             {
1379             # close session and alarm
1380 0           $self->error_end_session("Required command failed for " . $self->hostname);
1381 0           $log->debug(Dumper(%$cmd));
1382 0           return "Command failed.";
1383             }
1384 0           sleep(1);
1385             }
1386              
1387             # One last check to see if the last comand was invalid.
1388             # This is different than the one in the COMMAND loop
1389             # The Expect->expect method can't exit or return from _this_
1390             # method. So, detect the error and do our own exiting.
1391             $error_cmd = [
1392             -re => $self->invalid_cmd_regex,
1393             sub
1394             {
1395 0     0     $error_flag = TRUE;
1396 0           $log->warn("Invalid command entered! '"
1397             . $template_data->{cmds}->[-1]->{cmd}
1398             . "'"
1399             );
1400             }
1401 0           ];
1402            
1403 0 0         if ($log->is_trace)
1404             {
1405 0           $log->trace( "Error command: " . Dumper($error_cmd) );
1406             }
1407              
1408 0           $session->expect(SHORT_TIMEOUT, $error_cmd );
1409              
1410 0 0         if ($error_flag)
1411             {
1412 0           $self->error_end_session("Last command entered was invalid for " . $self->hostname);
1413 0           return "Last command was invalid.";
1414             }
1415              
1416 0           $log->info("All commands executed successfullly for " . $self->hostname . ".");
1417 0           return;
1418             }
1419              
1420             ########################################
1421             # lookup_model
1422             # public method
1423             #
1424             # Try to match the vendor and model device parameters against
1425             # a lookup tableto see if the model and vendor can be discerned.
1426             #
1427             # See the defined constants at the beginning of the module for
1428             # the definitions.
1429             #
1430             # Return the object name for the device.
1431             ########################################
1432             sub lookup_model {
1433 0     0 1   my $self = shift;
1434 0           my $class = ref($self);
1435 0           my $log = Log::Log4perl->get_logger($class);
1436              
1437 0   0       my $model = $self->model || '';
1438 0   0       my $vendor = $self->vendor || '';;
1439 0           my $models = GENERIC_DEVICE_MODEL_REGEX;
1440 0   0       my $snmp_community = $self->snmp_community || '';
1441 0           my $snmp_device_type; # holds the output from the snmp query
1442             my $device_model;
1443 0           my $device_vendor;
1444              
1445 0 0         if ( $self->hostname)
1446             {
1447 0           $log->debug($self->hostname . "Looking up device info (model/vendor).");
1448             }
1449              
1450 0           $self->identify_vendor;
1451 0           $self->identify_model;
1452              
1453 0 0         if ( $self->vendor )
1454             {
1455 0           $class = join('::', $class, $self->vendor );
1456 0           $log->debug($self->hostname . "Found device model: $class");
1457             }
1458             else
1459             {
1460 0           $log->debug($self->hostname
1461             . "Unable to determine device model. Using $class.");
1462             }
1463              
1464 0           return $class;
1465             }
1466              
1467             ########################################
1468             # identify_vendor
1469             # public method
1470             #
1471             # Lookup the device vendor. Use (in order)
1472             # one of the following methods. Sets the
1473             # vendor attribute of the device
1474             #
1475             # configured in device file
1476             # snmp (sysDescr.0)
1477             # console (show ver...doesn't always work)
1478             #
1479             # Returns:
1480             # success => undef
1481             # failure => error message
1482             ########################################
1483             sub identify_vendor {
1484 0     0 1   my $self = shift;
1485 0           my $log = Log::Log4perl->get_logger( ref($self) );
1486 0           my $info; # String to look at to determine the vendor
1487             my $vendor; # the name of the device vendor
1488              
1489 0 0 0       if ($self->vendor)
    0          
    0          
1490             {
1491 0           $log->debug($self->hostname . "Vendor already defined.");
1492 0           $vendor = _get_vendor_from_string( $self->vendor );
1493 0 0         if ( not ($self->vendor eq $vendor) )
1494             {
1495 0           $self->vendor($vendor);
1496 0           $log->trace("Defined vendor incorrect. Correcting...");
1497             }
1498 0           return;
1499             }
1500             elsif ($self->session and $self->provision)
1501             {
1502 0           $log->debug($self->hostname . " - Using terminal to determine vendor.");
1503 0           $info = $self->console_get_description;
1504             }
1505             elsif ($self->snmp_community)
1506             {
1507 0           $info = $self->snmp_get_description;
1508 0           $log->debug($self->hostname . "Using snmp to determine vendor.");
1509             }
1510             else
1511             {
1512 0           $log->info($self->hostname . "Unable to determine the vendor");
1513 0           return "Unable to determine the vendor.";
1514             }
1515              
1516 0 0         $info and $log->trace("Found snmp or console info: $info");
1517              
1518 0           $vendor = _get_vendor_from_string($info);
1519              
1520 0 0         if ($vendor)
1521             {
1522 0           $self->vendor($vendor);
1523             }
1524              
1525 0 0         return $info ? undef : "Unable to determine vendor.";
1526             }
1527              
1528             ########################################
1529             # identify_model
1530             # public method
1531             #
1532             # Lookup the device model. Use (in order)
1533             # one of the following methods. Sets the
1534             # model attribute of the device
1535             #
1536             # configured in device file
1537             # snmp (sysDescr.0)
1538             # console (show ver...doesn't always work)
1539             #
1540             # Returns:
1541             # success => undef
1542             # failure => error message
1543             ########################################
1544             sub identify_model {
1545 0     0 1   my $self = shift;
1546 0           my $log = Log::Log4perl->get_logger( ref($self) );
1547 0           my $info; # String to look at to determine the model
1548             my $model; # the device model
1549              
1550 0 0 0       if ($self->model)
    0          
    0          
1551             {
1552 0           $log->debug("Model already defined for " . $self->hostname);
1553 0           return;
1554             }
1555             elsif ($self->session and $self->provision)
1556             {
1557 0           $log->debug($self->hostname . " - Using terminal to determine model");
1558 0           $info = $self->console_get_description;
1559             }
1560             elsif ($self->snmp_community)
1561             {
1562 0           $info = $self->snmp_get_description;
1563 0           $log->debug($self->hostname . " - Using snmp to determine model");
1564             }
1565             else
1566             {
1567 0           $log->info("Unable to determine the model for " . $self->hostname);
1568             }
1569              
1570 0           $model = &_get_model_from_string($info);
1571              
1572 0 0         if ($model)
1573             {
1574 0           $self->model( $model );
1575             }
1576              
1577 0 0         return $model ? undef : "Unable to determine device model";
1578             }
1579              
1580             ########################################
1581             # snmp_get_description
1582             # public method
1583             #
1584             # Get the sysDescr.0 from the device
1585             #
1586             # Returns:
1587             # success => the sysDescr.0 string
1588             # failure => undef
1589             ########################################
1590             sub snmp_get_description {
1591 0     0 1   my $self = shift;
1592 0           my $log = Log::Log4perl->get_logger( ref($self) );
1593 0           my $snmp; # snmp session
1594             my $snmp_error; # the error from a snmp session
1595 0           my $snmp_vendor; # output from the snmp get request
1596 0           my $snmp_oid; # oid of the attribute to get
1597 0           my $snmp_result; # the result of the snmp query
1598              
1599 0 0         if ($self->provision)
1600             {
1601 0           $log->debug($self->hostname . " Ignored - Not using snmp to determine"
1602             . " device type.");
1603 0           return undef;
1604             }
1605              
1606 0           $log->debug("Using snmp to determine the vendor.");
1607 0           ($snmp, $snmp_error) = Net::SNMP->session(
1608             -hostname => $self->hostname,
1609             -version => $self->snmp_version,
1610             -community => $self->snmp_community,
1611             );
1612 0 0         if (not $snmp)
1613             {
1614 0           $log->warn($self->hostname . " - Error determining vendor using snmp.");
1615 0           return undef;
1616             }
1617              
1618             # sysDescr.0
1619 0           $snmp_oid = '.1.3.6.1.2.1.1.1.0';
1620              
1621             eval
1622 0           {
1623 0           $snmp_result = $snmp->get_request(
1624             -varbindlist => [ $snmp_oid ],
1625             );
1626             };
1627 0 0         if ($@)
1628             {
1629 0           $log->warn($self->hostname . " - Error getting snmp info - $@.");
1630 0           undef $snmp_result;
1631             }
1632              
1633 0 0         if ($snmp_result)
1634             {
1635 0           $log->debug("snmp sysDescr.0 for " . $self->hostname . " was "
1636             . $snmp_result->{$snmp_oid});
1637             }
1638             else
1639             {
1640 0           $log->warn("Unable to get the sysDescr via SNMP from "
1641             . $self->hostname . " using community " . $self->community
1642             . " with version " . $self->snmp_version);
1643             }
1644              
1645 0 0         return $snmp_result ? $snmp_result->{$snmp_oid} : undef;
1646             }
1647              
1648             ########################################
1649             # console_get_description
1650             # public method
1651             #
1652             # Get the output from "show version"
1653             #
1654             # Returns:
1655             # success => the result from "show version"
1656             # failure => undef
1657             ########################################
1658             sub console_get_description {
1659 0     0 1   my $self = shift;
1660 0           my $log = Log::Log4perl->get_logger( ref($self) );
1661 0           my $session = $self->session;
1662 0           my $command_failed; # a flag to indicate success or failure of the command.
1663             my $result; # the output from the show version command
1664 0           my $processed_result; # massage the data to return meaningful data
1665              
1666 0           $log->debug("Using the CLI to determine the device model.");
1667              
1668 0 0         if ($session)
1669             {
1670 0 0         if (not $self->admin_status)
1671             {
1672 0           $self->get_admin_rights;
1673             }
1674              
1675              
1676             # XXX
1677             # I know hp will fail if you try to "show ver" and not admin.
1678             # However, cisco will work. Maybe we should try it anyway...
1679 0 0         if ($self->admin_status)
1680             {
1681 0           $session->expect(MEDIUM_TIMEOUT, eval $expect_show_version_cmd
1682             , eval $expect_timeout_cmd);
1683 0           $session->expect(MEDIUM_TIMEOUT, eval $expect_get_priv_console_output
1684             , eval $expect_timeout_cmd);
1685 0 0         if ($command_failed)
1686             {
1687 0           $log->warn($self->hostname . " - Failed"
1688             . " - Unable to show version via cli.");
1689             }
1690 0           $result = $session->before();
1691 0           $log->debug($self->hostname
1692             . " - Got console description - '$result'");
1693             }
1694             else
1695             {
1696 0           $log->warn($self->hostname . " - Failed"
1697             . " - Unable to show version via cli");
1698             }
1699             }
1700              
1701             # if ($result =~ /[iI]mage\s*stamp/)
1702             # {
1703             # $processed_result = "HP";
1704             # }
1705             # elsif ($result =~ /cisco/i)
1706             # {
1707             # $processed_result = "Cisco";
1708             # }
1709             # else
1710             # {
1711             # $processed_result = "";
1712             # }
1713              
1714             # return $processed_result;
1715 0           return $result;
1716             }
1717              
1718              
1719             ########################################
1720             # get_admin_rights
1721             # public method
1722             #
1723             # Tries to gain administrative privileges
1724             # on the device. Should work with both
1725             # cisco and hp.
1726             #
1727             # Returns:
1728             # success = undef
1729             # failure = reason for failure (aka a true value)
1730             ########################################
1731             sub get_admin_rights {
1732 0     0 1   my $self = shift;
1733 0           my $session = $self->session;
1734 0           my $password = $self->enable_password;
1735 0           my $log = Log::Log4perl->get_logger( ref($self) );
1736 0           local $command_failed; # indicates of the command failed.
1737 0           local $connected_to_device; # Added so eval statements don't generate errors
1738 0           my @expect_commands; # the commands to run on the device
1739              
1740 0           $log->debug("Using default get_admin_rights method.");
1741              
1742             # Do some sanity checking
1743 0 0         if (not $self->session)
1744             {
1745 0           $log->warn("No session defined for get admin rights.");
1746 0           return "No session defined for get admin rights.";
1747             }
1748              
1749 0 0         if ($self->admin_status)
1750             {
1751 0           $log->debug("Already have admin rights.");
1752 0           return;
1753             }
1754              
1755             ####################
1756             # Setup Expect command array
1757             #
1758             # The commands are defined for the class, but they need
1759             # to be eval'ed before we can use them.
1760             ####################
1761             # Setup the expect commands to get admin rights
1762             # send "enable"
1763             # send the enable password
1764             # verify priv mode
1765             ####################
1766 0           push(@expect_commands, [
1767             _eval($expect_enable_cmd, $self),
1768             # eval $expect_already_enabled_cmd,
1769             _eval($expect_priv_mode_cmd, $self),
1770             ]);
1771 0           push(@expect_commands, [
1772             _eval($expect_enable_passwd_cmd, $self),
1773             _eval($expect_priv_mode_cmd, $self),
1774             ]);
1775 0           push(@expect_commands, [
1776             _eval($expect_priv_mode_cmd, $self),
1777             ]);
1778              
1779 0           foreach my $command (@expect_commands)
1780             {
1781 0           $self->session->expect(MEDIUM_TIMEOUT, @$command, _eval($expect_timeout_cmd, $self));
1782 0 0         if ($log->level == $TRACE)
1783             {
1784 0           $log->trace("Expect matching before: " . $session->before);
1785 0           $log->trace("Expect matching match : " . $session->match);
1786 0           $log->trace("Expect matching after : " . $session->after);
1787             }
1788 0 0         if ($command_failed) {
    0          
1789 0           $log->warn("Command failed.");
1790 0           $log->debug("Failed command(s): " . @$command);
1791 0           $self->admin_status(FALSE);
1792 0           return "Enable command failed.";
1793             }
1794             elsif ($self->admin_status)
1795             {
1796 0           $log->info($self->hostname
1797             . " - Administrative privileges granted");
1798 0           last;
1799             }
1800             }
1801              
1802 0           return;
1803             }
1804              
1805             ########################################
1806             # disable_paging
1807             # public method
1808             #
1809             # Disable terminal paging (press -Enter-
1810             # to continue) messages. They cause problems
1811             # when using expect.
1812             #
1813             # Returns:
1814             # success = undef
1815             # failure = reason for failure
1816              
1817             ########################################
1818             sub disable_paging {
1819 0     0 1   my $self = shift;
1820 0           my $session; # the object's expect session
1821 0           my $log = Log::Log4perl->get_logger( ref($self) );
1822 0           my $command_failed; # a flag to indicate if the command failed
1823             my @commands; # an array of commands to execute
1824              
1825 0           $session = $self->session;
1826 0 0         if (&_invalid_session($session))
1827             {
1828 0           return "Failed - session not defined";
1829             }
1830              
1831 0           $log->debug("Disabling paging");
1832              
1833 0           $session->expect(MEDIUM_TIMEOUT, eval $expect_disable_paging_cmd, eval $expect_timeout_cmd);
1834 0 0         if ($command_failed)
1835             {
1836 0           $log->warn("Failed to disable paging. The rest of the configuration could fail.");
1837 0           return "Failed - paging command timed out";
1838             }
1839              
1840             # $session->send("\n");
1841              
1842 0           $log->debug("Paging disabled.");
1843              
1844 0           return;
1845             }
1846              
1847             ########################################
1848             # end_session
1849             # public method
1850             #
1851             # If the device has a valid session,
1852             # end it.
1853             #
1854             # Returns undef
1855             ########################################
1856             sub end_session {
1857 0     0 1   my $self = shift;
1858 0           my $log = Log::Log4perl->get_logger( ref($self) );
1859              
1860 0 0         if ($self->session)
1861             {
1862 0           $log->info($self->hostname . " - Terminating session");
1863 0           $self->session->soft_close();
1864 0           $self->session(FALSE);
1865             }
1866             else
1867             {
1868 0           $log->info($self->hostname . " - No session to terminate");
1869             }
1870 0           return;
1871             }
1872              
1873             ########################################
1874             # error_end_session
1875             # public method
1876             #
1877             # Terminate a session due to an error.
1878             # Mainly it has different logging options
1879             # than the normal end_session method
1880             #
1881             # Takes:
1882             # A string to output to the log.
1883             #
1884             # Returns undef
1885             ########################################
1886             sub error_end_session {
1887 0     0 1   my $self = shift;
1888 0           my $message = shift;
1889 0           my $log = Log::Log4perl->get_logger("Net::Autoconfig");
1890              
1891 0 0         if (defined $message)
1892             {
1893 0           $log->warn($self->hostname, " - $message");
1894             }
1895              
1896 0 0         if ($self->session)
1897             {
1898 0           $log->warn($self->hostname . " - Terminating session");
1899 0           $self->session->soft_close();
1900 0           $self->session(FALSE);
1901             }
1902             else
1903             {
1904 0           $log->info($self->hostname . " - No session to terminate");
1905             }
1906 0           return;
1907             }
1908              
1909             ########################################
1910             # replace_command_variables
1911             # public method
1912             #
1913             # Replaces variables in comands
1914             #
1915             # Expects:
1916             # a command hash ref
1917             #
1918             # Returns
1919             # Success = sets the cmd->{cmd} value
1920             # returns undef
1921             # Failure = returns an error message
1922             ########################################
1923             sub replace_command_variables {
1924 0     0 0   my $self = shift;
1925 0           my $log = Log::Log4perl->get_logger( ref($self) );
1926 0           my $cmd = shift; # The command hash
1927 0           my $old_cmd; # The command with variables that need replacing
1928             my $new_cmd; # new string with variables replaced
1929              
1930 0 0         if ( not $cmd )
    0          
1931             {
1932 0           $log->warn($self->hostname . " - no command hash reference passed.");
1933 0           return "No comand hash reference passed.";
1934             }
1935             elsif ( not ref($cmd) eq 'HASH' )
1936             {
1937 0           $log->warn($self->hostnaem . " - command passed, but it was not a hash reference.");
1938 0           return "Command passed, but it was not a hash reference.";
1939             }
1940              
1941 0           $old_cmd = $cmd->{cmd};
1942              
1943             # Do some sanity checking
1944 0 0         if ( not $old_cmd )
1945             {
1946 0           $log->info($self->hostname . " - no command specified. Using \"\".");
1947 0           $old_cmd = "";
1948 0           $new_cmd = $old_cmd;
1949             }
1950 0           $new_cmd = $old_cmd;
1951              
1952             # matches $variable_name; not \$variable_name
1953             # "-" counts as a word boundry, which is good for things like "range $a-$b"
1954             FIND_VARIABLE:
1955 0           while ($old_cmd =~ /[^\\]\$(\w+)/g)
1956             {
1957 0           my $replacement = $self->get($1);
1958 0 0         if (defined $replacement)
1959             {
1960 0           $log->trace($self->hostname . "Replacing '$1' with '$replacement'"
1961             . " for cmd '$old_cmd'");
1962 0           $new_cmd =~ s/\$$1/$replacement/;
1963             }
1964             else
1965             {
1966 0 0         if ( $cmd->{required} )
1967             {
1968 0           my $message = $self->hostname . " - '$1' not defined"
1969             . " for required command '$old_cmd'";
1970 0           $log->warn( $message );
1971 0           return $message;
1972             }
1973             else
1974             {
1975 0           $log->info($self->hostname . " - '$1' not defined for"
1976             . " optinal command '$old_cmd'");
1977             }
1978             }
1979             }
1980              
1981             # Since we escape the $s, remove the
1982             # escape characters.
1983 0           $new_cmd =~ s/\\\$/\$/g;
1984 0 0         if (not $new_cmd eq $old_cmd)
1985             {
1986 0           $cmd->{cmd} = $new_cmd;
1987             }
1988              
1989             #Re-insert command characters
1990             # i.e. tabs and newlines
1991 0 0         if ( $cmd->{cmd} )
1992             {
1993 0           $cmd->{cmd} =~ s/\\t/\t/g;
1994 0           $cmd->{cmd} =~ s/\\n/\n/g;
1995 0           $log->trace($self->hostname . " - \$cmd->{cmd} after replacing"
1996             . " tabs and newlines = '" . $cmd->{cmd} . "'");
1997             }
1998 0           return undef;
1999             }
2000              
2001              
2002             ############################################################
2003             # Private Methods
2004             ############################################################
2005              
2006             ########################################
2007             # _connected
2008             # private method
2009             #
2010             # Accessor
2011             # Returns the connection status (TRUE/FALSE)
2012             #
2013             # Mutator
2014             # Sets the connection status to TRUE or FALSE
2015             # any perl "true" value => TRUE
2016             # any perl "false" value => FALSE
2017             # Returns undef
2018             ########################################
2019             sub _connected {
2020 0     0     my $self = shift;
2021 0           my $status = shift;
2022 0           my $log = Log::Log4perl->get_logger( ref($self) );
2023              
2024 0 0         if ( defined $status )
2025             {
2026 0 0         if ( $status )
2027             {
2028 0           $self->set('connected', TRUE);
2029 0           $log->trace($self->hostname . " - Setting connected status to TRUE");
2030             }
2031             else
2032             {
2033 0           $self->set('connected', FALSE);
2034 0           $log->trace($self->hostname . " - Setting connected status to FALSE");
2035             }
2036             }
2037              
2038 0 0         return defined $status ? undef : $self->{'connected'};
2039             }
2040              
2041             ########################################
2042             # _host_not_reachable
2043             # private function
2044             #
2045             # Ping the specified hostname / ip address.
2046             #
2047             # Returns
2048             # success = FALSE
2049             # failure = TRUE
2050             ########################################
2051             sub _host_not_reachable {
2052 0     0     my $hostname = shift;
2053 0           my $log = Log::Log4perl->get_logger(__PACKAGE__);
2054 0           my $ping; # Ping object
2055              
2056 0 0         if (not $hostname)
2057             {
2058 0           $log->warn("No hostname defined.");
2059 0           return TRUE;
2060             }
2061              
2062 0 0         $ping = eval { Net::Ping->new( $> ? "tcp" : "icmp" ) };
  0            
2063 0 0         if ($@)
2064             {
2065 0           $log->error("Net::Ping Failed - $@");
2066 0           $log->error("Connection to '$hostname' failed.");
2067 0           return TRUE;
2068             }
2069              
2070             # If using a console server, extract the console server
2071             # hostname so ping doesn't fail.
2072 0 0         if ($hostname =~ /.*\@(.*)/) {
2073 0           $hostname = $1;
2074             }
2075            
2076 0 0         if ($ping->ping($hostname))
2077             {
2078 0           $log->debug("'$hostname' is reachable via ping.");
2079 0           return FALSE;
2080             }
2081             else
2082             {
2083 0           $log->warn("Ping failed - '$hostname' not reachable via ping.");
2084 0           return TRUE;
2085             }
2086             }
2087              
2088              
2089              
2090             ########################################
2091             # _get_vendor_from_string
2092             # private function
2093             #
2094             # Given a string, search through it
2095             # to determine the manufacturer of the
2096             # device. The output of "show version"
2097             #
2098             # Example:
2099             #
2100             # $show_ver = "Cisco Systems, C3560E 12.2(46)SE...."
2101             # $vendor = _get_model_from_string($show_ver)
2102             #
2103             # Returns:
2104             # success - The name of the vendor
2105             # failure - undef
2106             ########################################
2107             sub _get_vendor_from_string {
2108 0     0     my $string = shift;
2109 0           my $vendors = VENDORS_REGEX; # a hash ref of regex => vendors
2110 0           my $device_model; # a string that links to the module for that device type
2111 0           my $log = Log::Log4perl->get_logger(__PACKAGE__);
2112              
2113 0 0         (defined $string) or $string = "";
2114              
2115 0           foreach my $regex (keys %$vendors)
2116             {
2117 0           my $vendor = $vendors->{$regex};
2118 0 0         if ($string =~ /$regex/)
2119             {
2120 0           $log->trace("Vendor matched: $regex => $vendor");
2121 0           $device_model = $vendor;
2122 0           last;
2123             }
2124             }
2125              
2126 0 0         if ($device_model)
2127             {
2128 0           $log->debug("Got vendor: $device_model");
2129             }
2130             else
2131             {
2132 0           $log->debug("Failed to get vendor.");
2133             }
2134              
2135 0 0         return $device_model ? $device_model : undef;
2136             }
2137              
2138             ########################################
2139             # _get_model_from_string
2140             # private function
2141             #
2142             # Given a string, search through it
2143             # to determine the model of the
2144             # device. Can be the output from show
2145             # version (cisco devices), or snmp (sysDescr.0)
2146             #
2147             # Example:
2148             #
2149             # $show_ver = "Cisco Systems, C3560E 12.2(46)SE...."
2150             # $vendor = _get_model_from_string($show_ver)
2151             #
2152             # The returned array or array ref contains
2153             # all of the different model types that
2154             # this devices matches. This makes it so
2155             # you can specify all switches, or hp2600
2156             # or hp2626 in the template file and it will
2157             # use the right template.
2158             #
2159             # Returns:
2160             # success
2161             # Scalar context = array ref
2162             # Array context = array
2163             # failure - undef
2164             ########################################
2165             sub _get_model_from_string {
2166 0     0     my $string = shift;
2167 0           my $specific_models = SPECIFIC_DEVICE_MODEL_REGEX;
2168 0           my $generic_models = GENERIC_DEVICE_MODEL_REGEX;
2169 0           my $all_types = ALL_TYPES_MODEL_HASH;
2170 0           my $models = []; # The array ref of models this device matches
2171 0           my $log = Log::Log4perl->get_logger(__PACKAGE__);
2172              
2173 0 0         if (not $string)
2174             {
2175 0           $log->debug("No or false string passed.");
2176 0           return undef;
2177             }
2178              
2179             SPECIFIC_MODEL:
2180 0           foreach my $model (keys %$specific_models)
2181             {
2182 0           my $regex = $specific_models->{$model};
2183 0 0         if ( $string =~ qr($regex) )
2184             {
2185 0           $log->debug("Found specifc model: $model");
2186 0           push(@$models, $model);
2187 0           last SPECIFIC_MODEL;
2188             }
2189             }
2190              
2191             GENERIC_MODEL:
2192 0           foreach my $model (keys %$generic_models)
2193             {
2194 0           my $regex = $generic_models->{$model};
2195 0 0         if ( $string =~ qr($regex) )
2196             {
2197 0           $log->debug("Found generic model: $model");
2198 0           push(@$models, $model);
2199 0           last GENERIC_MODEL;
2200             }
2201             }
2202              
2203             # Sanity checking
2204 0 0         if (not @$models)
2205             {
2206 0           $log->debug("Unable to determine model for '$string'");
2207 0           return undef;
2208             }
2209              
2210             # Look for the most generic model type
2211             # It should be the last one on the list
2212 0 0         if ( $all_types->{ $models->[-1] } )
2213             {
2214 0           my $type = $all_types->{ $models->[-1] };
2215 0           $log->debug("Found generic model: $type");
2216 0           push( @$models, $type );
2217             }
2218 0 0         return wantarray ? @$models : $models;
2219             }
2220              
2221             ########################################
2222             # _invalid_session
2223             # private function
2224             #
2225             # Determine if this is a valid session.
2226             # We're using expect, so it has to be an
2227             # expect object reference, and it has to
2228             # be defined.
2229             #
2230             # Returns:
2231             # true if invalid
2232             # undef if valid
2233             ########################################
2234             sub _invalid_session {
2235 0     0     my $session = shift;
2236 0           my $log = Log::Log4perl->get_logger(__PACKAGE__);
2237              
2238 0 0         if (not defined $session)
2239             {
2240 0           $log->debug("Invalid Session - FAILURE - Session not defined");
2241 0           return TRUE;
2242             }
2243            
2244 0 0         if (not ref($session))
2245             {
2246 0           $log->debug("Invalid Session - FAILURE - Session not a reference");
2247 0           return TRUE;
2248             }
2249            
2250 0 0         if (not ref($session) eq 'Expect')
2251             {
2252 0           $log->debug("Invalid Session - FAILURE - Session not an Expect.pm reference");
2253 0           return TRUE;
2254             }
2255             else
2256             {
2257 0           $log->debug("Invalid Session - SUCCESS - Valid Session");
2258 0           return;
2259             }
2260             }
2261              
2262             ########################################
2263             # _eval
2264             # private method
2265             #
2266             # This is used to evaluate strings/expressions at run-time
2267             # and report any errors. Mainly used for eval'ing
2268             # expect commands.
2269             #
2270             # Call eval and return the result.
2271             # Log any eval errors.
2272             # Assumes the result will be scalar, i.e. a
2273             # reference or a string.
2274             ########################################
2275             sub _eval {
2276 0     0     my $string = shift;
2277 0           my $self = shift;
2278 0           my $log = Log::Log4perl->get_logger(__PACKAGE__);
2279 0           my $session;
2280              
2281 0           $log->trace("EVAL - String = '$string'");
2282              
2283 0 0         if ($self)
2284             {
2285 0           $session = $self->session;
2286 0 0         if (not $session)
2287             {
2288 0           $log->warn($self->hostname . " - EVAL - ERROR - Session not defined.");
2289 0           return;
2290             }
2291             }
2292             else
2293             {
2294 0           undef $self;
2295 0           undef $session;
2296 0           $log->debug("EVAL - ERROR - \$self not defined");
2297 0           $log->debug("EVAL - ERROR - \$session not defined.");
2298             }
2299              
2300 0           my $result = eval $string;
2301              
2302 0 0         if ($@)
2303             {
2304 0           $log->error("EVAL - ERROR - $@");
2305 0           return;
2306             }
2307             else
2308             {
2309 0           $log->debug("EVAL - SUCCESS");
2310             }
2311              
2312 0           return $result;
2313             }
2314              
2315              
2316              
2317              
2318             ########################################
2319             # _is_ip_addr
2320             # private method
2321             #
2322             # Test to see if a string is an ip address.
2323             # Returns:
2324             # True if it is (or looks like it is)
2325             # False if it is not.
2326             ########################################
2327             sub _is_ip_addr {
2328 0     0     my $ip_addr = shift;
2329              
2330 0 0         $ip_addr or return FALSE;
2331              
2332 0 0         if ($ip_addr =~ /(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/)
2333             {
2334             # It slooks like it's valid, let's check and see
2335 0           foreach my $octet ($1, $2, $3, $4)
2336             {
2337 0 0         ($octet > 255) and return FALSE;
2338 0 0         ($octet < 0) and return FALSE;
2339             }
2340             }
2341             else
2342             {
2343 0           return FALSE;
2344             }
2345              
2346 0           return TRUE;
2347             }
2348              
2349             ########################################
2350             # _prefix_to_netmask
2351             #
2352             # Given a prefix, return the corresponding
2353             # netmask.
2354             #
2355             # Returns:
2356             # netmask upon success
2357             # undef upon failure
2358             ########################################
2359             sub _prefix_to_netmask {
2360 0     0     my $prefix = shift;
2361 0           my $prefix_octets;
2362             my $prefix_remainder;
2363 0           my @netmask;
2364              
2365 0 0         ($prefix) or return;
2366 0 0         ($prefix =~ /\/\d{1,2}$/) or return;
2367              
2368 0           $prefix =~ s/\///;
2369              
2370 0           $prefix_octets = int($prefix / 8);
2371 0           $prefix_remainder = ($prefix % 8);
2372              
2373 0           my $prefix_values = {
2374             0 => "0",
2375             1 => "128",
2376             2 => "192",
2377             3 => "224",
2378             4 => "240",
2379             5 => "248",
2380             6 => "252",
2381             7 => "254",
2382             8 => "255",
2383             };
2384              
2385 0           foreach my $octet (1..4)
2386             {
2387 0 0         if ($prefix_octets > 0)
    0          
2388             {
2389 0           $prefix_octets--;
2390 0           push(@netmask, $prefix_values->{8});
2391             }
2392             elsif ($prefix_remainder)
2393             {
2394 0           push(@netmask, $prefix_values->{$prefix_remainder});
2395 0           $prefix_remainder = 0;
2396             }
2397             else
2398             {
2399 0           push(@netmask, $prefix_values->{0});
2400             }
2401             }
2402             return
2403 0 0         wantarray ? @netmask : join(".", @netmask);
2404             }
2405              
2406              
2407             ########################################
2408             # _netmask_to_prefix
2409             #
2410             # Given a netmask, return the corresponding
2411             # prefix "/\d{1,2}"
2412             #
2413             # Returns:
2414             # prefix upon success
2415             # undef upon failure
2416             ########################################
2417             sub _netmask_to_prefix {
2418 0     0     my $netmask = shift;
2419 0           my @netmask; # the octets of the netmask
2420 0           my $prefix = 0; # the prefix form of the netmask
2421 0           my $log = Log::Log4perl->get_logger('Net::Autoconfig');
2422              
2423 0           my %netmask_values = {
2424             255 => "8",
2425             254 => "7",
2426             252 => "6",
2427             248 => "5",
2428             240 => "4",
2429             224 => "3",
2430             192 => "2",
2431             128 => "1",
2432             0 => "0",
2433             };
2434            
2435 0 0         if (! $netmask)
2436             {
2437 0           $log->info("No netmask was specified.");
2438 0           return;
2439             }
2440              
2441 0           @netmask = split(/\./, $netmask);
2442              
2443 0 0         if ( @netmask != 4)
2444             {
2445 0           $log->info("Invalid netmask. '" . $netmask . "'");
2446 0           return;
2447             }
2448              
2449 0           foreach my $octet (@netmask)
2450             {
2451 0 0         ($octet > 255) and $log->info("Netmask octect > 255");
2452 0 0         ($octet < 0) and $log->info("Netmask octect < 0");
2453            
2454 0           $prefix += $netmask_values{$octet};
2455             }
2456 0           return $prefix;
2457             }
2458              
2459              
2460             # Modules must return true.
2461             TRUE;
2462              
2463              
2464             __END__