]> git.uio.no Git - check_openmanage.git/blobdiff - check_openmanage
3.7.2
[check_openmanage.git] / check_openmanage
index a646f8b16c0d67f3aecee7caf81fc799cc636af6..5a1e30971fb4f5d07f3eb885d503d6029b42a8c6 100755 (executable)
@@ -51,7 +51,7 @@ $SIG{__WARN__} = sub { push @perl_warnings, [@_]; };
 
 # Version and similar info
 $NAME    = 'check_openmanage';
-$VERSION = '3.7.0-beta4';
+$VERSION = '3.7.2';
 $AUTHOR  = 'Trond H. Amundsen';
 $CONTACT = 't.h.amundsen@usit.uio.no';
 
@@ -74,11 +74,12 @@ $HELP = <<'END_HELP';
 
 GENERAL OPTIONS:
 
-   -f, --configfile     Configuration file
+   -f, --config         Specify configuration file
    -p, --perfdata       Output performance data [default=no]
    -t, --timeout        Plugin timeout in seconds [default=30]
    -c, --critical       Custom temperature critical limits
    -w, --warning        Custom temperature warning limits
+   -F, --fahrenheit     Use Fahrenheit as temperature unit
    -d, --debug          Debug output, reports everything
    -h, --help           Display this help text
    -V, --version        Display version info
@@ -130,11 +131,14 @@ END_LICENSE
         'check'             => [],       # check control
         'critical'          => [],       # temperature critical limits
         'warning'           => [],       # temperature warning limits
+         'tempunit'          => 'C',      # temperature unit
+        'fahrenheit'        => 0,        # Use fahrenheit
          'configfile'        => undef,    # configuration file
         'timeout'           => 30,       # default timeout is 30 seconds
         'debug'             => 0,        # debugging / verbose output
         'help'              => 0,        # display help output
         'perfdata'          => undef,    # output performance data
+        'legacy_perfdata'   => 0,        # legacy performance data output
         'info'              => 0,        # display servicetag
         'extinfo'           => 0,        # display extra info
         'htmlinfo'          => undef,    # html tags in output
@@ -163,6 +167,7 @@ END_LICENSE
         'privkey'           => undef,    # SMNP v3
         'privprotocol'      => undef,    # SMNP v3
          'use_get_table'     => 0,        # hack for SNMPv3 on Windows with net-snmp
+        'hide_servicetag'   => 0,        # hidden servicetag
        );
 
 # Get options
@@ -170,12 +175,15 @@ GetOptions('b|blacklist=s'      => \@{ $opt{blacklist} },
           'check=s'            => \@{ $opt{check} },
           'c|critical=s'       => \@{ $opt{critical} },
           'w|warning=s'        => \@{ $opt{warning} },
+          'tempunit=s'         => \$opt{tempunit},
+          'F|fahrenheit'       => \$opt{fahrenheit},
            'f|configfile=s'     => \$opt{configfile},
           't|timeout=i'        => \$opt{timeout},
           'd|debug'            => \$opt{debug},
           'h|help'             => \$opt{help},
           'V|version'          => \$opt{version},
           'p|perfdata:s'       => \$opt{perfdata},
+          'legacy-perfdata'    => \$opt{legacy_perfdata},
           'i|info'             => \$opt{info},
           'e|extinfo'          => \$opt{extinfo},
           'I|htmlinfo:s'       => \$opt{htmlinfo},
@@ -203,6 +211,7 @@ GetOptions('b|blacklist=s'      => \@{ $opt{blacklist} },
           'privkey=s'          => \$opt{privkey},
           'privprotocol=s'     => \$opt{privprotocol},
            'use-get_table'      => \$opt{use_get_table},
+          'hide-servicetag'    => \$opt{hide_servicetag},
          ) or do { print $USAGE; exit $E_UNKNOWN };
 
 # If user requested help
@@ -433,6 +442,16 @@ else {
     check_omreport_options();
 }
 
+# Temperature unit
+if ($opt{fahrenheit}) {
+    $opt{tempunit} = 'F';
+}
+
+# Check tempunit syntax
+if ($opt{tempunit} !~ m{\A C|F|K|R \z}xms) {
+    print "ERROR: Unknown temperature unit '$opt{tempunit}'\n";
+    exit $E_UNKNOWN;
+}
 
 #---------------------------------------------------------------------
 # Helper functions
@@ -465,17 +484,28 @@ sub parse_configfile {
     # Mapping between command line options and the corresponding
     # config file options
     our %opt2config
-      = ( 'info'           => 'output_servicetag',
-         'extinfo'        => 'output_sysinfo',
-         'state'          => 'output_servicestate',
-         'shortstate'     => 'output_servicestate_abbr',
-         'show_blacklist' => 'output_blacklist',
-         'htmlinfo'       => 'output_html',
-         'protocol'       => 'snmp_version',
-         'community'      => 'snmp_community',
-         'port'           => 'snmp_port',
-         'ipv6'           => 'snmp_use_ipv6',
-         'tcp'            => 'snmp_use_tcp',
+      = ( 'info'            => 'output_servicetag',
+         'extinfo'         => 'output_sysinfo',
+         'postmsg'         => 'output_post_message',
+         'state'           => 'output_servicestate',
+         'shortstate'      => 'output_servicestate_abbr',
+         'show_blacklist'  => 'output_blacklist',
+          'hide_servicetag' => 'output_hide_servicetag',
+         'htmlinfo'        => 'output_html',
+         'okinfo'          => 'output_ok_verbosity',
+         'protocol'        => 'snmp_version',
+         'community'       => 'snmp_community',
+         'port'            => 'snmp_port',
+         'ipv6'            => 'snmp_use_ipv6',
+         'tcp'             => 'snmp_use_tcp',
+         'warning'         => 'temp_threshold_warning',
+         'critical'        => 'temp_threshold_critical',
+         'all'             => 'check_everything',
+         'perfdata'        => 'performance_data',
+         'tempunit'        => 'temperature_unit',
+         'timeout'         => 'timeout',
+         'blacklist'       => 'blacklist',
+         'legacy_perfdata' => 'legacy_performance_data',
        );
 
     # Load the perl module
@@ -492,6 +522,32 @@ sub parse_configfile {
       or do { report('other', (sprintf q{Couldn't read configuration file: %s}, Config::Tiny->errstr()), $E_UNKNOWN);
              return; };
 
+    # Syntax check
+    foreach my $section (keys %{ $tiny }) {
+      KEYWORD:
+       foreach my $keyword (keys %{ $tiny->{$section} }) {
+           next KEYWORD if $keyword eq 'check_everything';
+           if ($keyword =~ m{\A check_(.+)}xms) {
+               my $c = $1;
+               foreach my $cl (keys %check) {
+                   next KEYWORD if $c eq $cl;
+               }
+           }
+           else {
+             LEGAL:
+               foreach my $legal (keys %opt2config) {
+                   next KEYWORD if $keyword eq $opt2config{$legal};
+               }
+           }
+           if ($section eq '_') {
+               report('other', qq{CONFIG ERROR: In the global section: Unknown statement "$keyword"}, $E_UNKNOWN);
+           }
+           else {
+               report('other', qq{CONFIG ERROR: Unknown statement "$keyword" in section "$section"}, $E_UNKNOWN);
+           }
+       }
+    }
+
     # Adjust checks according to statements in the configuration file
     sub configfile_adjust_checks {
        my $keyword = shift;
@@ -506,7 +562,7 @@ sub parse_configfile {
                $check{$key} = 0;
            }
            else {
-               report('other', "CONFIG ERROR: Rvalue for '$copt' must be boolean", $E_UNKNOWN);
+               report('other', "CONFIG ERROR: Rvalue for '$copt' must be boolean (True/False)", $E_UNKNOWN);
            }
        }
        return;
@@ -530,7 +586,7 @@ sub parse_configfile {
                $opt{timeout} = $tiny->{$keyword}->{timeout};
            }
            else {
-               report('other', "CONFIG ERROR: Rvalue for 'timeout' must be an integer", $E_UNKNOWN);
+               report('other', "CONFIG ERROR: Rvalue for 'timeout' must be a positive integer", $E_UNKNOWN);
            }
        }
        return;
@@ -548,7 +604,7 @@ sub parse_configfile {
                $opt{$bool} = 0;
            }
            else {
-               report('other', "CONFIG ERROR: Rvalue for '$cbool' must be boolean", $E_UNKNOWN);
+               report('other', "CONFIG ERROR: Rvalue for '$cbool' must be boolean (True/False)", $E_UNKNOWN);
            }
        }
        return;
@@ -572,6 +628,21 @@ sub parse_configfile {
        return;
     }
 
+    # Set OK output verbosity
+    sub configfile_set_ok_verbosity {
+       my $keyword = shift;
+       my $conf = $opt2config{okinfo};
+       if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+           if ($tiny->{$keyword}->{$conf} =~ m{\A \d+ \z}xms) {
+               $opt{okinfo} = $tiny->{$keyword}->{$conf};
+           }
+           else {
+               report('other', "CONFIG ERROR: Rvalue for '$conf' must be a positive integer", $E_UNKNOWN);
+           }
+       }
+       return;
+    }
+
     # Set SNMP protocol version from config file
     sub configfile_set_snmp_version {
        my $keyword = shift;
@@ -606,12 +677,69 @@ sub parse_configfile {
                $opt{port} = $tiny->{$keyword}->{$conf};
            }
            else {
-               report('other', "CONFIG ERROR: Rvalue for '$conf' must be an integer", $E_UNKNOWN);
+               report('other', "CONFIG ERROR: Rvalue for '$conf' must be a positive integer", $E_UNKNOWN);
+           }
+       }
+       return;
+    }
+
+    # Set temperature threshold from config file
+    sub configfile_set_temp_threshold {
+       my $keyword = shift;
+       my $level = shift;
+       my $conf = $opt2config{$level};
+       if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+           $opt{$level} = [$tiny->{$keyword}->{$conf}]; # array ref
+       }
+       return;
+    }
+
+    # Set perfdata from config file
+    sub configfile_set_perfdata {
+       my $keyword = shift;
+       my $conf = $opt2config{perfdata};
+       if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+           if ($tiny->{$keyword}->{$conf} =~ m{$on}ixms) {
+               $opt{perfdata} = 1;
+           }
+           elsif ($tiny->{$keyword}->{$conf} =~ m{$off}ixms) {
+               $opt{perfdata} = undef;
+           }
+           elsif ($tiny->{$keyword}->{$conf} =~ m{\A minimal|multiline \z}xms) {
+               $opt{perfdata} = $tiny->{$keyword}->{$conf};
+           }
+           else {
+               report('other', "CONFIG ERROR: Rvalue for '$conf' must be either boolean, 'minimal' or 'multiline'", $E_UNKNOWN);
            }
        }
        return;
     }
 
+    # Set temp unit from config file
+    sub configfile_set_tempunit {
+       my $keyword = shift;
+       my $conf = $opt2config{tempunit};
+       if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+           if ($tiny->{$keyword}->{$conf} =~ m{\A C|F|K|R \z}ixms) {
+               $opt{tempunit} = $tiny->{$keyword}->{$conf};
+           }
+           else {
+               report('other', "CONFIG ERROR: Rvalue for '$conf' must one of C/F/K/R", $E_UNKNOWN);
+           }
+       }
+       return;
+    }
+
+    # Set postmsg string from config file
+    sub configfile_set_postmsg {
+       my $keyword = shift;
+       my $conf = $opt2config{postmsg};
+       if (defined $tiny->{$keyword}->{$conf} and $tiny->{$keyword}->{$conf} ne q{}) {
+           $opt{postmsg} = $tiny->{$keyword}->{$conf}; # array ref
+       }
+       return;
+    }
+
     # Sections in the config file to check for statements
     my @sections = ();
 
@@ -641,6 +769,8 @@ sub parse_configfile {
        configfile_set_blacklist($sect);
        configfile_set_timeout($sect);
        configfile_set_htmlinfo($sect);
+        configfile_set_ok_verbosity($sect);
+       configfile_set_boolean($sect, 'all');
        configfile_set_boolean($sect, 'info');
        configfile_set_boolean($sect, 'extinfo');
        configfile_set_boolean($sect, 'state');
@@ -648,9 +778,16 @@ sub parse_configfile {
        configfile_set_boolean($sect, 'show_blacklist');
        configfile_set_boolean($sect, 'ipv6');
        configfile_set_boolean($sect, 'tcp');
+       configfile_set_boolean($sect, 'legacy_perfdata');
+       configfile_set_boolean($sect, 'hide_servicetag');
        configfile_set_snmp_version($sect);
        configfile_set_snmp_community($sect);
        configfile_set_snmp_port($sect);
+       configfile_set_temp_threshold($sect, 'warning');
+       configfile_set_temp_threshold($sect, 'critical');
+       configfile_set_perfdata($sect);
+       configfile_set_tempunit($sect);
+       configfile_set_postmsg($sect);
     }
 
     return;
@@ -834,14 +971,23 @@ sub snmp_check {
 # Detecting blade via SNMP
 #
 sub snmp_detect_blade {
-    my $DellBaseBoardType = '1.3.6.1.4.1.674.10892.1.300.80.1.7.1.1';
-    my $result = $snmp_session->get_request(-varbindlist => [$DellBaseBoardType]);
+    # In some setups, the IDs for the blade and interconnect
+    # board are mixed up, so we need to check both.
+    my $DellBaseBoardType1 = '1.3.6.1.4.1.674.10892.1.300.80.1.7.1.1';
+    my $DellBaseBoardType2 = '1.3.6.1.4.1.674.10892.1.300.80.1.7.1.2';
+    my $result1 = $snmp_session->get_request(-varbindlist => [$DellBaseBoardType1]);
+    my $result2 = $snmp_session->get_request(-varbindlist => [$DellBaseBoardType2]);
 
     # Identify blade. Older models (4th and 5th gen models) and/or old
     # OMSA (4.x) don't have this OID. If we get "noSuchInstance" or
     # similar, we assume that this isn't a blade
-    if (exists $result->{$DellBaseBoardType} && $result->{$DellBaseBoardType} eq '3') {
+    if (exists $result1->{$DellBaseBoardType1} && $result1->{$DellBaseBoardType1} eq '3') {
        $blade = 1;
+       return;
+    }
+    if (exists $result2->{$DellBaseBoardType2} && $result2->{$DellBaseBoardType2} eq '3') {
+       $blade = 1;
+       return;
     }
     return;
 }
@@ -1355,6 +1501,23 @@ sub get_nonempty_string {
     return $alt;
 }
 
+# Converts from Celsius to something else
+sub temp_from_celsius {
+    my $x  = shift;
+    my $to = shift;
+
+    if ($to eq 'F') {
+       return sprintf '%.1f', ($x * 9/5 + 32);
+    }
+    elsif ($to eq 'K') {
+       return sprintf '%.1f', ($x + 273.15);
+    }
+    elsif ($to eq 'R') {
+       return sprintf '%.1f', ($x * 9/5 + 32 + 459.67);
+    }
+    return $x;
+}
+
 
 #---------------------------------------------------------------------
 # Check functions
@@ -1810,6 +1973,13 @@ sub check_physical_disks {
                report('storage', $msg, $E_WARNING, $nexus);
            }
        }
+       # Special case: Foreign disk
+       elsif ($status eq 'Non-Critical' and $state eq 'Foreign'
+             and blacklisted('pdisk_foreign', $nexus)) {
+           my $msg = sprintf '%s [%s %s, %s] on ctrl %d is %s',
+             $name, $vendor, $product, $capacity, $ctrl, $state;
+           report('storage', $msg, $E_OK, $nexus);
+       }
        # Default
        elsif ($status ne 'Ok') {
            my $msg =  sprintf '%s [%s %s, %s] on ctrl %d needs attention: %s',
@@ -2070,7 +2240,7 @@ sub check_cache_battery {
            $state  = get_hashval($out->{batteryState}, \%bat_state) || 'Unknown state';
            $learn  = get_hashval($out->{batteryLearnState}, \%bat_learn_state) || 'Unknown learn state';
            $pred   = get_hashval($out->{batteryPredictedCapacity}, \%bat_pred_cap) || 'Unknown predicted capacity status';
-           $ctrl   = ($out->{batteryConnectionControllerNumber} || 10000) - 1;
+           $ctrl   = $snmp_controller{$out->{batteryConnectionControllerNumber}};
            $nexus  = convert_nexus(($out->{batteryNexusID} || 9999));
            $id     = $nexus;
            $id     =~ s{\A \d+:(\d+) \z}{$1}xms;
@@ -2695,6 +2865,15 @@ sub check_enclosure_temp {
        $min_warn =~ s{\A \s* (-?\d+) \s* C? \s* \z}{$1}xms or $min_warn = '[N/A]';
        $min_crit =~ s{\A \s* (-?\d+) \s* C? \s* \z}{$1}xms or $min_crit = '[N/A]';
 
+       # Convert temp units
+       if ($opt{tempunit} ne 'C') {
+           $reading  = temp_from_celsius($reading,  $opt{tempunit});
+           $max_warn = temp_from_celsius($max_warn, $opt{tempunit});
+           $max_crit = temp_from_celsius($max_crit, $opt{tempunit});
+           $min_warn = temp_from_celsius($min_warn, $opt{tempunit});
+           $min_crit = temp_from_celsius($min_crit, $opt{tempunit});
+       }
+
        # Inactive temp probes
        if ($status eq 'Unknown' and $state eq 'Inactive') {
            my $msg = sprintf '%s in enclosure %s [%s] is %s',
@@ -2702,26 +2881,26 @@ sub check_enclosure_temp {
            report('storage', $msg, $E_OK, $nexus);
        }
        elsif ($status ne 'Ok' and $max_crit ne '[N/A]' and $reading > $max_crit) {
-           my $msg = sprintf '%s in enclosure %s [%s] is critically high at %d C',
-             $name, $encl_id, $encl_name, $reading;
+           my $msg = sprintf '%s in enclosure %s [%s] is critically high at %s %s',
+             $name, $encl_id, $encl_name, $reading, $opt{tempunit};
            my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
            report('chassis', $msg, $err, $nexus);
        }
        elsif ($status ne 'Ok' and $max_warn ne '[N/A]' and $reading > $max_warn) {
-           my $msg = sprintf '%s in enclosure %s [%s] is too high at %d C',
-             $name, $encl_id, $encl_name, $reading;
+           my $msg = sprintf '%s in enclosure %s [%s] is too high at %s %s',
+             $name, $encl_id, $encl_name, $reading, $opt{tempunit};
            my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
            report('chassis', $msg, $err, $nexus);
        }
        elsif ($status ne 'Ok' and $min_crit ne '[N/A]' and $reading < $min_crit) {
-           my $msg = sprintf '%s in enclosure %s [%s] is critically low at %d C',
-             $name, $encl_id, $encl_name, $reading;
+           my $msg = sprintf '%s in enclosure %s [%s] is critically low at %s %s',
+             $name, $encl_id, $encl_name, $reading, $opt{tempunit};
            my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
            report('chassis', $msg, $err, $nexus);
        }
        elsif ($status ne 'Ok' and $min_warn ne '[N/A]' and $reading < $min_warn) {
-           my $msg = sprintf '%s in enclosure %s [%s] is too low at %d C',
-             $name, $encl_id, $encl_name, $reading;
+           my $msg = sprintf '%s in enclosure %s [%s] is too low at %s %s',
+             $name, $encl_id, $encl_name, $reading, $opt{tempunit};
            my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
            report('chassis', $msg, $err, $nexus);
        }
@@ -2732,7 +2911,7 @@ sub check_enclosure_temp {
            if (defined $reading && $reading =~ m{\A -?\d+ \z}xms) {
                # take into account that with certain states the
                # reading doesn't exist or is not an integer
-               $msg .= sprintf ' at %s C', $reading;
+               $msg .= sprintf ' at %s %s', $reading, $opt{tempunit};
                if ($min_warn eq '[N/A]' or $min_crit eq '[N/A]') {
                    $msg .= sprintf ' (max=%s/%s)', $max_warn, $max_crit;
                }
@@ -2751,7 +2930,7 @@ sub check_enclosure_temp {
            if (defined $reading && $reading ne '[N/A]') {
                # take into account that with certain states the
                # reading doesn't exist or is not an integer
-               $msg .= sprintf ' reads %d C', $reading;
+               $msg .= sprintf ' reads %s %s', $reading, $opt{tempunit};
                if ($min_warn eq '[N/A]' or $min_crit eq '[N/A]') {
                    $msg .= sprintf ' (max=%s/%s)', $max_warn, $max_crit;
                }
@@ -2770,14 +2949,21 @@ sub check_enclosure_temp {
        if (defined $opt{perfdata} && $reading ne '[N/A]') {
            my $index = $name;
            $index =~ s{\A Temperature\sProbe\s(\d+) \z}{$1}gxms;
+           my $legacy_name = $name;
+           $legacy_name =~ s{\A Temperature\sProbe\s(\d+) \z}{temp_$1}gxms;
+           my $legacy_label = lc "enclosure_${encl_id}_${legacy_name}";
+           my $legacy_mini = $legacy_label;
+            $legacy_mini =~ s{enclosure_(.+?)_temp_(.+?)}{e$1t$2}xms;
            push @perfdata, {
-                            type  => 'E',
-                            id    => $opt{perfdata} eq 'minimal' ? "${encl_id}_t${index}" : "${encl_id}_temp_${index}",
-                            unit  => 'C',
-                            label => q{},
-                            value => $reading,
-                            warn  => $max_warn,
-                            crit  => $max_crit,
+                            type   => 'E',
+                            id     => $opt{perfdata} eq 'minimal' ? "${encl_id}_t${index}" : "${encl_id}_temp_${index}",
+                            unit   => $opt{tempunit},
+                            label  => q{},
+                            legacy => $legacy_label,
+                            mini   => $legacy_mini,
+                            value  => $reading,
+                            warn   => $max_warn,
+                            crit   => $max_crit,
                            };
        }
     }
@@ -3107,15 +3293,18 @@ sub check_fans {
            my $pname = $location;
            $pname =~ s{\s}{_}gxms;
            $pname =~ s{proc_}{cpu#}xms;
+           my $legacy_pname = $pname;
            $pname =~ s{_rpm\z}{}ixms;
            push @perfdata, {
-                            type  => 'F',
-                            id    => $index,
-                            unit  => 'rpm',
-                            label => $pname,
-                            value => $reading,
-                            warn  => $max_warn,
-                            crit  => $max_crit,
+                            type   => 'F',
+                            id     => $index,
+                            unit   => 'rpm',
+                            label  => $pname,
+                            legacy => lc "fan_${index}_${legacy_pname}",
+                             mini   => "f$index",
+                            value  => $reading,
+                            warn   => $max_warn,
+                            crit   => $max_crit,
                            };
        }
     }
@@ -3357,6 +3546,15 @@ sub check_temperatures {
        $count{temp}++;
        next TEMP if blacklisted('temp', $index);
 
+       # Convert temp units
+       if ($opt{tempunit} ne 'C') {
+           $reading  = temp_from_celsius($reading,  $opt{tempunit});
+           $max_warn = temp_from_celsius($max_warn, $opt{tempunit});
+           $max_crit = temp_from_celsius($max_crit, $opt{tempunit});
+           $min_warn = temp_from_celsius($min_warn, $opt{tempunit});
+           $min_crit = temp_from_celsius($min_crit, $opt{tempunit});
+       }
+
        if ($type eq 'Discrete') {
            my $msg = sprintf 'Temperature probe %d [%s] is %s',
              $index, $location, $discrete;
@@ -3367,56 +3565,56 @@ sub check_temperatures {
            # First check according to custom thresholds
            if (exists $crit_threshold{$index}{max} and $reading > $crit_threshold{$index}{max}) {
                # Custom critical MAX
-               my $msg = sprintf 'Temperature Probe %d [%s] reads %d C (custom max=%d)',
-                 $index, $location, $reading, $crit_threshold{$index}{max};
+               my $msg = sprintf 'Temperature Probe %d [%s] reads %s %s (custom max=%s)',
+                 $index, $location, $reading, $opt{tempunit}, $crit_threshold{$index}{max};
                report('chassis', $msg, $E_CRITICAL, $index);
            }
            elsif (exists $warn_threshold{$index}{max} and $reading > $warn_threshold{$index}{max}) {
                # Custom warning MAX
-               my $msg = sprintf 'Temperature Probe %d [%s] reads %d C (custom max=%d)',
-                 $index, $location, $reading, $warn_threshold{$index}{max};
+               my $msg = sprintf 'Temperature Probe %d [%s] reads %s %s (custom max=%s)',
+                 $index, $location, $reading, $opt{tempunit}, $warn_threshold{$index}{max};
                report('chassis', $msg, $E_WARNING, $index);
            }
            elsif (exists $crit_threshold{$index}{min} and $reading < $crit_threshold{$index}{min}) {
                # Custom critical MIN
-               my $msg = sprintf 'Temperature Probe %d [%s] reads %d C (custom min=%d)',
-                 $index, $location, $reading, $crit_threshold{$index}{min};
+               my $msg = sprintf 'Temperature Probe %d [%s] reads %s %s (custom min=%s)',
+                 $index, $location, $reading, $opt{tempunit}, $crit_threshold{$index}{min};
                report('chassis', $msg, $E_CRITICAL, $index);
            }
            elsif (exists $warn_threshold{$index}{min} and $reading < $warn_threshold{$index}{min}) {
                # Custom warning MIN
-               my $msg = sprintf 'Temperature Probe %d [%s] reads %d C (custom min=%d)',
-                 $index, $location, $reading, $warn_threshold{$index}{min};
+               my $msg = sprintf 'Temperature Probe %d [%s] reads %s %s (custom min=%s)',
+                 $index, $location, $reading, $opt{tempunit}, $warn_threshold{$index}{min};
                report('chassis', $msg, $E_WARNING, $index);
            }
            elsif ($status ne 'Ok' and $max_crit ne '[N/A]' and $reading > $max_crit) {
-               my $msg = sprintf 'Temperature Probe %d [%s] is critically high at %d C',
-                 $index, $location, $reading;
+               my $msg = sprintf 'Temperature Probe %d [%s] is critically high at %s %s',
+                 $index, $location, $reading, $opt{tempunit};
                my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
                report('chassis', $msg, $err, $index);
            }
            elsif ($status ne 'Ok' and $max_warn ne '[N/A]' and $reading > $max_warn) {
-               my $msg = sprintf 'Temperature Probe %d [%s] is too high at %d C',
-                 $index, $location, $reading;
+               my $msg = sprintf 'Temperature Probe %d [%s] is too high at %s %s',
+                 $index, $location, $reading, $opt{tempunit};
                my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
                report('chassis', $msg, $err, $index);
            }
            elsif ($status ne 'Ok' and $min_crit ne '[N/A]' and $reading < $min_crit) {
-               my $msg = sprintf 'Temperature Probe %d [%s] is critically low at %d C',
-                 $index, $location, $reading;
+               my $msg = sprintf 'Temperature Probe %d [%s] is critically low at %s %s',
+                 $index, $location, $reading, $opt{tempunit};
                my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
                report('chassis', $msg, $err, $index);
            }
            elsif ($status ne 'Ok' and $min_warn ne '[N/A]' and $reading < $min_warn) {
-               my $msg = sprintf 'Temperature Probe %d [%s] is too low at %d C',
-                 $index, $location, $reading;
+               my $msg = sprintf 'Temperature Probe %d [%s] is too low at %s %s',
+                 $index, $location, $reading, $opt{tempunit};
                my $err = $snmp ? $probestatus2nagios{$status} : $status2nagios{$status};
                report('chassis', $msg, $err, $index);
            }
            # Ok
            else {
-               my $msg = sprintf 'Temperature Probe %d [%s] reads %d C',
-                 $index, $location, $reading;
+               my $msg = sprintf 'Temperature Probe %d [%s] reads %s %s',
+                 $index, $location, $reading, $opt{tempunit};
                if ($min_warn eq '[N/A]' and $min_crit eq '[N/A]') {
                    $msg .= sprintf ' (max=%s/%s)', $max_warn, $max_crit;
                }
@@ -3432,16 +3630,18 @@ sub check_temperatures {
            if (defined $opt{perfdata}) {
                my $pname = $location;
                $pname =~ s{\s}{_}gxms;
-               $pname =~ s{_temp\z}{}xms;
+               $pname =~ s{_temp\z}{}ixms;
                $pname =~ s{proc_}{cpu#}xms;
                push @perfdata, {
-                                type  => 'T',
-                                id    => $index,
-                                unit  => 'C',
-                                label => $pname,
-                                value => $reading,
-                                warn  => $max_warn,
-                                crit  => $max_crit,
+                                type   => 'T',
+                                id     => $index,
+                                unit   => $opt{tempunit},
+                                label  => $pname,
+                                legacy => lc "temp_${index}_${pname}",
+                                 mini   => "t$index",
+                                value  => $reading,
+                                warn   => $max_warn,
+                                crit   => $max_crit,
                                };
            }
        }
@@ -3823,20 +4023,20 @@ sub check_volts {
        report('chassis', $msg, $err, $index);
 
        # Collect performance data
-       if (defined $opt{perfdata}) {
+       if (defined $opt{perfdata} and !$opt{legacy_perfdata}) {
            $reading =~ s{\s+V\z}{}xms;  # remove unit
            $reading =~ s{\.000\z}{}xms; # if integer
            next VOLT if $reading !~ m{\A \d+(\.\d+)? \z}xms; # discrete reading (not number)
            my $label = join q{_}, $location;
            $label =~ s{\s}{_}gxms;
            push @perfdata, {
-                            type  => 'V',
-                            id    => $index,
-                            unit  => 'V',
-                            label => $label,
-                            value => $reading,
-                            warn  => 0,
-                            crit  => 0,
+                            type   => 'V',
+                            id     => $index,
+                            unit   => 'V',
+                            label  => $label,
+                            value  => $reading,
+                            warn   => 0,
+                            crit   => 0,
                            };
        }
     }
@@ -4018,6 +4218,12 @@ sub check_pwrmonitoring {
                $max_warn /= 10;
                $unit      = 'A';
            }
+           if ($unit eq 'mA' and $type ne 'amperageProbeTypeIsDiscrete') {
+               $reading  /= 1000;
+               $max_crit /= 1000;
+               $max_warn /= 1000;
+               $unit      = 'A';
+           }
        }
        else {
            $index    = get_nonempty_string('Index', $out, 9999);
@@ -4071,13 +4277,15 @@ sub check_pwrmonitoring {
            my $label = join q{_},  $location;
            $label =~ s{\s}{_}gxms;
            push @perfdata, {
-                            type  => $unit,
-                            id    => $index,
-                            unit  => $unit,
-                            label => $label,
-                            value => $reading,
-                            warn  => $max_warn,
-                            crit  => $max_crit,
+                            type   => $unit,
+                            id     => $index,
+                            unit   => $unit,
+                            label  => $label,
+                            legacy => (join q{_}, 'pwr_mon', $index, lc $label),
+                             mini   => "p${index}" . lc $unit,
+                            value  => $reading,
+                            warn   => $max_warn,
+                            crit   => $max_crit,
                            };
        }
     }
@@ -4099,7 +4307,7 @@ sub check_pwrmonitoring {
       AMP2:
        foreach my $line (@{ run_command("$omreport $omopt_chassis pwrmonitoring -fmt ssv") }) {
            chop $line;
-           if ($line eq 'Location;Reading') {
+           if ($line eq 'Location;Reading' or $line eq 'Amperage') {
                $found = 1;
                next AMP2;
            }
@@ -4117,13 +4325,15 @@ sub check_pwrmonitoring {
                while (exists $used{$index}) { ++$index; }
 
                push @perfdata, {
-                                type  => $aunit,
-                                id    => $index,
-                                unit  => $aunit,
-                                label => $aname,
-                                value => $aval,
-                                warn  => 0,
-                                crit  => 0,
+                                type   => $aunit,
+                                id     => $index,
+                                unit   => $aunit,
+                                label  => $aname,
+                                legacy => "pwr_mon_${index}_${aname}",
+                                 mini   => "p${index}a",
+                                value  => $aval,
+                                warn   => 0,
+                                crit   => 0,
                                };
                ++$index;
            }
@@ -4475,7 +4685,7 @@ sub get_omreport_chassis_info {
                $sysinfo{model}  = $val;
            }
            if ($key eq 'Chassis Service Tag' or $key eq 'Service Tag') {
-               $sysinfo{serial} = $val;
+               $sysinfo{serial} = $opt{hide_servicetag} ? 'XXXXXXX' : $val;
            }
            if ($key eq 'System Revision') {
                $sysinfo{rev} = q{ } . $val;
@@ -4565,7 +4775,7 @@ sub get_snmp_chassis_info {
                $sysinfo{model} =~ s{\s+\z}{}xms; # remove trailing whitespace
            }
            elsif (exists $chassis_oid{$oid} and $chassis_oid{$oid} eq 'chassisServiceTagName') {
-               $sysinfo{serial} = $result->{$oid};
+               $sysinfo{serial} = $opt{hide_servicetag} ? 'XXXXXXX' : $result->{$oid};
            }
            elsif (exists $chassis_oid{$oid} and $chassis_oid{$oid} eq 'chassisSystemRevisionName') {
                $sysinfo{rev} = q{ } . $result->{$oid};
@@ -4933,8 +5143,8 @@ else {
 
        # Prefix with service tag if specified with option '-i|--info'
        if ($opt{info}) {
-           if (defined $opt{htmlinfo}) {
-               $msg = '[<a href="' . warranty_url($sysinfo{serial})
+           if (defined $opt{htmlinfo} and !$opt{hide_servicetag}) {
+               $msg = '[<a target="_blank" href="' . warranty_url($sysinfo{serial})
                  . "\">$sysinfo{serial}</a>] " . $msg;
            }
            else {
@@ -5001,11 +5211,16 @@ if ($exit_code == $E_OK && defined $opt{only} && $opt{only} !~ m{\A critical|war
     }
 }
 elsif ($exit_code == $E_OK && !$opt{debug}) {
-    if (defined $opt{htmlinfo}) {
-       printf q{OK - System: '<a href="%s">%s%s</a>', SN: '<a href="%s">%s</a>'},
+    if (defined $opt{htmlinfo} and !$opt{hide_servicetag}) {
+       printf q{OK - System: '<a target="_blank" href="%s">%s%s</a>', SN: '<a target="_blank" href="%s">%s</a>'},
          documentation_url($sysinfo{model}), $sysinfo{model}, $sysinfo{rev},
            warranty_url($sysinfo{serial}), $sysinfo{serial};
     }
+    if (defined $opt{htmlinfo} and $opt{hide_servicetag}) {
+       printf q{OK - System: '<a target="_blank" href="%s">%s%s</a>', SN: '%s'},
+         documentation_url($sysinfo{model}), $sysinfo{model}, $sysinfo{rev},
+           $sysinfo{serial};
+    }
     else {
        printf q{OK - System: '%s%s', SN: '%s'},
          $sysinfo{model}, $sysinfo{rev}, $sysinfo{serial};
@@ -5087,11 +5302,16 @@ elsif ($exit_code == $E_OK && !$opt{debug}) {
 else {
     if ($opt{extinfo}) {
        print $linebreak;
-       if (defined $opt{htmlinfo}) {
-           printf '------ SYSTEM: <a href="%s">%s%s</a>, SN: <a href="%s">%s</a>',
+       if (defined $opt{htmlinfo} && !$opt{hide_servicetag}) {
+           printf '------ SYSTEM: <a target="_blank" href="%s">%s%s</a>, SN: <a target="_blank" href="%s">%s</a>',
              documentation_url($sysinfo{model}), $sysinfo{model}, $sysinfo{rev},
                warranty_url($sysinfo{serial}), $sysinfo{serial};
        }
+       elsif (defined $opt{htmlinfo} && $opt{hide_servicetag}) {
+           printf '------ SYSTEM: <a target="_blank" href="%s">%s%s</a>, SN: %s',
+             documentation_url($sysinfo{model}), $sysinfo{model}, $sysinfo{rev},
+               $sysinfo{serial};
+       }
        else {
            printf '------ SYSTEM: %s%s, SN: %s',
              $sysinfo{model}, $sysinfo{rev}, $sysinfo{serial};
@@ -5160,12 +5380,25 @@ if (defined $opt{perfdata} && !$opt{debug} && @perfdata) {
              $a->{label} cmp $b->{label};
     }
 
+    # LEGACY sort routine for performance data
+    sub perfsort_legacy {
+       my %order = ( fan => 0, pwr => 1, tem => 2, enc => 3, );
+       return ($order{(substr $a->{legacy}, 0, 3)} cmp $order{(substr $b->{legacy}, 0, 3)}) ||
+         $a->{legacy} cmp $b->{legacy};
+    }
+
     # Print performance data sorted
-    if ($opt{perfdata} eq 'minimal') {
-       print join $lb, map { "$_->{type}$_->{id}=$_->{value}$_->{unit};$_->{warn};$_->{crit}" } sort perfsort @perfdata;
+    if ($opt{legacy_perfdata}) {
+       my $type = $opt{perfdata} eq 'minimal' ? 'mini' : 'legacy';
+       print join $lb, map { "$_->{$type}=$_->{value};$_->{warn};$_->{crit}" } sort perfsort_legacy @perfdata;
     }
     else {
-       print join $lb, map { "$_->{type}$_->{id}_$_->{label}=$_->{value}$_->{unit};$_->{warn};$_->{crit}" } sort perfsort @perfdata;
+       if ($opt{perfdata} eq 'minimal') {
+           print join $lb, map { "$_->{type}$_->{id}=$_->{value}$_->{unit};$_->{warn};$_->{crit}" } sort perfsort @perfdata;
+       }
+       else {
+           print join $lb, map { "$_->{type}$_->{id}_$_->{label}=$_->{value}$_->{unit};$_->{warn};$_->{crit}" } sort perfsort @perfdata;
+       }
     }
 }