diff --git a/.travis.yml b/.travis.yml index 1dae4fe6..ebd46574 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.006/netdisco-mibs.tar.gz | tar --strip-components=1 -zxf - + - curl -sL https://github.com/netdisco/netdisco-mibs/releases/download/4.007/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/MANIFEST b/MANIFEST index 4dbbec21..d0505566 100644 --- a/MANIFEST +++ b/MANIFEST @@ -148,4 +148,5 @@ xt/lib/My/Test/Class.pm xt/lib/Test/SNMP/Info.pm xt/lib/Test/SNMP/Info/Layer1/Allied.pm xt/lib/Test/SNMP/Info/Layer1/Asante.pm +xt/lib/Test/SNMP/Info/Layer1/Cyclades.pm xt/lib/Test/SNMP/Info/Layer3/Timetra.pm diff --git a/lib/SNMP/Info.pm b/lib/SNMP/Info.pm index c4d24209..122ee9f4 100644 --- a/lib/SNMP/Info.pm +++ b/lib/SNMP/Info.pm @@ -474,7 +474,7 @@ See documentation in L for details. =item SNMP::Info::Layer1::Cyclades -Subclass for Cyclades terminal servers. +Subclass for Cyclades/Avocent terminal servers. See documentation in L for details. @@ -1582,6 +1582,7 @@ sub device_type { 8072 => 'SNMP::Info::Layer3::NetSNMP', 9303 => 'SNMP::Info::Layer3::PacketFront', 10002 => 'SNMP::Info::Layer2::Ubiquiti', + 10418 => 'SNMP::Info::Layer1::Cyclades', 12325 => 'SNMP::Info::Layer3::Pf', 12356 => 'SNMP::Info::Layer3::Fortinet', 14179 => 'SNMP::Info::Layer2::Airespace', @@ -1621,6 +1622,7 @@ sub device_type { 5624 => 'SNMP::Info::Layer3::Enterasys', 6486 => 'SNMP::Info::Layer3::AlcatelLucent', 9303 => 'SNMP::Info::Layer3::PacketFront', + 10418 => 'SNMP::Info::Layer1::Cyclades', 11898 => 'SNMP::Info::Layer2::Orinoco', 14179 => 'SNMP::Info::Layer2::Airespace', 14525 => 'SNMP::Info::Layer2::Trapeze', @@ -1631,6 +1633,7 @@ sub device_type { my %l1sysoidmap = ( 2925 => 'SNMP::Info::Layer1::Cyclades', + 10418 => 'SNMP::Info::Layer1::Cyclades', ); my %l7sysoidmap = ( diff --git a/lib/SNMP/Info/Layer1/Cyclades.pm b/lib/SNMP/Info/Layer1/Cyclades.pm index 6a4272a1..39b15468 100644 --- a/lib/SNMP/Info/Layer1/Cyclades.pm +++ b/lib/SNMP/Info/Layer1/Cyclades.pm @@ -1,7 +1,7 @@ # SNMP::Info::Layer1::Cyclades # $Id$ # -# Copyright (c) 2008 Eric Miller +# Copyright (c) 2018 Eric Miller # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -43,34 +43,101 @@ $VERSION = '3.53'; %MIBS = ( %SNMP::Info::Layer1::MIBS, - 'CYCLADES-ACS-SYS-MIB' => 'cyACSversion', - 'CYCLADES-ACS-CONF-MIB' => 'cyEthIPaddr', - 'CYCLADES-ACS-INFO-MIB' => 'cyISPortTty', + 'CYCLADES-ACS-SYS-MIB' => 'cyACSversion', + 'CYCLADES-ACS5K-SYS-MIB' => 'cyACS5Kversion', + 'CYCLADES-ACS-CONF-MIB' => 'cyACSConf', + 'CYCLADES-ACS5K-CONF-MIB' => 'cyACS5KConf', + 'CYCLADES-ACS-INFO-MIB' => 'cyACSInfo', + 'CYCLADES-ACS5K-INFO-MIB' => 'cyACS5KInfo', + 'ACS-MIB' => 'acs6016', + 'ACS8000-MIB' => 'acs8048', ); %GLOBALS = ( - # CYCLADES-ACS-SYS-MIB %SNMP::Info::Layer1::GLOBALS, - 'os_ver' => 'cyACSversion', - 'cy_model' => 'cyACSpname', - 'serial' => 'cyACSDevId', - 'root_ip' => 'cyEthIPaddr', - 'ps1_status' => 'cyACSPw1', - 'ps2_status' => 'cyACSPw2', + + # CYCLADES-ACS-SYS-MIB + 'cy_os_ver' => 'cyACSversion', + 'cy_model' => 'cyACSpname', + 'cy_serial' => 'cyACSDevId', + 'cy_ps1_status' => 'cyACSPw1', + 'cy_ps2_status' => 'cyACSPw2', + + # CYCLADES-ACS-CONF-MIB + 'cy_root_ip' => 'CYCLADES_ACS_CONF_MIB__cyEthIPaddr', + + # CYCLADES-ACS5K-SYS-MIB + 'cy5k_os_ver' => 'cyACS5Kversion', + 'cy5k_model' => 'cyACS5Kpname', + 'cy5k_serial' => 'cyACS5KDevId', + 'cy5k_ps1_status' => 'cyACS5KPw1', + 'cy5k_ps2_status' => 'cyACS5KPw2', + + # CYCLADES-ACS5K-CONF-MIB + 'cy5k_root_ip' => 'CYCLADES_ACS5K_CONF_MIB__cyEthIPaddr', + + # ACS-MIB + 'acs_os_ver' => 'ACS_MIB__acsFirmwareVersion', + 'acs_model' => 'ACS_MIB__acsProductModel', + 'acs_serial' => 'ACS_MIB__acsSerialNumber', + 'acs_ps1_status' => 'ACS_MIB__acsPowerSupplyStatePw1', + 'acs_ps2_status' => 'ACS_MIB__acsPowerSupplyStatePw2', + + # ACS8000-MIB + 'acs8k_os_ver' => 'ACS8000_MIB__acsFirmwareVersion', + 'acs8k_model' => 'ACS8000_MIB__acsProductModel', + 'acs8k_serial' => 'ACS8000_MIB__acsSerialNumber', + 'acs8k_ps1_status' => 'ACS8000_MIB__acsPowerSupplyStatePw1', + 'acs8k_ps2_status' => 'ACS8000_MIB__acsPowerSupplyStatePw2', ); %FUNCS = ( %SNMP::Info::Layer1::FUNCS, # CYCLADES-ACS-INFO-MIB::cyInfoSerialTable - 'cy_port_tty' => 'cyISPortTty', - 'cy_port_name' => 'cyISPortName', - 'cy_port_speed' => 'cyISPortSpeed', - 'cy_port_cd' => 'cyISPortSigCD', + 'cy_port_tty' => 'CYCLADES_ACS_INFO_MIB__cyISPortTty', + 'cy_port_name' => 'CYCLADES_ACS_INFO_MIB__cyISPortName', + 'cy_port_speed' => 'CYCLADES_ACS_INFO_MIB__cyISPortSpeed', + 'cy_port_cd' => 'CYCLADES_ACS_INFO_MIB__cyISPortSigCD', # CYCLADES-ACS-CONF-MIB::cySerialPortTable - 'cy_port_socket' => 'cySPortSocketPort', + 'cy_port_socket' => 'CYCLADES_ACS_CONF_MIB__cySPortSocketPort', + + # CYCLADES-ACS5K-INFO-MIB::cyInfoSerialTable + 'cy5k_port_tty' => 'CYCLADES_ACS5K_INFO_MIB__cyISPortTty', + 'cy5k_port_name' => 'CYCLADES_ACS5K_INFO_MIB__cyISPortName', + 'cy5k_port_speed' => 'CYCLADES_ACS5K_INFO_MIB__cyISPortSpeed', + 'cy5k_port_cd' => 'CYCLADES_ACS5K_INFO_MIB__cyISPortSigCD', + + # CYCLADES-ACS5K-CONF-MIB::cySerialPortTable + 'cy5k_port_socket' => 'CYCLADES_ACS5K_CONF_MIB__cySPortSocketPort', + + # ACS-MIB::acsSerialPortTable + 'acs_port_tty' => 'ACS_MIB__acsSerialPortTableDeviceName', + 'acs_port_name' => 'ACS_MIB__acsSerialPortTableName', + 'acs_port_speed' => 'ACS_MIB__acsSerialPortTableComSpeed', + 'acs_port_cd' => 'ACS_MIB__acsSerialPortTableSignalStateDCD', + + # Equivalent to cySPortSocketPort doesn't exist in ACS-MIB + # Use 'acsSerialPortTableDeviceName' as an equivalent, it just needs + # to be unique so that we can differentiate between the index in the + # acsSerialPortTable from ifIndex which are both integers + # ACS-MIB::acsSerialPortTableEntry + 'acs_port_socket' => 'ACS_MIB__acsSerialPortTableDeviceName', + + # ACS8000-MIB::acsSerialPortTable + 'acs8k_port_tty' => 'ACS8000_MIB__acsSerialPortTableDeviceName', + 'acs8k_port_name' => 'ACS8000_MIB__acsSerialPortTableName', + 'acs8k_port_speed' => 'ACS8000_MIB__acsSerialPortTableComSpeed', + 'acs8k_port_cd' => 'ACS8000_MIB__acsSerialPortTableSignalStateDCD', + + # Equivalent to cySPortSocketPort doesn't exist in ACS-MIB + # Use 'acsSerialPortTableDeviceName' as an equivalent, it just needs + # to be unique so that we can differentiate between the index in the + # acsSerialPortTable from ifIndex which are both integers + # ACS8000-MIB::acsSerialPortTableEntry + 'acs8k_port_socket' => 'ACS8000_MIB__acsSerialPortTableDeviceName', ); %MUNGE = ( %SNMP::Info::Layer1::MUNGE, ); @@ -82,21 +149,85 @@ sub layers { } sub os { - return 'cyclades'; + return 'avocent'; +} + +# Use "short circuit" to return the first MIB instance that returns data to +# reduce network communications +# We'll try newest (acs*) first assuming those are most likely deployed +sub os_ver { + my $cyclades = shift; + + return + $cyclades->acs_os_ver() + || $cyclades->acs8k_os_ver() + || $cyclades->cy5k_os_ver() + || $cyclades->cy_os_ver() + || undef; } sub vendor { - return 'cyclades'; + return 'vertiv'; } sub model { my $cyclades = shift; - my $model = $cyclades->cy_model(); + my $model + = $cyclades->acs_model() + || $cyclades->acs8k_model() + || $cyclades->cy5k_model() + || $cyclades->cy_model() + || undef; - return unless defined $model; + return lc($model) if ( defined $model ); - return lc($model); + my $id = $cyclades->id(); + my $prod = SNMP::translateObj($id); + + return $prod || $id; +} + +sub serial { + my $cyclades = shift; + + return + $cyclades->acs_serial() + || $cyclades->acs8k_serial() + || $cyclades->cy5k_serial() + || $cyclades->cy_serial() + || undef; +} + +sub root_ip { + my $cyclades = shift; + + return + $cyclades->cy5k_root_ip() + || $cyclades->cy_root_ip() + || undef; +} + +sub ps1_status { + my $cyclades = shift; + + return + $cyclades->acs_ps1_status() + || $cyclades->acs8k_ps1_status() + || $cyclades->cy5k_ps1_status() + || $cyclades->cy_ps1_status() + || undef; +} + +sub ps2_status { + my $cyclades = shift; + + return + $cyclades->acs_ps2_status() + || $cyclades->acs8k_ps2_status() + || $cyclades->cy5k_ps2_status() + || $cyclades->cy_ps2_status() + || undef; } # Extend interface methods to include serial ports @@ -109,7 +240,12 @@ sub i_index { my $partial = shift; my $orig_index = $cyclades->orig_i_index($partial) || {}; - my $cy_index = $cyclades->cy_port_socket() || {}; + my $cy_index + = $cyclades->acs_port_socket() + || $cyclades->acs8k_port_socket() + || $cyclades->cy5k_port_socket() + || $cyclades->cy_port_socket() + || {}; my %i_index; foreach my $iid ( keys %$orig_index ) { @@ -136,9 +272,19 @@ sub interfaces { my $cyclades = shift; my $partial = shift; - my $i_descr = $cyclades->orig_i_description($partial) || {}; - my $cy_index = $cyclades->cy_port_socket() || {}; - my $cy_p_tty = $cyclades->cy_port_tty() || {}; + my $i_descr = $cyclades->orig_i_description($partial) || {}; + my $cy_index + = $cyclades->acs_port_socket() + || $cyclades->acs8k_port_socket() + || $cyclades->cy5k_port_socket() + || $cyclades->cy_port_socket() + || {}; + my $cy_p_tty + = $cyclades->acs_port_tty() + || $cyclades->acs8k_port_tty() + || $cyclades->cy5k_port_tty() + || $cyclades->cy_port_tty() + || {}; my %if; foreach my $iid ( keys %$i_descr ) { @@ -166,8 +312,18 @@ sub i_speed { my $partial = shift; my $i_speed = $cyclades->orig_i_speed($partial) || {}; - my $cy_index = $cyclades->cy_port_socket() || {}; - my $cy_p_speed = $cyclades->cy_port_speed() || {}; + my $cy_index + = $cyclades->acs_port_socket() + || $cyclades->acs8k_port_socket() + || $cyclades->cy5k_port_socket() + || $cyclades->cy_port_socket() + || {}; + my $cy_p_speed + = $cyclades->acs_port_speed() + || $cyclades->acs8k_port_speed() + || $cyclades->cy5k_port_speed() + || $cyclades->cy_port_speed() + || {}; my %i_speed; foreach my $iid ( keys %$i_speed ) { @@ -195,8 +351,18 @@ sub i_up { my $partial = shift; my $i_up = $cyclades->orig_i_up($partial) || {}; - my $cy_index = $cyclades->cy_port_socket() || {}; - my $cy_p_up = $cyclades->cy_port_cd() || {}; + my $cy_index + = $cyclades->acs_port_socket() + || $cyclades->acs8k_port_socket() + || $cyclades->cy5k_port_socket() + || $cyclades->cy_port_socket() + || {}; + my $cy_p_up + = $cyclades->acs_port_cd() + || $cyclades->acs8k_port_cd() + || $cyclades->cy5k_port_cd() + || $cyclades->cy_port_cd() + || {}; my %i_up; foreach my $iid ( keys %$i_up ) { @@ -224,8 +390,18 @@ sub i_description { my $partial = shift; my $i_desc = $cyclades->orig_i_description($partial) || {}; - my $cy_index = $cyclades->cy_port_socket() || {}; - my $cy_p_desc = $cyclades->cy_port_name() || {}; + my $cy_index + = $cyclades->acs_port_socket() + || $cyclades->acs8k_port_socket() + || $cyclades->cy5k_port_socket() + || $cyclades->cy_port_socket() + || {}; + my $cy_p_desc + = $cyclades->acs_port_name() + || $cyclades->acs8k_port_name() + || $cyclades->cy5k_port_name() + || $cyclades->cy_port_name() + || {}; my %descr; foreach my $iid ( keys %$i_desc ) { @@ -253,8 +429,18 @@ sub i_name { my $partial = shift; my $i_name = $cyclades->orig_i_name($partial) || {}; - my $cy_index = $cyclades->cy_port_socket() || {}; - my $cy_p_desc = $cyclades->cy_port_name() || {}; + my $cy_index + = $cyclades->acs_port_socket() + || $cyclades->acs8k_port_socket() + || $cyclades->cy5k_port_socket() + || $cyclades->cy_port_socket() + || {}; + my $cy_p_desc + = $cyclades->acs_port_name() + || $cyclades->acs8k_port_name() + || $cyclades->cy5k_port_name() + || $cyclades->cy_port_name() + || {}; my %i_name; foreach my $iid ( keys %$i_name ) { @@ -282,7 +468,8 @@ __END__ =head1 NAME -SNMP::Info::Layer1::Cyclades - SNMP Interface to Cyclades terminal servers +SNMP::Info::Layer1::Cyclades - SNMP Interface to Cyclades/Avocent terminal +servers =head1 AUTHOR @@ -309,7 +496,7 @@ Eric Miller =head1 DESCRIPTION Provides abstraction to the configuration information obtainable from a -Cyclades device through SNMP. +Cyclades/Avocent device through SNMP. For speed or debugging purposes you can call the subclass directly, but not after determining a more specific class using the method above. @@ -334,6 +521,14 @@ my $cyclades = new SNMP::Info::Layer1::Cyclades(...); =item F +=item F + +=item F + +=item F + +=item F + =back =head2 Inherited MIBs @@ -348,11 +543,11 @@ These are methods that return scalar value from SNMP =item $cyclades->os_ver() -(C) +(C), (C), or (C) =item $cyclades->serial() -(C) +(C), (C), or (C) =item $cyclades->root_ip() @@ -360,11 +555,11 @@ These are methods that return scalar value from SNMP =item $cyclades->ps1_status() -(C) +(C), (C), or (C) =item $cyclades->ps2_status() -(C) +(C), (C), or (C) =back @@ -379,15 +574,16 @@ to poll for an ARP cache so turn off reported Layer 2 and Layer 3. =item $cyclades->vendor() -Returns 'cyclades' +Returns 'vertiv' =item $cyclades->os() -Returns 'cyclades' +Returns 'avocent' =item $cyclades->model() -Returns lower case (C) +Returns lower case (C) or (C) if it exists +otherwise tries to reference $cyclades->id() to one of the MIBs listed above =back @@ -409,31 +605,34 @@ to a hash. Returns reference to map of IIDs to Interface index. Extended to include serial ports. Serial ports are indexed with the -alternative labeling system for the serial port, the listening socket port -C to avoid conflicts with C. +alternative labeling system for the serial port, either the listening socket +port C or C name to avoid +conflicts with C. =item $cyclades->interfaces() Returns reference to map of IIDs to physical ports. Extended to include -serial ports, C. +serial ports, C or C. =item $cyclades->i_speed() -Returns interface speed. Extended to include serial ports, C. +Returns interface speed. Extended to include serial ports, +C or C. =item $cyclades->i_up() Returns link status for each port. Extended to include serial ports, -C. +C or C. =item $cyclades->i_description() Returns description of each port. Extended to include serial ports, -C. +C or C. =item $cyclades->i_name() -Returns name of each port. Extended to include serial ports, C. +Returns name of each port. Extended to include serial ports, +C or C. =back diff --git a/xt/lib/Test/SNMP/Info/Layer1/Cyclades.pm b/xt/lib/Test/SNMP/Info/Layer1/Cyclades.pm new file mode 100644 index 00000000..a828ab31 --- /dev/null +++ b/xt/lib/Test/SNMP/Info/Layer1/Cyclades.pm @@ -0,0 +1,610 @@ +# Test::SNMP::Info::Layer1::Cyclades +# +# Copyright (c) 2018 Eric Miller +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the University of California, Santa Cruz nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +package Test::SNMP::Info::Layer1::Cyclades; + +use Test::Class::Most parent => 'My::Test::Class'; + +use SNMP::Info::Layer1::Cyclades; + +sub setup : Tests(setup) { + my $test = shift; + $test->SUPER::setup; + + my $phy_addr = pack( "H*", '0000944037B3' ); + + # Start with a common cache that will serve most tests + # Just define all alternatives to start with and alternatives in sequence to + # test short circuits, we can verify conditional coverage with Devel::Cover + my $cache_data = { + '_layers' => 1, + '_description' => 'My Bogus ACS6008 Description', + + # ACS-MIB::acs6008 + '_id' => '.1.3.6.1.4.1.10418.16.1.5', + + '_acs_os_ver' => '6.00', + '_acs8k_os_ver' => '8.00', + '_cy5k_os_ver' => '2.02', + '_cy_os_ver' => '3.00', + '_acs_model' => 'ACS6032', + '_acs8k_model' => 'ACS8032', + '_cy5k_model' => 'ACS5024', + '_cy_model' => 'TS3000', + '_acs_serial' => 'ABC6000', + '_acs8k_serial' => 'ABC8000', + '_cy5k_serial' => 'ABC5000', + '_cy_serial' => 'ABC3000', + '_acs_ps1_status' => 'statePowerOn', + '_acs8k_ps1_status' => 'statePowerOff', + '_cy5k_ps1_status' => 'powerOFF', + '_cy_ps1_status' => 'powerON', + '_acs_ps2_status' => 'powerNotInstaled', + '_acs8k_ps2_status' => 'statePowerOn', + '_cy5k_ps2_status' => 'powerON', + '_cy_ps2_status' => 'noinstalled', + '_cy5k_root_ip' => '2.3.4.5', + '_cy_root_ip' => '1.2.3.4', + '_acs_port_tty' => 1, + '_acs8k_port_tty' => 1, + '_cy5k_port_tty' => 1, + '_cy_port_tty' => 1, + '_acs_port_name' => 1, + '_acs8k_port_name' => 1, + '_cy5k_port_name' => 1, + '_cy_port_name' => 1, + '_acs_port_speed' => 1, + '_acs8k_port_speed' => 1, + '_cy5k_port_speed' => 1, + '_cy_port_speed' => 1, + '_acs_port_cd' => 1, + '_acs8k_port_cd' => 1, + '_cy5k_port_cd' => 1, + '_cy_port_cd' => 1, + '_acs_port_socket' => 1, + '_acs8k_port_socket' => 1, + '_cy5k_port_socket' => 1, + '_cy_port_socket' => 1, + '_i_index' => 1, + '_i_description' => 1, + '_i_speed' => 1, + '_i_up' => 1, + '_i_name' => 1, + + 'store' => { + 'i_index' => { 1 => 1 }, + 'i_speed' => { 1 => 10000000 }, + 'i_description' => { 1 => 'Interface 1 Description' }, + 'i_name' => { 1 => 'Interface 1 Name' }, + 'i_up' => { 1 => 'up' }, + 'acs_port_socket' => { 1 => 'ACS 1 Name', 2 => 'ACS 2 Name' }, + 'acs8k_port_socket' => { 1 => '8K 1 Name', 2 => '8K 2 Name' }, + 'cy5k_port_socket' => { 1 => '5K 1 Sock', 2 => '5K 2 Sock' }, + 'cy_port_socket' => { 1 => 'Port 1 Sock', 2 => 'Port 2 Sock' }, + 'acs_port_tty' => { 1 => 'ACS 1 TTY', 2 => 'ACS 2 TTY' }, + 'acs8k_port_tty' => { 1 => '8K 1 TTY', 2 => '8K 2 TTY' }, + 'cy5k_port_tty' => { 1 => '5K 1 TTY', 2 => '5K 2 TTY' }, + 'cy_port_tty' => { 1 => 'Port 1 TTY', 2 => 'Port 2 TTY' }, + 'acs_port_name' => { 1 => 'ACS 1 Name', 2 => 'ACS 2 Name' }, + 'acs8k_port_name' => { 1 => '8K 1 Name', 2 => '8K 2 Name' }, + 'cy5k_port_name' => { 1 => '5K 1 Name', 2 => '5K 2 Name' }, + 'cy_port_name' => { 1 => 'Port 1 Name', 2 => 'Port 2 Name' }, + 'acs_port_speed' => { 1 => 56000, 2 => 112000 }, + 'acs8k_port_speed' => { 1 => 112000, 2 => 384000 }, + 'cy5k_port_speed' => { 1 => 9600, 2 => 56000 }, + 'cy_port_speed' => { 1 => 2400, 2 => 9600 }, + 'acs_port_cd' => { 1 => 'down', 2 => 'up' }, + 'acs8k_port_cd' => { 1 => 'up', 2 => 'down' }, + 'cy5k_port_cd' => { 1 => 'down', 2 => 'down' }, + 'cy_port_cd' => { 1 => 'down', 2 => 'up' }, + } + }; + $test->{info}->cache($cache_data); +} + +sub os : Tests(2) { + my $test = shift; + + can_ok( $test->{info}, 'os' ); + is( $test->{info}->os(), 'avocent', q(Vendor returns 'avocent') ); +} + +sub os_ver : Tests(6) { + my $test = shift; + + can_ok( $test->{info}, 'os_ver' ); + is( $test->{info}->os_ver(), '6.00', q(ACS version is expected value) ); + + delete $test->{info}{_acs_os_ver}; + is( $test->{info}->os_ver(), '8.00', + q(ACS 8K version is expected value) ); + + delete $test->{info}{_acs8k_os_ver}; + is( $test->{info}->os_ver(), '2.02', + q(ACS 5K version is expected value) ); + + delete $test->{info}{_cy5k_os_ver}; + is( $test->{info}->os_ver(), + '3.00', q(Original Cyclades version is expected value) ); + + delete $test->{info}{_cy_os_ver}; + is( $test->{info}->os_ver(), + undef, q(No MIB leaf data returns undef os_ver) ); +} + +sub vendor : Tests(2) { + my $test = shift; + + can_ok( $test->{info}, 'vendor' ); + is( $test->{info}->vendor(), 'vertiv', q(Vendor returns 'vertiv') ); +} + +sub model : Tests(7) { + my $test = shift; + + can_ok( $test->{info}, 'model' ); + is( $test->{info}->model(), 'acs6032', q(ACS model is expected value) ); + + delete $test->{info}{_acs_model}; + is( $test->{info}->model(), 'acs8032', + q(ACS 8K model is expected value) ); + + delete $test->{info}{_acs8k_model}; + is( $test->{info}->model(), 'acs5024', + q(ACS 5K model is expected value) ); + + delete $test->{info}{_cy5k_model}; + is( $test->{info}->model(), + 'ts3000', q(Original Cyclades model is expected value) ); + + delete $test->{info}{_cy_model}; + is( $test->{info}->model(), + 'acs6008', q(No MIB leaf data returns translated id) ); + + # We won't get to class without sysObjectID that matches enterprise id, + # so use one that isn't defined in MIB + $test->{info}{_id} = '.1.3.6.1.4.1.10418.16.1.6'; + is( $test->{info}->model(), + 'acsProducts.6', + q(Unknown id returns partially translated id) ); +} + +sub serial : Tests(6) { + my $test = shift; + + can_ok( $test->{info}, 'serial' ); + is( $test->{info}->serial(), 'ABC6000', q(ACS serial is expected value) ); + + delete $test->{info}{_acs_serial}; + is( $test->{info}->serial(), + 'ABC8000', q(ACS 8K serial is expected value) ); + + delete $test->{info}{_acs8k_serial}; + is( $test->{info}->serial(), + 'ABC5000', q(ACS 5K serial is expected value) ); + + delete $test->{info}{_cy5k_serial}; + is( $test->{info}->serial(), + 'ABC3000', q(Original Cyclades serial is expected value) ); + + delete $test->{info}{_cy_serial}; + is( $test->{info}->serial(), + undef, q(No MIB leaf data returns undef serial) ); +} + +sub root_ip : Tests(4) { + my $test = shift; + + can_ok( $test->{info}, 'root_ip' ); + is( $test->{info}->root_ip(), + '2.3.4.5', q(ACS 5K root IP is expected value) ); + + delete $test->{info}{_cy5k_root_ip}; + is( $test->{info}->root_ip(), + '1.2.3.4', q(Original Cyclades root IP is expected value) ); + + delete $test->{info}{_cy_root_ip}; + is( $test->{info}->root_ip(), + undef, q(No MIB leaf data returns undef root IP) ); +} + +sub ps1_status : Tests(6) { + my $test = shift; + + can_ok( $test->{info}, 'ps1_status' ); + is( $test->{info}->ps1_status(), + 'statePowerOn', q(ACS power supply 1 status is expected value) ); + + delete $test->{info}{_acs_ps1_status}; + is( $test->{info}->ps1_status(), + 'statePowerOff', q(ACS 8K power supply 1 status is expected value) ); + + delete $test->{info}{_acs8k_ps1_status}; + is( $test->{info}->ps1_status(), + 'powerOFF', q(ACS 5K power supply 1 status is expected value) ); + + delete $test->{info}{_cy5k_ps1_status}; + is( $test->{info}->ps1_status(), + 'powerON', + q(Original Cyclades power supply 1 status is expected value) ); + + delete $test->{info}{_cy_ps1_status}; + is( $test->{info}->ps1_status(), + undef, q(No MIB leaf data returns undef power supply 1 status) ); +} + +sub ps2_status : Tests(6) { + my $test = shift; + + can_ok( $test->{info}, 'ps2_status' ); + is( $test->{info}->ps2_status(), + 'powerNotInstaled', q(ACS power supply 2 status is expected value) ); + + delete $test->{info}{_acs_ps2_status}; + is( $test->{info}->ps2_status(), + 'statePowerOn', q(ACS 8K power supply 2 status is expected value) ); + + delete $test->{info}{_acs8k_ps2_status}; + is( $test->{info}->ps2_status(), + 'powerON', q(ACS 5K power supply 2 status is expected value) ); + + delete $test->{info}{_cy5k_ps2_status}; + is( $test->{info}->ps2_status(), + 'noinstalled', + q(Original Cyclades power supply 2 status is expected value) ); + + delete $test->{info}{_cy_ps2_status}; + is( $test->{info}->ps2_status(), + undef, q(No MIB leaf data returns undef power supply 2 status) ); +} + +sub i_index : Tests(6) { + my $test = shift; + + can_ok( $test->{info}, 'i_index' ); + + my $expected = { + '1' => '1', + 'ACS 1 Name' => 'ACS 1 Name', + 'ACS 2 Name' => 'ACS 2 Name' + }; + cmp_deeply( $test->{info}->i_index(), + $expected, q(ACS interface indices have expected values) ); + + delete $test->{info}{_acs_port_socket}; + delete $test->{info}{store}{acs_port_socket}; + $expected = { + '1' => '1', + '8K 1 Name' => '8K 1 Name', + '8K 2 Name' => '8K 2 Name' + }; + cmp_deeply( $test->{info}->i_index(), + $expected, q(ACS 8K interface indices have expected values) ); + + delete $test->{info}{_acs8k_port_socket}; + delete $test->{info}{store}{acs8k_port_socket}; + $expected = { + '1' => '1', + '5K 1 Sock' => '5K 1 Sock', + '5K 2 Sock' => '5K 2 Sock' + }; + cmp_deeply( $test->{info}->i_index(), + $expected, q(ACS 5K interface indices have expected values) ); + + delete $test->{info}{_cy5k_port_socket}; + delete $test->{info}{store}{cy5k_port_socket}; + $expected = { + '1' => '1', + 'Port 1 Sock' => 'Port 1 Sock', + 'Port 2 Sock' => 'Port 2 Sock' + }; + cmp_deeply( $test->{info}->i_index(), + $expected, + q(Original Cyclades interface indices have expected values) ); + + $test->{info}->clear_cache(); + cmp_deeply( $test->{info}->interfaces(), + {}, q(Empty SNMP table results in empty hash) ); +} + +sub interfaces : Tests(6) { + my $test = shift; + + can_ok( $test->{info}, 'interfaces' ); + my $expected = { + '1' => 'Interface 1 Description', + 'ACS 1 Name' => 'ACS 1 TTY', + 'ACS 2 Name' => 'ACS 2 TTY' + }; + cmp_deeply( $test->{info}->interfaces(), + $expected, q(ACS interfaces have expected values) ); + + delete $test->{info}{_acs_port_socket}; + delete $test->{info}{store}{acs_port_socket}; + delete $test->{info}{_acs_port_tty}; + delete $test->{info}{store}{acs_port_tty}; + $expected = { + '1' => 'Interface 1 Description', + '8K 1 Name' => '8K 1 TTY', + '8K 2 Name' => '8K 2 TTY' + }; + cmp_deeply( $test->{info}->interfaces(), + $expected, q(ACS 8K interfaces have expected values) ); + + delete $test->{info}{_acs8k_port_socket}; + delete $test->{info}{store}{acs8k_port_socket}; + delete $test->{info}{_acs8k_port_tty}; + delete $test->{info}{store}{acs8k_port_tty}; + $expected = { + '1' => 'Interface 1 Description', + '5K 1 Sock' => '5K 1 TTY', + '5K 2 Sock' => '5K 2 TTY' + }; + cmp_deeply( $test->{info}->interfaces(), + $expected, q(ACS 5K interfaces have expected values) ); + + delete $test->{info}{_cy5k_port_socket}; + delete $test->{info}{store}{cy5k_port_socket}; + delete $test->{info}{_cy5k_port_tty}; + delete $test->{info}{store}{cy5k_port_tty}; + $expected = { + '1' => 'Interface 1 Description', + 'Port 1 Sock' => 'Port 1 TTY', + 'Port 2 Sock' => 'Port 2 TTY' + }; + cmp_deeply( $test->{info}->interfaces(), + $expected, q(Original Cyclades interfaces have expected values) ); + + $test->{info}->clear_cache(); + cmp_deeply( $test->{info}->interfaces(), + {}, q(Empty SNMP table results in empty hash) ); +} + +sub i_speed : Tests(6) { + my $test = shift; + + can_ok( $test->{info}, 'i_speed' ); + + # Munge in effect + my $expected = { + '1' => '10 Mbps', + 'ACS 1 Name' => 56000, + 'ACS 2 Name' => 112000 + }; + cmp_deeply( $test->{info}->i_speed(), + $expected, q(ACS interface speeds have expected values) ); + + delete $test->{info}{_acs_port_socket}; + delete $test->{info}{store}{acs_port_socket}; + delete $test->{info}{_acs_port_speed}; + delete $test->{info}{store}{acs_port_speed}; + $expected = { + '1' => '10 Mbps', + '8K 1 Name' => 112000, + '8K 2 Name' => 384000 + }; + cmp_deeply( $test->{info}->i_speed(), + $expected, q(ACS 8K interface speeds have expected values) ); + + delete $test->{info}{_acs8k_port_socket}; + delete $test->{info}{store}{acs8k_port_socket}; + delete $test->{info}{_acs8k_port_speed}; + delete $test->{info}{store}{acs8k_port_speed}; + $expected = { + '1' => '10 Mbps', + '5K 1 Sock' => 9600, + '5K 2 Sock' => 56000 + }; + cmp_deeply( $test->{info}->i_speed(), + $expected, q(ACS 5K interface speeds have expected values) ); + + delete $test->{info}{_cy5k_port_socket}; + delete $test->{info}{store}{cy5k_port_socket}; + delete $test->{info}{_cy5k_port_speed}; + delete $test->{info}{store}{cy5k_port_speed}; + $expected = { + '1' => '10 Mbps', + 'Port 1 Sock' => 2400, + 'Port 2 Sock' => 9600 + }; + cmp_deeply( $test->{info}->i_speed(), + $expected, + q(Original Cyclades interface speeds have expected values) ); + + $test->{info}->clear_cache(); + cmp_deeply( $test->{info}->i_speed(), + {}, q(Empty SNMP table results in empty hash) ); +} + +sub i_up : Tests(6) { + my $test = shift; + + can_ok( $test->{info}, 'i_up' ); + + my $expected = { + '1' => 'up', + 'ACS 1 Name' => 'down', + 'ACS 2 Name' => 'up' + }; + cmp_deeply( $test->{info}->i_up(), + $expected, q(ACS interface statuses have expected values) ); + + delete $test->{info}{_acs_port_socket}; + delete $test->{info}{store}{acs_port_socket}; + delete $test->{info}{_acs_port_cd}; + delete $test->{info}{store}{acs_port_cd}; + $expected = { + '1' => 'up', + '8K 1 Name' => 'up', + '8K 2 Name' => 'down' + }; + cmp_deeply( $test->{info}->i_up(), + $expected, q(ACS 8K interface statuses have expected values) ); + + delete $test->{info}{_acs8k_port_socket}; + delete $test->{info}{store}{acs8k_port_socket}; + delete $test->{info}{_acs8k_port_cd}; + delete $test->{info}{store}{acs8k_port_cd}; + $expected = { + '1' => 'up', + '5K 1 Sock' => 'down', + '5K 2 Sock' => 'down' + }; + cmp_deeply( $test->{info}->i_up(), + $expected, q(ACS 5K interface statuses have expected values) ); + + delete $test->{info}{_cy5k_port_socket}; + delete $test->{info}{store}{cy5k_port_socket}; + delete $test->{info}{_cy5k_port_cd}; + delete $test->{info}{store}{cy5k_port_cd}; + $expected = { + '1' => 'up', + 'Port 1 Sock' => 'down', + 'Port 2 Sock' => 'up' + }; + cmp_deeply( $test->{info}->i_up(), + $expected, + q(Original Cyclades interface statuses have expected values) ); + + $test->{info}->clear_cache(); + cmp_deeply( $test->{info}->i_up(), + {}, q(Empty SNMP table results in empty hash) ); +} + +sub i_description : Tests(6) { + my $test = shift; + + can_ok( $test->{info}, 'i_description' ); + + my $expected = { + '1' => 'Interface 1 Description', + 'ACS 1 Name' => 'ACS 1 Name', + 'ACS 2 Name' => 'ACS 2 Name' + }; + cmp_deeply( $test->{info}->i_description(), + $expected, q(ACS interface descriptions have expected values) ); + + delete $test->{info}{_acs_port_socket}; + delete $test->{info}{store}{acs_port_socket}; + delete $test->{info}{_acs_port_name}; + delete $test->{info}{store}{acs_port_name}; + $expected = { + '1' => 'Interface 1 Description', + '8K 1 Name' => '8K 1 Name', + '8K 2 Name' => '8K 2 Name' + }; + cmp_deeply( $test->{info}->i_description(), + $expected, q(ACS 8K interface descriptions have expected values) ); + + delete $test->{info}{_acs8k_port_socket}; + delete $test->{info}{store}{acs8k_port_socket}; + delete $test->{info}{_acs8k_port_name}; + delete $test->{info}{store}{acs8k_port_name}; + $expected = { + '1' => 'Interface 1 Description', + '5K 1 Sock' => '5K 1 Name', + '5K 2 Sock' => '5K 2 Name' + }; + cmp_deeply( $test->{info}->i_description(), + $expected, q(ACS 5K interface descriptions have expected values) ); + + delete $test->{info}{_cy5k_port_socket}; + delete $test->{info}{store}{cy5k_port_socket}; + delete $test->{info}{_cy5k_port_name}; + delete $test->{info}{store}{cy5k_port_name}; + $expected = { + '1' => 'Interface 1 Description', + 'Port 1 Sock' => 'Port 1 Name', + 'Port 2 Sock' => 'Port 2 Name' + }; + cmp_deeply( $test->{info}->i_description(), + $expected, + q(Original Cyclades interface descriptions have expected values) ); + + $test->{info}->clear_cache(); + cmp_deeply( $test->{info}->i_description(), + {}, q(Empty SNMP table results in empty hash) ); +} + +sub i_name : Tests(6) { + my $test = shift; + + can_ok( $test->{info}, 'i_name' ); + + my $expected = { + '1' => 'Interface 1 Name', + 'ACS 1 Name' => 'ACS 1 Name', + 'ACS 2 Name' => 'ACS 2 Name' + }; + cmp_deeply( $test->{info}->i_name(), + $expected, q(ACS interface descriptions have expected values) ); + + delete $test->{info}{_acs_port_socket}; + delete $test->{info}{store}{acs_port_socket}; + delete $test->{info}{_acs_port_name}; + delete $test->{info}{store}{acs_port_name}; + $expected = { + '1' => 'Interface 1 Name', + '8K 1 Name' => '8K 1 Name', + '8K 2 Name' => '8K 2 Name' + }; + cmp_deeply( $test->{info}->i_name(), + $expected, q(ACS 8K interface descriptions have expected values) ); + + delete $test->{info}{_acs8k_port_socket}; + delete $test->{info}{store}{acs8k_port_socket}; + delete $test->{info}{_acs8k_port_name}; + delete $test->{info}{store}{acs8k_port_name}; + $expected = { + '1' => 'Interface 1 Name', + '5K 1 Sock' => '5K 1 Name', + '5K 2 Sock' => '5K 2 Name' + }; + cmp_deeply( $test->{info}->i_name(), + $expected, q(ACS 5K interface descriptions have expected values) ); + + delete $test->{info}{_cy5k_port_socket}; + delete $test->{info}{store}{cy5k_port_socket}; + delete $test->{info}{_cy5k_port_name}; + delete $test->{info}{store}{cy5k_port_name}; + $expected = { + '1' => 'Interface 1 Name', + 'Port 1 Sock' => 'Port 1 Name', + 'Port 2 Sock' => 'Port 2 Name' + }; + cmp_deeply( $test->{info}->i_name(), + $expected, + q(Original Cyclades interface descriptions have expected values) ); + + $test->{info}->clear_cache(); + cmp_deeply( $test->{info}->i_name(), + {}, q(Empty SNMP table results in empty hash) ); +} + +1;