lets see what breaks...

This commit is contained in:
2025-06-30 14:22:43 -05:00
parent 55178257ef
commit 94eed1ab9d
9 changed files with 2994 additions and 276 deletions

View File

@ -0,0 +1,46 @@
#!/bin/bash
#######################################
# please read DOCS to succesfully get #
# raspberry sensors into your host #
#######################################
picmd='/usr/bin/vcgencmd'
pised='/bin/sed'
getTemp='measure_temp'
getVoltsCore='measure_volts core'
getVoltsRamC='measure_volts sdram_c'
getVoltsRamI='measure_volts sdram_i'
getVoltsRamP='measure_volts sdram_p'
getFreqArm='measure_clock arm'
getFreqCore='measure_clock core'
getStatusH264='codec_enabled H264'
getStatusMPG2='codec_enabled MPG2'
getStatusWVC1='codec_enabled WVC1'
getStatusMPG4='codec_enabled MPG4'
getStatusMJPG='codec_enabled MJPG'
getStatusWMV9='codec_enabled WMV9'
$picmd $getTemp | $pised 's|[^0-9.]||g'
$picmd "$getVoltsCore" | $pised 's|[^0-9.]||g'
$picmd "$getVoltsRamC" | $pised 's|[^0-9.]||g'
$picmd "$getVoltsRamI" | $pised 's|[^0-9.]||g'
$picmd "$getVoltsRamP" | $pised 's|[^0-9.]||g'
$picmd "$getFreqArm" | $pised 's/frequency([0-9]*)=//g'
$picmd "$getFreqCore" | $pised 's/frequency([0-9]*)=//g'
$picmd "$getStatusH264" | $pised 's/H264=//g'
$picmd "$getStatusMPG2" | $pised 's/MPG2=//g'
$picmd "$getStatusWVC1" | $pised 's/WVC1=//g'
$picmd "$getStatusMPG4" | $pised 's/MPG4=//g'
$picmd "$getStatusMJPG" | $pised 's/MJPG=//g'
$picmd "$getStatusWMV9" | $pised 's/WMV9=//g'
$picmd "$getStatusH264" | $pised 's/enabled/2/g'
$picmd "$getStatusMPG2" | $pised 's/enabled/2/g'
$picmd "$getStatusWVC1" | $pised 's/enabled/2/g'
$picmd "$getStatusMPG4" | $pised 's/enabled/2/g'
$picmd "$getStatusMJPG" | $pised 's/enabled/2/g'
$picmd "$getStatusWMV9" | $pised 's/enabled/2/g'
$picmd "$getStatusH264" | $pised 's/disabled/1/g'
$picmd "$getStatusMPG2" | $pised 's/disabled/1/g'
$picmd "$getStatusWVC1" | $pised 's/disabled/1/g'
$picmd "$getStatusMPG4" | $pised 's/disabled/1/g'
$picmd "$getStatusMJPG" | $pised 's/disabled/1/g'
$picmd "$getStatusWMV9" | $pised 's/disabled/1/g'

View File

@ -1,5 +1,5 @@
#!/usr/bin/env perl
#Copyright (c) 2017, Zane C. Bowers-Hadley
#Copyright (c) 2024, Zane C. Bowers-Hadley
#All rights reserved.
#
#Redistribution and use in source and binary forms, with or without modification,
@ -30,22 +30,25 @@ Add this to snmpd.conf like below.
Then add to root's cron tab, if you have more than a few disks.
*/3 * * * * /etc/snmp/smart -u
*/5 * * * * /etc/snmp/extends/smart -u
You will also need to create the config file, which defaults to the same path as the script,
but with .config appended. So if the script is located at /etc/snmp/smart, the config file
will be /etc/snmp/smart.config. Alternatively you can also specific a config via -c.
will be /etc/snmp/extends/smart.config. Alternatively you can also specific a config via -c.
Anything starting with a # is comment. The format for variables is $variable=$value. Empty
lines are ignored. Spaces and tabes at either the start or end of a line are ignored. Any
line with out a = or # are treated as a disk.
line with out a matched variable or # are treated as a disk.
#This is a comment
cache=/var/cache/smart
smartctl=/usr/local/sbin/smartctl
useSN=0
ada0
ada1
da5 /dev/da5 -d sat
twl0,0 /dev/twl0 -d 3ware,0
twl0,1 /dev/twl0 -d 3ware,1
twl0,2 /dev/twl0 -d 3ware,2
The variables are as below.
@ -54,9 +57,42 @@ The variables are as below.
useSN = If set to 1, it will use the disks SN for reporting instead of the device name.
1 is the default. 0 will use the device name.
A disk line is can be as simple as just a disk name under /dev/. Such as in the config above
The line "ada0" would resolve to "/dev/ada0" and would be called with no special argument. If
a line has a space in it, everything before the space is treated as the disk name and is what
used for reporting and everything after that is used as the argument to be passed to smartctl.
If you want to guess at the configuration, call it with -g and it will print out what it thinks
it should be.
Switches:
-c <config> The config file to use.
-u Update
-p Pretty print the JSON.
-Z GZip+Base64 compress the results.
-g Guess at the config and print it to STDOUT
-C Enable manual checking for guess and cciss.
-S Set useSN to 0 when using -g
-t <test> Run the specified smart self test on all the devices.
-U When calling cciss_vol_status, call it with -u.
-G <modes> Guess modes to use. This is a comma seperated list.
Default :: scan-open,cciss-vol-status
Guess Modes:
- scan :: Use "--scan" with smartctl. "scan-open" will take presidence.
- scan-open :: Call smartctl with "--scan-open".
- cciss-vol-status :: Freebsd/Linux specific and if it sees /dev/sg0(on Linux) or
/dev/ciss0(on FreebSD) it will attempt to find drives via cciss-vol-status,
and then optionally checking for disks via smrtctl if -C is given. Should be noted
though that -C will not find drives that are currently missing/failed. If -U is given,
cciss_vol_status will be called with -u.
=cut
##
@ -65,6 +101,9 @@ it should be.
use warnings;
use strict;
use Getopt::Std;
use JSON;
use MIME::Base64;
use IO::Compress::Gzip qw(gzip $GzipError);
my $cache = '/var/cache/smart';
my $smartctl = '/usr/bin/env smartctl';
@ -72,23 +111,91 @@ my @disks;
my $useSN = 1;
$Getopt::Std::STANDARD_HELP_VERSION = 1;
sub main::VERSION_MESSAGE {
print "SMART SNMP extend 0.0.0\n";
};
sub main::VERSION_MESSAGE {
print "SMART SNMP extend 0.3.2\n";
}
sub main::HELP_MESSAGE {
print "\n".
"-u Update '".$cache."'\n".
"-g Guess at the config and print it to STDOUT.\n".
"-c <config> The config file to use.\n";
}
&VERSION_MESSAGE;
print "\n" . "-u Update '" . $cache . "'\n" . '-g Guess at the config and print it to STDOUT
-c <config> The config file to use.
-p Pretty print the JSON.
-Z GZip+Base64 compress the results.
-C Enable manual checking for guess and cciss.
-S Set useSN to 0 when using -g
-t <test> Run the specified smart self test on all the devices.
-U When calling cciss_vol_status, call it with -u.
-G <modes> Guess modes to use. This is a comma seperated list.
Default :: scan-open,cciss-vol-status
Scan Modes:
- scan :: Use "--scan" with smartctl. "scan-open" will take presidence.
- scan-open :: Call smartctl with "--scan-open".
- cciss-vol-status :: Freebsd/Linux specific and if it sees /dev/sg0(on Linux) or
/dev/ciss0(on FreebSD) it will attempt to find drives via cciss-vol-status,
and then optionally checking for disks via smrtctl if -C is given. Should be noted
though that -C will not find drives that are currently missing/failed. If -U is given,
cciss_vol_status will be called with -u.
';
} ## end sub main::HELP_MESSAGE
#gets the options
my %opts = ();
getopts('ugc:', \%opts);
getopts( 'ugc:pZhvCSGt:U', \%opts );
if ( $opts{h} ) {
&HELP_MESSAGE;
exit;
}
if ( $opts{v} ) {
&VERSION_MESSAGE;
exit;
}
#
# figure out what scan modes to use if -g specified
#
my $scan_modes = {
'scan-open' => 0,
'scan' => 0,
'cciss_vol_status' => 0,
};
if ( $opts{g} ) {
if ( !defined( $opts{G} ) ) {
$opts{G} = 'scan-open,cciss_vol_status';
}
$opts{G} =~ s/[\ \t]//g;
my @scan_modes_split = split( /,/, $opts{G} );
foreach my $mode (@scan_modes_split) {
if ( !defined $scan_modes->{$mode} ) {
die( '"' . $mode . '" is not a recognized scan mode' );
}
$scan_modes->{$mode} = 1;
}
} ## end if ( $opts{g} )
# configure JSON for later usage
# only need to do this if actually running as in -g is not specified
my $json;
if ( !$opts{g} ) {
$json = JSON->new->allow_nonref->canonical(1);
if ( $opts{p} ) {
$json->pretty;
}
}
#
#
# guess if asked
#
#
if ( defined( $opts{g} ) ) {
#get what path to use for smartctl
@ -102,83 +209,234 @@ if ( defined( $opts{g} ) ){
#try to touch the default cache location and warn if it can't be done
system( 'touch ' . $cache . '>/dev/null' );
if ( $? != 0 ) {
$cache='#Could not touch '.$cache. "You will need to manually set it\n".
"cache=?\n";
$cache = '#Could not touch ' . $cache . "You will need to manually set it\n" . "cache=?\n";
} else {
system( 'rm -f ' . $cache . '>/dev/null' );
$cache = 'cache=' . $cache . "\n";
}
my %found_disks;
my $drive_lines = '';
#check for drives named /dev/sd*
my @matches=glob('/dev/sd*');
@matches=grep(!/[0-9]/, @matches);
my $matches_int=0;
while ( defined( $matches[$matches_int] ) ){
my $device=$matches[$matches_int];
system( $smartctl.' -A '.$device.' > /dev/null' );
if ( $? == 0 ){
$device =~ s/\/dev\///;
$found_disks{$device}=1;
}
#
#
# scan-open and scan guess mode handling
#
#
if ( $scan_modes->{'scan-open'} || $scan_modes->{'scan'} ) {
# used for checking if a disk has been found more than once
my %found_disks_names;
my @argumentsA;
$matches_int++;
}
#check for drives named /dev/ada*
@matches=glob('/dev/ada*');
@matches=grep(!/[ps]/, @matches);
$matches_int=0;
while ( defined( $matches[$matches_int] ) ){
my $device=$matches[$matches_int];
system( $smartctl.' -A '.$device.' > /dev/null' );
if ( $? == 0 ){
$device =~ s/\/dev\///;
$found_disks{$device}=1;
}
$matches_int++;
}
#check for drives named /dev/da*
@matches=glob('/dev/da*');
@matches=grep(!/[ps]/, @matches);
$matches_int=0;
while ( defined( $matches[$matches_int] ) ){
my $device=$matches[$matches_int];
system( $smartctl.' -A '.$device.' > /dev/null' );
if ( $? == 0 ){
$device =~ s/\/dev\///;
$found_disks{$device}=1;
}
$matches_int++;
# use scan-open if it is set, overriding scan if it is also set
my $mode = 'scan';
if ( $scan_modes->{'scan-open'} ) {
$mode = 'scan-open';
}
#have smartctl scan and see if it finds anythings not get found
my $scan_output=`$smartctl --scan-open`;
my $scan_output = `$smartctl --$mode`;
my @scan_outputA = split( /\n/, $scan_output );
# remove non-SMART devices sometimes returned
@scan_outputA = grep( !/ses[0-9]/, @scan_outputA ); # not a disk, but may or may not have SMART attributes
@scan_outputA = grep( !/pass[0-9]/, @scan_outputA ); # very likely a duplicate and a disk under another name
$matches_int=0;
while ( defined( $scan_outputA[$matches_int] ) ){
my $device=$scan_outputA[$matches_int];
$device =~ s/ .*//;
system( $smartctl.' -A '.$device.' > /dev/null' );
if ( $? == 0 ){
$device =~ s/\/dev\///;
$found_disks{$device}=1;
@scan_outputA = grep( !/cd[0-9]/, @scan_outputA ); # CD drive
if ( $^O eq 'freebsd' ) {
@scan_outputA = grep( !/sa[0-9]/, @scan_outputA ); # tape drive
@scan_outputA = grep( !/ctl[0-9]/, @scan_outputA ); # CAM target layer
} elsif ( $^O eq 'linux' ) {
@scan_outputA = grep( !/st[0-9]/, @scan_outputA ); # SCSI tape drive
@scan_outputA = grep( !/ht[0-9]/, @scan_outputA ); # ATA tape drive
}
$matches_int++;
# make the first pass, figuring out what all we have and trimming comments
foreach my $arguments (@scan_outputA) {
my $name = $arguments;
$arguments =~ s/ \#.*//; # trim the comment out of the argument
$name =~ s/ .*//;
$name =~ s/\/dev\///;
if ( defined( $found_disks_names{$name} ) ) {
$found_disks_names{$name}++;
} else {
$found_disks_names{$name} = 0;
}
print "useSN=0\n".'smartctl='.$smartctl."\n".
$cache.
join( "\n", keys(%found_disks) )."\n";
push( @argumentsA, $arguments );
} ## end foreach my $arguments (@scan_outputA)
# second pass, putting the lines together
my %current_disk;
foreach my $arguments (@argumentsA) {
my $not_virt = 1;
# check to see if we have a virtual device
my @virt_check = split( /\n/, `smartctl -i $arguments 2> /dev/null` );
foreach my $virt_check_line (@virt_check) {
if ( $virt_check_line =~ /(?i)Product\:.*LOGICAL VOLUME/ ) {
$not_virt = 0;
}
}
my $name = $arguments;
$name =~ s/ .*//;
$name =~ s/\/dev\///;
# only add it if not a virtual RAID drive
# HP RAID virtual disks will show up with very basical but totally useless smart data
if ($not_virt) {
if ( $found_disks_names{$name} == 0 ) {
# If no other devices, just name it after the base device.
$drive_lines = $drive_lines . $name . " " . $arguments . "\n";
} else {
# if more than one, start at zero and increment, apennding comma number to the base device name
if ( defined( $current_disk{$name} ) ) {
$current_disk{$name}++;
} else {
$current_disk{$name} = 0;
}
$drive_lines = $drive_lines . $name . "," . $current_disk{$name} . " " . $arguments . "\n";
}
} ## end if ($not_virt)
} ## end foreach my $arguments (@argumentsA)
} ## end if ( $scan_modes->{'scan-open'} || $scan_modes...)
#
#
# scan mode handler for cciss_vol_status
# /dev/sg* devices for cciss on Linux
# /dev/ccis* devices for cciss on FreeBSD
#
#
if ( $scan_modes->{'cciss_vol_status'} && ( $^O eq 'linux' || $^O eq 'freebsd' ) ) {
my $cciss;
if ( $^O eq 'freebsd' ) {
$cciss = 'ciss';
} elsif ( $^O eq 'linux' ) {
$cciss = 'sg';
}
my $uarg = '';
if ( $opts{U} ) {
$uarg = '-u';
}
# generate the initial device path that will be checked
my $sg_int = 0;
my $device = '/dev/' . $cciss . $sg_int;
my $sg_process = 1;
if ( -e $device ) {
my $output = `which cciss_vol_status 2> /dev/null`;
if ( $? != 0 && !$opts{C} ) {
$sg_process = 0;
$drive_lines
= $drive_lines
. "# -C not given, but "
. $device
. " exists and cciss_vol_status is not present\n"
. "# in path or 'ccis_vol_status -V "
. $device
. "' is failing\n";
} ## end if ( $? != 0 && !$opts{C} )
} ## end if ( -e $device )
my $seen_lines = {};
my $ignore_lines = {};
while ( -e $device && $sg_process ) {
my $output = `cciss_vol_status -V $uarg $device 2> /dev/null`;
if ( $? != 0 && $output eq '' && !$opts{C} ) {
# just empty here as we just want to skip it if it fails and there is no C
# warning is above
} elsif ( $? != 0 && $output eq '' && $opts{C} ) {
my $drive_count = 0;
my $continue = 1;
while ($continue) {
my $output = `$smartctl -i $device -d cciss,$drive_count 2> /dev/null`;
if ( $? != 0 ) {
$continue = 0;
} else {
my $add_it = 0;
my $id;
while ( $output =~ /(?i)Serial Number:(.*)/g ) {
$id = $1;
$id =~ s/^\s+|\s+$//g;
}
if ( defined($id) && !defined( $seen_lines->{$id} ) ) {
$add_it = 1;
$seen_lines->{$id} = 1;
}
if ( $continue && $add_it ) {
$drive_lines
= $drive_lines
. $cciss . '0-'
. $drive_count . ' '
. $device
. ' -d cciss,'
. $drive_count . "\n";
}
} ## end else [ if ( $? != 0 ) ]
$drive_count++;
} ## end while ($continue)
} else {
my $drive_count = 0;
# count the connector lines, this will make sure failed are founded as well
my $seen_conectors = {};
while ( $output =~ /(connector +\d+[IA]\ +box +\d+\ +bay +\d+.*)/g ) {
my $cciss_drive_line = $1;
my $connector = $cciss_drive_line;
$connector =~ s/(.*\ bay +\d+).*/$1/;
if ( !defined( $seen_lines->{$cciss_drive_line} )
&& !defined( $seen_conectors->{$connector} )
&& !defined( $ignore_lines->{$cciss_drive_line} ) )
{
$seen_lines->{$cciss_drive_line} = 1;
$seen_conectors->{$connector} = 1;
$drive_count++;
} else {
# going to be a connector we've already seen
# which will happen when it is processing replacement drives
# so save this as a device to ignore
$ignore_lines->{$cciss_drive_line} = 1;
}
} ## end while ( $output =~ /(connector +\d+[IA]\ +box +\d+\ +bay +\d+.*)/g)
my $drive_int = 0;
while ( $drive_int < $drive_count ) {
$drive_lines
= $drive_lines
. $cciss
. $sg_int . '-'
. $drive_int . ' '
. $device
. ' -d cciss,'
. $drive_int . "\n";
$drive_int++;
} ## end while ( $drive_int < $drive_count )
} ## end else [ if ( $? != 0 && $output eq '' && !$opts{C})]
$sg_int++;
$device = '/dev/' . $cciss . $sg_int;
} ## end while ( -e $device && $sg_process )
} ## end if ( $scan_modes->{'cciss_vol_status'} && ...)
my $useSN = 1;
if ( $opts{S} ) {
$useSN = 0;
}
print '# scan_modes='
. $opts{G}
. "\nuseSN="
. $useSN . "\n"
. 'smartctl='
. $smartctl . "\n"
. $cache
. $drive_lines;
exit 0;
}
} ## end if ( defined( $opts{g} ) )
#get which config file to use
my $config = $0 . '.config';
@ -192,7 +450,11 @@ open(my $readfh, "<", $config) or die "Can't open '".$config."'";
read( $readfh, $config_file, 1000000 );
close($readfh);
#
#
# parse the config file and remove comments and empty lines
#
#
my @configA = split( /\n/, $config_file );
@configA = grep( !/^$/, @configA );
@configA = grep( !/^\#/, @configA );
@ -200,34 +462,90 @@ my @configA=split(/\n/, $config_file);
my $configA_int = 0;
while ( defined( $configA[$configA_int] ) ) {
my $line = $configA[$configA_int];
chomp($line);
$line =~ s/^[\t\s]+//;
$line =~ s/[\t\s]+$//;
my ( $var, $val ) = split( /=/, $line, 2 );
my $matched;
if ( $var eq 'cache' ) {
$cache = $val;
$matched = 1;
}
if ( $var eq 'smartctl' ) {
$smartctl = $val;
$matched = 1;
}
if ( $var eq 'useSN' ) {
$useSN = $val;
$matched = 1;
}
if ( !defined($val) ) {
push(@disks, $var);
push( @disks, $line );
}
$configA_int++;
} ## end while ( defined( $configA[$configA_int] ) )
#
#
# run the specified self test on all disks if asked
#
#
if ( defined( $opts{t} ) ) {
# make sure we have something that atleast appears sane for the test name
my $valid_tesks = {
'offline' => 1,
'short' => 1,
'long' => 1,
'conveyance' => 1,
'afterselect,on' => 1,
};
if ( !defined( $valid_tesks->{ $opts{t} } ) && $opts{t} !~ /select,(\d+[\-\+]\d+|next|next\+\d+|redo\+\d+)/ ) {
print '"' . $opts{t} . "\" does not appear to be a valid test\n";
exit 1;
}
print "Running the SMART $opts{t} on all devices in the config...\n\n";
foreach my $line (@disks) {
my $disk;
my $name;
if ( $line =~ /\ / ) {
( $name, $disk ) = split( /\ /, $line, 2 );
} else {
$disk = $line;
$name = $line;
}
if ( $disk !~ /\// ) {
$disk = '/dev/' . $disk;
}
print "\n------------------------------------------------------------------\nDoing "
. $smartctl . ' -t '
. $opts{t} . ' '
. $disk
. " ...\n\n";
print `$smartctl -t $opts{t} $disk` . "\n";
} ## end foreach my $line (@disks)
exit 0;
} ## end if ( defined( $opts{t} ) )
#if set to 1, no cache will be written and it will be printed instead
my $noWrite = 0;
#
#
# if no -u, it means we are being called from snmped
#
#
if ( !defined( $opts{u} ) ) {
# if the cache file exists, print it, otherwise assume one is not being used
if ( -f $cache ) {
@ -241,16 +559,35 @@ if ( ! defined( $opts{u} ) ){
$opts{u} = 1;
$noWrite = 1;
}
} ## end if ( !defined( $opts{u} ) )
#
#
# Process each disk
#
#
my $to_return = {
data => { disks => {}, exit_nonzero => 0, unhealthy => 0, useSN => $useSN },
version => 1,
error => 0,
errorString => '',
};
foreach my $line (@disks) {
my $disk;
my $name;
if ( $line =~ /\ / ) {
( $name, $disk ) = split( /\ /, $line, 2 );
} else {
$disk = $line;
$name = $line;
}
if ( $disk !~ /\// ) {
$disk = '/dev/' . $disk;
}
my $toReturn='';
my $int=0;
while ( defined($disks[$int]) ) {
my $disk=$disks[$int];
my $disk_sn=$disk;
my $output=`$smartctl -A /dev/$disk`;
my %IDs=( '5'=>'null',
my $output = `$smartctl -A $disk`;
my %IDs = (
'5' => 'null',
'10' => 'null',
'173' => 'null',
'177' => 'null',
@ -265,10 +602,49 @@ while ( defined($disks[$int]) ) {
'198' => 'null',
'199' => 'null',
'231' => 'null',
'232' => 'null',
'233' => 'null',
'9' => 'null',
'disk' => $disk,
'serial' => undef,
'selftest_log' => undef,
'health_pass' => 0,
max_temp => 'null',
exit => $?,
);
$IDs{'disk'} =~ s/^\/dev\///;
my @outputA=split( /\n/, $output );
# if polling exited non-zero above, no reason running the rest of the checks
my $disk_id = $name;
if ( $IDs{exit} != 0 ) {
$to_return->{data}{exit_nonzero}++;
} else {
my @outputA;
if ( $output =~ /NVMe Log/ ) {
# we have an NVMe drive with annoyingly different output
my %mappings = (
'Temperature' => 194,
'Power Cycles' => 12,
'Power On Hours' => 9,
'Percentage Used' => 231,
);
foreach ( split( /\n/, $output ) ) {
if (/:/) {
my ( $key, $val ) = split(/:/);
$val =~ s/^\s+|\s+$|\D+//g;
if ( exists( $mappings{$key} ) ) {
if ( $mappings{$key} == 231 ) {
$IDs{ $mappings{$key} } = 100 - $val;
} else {
$IDs{ $mappings{$key} } = $val;
}
}
} ## end if (/:/)
} ## end foreach ( split( /\n/, $output ) )
} else {
@outputA = split( /\n/, $output );
my $outputAint = 0;
while ( defined( $outputA[$outputAint] ) ) {
my $line = $outputA[$outputAint];
@ -278,25 +654,70 @@ while ( defined($disks[$int]) ) {
if ( $line =~ /^[0123456789]+ / ) {
my @lineA = split( /\ /, $line, 10 );
my $raw = $lineA[9];
my $normalized = $lineA[3];
my $id = $lineA[0];
# Crucial SSD
# 202, Percent_Lifetime_Remain, same as 231, SSD Life Left
if ( $id == 202
&& $line =~ /Percent_Lifetime_Remain/ )
{
$IDs{231} = $raw;
}
# single int raw values
if (
( $id == 5 ) ||
( $id == 10 ) ||
( $id == 173 ) ||
( $id == 177 ) ||
( $id == 183 ) ||
( $id == 184 ) ||
( $id == 187 ) ||
( $id == 196 ) ||
( $id == 197 ) ||
( $id == 198 ) ||
( $id == 199 ) ||
( $id == 231 ) ||
( $id == 233 )
) {
$IDs{$id}=$raw;
if ( ( $id == 5 )
|| ( $id == 10 )
|| ( $id == 173 )
|| ( $id == 183 )
|| ( $id == 184 )
|| ( $id == 187 )
|| ( $id == 196 )
|| ( $id == 197 )
|| ( $id == 198 )
|| ( $id == 199 ) )
{
my @rawA = split( /\ /, $raw );
$IDs{$id} = $rawA[0];
} ## end if ( ( $id == 5 ) || ( $id == 10 ) || ( $id...))
# single int normalized values
if ( ( $id == 177 )
|| ( $id == 230 )
|| ( $id == 231 )
|| ( $id == 232 )
|| ( $id == 233 ) )
{
# annoying non-standard disk
# WDC WDS500G2B0A
# 230 Media_Wearout_Indicator 0x0032 100 100 --- Old_age Always - 0x002e000a002e
# 232 Available_Reservd_Space 0x0033 100 100 004 Pre-fail Always - 100
# 233 NAND_GB_Written_TLC 0x0032 100 100 --- Old_age Always - 9816
if ( $id == 230
&& $line =~ /Media_Wearout_Indicator/ )
{
$IDs{233} = int($normalized);
} elsif ( $id == 232
&& $line =~ /Available_Reservd_Space/ )
{
$IDs{232} = int($normalized);
} else {
# only set 233 if it has not been set yet
# if it was set already then the above did it and we don't want
# to overwrite it
if ( $id == 233 && $IDs{233} eq "null" ) {
$IDs{$id} = int($normalized);
} elsif ( $id != 233 ) {
$IDs{$id} = int($normalized);
}
} ## end else [ if ( $id == 230 && $line =~ /Media_Wearout_Indicator/)]
} ## end if ( ( $id == 177 ) || ( $id == 230 ) || (...))
# 9, power on hours
if ( $id == 9 ) {
my @runtime = split( /[\ h]/, $raw );
$IDs{$id} = $runtime[0];
}
# 188, Command_Timeout
@ -309,51 +730,196 @@ while ( defined($disks[$int]) ) {
$rawAint++;
}
$IDs{$id} = $total;
}
} ## end if ( $id == 188 )
# 190, airflow temp
# 194, temp
if (
( $id == 190 ) ||
( $id == 194 )
) {
if ( ( $id == 190 )
|| ( $id == 194 ) )
{
my ($temp) = split( /\ /, $raw );
$IDs{$id} = $temp;
}
} ## end if ( $line =~ /^[0123456789]+ / )
# SAS Wrapping
# Section by Cameron Munroe (munroenet[at]gmail.com)
# Elements in Grown Defect List.
# Marking as 5 Reallocated_Sector_Ct
if ( $line =~ "Elements in grown defect list:" ) {
my @lineA = split( /\ /, $line, 10 );
my $raw = $lineA[5];
# Reallocated Sector Count ID
$IDs{5} = $raw;
}
# Current Drive Temperature
# Marking as 194 Temperature_Celsius
if ( $line =~ "Current Drive Temperature:" ) {
my @lineA = split( /\ /, $line, 10 );
my $raw = $lineA[3];
# Temperature C ID
$IDs{194} = $raw;
}
# End of SAS Wrapper
$outputAint++;
}
} ## end while ( defined( $outputA[$outputAint] ) )
} ## end else [ if ( $output =~ /NVMe Log/ ) ]
#get the selftest logs
$output=`$smartctl -l selftest /dev/$disk`;
$output = `$smartctl -l selftest $disk`;
@outputA = split( /\n/, $output );
my $completed=scalar grep(/Completed without error/, @outputA);
my $interrupted=scalar grep(/Interrupted/, @outputA);
my $read_failure=scalar grep(/read failure/, @outputA);
my $unknown_failure=scalar grep(/unknown failure/, @outputA);
my $extended=scalar grep(/Extended/, @outputA);
my $short=scalar grep(/Short/, @outputA);
my $conveyance=scalar grep(/Conveyance/, @outputA);
my $selective=scalar grep(/Selective/, @outputA);
my @completed = grep( /Completed/, @outputA );
$IDs{'completed'} = scalar @completed;
my @interrupted = grep( /Interrupted/, @outputA );
$IDs{'interrupted'} = scalar @interrupted;
my @read_failure = grep( /read failure/, @outputA );
$IDs{'read_failure'} = scalar @read_failure;
my @read_failure2 = grep( /Failed in segment/, @outputA );
$IDs{'read_failure'} = $IDs{'read_failure'} + scalar @read_failure2;
my @unknown_failure = grep( /unknown failure/, @outputA );
$IDs{'unknown_failure'} = scalar @unknown_failure;
my @extended = grep( /\d.*\ ([Ee]xtended|[Ll]ong).*(?![Dd]uration)/, @outputA );
$IDs{'extended'} = scalar @extended;
my @short = grep( /[Ss]hort/, @outputA );
$IDs{'short'} = scalar @short;
my @conveyance = grep( /[Cc]onveyance/, @outputA );
$IDs{'conveyance'} = scalar @conveyance;
my @selective = grep( /[Ss]elective/, @outputA );
$IDs{'selective'} = scalar @selective;
my @offline = grep( /(\d|[Bb]ackground|[Ff]oreground)+\ +[Oo]ffline/, @outputA );
$IDs{'offline'} = scalar @offline;
# if we have logs, actually grab the log output
if ( $IDs{'completed'} > 0
|| $IDs{'interrupted'} > 0
|| $IDs{'read_failure'} > 0
|| $IDs{'extended'} > 0
|| $IDs{'short'} > 0
|| $IDs{'conveyance'} > 0
|| $IDs{'selective'} > 0
|| $IDs{'offline'} > 0 )
{
my @headers = grep( /(Num\ +Test.*LBA| Description .*[Hh]ours)/, @outputA );
my @log_lines;
push( @log_lines, @extended, @short, @conveyance, @selective, @offline );
$IDs{'selftest_log'} = join( "\n", @headers, sort(@log_lines) );
} ## end if ( $IDs{'completed'} > 0 || $IDs{'interrupted'...})
# get the drive serial number, if needed
my $disk_id=$disk;
$disk_id = $name;
$output = `$smartctl -i $disk`;
# generally upper case, HP branded drives seem to report with lower case n
while ( $output =~ /(?i)Serial Number:(.*)/g ) {
$IDs{'serial'} = $1;
$IDs{'serial'} =~ s/^\s+|\s+$//g;
}
if ($useSN) {
while (`$smartctl -i /dev/$disk` =~ /Serial Number:(.*)/g) {
$disk_id = $1;
$disk_id =~ s/^\s+|\s+$//g;
}
$disk_id = $IDs{'serial'};
}
$toReturn=$toReturn.$disk_id.','.$IDs{'5'}.','.$IDs{'10'}.','.$IDs{'173'}.','.$IDs{'177'}.','.$IDs{'183'}.','.$IDs{'184'}.','.$IDs{'187'}.','.$IDs{'188'}
.','.$IDs{'190'} .','.$IDs{'194'}.','.$IDs{'196'}.','.$IDs{'197'}.','.$IDs{'198'}.','.$IDs{'199'}.','.$IDs{'231'}.','.$IDs{'233'}.','.
$completed.','.$interrupted.','.$read_failure.','.$unknown_failure.','.$extended.','.$short.','.$conveyance.','.$selective."\n";
$int++;
while ( $output =~ /(?i)Model Family:(.*)/g ) {
$IDs{'model_family'} = $1;
$IDs{'model_family'} =~ s/^\s+|\s+$//g;
}
while ( $output =~ /(?i)Device Model:(.*)/g ) {
$IDs{'device_model'} = $1;
$IDs{'device_model'} =~ s/^\s+|\s+$//g;
}
while ( $output =~ /(?i)Model Number:(.*)/g ) {
$IDs{'model_number'} = $1;
$IDs{'model_number'} =~ s/^\s+|\s+$//g;
}
while ( $output =~ /(?i)Firmware Version:(.*)/g ) {
$IDs{'fw_version'} = $1;
$IDs{'fw_version'} =~ s/^\s+|\s+$//g;
}
# mainly HP drives
while ( $output =~ /(?i)Vendor:(.*)/g ) {
$IDs{'vendor'} = $1;
$IDs{'vendor'} =~ s/^\s+|\s+$//g;
}
# mainly HP drives
while ( $output =~ /(?i)Product:(.*)/g ) {
$IDs{'product'} = $1;
$IDs{'product'} =~ s/^\s+|\s+$//g;
}
# mainly HP drives
while ( $output =~ /(?i)Revision:(.*)/g ) {
$IDs{'revision'} = $1;
$IDs{'revision'} =~ s/^\s+|\s+$//g;
}
# figure out what to use for the max temp, if there is one
if ( $IDs{'190'} =~ /^\d+$/ ) {
$IDs{max_temp} = $IDs{'190'};
} elsif ( $IDs{'194'} =~ /^\d+$/ ) {
$IDs{max_temp} = $IDs{'194'};
}
if ( $IDs{'194'} =~ /^\d+$/ && defined( $IDs{max_temp} ) && $IDs{'194'} > $IDs{max_temp} ) {
$IDs{max_temp} = $IDs{'194'};
}
$output = `$smartctl -H $disk`;
if ( $output =~ /SMART\ overall\-health\ self\-assessment\ test\ result\:\ PASSED/ ) {
$IDs{'health_pass'} = 1;
} elsif ( $output =~ /SMART\ Health\ Status\:\ OK/ ) {
$IDs{'health_pass'} = 1;
}
if ( !$IDs{'health_pass'} ) {
$to_return->{data}{unhealthy}++;
}
} ## end else [ if ( $IDs{exit} != 0 ) ]
# only bother to save this if useSN is not being used
if ( !$useSN ) {
$to_return->{data}{disks}{$disk_id} = \%IDs;
} elsif ( $IDs{exit} == 0 && defined($disk_id) ) {
$to_return->{data}{disks}{$disk_id} = \%IDs;
}
# smartctl will in some cases exit zero when it can't pull data for cciss
# so if we get a zero exit, but no serial then it means something errored
# and the device is likely dead
if ( $IDs{exit} == 0 && !defined( $IDs{serial} ) ) {
$to_return->{data}{unhealthy}++;
}
} ## end foreach my $line (@disks)
my $toReturn = $json->encode($to_return);
if ( !$opts{p} ) {
$toReturn = $toReturn . "\n";
}
if ( $opts{Z} ) {
my $toReturnCompressed;
gzip \$toReturn => \$toReturnCompressed;
my $compressed = encode_base64($toReturnCompressed);
$compressed =~ s/\n//g;
$compressed = $compressed . "\n";
if ( length($compressed) < length($toReturn) ) {
$toReturn = $compressed;
}
} ## end if ( $opts{Z} )
if ( !$noWrite ) {
open( my $writefh, ">", $cache ) or die "Can't open '" . $cache . "'";
print $writefh $toReturn;

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,45 @@
#!/bin/sh
################################################################
# Instructions: #
# 1. copy this script to /etc/snmp/ and make it executable: #
# chmod +x ups-nut.sh #
# 2. make sure UPS_NAME below matches the name of your UPS #
# 3. edit your snmpd.conf to include this line: #
# extend ups-nut /etc/snmp/ups-nut.sh #
# 4. restart snmpd on the host #
# 5. activate the app for the desired host in LibreNMS #
################################################################
UPS_NAME="${1:-APCUPS}"
PATH=$PATH:/usr/bin:/bin
TMP=$(upsc $UPS_NAME 2>/dev/null)
for value in "battery\.charge: [0-9.]+" "battery\.(runtime\.)?low: [0-9]+" "battery\.runtime: [0-9]+" "battery\.voltage: [0-9.]+" "battery\.voltage\.nominal: [0-9]+" "input\.voltage\.nominal: [0-9.]+" "input\.voltage: [0-9.]+" "ups\.load: [0-9.]+"
do
OUT=$(echo "$TMP" | grep -Eo "$value" | awk '{print $2}' | LANG=C sort | head -n 1)
if [ -n "$OUT" ]; then
echo "$OUT"
else
echo "Unknown"
fi
done
for value in "ups\.status:[A-Z ]{0,}OL" "ups\.status:[A-Z ]{0,}OB" "ups\.status:[A-Z ]{0,}LB" "ups\.status:[A-Z ]{0,}HB" "ups\.status:[A-Z ]{0,}RB" "ups\.status:[A-Z ]{0,}CHRG" "ups\.status:[A-Z ]{0,}DISCHRG" "ups\.status:[A-Z ]{0,}BYPASS" "ups\.status:[A-Z ]{0,}CAL" "ups\.status:[A-Z ]{0,}OFF" "ups\.status:[A-Z ]{0,}OVER" "ups\.status:[A-Z ]{0,}TRIM" "ups\.status:[A-Z ]{0,}BOOST" "ups\.status:[A-Z ]{0,}FSD" "ups\.alarm:[A-Z ]"
do
UNKNOWN=$(echo "$TMP" | grep -Eo "ups\.status:")
if [ -z "$UNKNOWN" ]; then
echo "Unknown"
else
OUT=$(echo "$TMP" | grep -Eo "$value")
if [ -n "$OUT" ]; then
echo "1"
else
echo "0"
fi
fi
done
UPSTEMP="ups\.temperature: [0-9.]+"
OUT=$(echo "$TMP" | grep -Eo "$UPSTEMP" | awk '{print $2}' | LANG=C sort | head -n 1)
[ -n "$OUT" ] && echo "$OUT" || echo "Unknown"

View File

@ -18,16 +18,15 @@ syslocation R4, Server Room, SITER, Pflugerville, United States
syscontact coo@turnsys.com
#NTP
extend ntp-client /usr/local/librenms/ntp-client.sh
extend ntp-client /usr/lib/check_mk_agent/local/ntp-client.sh
#SMTP
extend mailq /usr/local/librenms/postfix-queues
extend postfixdetailed /usr/local/librenms/postfixdetailed
extend mailq /usr/lib/check_mk_agent/local/postfix-queues
extend postfixdetailed /usr/lib/check_mk_agent/local/postfixdetailed
#OS Distribution Detection
extend distro /usr/local/bin/distro
extend osupdate /usr/local/librenms/os-updates.sh
extend distro /usr/lib/bin/distro
extend osupdate /usr/lib/check_mk_agent/local/os-updates.sh
#Hardware Detection
extend manufacturer /usr/bin/sudo /usr/bin/cat /sys/devices/virtual/dmi/id/sys_vendor
@ -40,6 +39,5 @@ extend smart /bin/cat /var/cache/smart
#Temperature
pass_persist .1.3.6.1.4.1.9.9.13.1.3 /usr/local/bin/temper-snmp
# Allow Systems Management Data Engine SNMP to connect to snmpd using SMUX
# smuxpeer .1.3.6.1.4.1.674.10892.1

View File

@ -18,15 +18,15 @@ syslocation SITER, Pflugerville, United States
syscontact coo@turnsys.com
#NTP
extend ntp-client /usr/local/librenms/ntp-client.sh
extend ntp-client /usr/lib/check_mk_agent/local/ntp-client.sh
#SMTP
extend mailq /usr/local/librenms/postfix-queues
extend postfixdetailed /usr/local/librenms/postfixdetailed
extend mailq /usr/lib/check_mk_agent/local/postfix-queues
extend postfixdetailed /usr/lib/check_mk_agent/local/postfixdetailed
#OS Distribution Detection
extend distro /usr/local/bin/distro
extend osupdate /usr/local/librenms/os-updates.sh
extend distro /usr/lib/bin/distro
extend osupdate /usr/lib/check_mk_agent/local/os-updates.sh
#Hardware Detection

View File

@ -18,16 +18,18 @@ syslocation R4, Server Room, SITER, Pflugerville, United States
syscontact coo@turnsys.com
#NTP
extend ntp-client /usr/local/librenms/ntp-client.sh
extend ntp-client /usr/lib/check_mk_agent/local/ntp-client.sh
#SMTP
extend mailq /usr/local/librenms/postfix-queues
extend postfixdetailed /usr/local/librenms/postfixdetailed
extend mailq /usr/lib/check_mk_agent/local/postfix-queues
extend postfixdetailed /usr/lib/check_mk_agent/local/postfixdetailed
#OS Distribution Detection
extend distro /usr/local/bin/distro
extend osupdate /usr/local/librenms/os-updates.sh
extend distro /usr/lib/bin/distro
extend osupdate /usr/lib/check_mk_agent/local/os-updates.sh
# Socket statistics
extend ss /usr/lib/check_mk_agent/local/ss.py
#Hardware Detection
# (uncomment for x86 platforms)
@ -35,6 +37,5 @@ extend manufacturer /usr/bin/sudo /usr/bin/cat /sys/devices/virtual/dmi/id/sys_v
extend hardware /usr/bin/sudo /usr/bin/cat /sys/devices/virtual/dmi/id/product_name
extend serial /usr/bin/sudo /usr/bin/cat /sys/devices/virtual/dmi/id/product_serial
# Allow Systems Management Data Engine SNMP to connect to snmpd using SMUX
# smuxpeer .1.3.6.1.4.1.674.10892.1

View File

@ -3,19 +3,33 @@ print_info "Setting up librenms agent..."
cat ./scripts/distro > /usr/local/bin/distro && chmod +x /usr/local/bin/distro
if [ ! -d /usr/local/librenms-agent ]; then
mkdir -p /usr/local/librenms-agent
if [ ! -d /usr/local/check_mk_agent ]; then
mkdir -p /usr/local/check_mk_agent
fi
cat ../Agents/librenms/ntp-client.sh > /usr/local/librenms-agent/ntp-client.sh
cat ../Agents/librenms/ntp-server.sh > /usr/local/librenms-agent/ntp-server.sh
cat ../Agents/librenms/os-updates.sh > /usr/local/librenms-agent/os-updates.sh
cat ../Agents/librenms/postfixdetailed.sh > /usr/local/librenms-agent/postfixdetailed.sh
cat ../Agents/librenms/postfix-queues.sh > /usr/local/librenms-agent/postfixdetailed.sh
cat ../Agents/librenms/smart > /usr/local/librenms-agent/smart
cp ../Agents/librenms/check_mk@.service check_mk.socket /etc/systemd/system
cp ../Agents/librenms/check_mk_agent /usr/bin/check_mk_agent
if [ ! -d /usr/local/check_mk_agent/plugins ]; then
mkdir -p /usr/local/check_mk_agent/plugins
fi
if [ ! -d /usr/local/check_mk_agent/local ]; then
mkdir -p /usr/local/check_mk_agent/local
fi
cat ../Agents/librenms/check_mk_agent > /usr/bin/check_mk_agent
chmod +x /usr/bin/check_mk_agent
mkdir -p /usr/lib/check_mk_agent/plugins || true
mkdir -p /usr/lib/check_mk_agent/local || true
cat ../Agents/librenms/check_mk@.service check_mk.socket > /etc/systemd/system
systemctl enable check_mk.socket
systemctl start check_mk.socket
cat ../Agents/librenms/ntp-client.sh > /usr/lib/check_mk_agent/local/ntp-client.sh
cat ../Agents/librenms/ntp-server.sh > /usr/lib/check_mk_agent/local/ntp-server.sh
cat ../Agents/librenms/os-updates.sh > /usr/local/check_mk_agent/local/os-updates.sh
cat ../Agents/librenms/postfixdetailed.sh > /usr/local/check_mk_agent/local/postfixdetailed.sh
cat ../Agents/librenms/postfix-queues.sh > /usr/local/check_mk_agent/local/postfix_queues.sh
cat ../Agents/librenms/smart > /usr/local/check_mk_agent/local/smart
cat ../Agents/librenms/smart.config > /usr/local/check_mk_agent/local/smart.config
chmod +x /usr/lib/check_mk_agent/local/*

View File

@ -296,21 +296,21 @@ curl --silent ${DL_ROOT}/ConfigFiles/DHCP/dhclient.conf > /etc/dhcp/dhclient.con
systemctl stop snmpd && /etc/init.d/snmpd stop
curl --silent ${DL_ROOT}/ConfigFiles/SNMP/snmp-sudo.conf > /etc/sudoers.d/Debian-snmp
cat ./ConfigFiles/SNMP/snmp-sudo.conf > /etc/sudoers.d/Debian-snmp
sed -i "s|-Lsd|-LS6d|" /lib/systemd/system/snmpd.service
pi-detect
if [ "$IS_RASPI" = 1 ] ; then
curl --silent ${DL_ROOT}/ConfigFiles/SNMP/snmpd-rpi.conf > /etc/snmp/snmpd.conf
cat ./ConfigFiles/SNMP/snmpd-rpi.conf > /etc/snmp/snmpd.conf
fi
if [ "$IS_PHYSICAL_HOST" = 1 ] ; then
curl --silent ${DL_ROOT}/ConfigFiles/SNMP/snmpd-physicalhost.conf > /etc/snmp/snmpd.conf
cat ./ConfigFiles/SNMP/snmpd-physicalhost.conf > /etc/snmp/snmpd.conf
fi
if [ "$IS_VIRT_GUEST" = 1 ] ; then
curl --silent ${DL_ROOT}/ConfigFiles/SNMP/snmpd.conf > /etc/snmp/snmpd.conf
cat ./ConfigFiles/SNMP/snmpd.conf > /etc/snmp/snmpd.conf
fi
systemctl daemon-reload && systemctl restart snmpd && /etc/init.d/snmpd restart
@ -319,12 +319,12 @@ systemctl stop rsyslog
systemctl start rsyslog
if [ "$KALI_CHECK" = 0 ]; then
curl --silent ${DL_ROOT}/ConfigFiles/NTP/ntp.conf > /etc/ntp.conf
cat ./ConfigFiles/NTP/ntp.conf > /etc/ntp.conf
systemctl restart ntp
fi
if [ "$KALI_CHECK" = 1 ]; then
curl --silent ${DL_ROOT}/ConfigFiles/NTP/ntp.conf > /etc/ntpsec/ntp.conf
cat ./ConfigFiles/NTP/ntp.conf > /etc/ntpsec/ntp.conf
systemctl restart ntpsec.service
fi
@ -368,7 +368,7 @@ function secharden-ssh()
{
print_info "Now running "$FUNCNAME""
curl --silent ${DL_ROOT}/Modules/Security/secharden-ssh.sh|$(which bash)
bash ./Modules/Security/secharden-ssh.sh|$(which bash)
print_info "Completed running "$FUNCNAME""
}