From 1af11bd088d33aff1a3340d2bc48cb4dfad13d60 Mon Sep 17 00:00:00 2001 From: "Eric A. Miller" Date: Sun, 29 Apr 2018 23:35:09 -0400 Subject: [PATCH] #220 Alcatel-Lucent / Nokia SR 7750 missing port information. Add duplex, fan, and power supply status, as well as, module inventory to L3::Timetra --- .travis.yml | 2 +- Changes | 2 + lib/SNMP/Info/Layer3/Timetra.pm | 514 +++++++++++++++++++----- xt/lib/Test/SNMP/Info/Layer3/Timetra.pm | 279 ++++++++++++- 4 files changed, 684 insertions(+), 113 deletions(-) diff --git a/.travis.yml b/.travis.yml index d4eaf172..4eb5776c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ before_install: - mkdir ~/netdisco-mibs - cd ~/netdisco-mibs install: - - curl -sL https://github.com/netdisco/netdisco-mibs/releases/download/4.009/netdisco-mibs.tar.gz | tar --strip-components=1 -zxf - + - curl -sL https://github.com/netdisco/netdisco-mibs/releases/download/4.010/netdisco-mibs.tar.gz | tar --strip-components=1 -zxf - - cpanm --quiet --notest PkgConfig Test::CChecker Alien::zlib::Static Alien::OpenSSL::Static Alien::SNMP::MAXTC before_script: - 'cd ${TRAVIS_BUILD_DIR}' diff --git a/Changes b/Changes index 967ba612..dcd76296 100644 --- a/Changes +++ b/Changes @@ -6,6 +6,8 @@ Version 3.58 [ENHANCEMENTS] + * #220 Alcatel-Lucent / Nokia SR 7750 missing port information. Add duplex, + fan, and power supply status, as well as, module inventory to L3::Timetra * Add fan and power supply status to L3::Huawei * Override ifMTU with max frame size when applicable in L3::Huawei diff --git a/lib/SNMP/Info/Layer3/Timetra.pm b/lib/SNMP/Info/Layer3/Timetra.pm index 9be2386d..c6fa2635 100644 --- a/lib/SNMP/Info/Layer3/Timetra.pm +++ b/lib/SNMP/Info/Layer3/Timetra.pm @@ -33,9 +33,11 @@ use strict; use Exporter; use SNMP::Info::Layer3; +use SNMP::Info::Aggregate; -@SNMP::Info::Layer3::Timetra::ISA = qw/SNMP::Info::Layer3 - Exporter/; +@SNMP::Info::Layer3::Timetra::ISA + = qw/SNMP::Info::Aggregate SNMP::Info::Layer3 + Exporter/; @SNMP::Info::Layer3::Timetra::EXPORT_OK = qw//; use vars qw/$VERSION %GLOBALS %MIBS %FUNCS %MUNGE/; @@ -43,102 +45,141 @@ use vars qw/$VERSION %GLOBALS %MIBS %FUNCS %MUNGE/; $VERSION = '3.57'; %MIBS = ( - %SNMP::Info::Layer3::MIBS, - 'TIMETRA-GLOBAL-MIB' => 'timetraReg', - 'TIMETRA-LLDP-MIB' => 'tmnxLldpAdminStatus', + %SNMP::Info::Layer3::MIBS, + %SNMP::Info::Aggregate::MIBS, + 'TIMETRA-GLOBAL-MIB' => 'timetraReg', + 'TIMETRA-LLDP-MIB' => 'tmnxLldpAdminStatus', + 'TIMETRA-PORT-MIB' => 'tmnxPortEtherDuplex', + 'TIMETRA-CHASSIS-MIB' => 'tmnxChassisFanOperStatus', ); -%GLOBALS = (%SNMP::Info::Layer3::GLOBALS,); +%GLOBALS = ( %SNMP::Info::Layer3::GLOBALS, ); %FUNCS = ( - %SNMP::Info::Layer3::FUNCS, + %SNMP::Info::Layer3::FUNCS, - # For some reason LLDP-MIB::lldpLocManAddrTable is populated - # but LLDP-MIB::lldpRemTable is not and we need to use the - # proprietary TIMETRA-LLDP-MIB Note: these tables are - # indexed differently than LLDP-MIB - # TIMETRA-LLDP-MIB::tmnxLldpRemTable - 'lldp_rem_id_type' => 'tmnxLldpRemChassisIdSubtype', - 'lldp_rem_id' => 'tmnxLldpRemChassisId', - 'lldp_rem_pid_type' => 'tmnxLldpRemPortIdSubtype', - 'lldp_rem_pid' => 'tmnxLldpRemPortId', - 'lldp_rem_desc' => 'tmnxLldpRemPortDesc', - 'lldp_rem_sysname' => 'tmnxLldpRemSysName', - 'lldp_rem_sysdesc' => 'tmnxLldpRemSysDesc', - 'lldp_rem_sys_cap' => 'tmnxLldpRemSysCapEnabled', - 'lldp_rem_cap_spt' => 'tmnxLldpRemSysCapSupported', + # For some reason LLDP-MIB::lldpLocManAddrTable is populated + # but LLDP-MIB::lldpRemTable is not and we need to use the + # proprietary TIMETRA-LLDP-MIB Note: these tables are + # indexed differently than LLDP-MIB + # TIMETRA-LLDP-MIB::tmnxLldpRemTable + 'lldp_rem_id_type' => 'tmnxLldpRemChassisIdSubtype', + 'lldp_rem_id' => 'tmnxLldpRemChassisId', + 'lldp_rem_pid_type' => 'tmnxLldpRemPortIdSubtype', + 'lldp_rem_pid' => 'tmnxLldpRemPortId', + 'lldp_rem_desc' => 'tmnxLldpRemPortDesc', + 'lldp_rem_sysname' => 'tmnxLldpRemSysName', + 'lldp_rem_sysdesc' => 'tmnxLldpRemSysDesc', + 'lldp_rem_sys_cap' => 'tmnxLldpRemSysCapEnabled', + 'lldp_rem_cap_spt' => 'tmnxLldpRemSysCapSupported', - # TIMETRA-LLDP-MIB::tmnxLldpRemManAddrTable - 'lldp_rman_addr' => 'tmnxLldpRemManAddrIfSubtype', + # TIMETRA-LLDP-MIB::tmnxLldpRemManAddrTable + 'lldp_rman_addr' => 'tmnxLldpRemManAddrIfSubtype', + + # TIMETRA-PORT-MIB::tmnxPortEtherTable + 'tmnx_eth_speed_admin' => 'tmnxPortEtherSpeed', + 'tmnx_eth_duplex' => 'tmnxPortEtherOperDuplex', + 'tmnx_eth_duplex_admin' => 'tmnxPortEtherDuplex', + 'tmnx_eth_auto' => 'tmnxPortEtherAutoNegotiate', + + # TIMETRA-CHASSIS-MIB::tmnxChassisFanTable + 'tmnx_fan_state' => 'tmnxChassisFanOperStatus', + + # TIMETRA-CHASSIS-MIB::tmnxChassisPowerSupplyTable + 'tmnx_ps1_state' => 'tmnxChassisPowerSupply1Status', + 'tmnx_ps2_state' => 'tmnxChassisPowerSupply2Status', + + # TIMETRA-CHASSIS-MIB::tmnxHwTable + 'e_descr' => 'tmnxHwName', + 'e_parent' => 'tmnxHwContainedIn', + 'e_name' => 'tmnxHwName', + 'e_class' => 'tmnxHwClass', + 'e_pos' => 'tmnxHwParentRelPos', + 'e_swver' => 'tmnxHwSoftwareCodeVersion', + 'e_model' => 'tmnxHwMfgBoardNumber', + 'e_serial' => 'tmnxHwSerialNumber', + 'e_fru' => 'tmnxHwIsFRU', + 'e_fwver' => 'tmnxHwFirmwareCodeVersion', ); -%MUNGE = (%SNMP::Info::Layer3::MUNGE,); +%MUNGE = ( + %SNMP::Info::Layer3::MUNGE, + 'tmnx_fan_state' => \&SNMP::Info::Layer3::Timetra::munge_tmnx_state, + 'tmnx_ps1_state' => \&SNMP::Info::Layer3::Timetra::munge_tmnx_state, + 'tmnx_ps2_state' => \&SNMP::Info::Layer3::Timetra::munge_tmnx_state, + 'e_type' => \&SNMP::Info::munge_e_type, + 'e_class' => \&SNMP::Info::Layer3::Timetra::munge_tmnx_e_class, + 'e_swver' => \&SNMP::Info::Layer3::Timetra::munge_tmnx_e_swver, +); sub model { - my $timetra = shift; - my $id = $timetra->id(); - my $model = SNMP::translateObj($id); - my $descr = $timetra->description(); + my $timetra = shift; + my $id = $timetra->id(); + my $model = SNMP::translateObj($id); + my $descr = $timetra->description(); - if (defined $model && $model =~ /^tmnxModel/) { - $model =~ s/^tmnxModel//; - $model =~ s/Reg$//; - return $model; - } + my $str; - if ($descr =~ /\s+(7\d{3})/) { - return $1; - } + if ( $descr =~ /\s+(7\d{3})/ ) { + $str = $1; + } - return $model || $id; + if ( defined $model && $model =~ /^tmnxModel/ ) { + $model =~ s/^tmnxModel//; + $model =~ s/Reg$//; + $str .= $str ? " " : ""; + $str .= $model; + } + + return $str || $id; } sub os { - return 'TiMOS'; + return 'TiMOS'; } sub vendor { - return 'nokia'; + return 'nokia'; } sub os_ver { - my $timetra = shift; + my $timetra = shift; - my $descr = $timetra->description(); - if ($descr =~ m/^TiMOS-(\S+)/) { - return $1; - } - return; + my $descr = $timetra->description(); + if ( $descr =~ m/^TiMOS-(\S+)/x ) { + return $1; + } + return; } # The interface description contains the SFP type, so # to avoid losing historical information through a configuration change # we use interface name instead. sub interfaces { - my $alu = shift; - my $partial = shift; + my $alu = shift; + my $partial = shift; - return $alu->orig_i_name($partial); + return $alu->orig_i_name($partial); } # The TIMETRA-LLDP-MIB::tmnxLldpRemTable unambiguously states it uses ifIndex # Trying to cross reference to ifDescr or ifAlias would cause unpredictable # results based upon how the device names ports. sub lldp_if { - my $alu = shift; - my $partial = shift; + my $alu = shift; + my $partial = shift; - my $addr = $alu->lldp_rem_pid($partial) || {}; + my $addr = $alu->lldp_rem_pid($partial) || {}; - my %lldp_if; - foreach my $key (keys %$addr) { - my @aOID = split('\.', $key); - my $port = $aOID[1]; - next unless $port; + my %lldp_if; + foreach my $key ( keys %$addr ) { + my @aOID = split( '\.', $key ); + my $port = $aOID[1]; + next unless $port; - $lldp_if{$key} = $port; - } - return \%lldp_if; + $lldp_if{$key} = $port; + } + return \%lldp_if; } # The proprietary TIMETRA-LLDP-MIB tables are indexed differently than LLDP-MIB @@ -149,35 +190,206 @@ sub lldp_if { # in SNMP::Info::LLDP. This brute force redefines the code in the symbol table. *SNMP::Info::LLDP::_lldp_addr_index = sub { - my $idx = shift; - my @oids = split(/\./, $idx); + my $idx = shift; + my @oids = split( /\./, $idx ); - # Index has extra field compared to LLDP-MIB - my $index = join('.', splice(@oids, 0, 4)); - my $proto = shift(@oids); - shift(@oids) if scalar @oids > 4; # $length + # Index has extra field compared to LLDP-MIB + my $index = join( '.', splice( @oids, 0, 4 ) ); + my $proto = shift(@oids); + shift(@oids) if scalar @oids > 4; # $length - # IPv4 - if ($proto == 1) { - return ($index, $proto, join('.', @oids)); - } + # IPv4 + if ( $proto == 1 ) { + return ( $index, $proto, join( '.', @oids ) ); + } - # IPv6 - elsif ($proto == 2) { - return ($index, $proto, join(':', unpack('(H4)*', pack('C*', @oids)))); - } + # IPv6 + elsif ( $proto == 2 ) { + return ( $index, $proto, + join( ':', unpack( '(H4)*', pack( 'C*', @oids ) ) ) ); + } - # MAC - elsif ($proto == 6) { - return ($index, $proto, join(':', map { sprintf "%02x", $_ } @oids)); - } + # MAC + elsif ( $proto == 6 ) { + return ( $index, $proto, + join( ':', map { sprintf "%02x", $_ } @oids ) ); + } - # TODO - Other protocols may be used as well; implement when needed? - else { - return; - } + # TODO - Other protocols may be used as well; implement when needed? + else { + return; + } }; +sub i_duplex { + my $alu = shift; + my $partial = shift; + + my $hw_duplex = $alu->tmnx_eth_duplex($partial) || {}; + + my %i_duplex; + if ( ref {} eq ref $hw_duplex and scalar keys %$hw_duplex ) { + foreach my $if ( keys %$hw_duplex ) { + my $duplex = $hw_duplex->{$if}; + next unless defined $duplex; + next if $duplex eq 'notApplicable'; + my ( $slot, $ifindex ) = split( /\./, $if ); + + $duplex = 'half' + if ( $duplex =~ /half/i ); + $duplex = 'full' + if ( $duplex =~ /full/i ); + + $i_duplex{$ifindex} = $duplex; + } + return \%i_duplex; + } + return $alu->SUPER::i_duplex($partial); +} + +sub i_duplex_admin { + my $alu = shift; + my $partial = shift; + + my $hw_duplex_admin = $alu->tmnx_eth_duplex_admin($partial) || {}; + my $hw_auto = $alu->tmnx_eth_auto($partial) || {}; + + my %i_duplex_admin; + foreach my $if ( keys %$hw_duplex_admin ) { + my $duplex = $hw_duplex_admin->{$if}; + next unless defined $duplex; + next if $duplex eq 'notApplicable'; + my $auto = $hw_auto->{$if} || 'false'; + my ( $slot, $ifindex ) = split( /\./, $if ); + + my $string = 'other'; + $string = 'half' + if ( $duplex =~ /half/i and $auto =~ /false/i ); + $string = 'full' + if ( $duplex =~ /full/i and $auto =~ /false/i ); + $string = 'auto' if $auto =~ /true/i; + + $i_duplex_admin{$ifindex} = $string; + } + return \%i_duplex_admin; +} + +sub agg_ports { + my $alu = shift; + + return $alu->agg_ports_ifstack(); +} + +sub fan { + my $alu = shift; + + my $state = $alu->tmnx_fan_state() || {}; + + if ( scalar keys %$state ) { + my @messages = (); + + foreach my $k ( keys %$state ) { + next if $state->{$k} and $state->{$k} eq 'Ok'; + my ( $chassis, $fan ) = split( /\./, $k ); + push @messages, "Fan $fan, Chassis $chassis: $state->{$k}"; + } + + push @messages, ( ( scalar keys %$state ) . " fans OK" ) + if scalar @messages == 0; + + return ( join ", ", @messages ); + } + return; +} + +sub ps1_status { + my $alu = shift; + + my $pwr_state = $alu->tmnx_ps1_state() || {}; + + my $ret = ""; + my $s = ""; + foreach my $i ( sort keys %$pwr_state ) { + my ( $chassis, $num ) = split( /\./, $i ); + $ret + .= $s + . "Chassis " + . $chassis . " PS " + . $num . ": " + . $pwr_state->{$i}; + $s = ", "; + } + return if ( $s eq "" ); + return $ret; +} + +sub ps2_status { + my $alu = shift; + + my $pwr_state = $alu->tmnx_ps2_state() || {}; + + my $ret = ""; + my $s = ""; + foreach my $i ( sort keys %$pwr_state ) { + my ( $chassis, $num ) = split( /\./, $i ); + $ret + .= $s + . "Chassis " + . $chassis . " PS " + . $num . ": " + . $pwr_state->{$i}; + $s = ", "; + } + return if ( $s eq "" ); + return $ret; +} + +sub e_index { + my $alu = shift; + my $partial = shift; + + # Use MIB leaf to force load here + my $e_descr = $alu->tmnxHwID($partial); + + return unless ( ref {} eq ref $e_descr and scalar keys %$e_descr ); + + my %e_index; + + foreach my $iid ( keys %$e_descr ) { + $e_index{$iid} = $iid; + } + return \%e_index; +} + +sub munge_tmnx_state { + my $state = shift; + + $state =~ s/deviceState//; + $state =~ s/device//; + return $state; +} + +sub munge_tmnx_e_class { + my $class = shift; + + if ($class eq 'physChassis') { + $class = 'chassis'; + } + elsif ($class =~ /Module/i) { + $class = 'module'; + } + return $class; +} + +sub munge_tmnx_e_swver { + my $swver = shift; + + if ( $swver =~ m/^TiMOS-(\S+)/x ) { + return $1; + } + return $swver; +} + 1; __END__ @@ -225,6 +437,10 @@ Subclass for Alcatel-Lucent Service Routers =item F +=item F + +=item F + =item Inherited Classes' MIBs See L for its own MIB requirements. @@ -251,10 +467,27 @@ Grabs the version string from C. =item $alu->model() -Tries to reference $alu->id() to one of the product MIBs listed above +Tries to combine series and model extracted from $alu->id() to one of the +product MIBs. Removes 'tmnxModel' from the name for readability. +=item $alu->fan() + +Return the status of all fans from the F. Returns +a string indicating the number of fans 'OK' or identification of any fan without +a 'Ok' operating status. + +=item $alu->ps1_status() + +Return the status of the first power supply in each chassis from +the F. + +=item $alu->ps2_status() + +Return the status of the second power supply in each chassis from +the F. + =back =head2 Globals imported from SNMP::Info::Layer3 @@ -266,6 +499,24 @@ See documentation in L for details. These are methods that return tables of information in the form of a reference to a hash. +=over + +=item $alu->i_duplex() + +Returns reference to map of IIDs to current link duplex. + +=item $alu->i_duplex_admin() + +Returns reference to hash of IIDs to admin duplex setting. + +=item $alu->agg_ports() + +Returns a HASH reference mapping from slave to master port for each member of +a port bundle on the device. Keys are ifIndex of the slave ports, Values are +ifIndex of the corresponding master ports. + +=back + =head2 Overrides =over @@ -280,49 +531,130 @@ upon the transceiver inserted. Returns the mapping to the SNMP Interface Table. Utilizes (C) from the (C) index. - =back =head2 LLDP Remote Table (C) uses (C) =over -=item $lldp->lldp_rem_id_type() +=item $alu->lldp_rem_id_type() (C) -=item $lldp->lldp_rem_id() +=item $alu->lldp_rem_id() (C) -=item $lldp->lldp_rem_pid_type() +=item $alu->lldp_rem_pid_type() (C) -=item $lldp->lldp_rem_pid() +=item $alu->lldp_rem_pid() (C) -=item $lldp->lldp_rem_desc() +=item $alu->lldp_rem_desc() (C) -=item $lldp->lldp_rem_sysname() +=item $alu->lldp_rem_sysname() (C) -=item $lldp->lldp_rem_sysdesc() +=item $alu->lldp_rem_sysdesc() (C) -=item $lldp->lldp_rem_sys_cap() +=item $alu->lldp_rem_sys_cap() (C) =back +=head2 Entity Table + +=over + +=item $alu->e_index() + +(C) + +=item $alu->e_class() + +Chassis, Module, Fan, Power Supply ... + +(C) + +=item $alu->e_descr() + +Human Friendly + +(C) + +=item $alu->e_fwver() + +(C) + +=item $alu->e_fru() + +BOOLEAN. Is a Field Replaceable unit? + +(C) + +=item $alu->e_model() + +Model Name of Entity. + +(C) + +=item $alu->e_name() + +More computer friendly name of entity. + +(C) + +=item $alu->e_parent() + +0 if root. + +(C) + +=item $alu->e_pos() + +The relative position among all entities sharing the same parent. + +(C) + +=item $alu->e_serial() + +(C) + +=item $alu->e_swver() + +(C) + +=back + =head2 Table Methods imported from SNMP::Info::Layer3 See documentation in L for details. +=head1 Data Munging Callback Subroutines + +=over + +=item $alu->munge_tmnx_state() + +Removes 'deviceState' or 'device' from C strings. + +=item $alu->munge_tmnx_e_class() + +Attempts to normalize C to an C. + +=item $alu->munge_tmnx_e_swver() + +Extracts the software version from C string. + +=back + =cut diff --git a/xt/lib/Test/SNMP/Info/Layer3/Timetra.pm b/xt/lib/Test/SNMP/Info/Layer3/Timetra.pm index 73f8151c..488210b4 100644 --- a/xt/lib/Test/SNMP/Info/Layer3/Timetra.pm +++ b/xt/lib/Test/SNMP/Info/Layer3/Timetra.pm @@ -39,22 +39,36 @@ sub setup : Tests(setup) { # Start with a common cache that will serve most tests my $cache_data = { - '_layers' => 79, - '_description' => 'TiMOS-B-6.1.R4 both/hops ALCATEL-LUCENT SAR 7705 ', - '_id' => '.1.3.6.1.4.1.6527.6.1.1.2.2', - '_lldp_sys_cap' => pack("H*", '2800'), - '_i_description' => 1, - '_i_name' => 1, - '_lldp_rem_cap_spt' => 1, - '_lldp_rem_sys_cap' => 1, - '_lldp_rem_id_type' => 1, - '_lldp_rem_id' => 1, - '_lldp_rem_pid_type' => 1, - '_lldp_rem_pid' => 1, - '_lldp_rem_desc' => 1, - '_lldp_rem_sysname' => 1, - '_lldp_rman_addr' => 1, - 'store' => { + '_layers' => 79, + '_description' => 'TiMOS-C-14.0.R5 cpm/hops64 Nokia 7750 SR Copyright', + + # TIMETRA-GLOBAL-MIB::tmnxModelSRa4Reg + '_id' => '.1.3.6.1.4.1.6527.1.3.9', + + '_lldp_sys_cap' => pack("H*", '2800'), + '_i_description' => 1, + '_i_name' => 1, + '_lldp_rem_cap_spt' => 1, + '_lldp_rem_sys_cap' => 1, + '_lldp_rem_id_type' => 1, + '_lldp_rem_id' => 1, + '_lldp_rem_pid_type' => 1, + '_lldp_rem_pid' => 1, + '_lldp_rem_desc' => 1, + '_lldp_rem_sysname' => 1, + '_lldp_rman_addr' => 1, + '_tmnx_eth_duplex' => 1, + '_tmnx_eth_duplex_admin' => 1, + '_tmnx_eth_auto' => 1, + '_el_index' => 1, + '_el_duplex' => 1, + '_ifStackStatus' => 1, + '_ifType' => 1, + '_tmnx_fan_state' => 1, + '_tmnx_ps1_state' => 1, + '_tmnx_ps2_state' => 1, + '_tmnxHwID' => 1, + 'store' => { 'i_description' => { '1' => 'system, Loopback IP interface', '40108032' => '1/3/8, 10/100/Gig Ethernet SFP', @@ -69,6 +83,47 @@ sub setup : Tests(setup) { 'lldp_rem_desc' => {'230425271.40108032.1.2' => 'Another-7705-Port'}, 'lldp_rem_sysname' => {'230425271.40108032.1.2' => 'Another-7705'}, 'lldp_rman_addr' => {'230425271.40108032.1.2.1.4.1.2.3.4' => 'unknown'}, + + 'tmnx_eth_duplex' => { + '1.35979264' => 'fullDuplex', + '1.39878656' => 'fullDuplex', + '1.39911424' => 'notApplicable', + '1.39944192' => 'halfDuplex' + }, + 'tmnx_eth_duplex_admin' => { + '1.35979264' => 'notApplicable', + '1.39878656' => 'fullDuplex', + '1.39911424' => 'fullDuplex', + '1.39944192' => 'halfDuplex' + }, + 'tmnx_eth_auto' => { + '1.35979264' => 'notApplicable', + '1.39878656' => 'true', + '1.39911424' => 'false', + '1.39944192' => 'false' + }, + 'el_index' => {67141632 => 67141632, 100696064 => 100696064}, + 'el_duplex' => {67141632 => 'fullDuplex', 100696064 => 'halfDuplex'}, + 'ifStackStatus' => { + '35684352.0' => 'active', + '3.1342177281' => 'active', + '1342177281.35684352' => 'active', + }, + 'ifType' => { + '3' => 'ipForward', + '35684352' => 'ethernetCsmacd', + '1342177281' => 'ieee8023adLag', + }, + 'tmnx_fan_state' => + {'1.1' => 'deviceStateOk', '1.2' => 'deviceStateFailed'}, + 'tmnx_ps1_state' => + {'1.1' => 'deviceStateOk', '1.2' => 'deviceNotEquipped'}, + 'tmnx_ps2_state' => + {'1.3' => 'deviceStateOutOfService', '1.4' => 'deviceStateUnknown'}, + 'tmnxHwID' => { + '1.50331649' => '.1.3.6.1.4.1.6527.3.1.2.2.1.21.1.4.1.3.1', + '1.83886081' => '.1.3.6.1.4.1.6527.3.1.2.2.1.5.1.2.1.1' + }, } }; $test->{info}->cache($cache_data); @@ -92,7 +147,7 @@ sub os_ver : Tests(3) { my $test = shift; can_ok($test->{info}, 'os_ver'); - is($test->{info}->os_ver(), 'B-6.1.R4', q(OS version is expected value)); + is($test->{info}->os_ver(), 'C-14.0.R5', q(OS version is expected value)); $test->{info}->clear_cache(); is($test->{info}->os_ver(), undef, q(No description returns undef os_ver)); @@ -102,14 +157,13 @@ sub model : Tests(5) { my $test = shift; can_ok($test->{info}, 'model'); - is($test->{info}->model(), '7705', q(Model uses description)); + is($test->{info}->model(), '7750 SRa4', q(Model uses description and id)); delete $test->{info}{_description}; - is($test->{info}->model(), - 'timetra.6.1.1.2.2', q(Model partially translated id)); + is($test->{info}->model(), 'SRa4', q(Model translates to 'SRa4')); $test->{info}{_id} = '.1.3.6.1.4.1.6527.1.3.1'; - is($test->{info}->model(), 'SR1', q(Model translates id)); + is($test->{info}->model(), 'SR1', q(Model translates to 'SR1')); $test->{info}{_id} = '.100.3.6.1.4.1.6527.1.3.1'; is($test->{info}->model(), '.100.3.6.1.4.1.6527.1.3.1', q(Model uses id)); @@ -188,4 +242,187 @@ sub topo_example_test : Tests(1) { } } +sub i_duplex : Tests(4) { + my $test = shift; + + can_ok($test->{info}, 'i_duplex'); + + my $expected + = {'35979264' => 'full', '39878656' => 'full', '39944192' => 'half'}; + cmp_deeply($test->{info}->i_duplex(), + $expected, q(Duplex values using 'tmnxPortEtherOperDuplex')); + + delete $test->{info}{'_tmnx_eth_duplex'}; + $expected = {'67141632' => 'full', '100696064' => 'half',}; + cmp_deeply($test->{info}->i_duplex(), + $expected, q(Duplex values using 'EtherLike-MIB')); + + $test->{info}->clear_cache(); + cmp_deeply($test->{info}->i_duplex(), {}, q(No mapping returns empty hash)); +} + +sub i_duplex_admin : Tests(3) { + my $test = shift; + + can_ok($test->{info}, 'i_duplex_admin'); + + my $expected + = {'39878656' => 'auto', '39911424' => 'full', '39944192' => 'half'}; + cmp_deeply($test->{info}->i_duplex_admin(), + $expected, q(Duplex admin values using 'tmnxPortEtherDuplex')); + + $test->{info}->clear_cache(); + cmp_deeply($test->{info}->i_duplex_admin(), + {}, q(No mapping returns empty hash)); +} + +sub agg_ports : Tests(3) { + my $test = shift; + + can_ok($test->{info}, 'agg_ports'); + + my $expected = {35684352 => 1342177281}; + + cmp_deeply($test->{info}->agg_ports(), + $expected, + q(Aggregated links have expected values using 'IEEE8023-LAG-MIB')); + + $test->{info}->clear_cache(); + cmp_deeply($test->{info}->agg_ports(), {}, q(No data returns empty hash)); +} + + +sub fan : Tests(4) { + my $test = shift; + + can_ok($test->{info}, 'fan'); + + my $expected = 'Fan 2, Chassis 1: Failed'; + + is($test->{info}->fan(), $expected, q(Fan returns expected value)); + + # Change failed fan state to normal to test alternate message + $test->{info}{store}{tmnx_fan_state}{'1.2'} = 'deviceStateOk'; + $expected = '2 fans OK'; + + is($test->{info}->fan(), $expected, q(Fans OK returns expected value)); + + $test->{info}->clear_cache(); + is($test->{info}->fan(), undef, q(No data returns undef)); +} + +sub ps1_status : Tests(3) { + my $test = shift; + + can_ok($test->{info}, 'ps1_status'); + + my $expected = 'Chassis 1 PS 1: Ok, Chassis 1 PS 2: NotEquipped'; + + is($test->{info}->ps1_status(), $expected, q(PS1 returns expected value)); + + $test->{info}->clear_cache(); + is($test->{info}->ps1_status(), undef, q(No data returns undef)); +} + +sub ps2_status : Tests(3) { + my $test = shift; + + can_ok($test->{info}, 'ps2_status'); + + my $expected = 'Chassis 1 PS 3: OutOfService, Chassis 1 PS 4: Unknown'; + + is($test->{info}->ps2_status(), $expected, q(PS2 returns expected value)); + + $test->{info}->clear_cache(); + is($test->{info}->ps2_status(), undef, q(No data returns undef)); +} + +sub e_index : Tests(3) { + my $test = shift; + + can_ok($test->{info}, 'e_index'); + + my $expected = { + '1.50331649' => '1.50331649', + '1.83886081' => '1.83886081' + }; + + cmp_deeply($test->{info}->e_index(), $expected, q(Entity index returns expected value)); + + $test->{info}->clear_cache(); + is($test->{info}->e_index(), undef, q(No data returns undef)); +} + +sub munge_tmnx_state : Tests(8) { + my $test = shift; + + can_ok($test->{info}, 'munge_tmnx_state'); + + my $expected = 'Unknown'; + is(SNMP::Info::Layer3::Timetra::munge_tmnx_state('deviceStateUnknown'), + $expected, q(... deviceStateUnknown munges to Unknown)); + + $expected = 'NotEquipped'; + is(SNMP::Info::Layer3::Timetra::munge_tmnx_state('deviceNotEquipped'), + $expected, q(... deviceNotEquipped munges to NotEquipped)); + + $expected = 'Ok'; + is(SNMP::Info::Layer3::Timetra::munge_tmnx_state('deviceStateOk'), + $expected, q(... deviceStateOk munges to Ok)); + + $expected = 'Failed'; + is(SNMP::Info::Layer3::Timetra::munge_tmnx_state('deviceStateFailed'), + $expected, q(... deviceStateFailed munges to Failed)); + + $expected = 'OutOfService'; + is(SNMP::Info::Layer3::Timetra::munge_tmnx_state('deviceStateOutOfService'), + $expected, q(... deviceStateOutOfService munges to OutOfService)); + + $expected = 'NotProvisioned'; + is(SNMP::Info::Layer3::Timetra::munge_tmnx_state('deviceNotProvisioned'), + $expected, q(... deviceNotProvisioned munges to NotProvisioned)); + + is(SNMP::Info::Layer3::Timetra::munge_tmnx_state('huh'), + 'huh', q(... anything else not munged)); +} + +sub munge_tmnx_e_class : Tests(5) { + my $test = shift; + + can_ok($test->{info}, 'munge_tmnx_e_class'); + + my $expected = 'chassis'; + is(SNMP::Info::Layer3::Timetra::munge_tmnx_e_class('physChassis'), + $expected, q(... physChassis munges to chassis)); + + $expected = 'module'; + is(SNMP::Info::Layer3::Timetra::munge_tmnx_e_class('ioModule'), + $expected, q(... ioModule munges to module)); + + $expected = 'powerSupply'; + is(SNMP::Info::Layer3::Timetra::munge_tmnx_e_class('powerSupply'), + $expected, q(... powerSupply doesn't munge)); + + is(SNMP::Info::Layer3::Timetra::munge_tmnx_state('huh'), + 'huh', q(... anything else not munged)); +} + +sub munge_tmnx_e_swver : Tests(3) { + my $test = shift; + + can_ok($test->{info}, 'munge_tmnx_e_swver'); + + my $swver = 'TiMOS-I-14.0.R6 iom/hops Nokia 7750 SR Copyright (c) '; + $swver .= '2000-2016 Nokia. All rights reserved. All use subject to '; + $swver .= 'applicable license agreements. Built on Mon Nov 21 15:19:29 '; + $swver .= 'PST 2016 by builder in /rel14.0/b1/R6/panos/main'; + + my $expected = 'I-14.0.R6'; + is(SNMP::Info::Layer3::Timetra::munge_tmnx_e_swver($swver), + $expected, q(... matching version string extracted)); + + is(SNMP::Info::Layer3::Timetra::munge_tmnx_e_swver('huh'), + 'huh', q(... anything else not munged)); +} + 1;