#!/usr/bin/perl use warnings; use strict; use POSIX; use RRDs; use IPC::Open3; use Symbol; use Carp; use esmith::config; use esmith::db; use sigtrap; use File::Slurp qw/ read_file /; use File::Find::Rule; $ENV {'PATH'} = '/bin:/sbin:/usr/bin:/usr/sbin:/usr/lib/sa'; $ENV {'LANG'} = 'C'; croak "ERROR: Already running!" if (-e "/var/lock/sysmon"); my $pingfactor; my $return = `fping -C 1 localhost 2>&1`; croak "ERROR: FPing must be installed setuid root or it will not work\n" if $return =~ m/only.+root/; if ($return =~ m/bytes, ([0-9.]+)\sms\s+.*\n.*\n.*:\s+([0-9.]+)/) { $pingfactor = 1000 * $2/$1; } else { $pingfactor = 1000; } my %conf; tie %conf, 'esmith::config'; my $status = db_get_prop(\%conf, 'sysmon', 'status') || "disabled"; croak "ERROR: sysmon is not enabled" if $status ne 'enabled'; my $upsstatus = db_get_prop(\%conf, 'nut', 'status') || "disabled"; my $rrddir = '/var/lib/rrd'; unless (fork) { open (FILELOCK,">/var/lock/sysmon"); print FILELOCK $$; close FILELOCK; &POSIX::setsid; unlink("/var/log/sysmon.old") if -e "/var/log/sysmon.old"; rename("/var/log/sysmon","/var/log/sysmon.old") if -e "/var/log/sysmon"; open STDOUT,'>>/var/log/sysmon'; open STDERR,'>>/var/log/sysmon'; open STDIN, 'file("*.rrd") ->maxdepth(1) ->in($rrddir); for my $file (@files){ if (-M $file > $days){ print "deleting $file\n"; unlink $file or warn $!; } } my $lastupdate = RRDs::last("/var/lib/rrd/sysmon.rrd") || 0; my $datahash = (); my $badifaces = `/sbin/ifconfig -a | /bin/sed -ne '/^\\w\\+[0-9]/{;x;n;/inet addr/bd;x;s/^\\(\\w\\+[0-9]\\+\\).*/\\1/p;:d;}'` || 'none'; chomp($badifaces); rename("/var/lib/rrd/sysmon.stats","/var/lib/rrd/sysmon.process"); if ( -x '/usr/lib/sa/sadc' ) { `/usr/lib/sa/sadc 1 1 /var/lib/rrd/sysmon.process > /dev/null 2>&1; /usr/lib/sa/sadc 1 1 /var/lib/rrd/sysmon.stats > /dev/null 2>&1`;} else { `/usr/lib64/sa/sadc 1 1 /var/lib/rrd/sysmon.process > /dev/null 2>&1; /usr/lib64/sa/sadc 1 1 /var/lib/rrd/sysmon.stats > /dev/null 2>&1`;} my @sardata; if ( -x '/usr/bin/sadf' ) { @sardata=`/usr/bin/sadf -U -- -qrbuS -n DEV /var/lib/rrd/sysmon.process 2> /dev/null`; }# sadf else { @sardata = `/usr/bin/sar -hqruS -P ALL -n DEV -f /var/lib/rrd/sysmon.process 2> /dev/null`; }# old systat unlink("/var/lib/rrd/sysmon.process"); if($#sardata > 0 && $sardata[0] =~ /\s+(\d+)\s+(\d{10})/ && $1 >= 45 && $1 <= 135 && $2 > $lastupdate) { open(FILE,"; close(FILE); if ($filedata[0] =~ /^([0-9,.]+)/) { $datahash->{uptime} = $1; }; my @gethd = `/bin/df --block-size=1 --portability --local | grep '^/dev'`; foreach (@gethd) { if(/^\/dev\/(?:mapper\/)?(\S+)\s+\d+\s+(\d+)\s+(\d+)\s+\d+\%/) { $datahash->{hdtotal}->{$1} = $2 + $3; $datahash->{hdfree}->{$1} = $3; $datahash->{hdused}->{$1} = $2; $datahash->{hdtotal}->{all} += $2 + $3; $datahash->{hdfree}->{all} += $3; $datahash->{hdused}->{all} += $2; } } foreach(@sardata) { if(/(all|cpu\d+)\s+\%(user|nice|system|iowait|idle)\s+([0-9,.]+)/) { $datahash->{$2}->{$1}=$3/100; } if(/(runq-sz|plist-sz|ldavg-[15]+)\s+([0-9,.]+)/) { $datahash->{$1}=$2; } if(/kb(memfree|memused|buffers|cached|swpfree|swpused)\s+([0-9,.]+)/) { $datahash->{$1}=$2*1024; } if(/(\w+)\s+(rxkB|txkB|rxpck|txpck)\/s\s+([0-9,.]+)/) { $datahash->{$2}->{$1}=$3; } } foreach (keys %{$datahash->{idle}}) { $datahash->{total}->{$_}=1-$datahash->{idle}->{$_}; } $datahash->{memtotal} = $datahash->{memused} + $datahash->{memfree}; $datahash->{memused} -= $datahash->{cached} + $datahash->{buffers}; $datahash->{memfree} += $datahash->{cached} + $datahash->{buffers}; $datahash->{swptotal} = $datahash->{swpused} + $datahash->{swpfree}; RRDs::create("/var/lib/rrd/sysmon.rrd","-s","60", "DS:total:GAUGE:120:0:150", "DS:user:GAUGE:120:0:150", "DS:nice:GAUGE:120:0:150", "DS:system:GAUGE:120:0:150", "DS:iowait:GAUGE:120:0:150", "DS:idle:GAUGE:120:0:150", "DS:runq-sz:GAUGE:120:0:100", "DS:plist-sz:GAUGE:120:0:1000", "DS:ldavg-1:GAUGE:120:0:100", "DS:ldavg-5:GAUGE:120:0:100", "DS:memtotal:GAUGE:120:0:U", "DS:memfree:GAUGE:120:0:U", "DS:memused:GAUGE:120:0:U", "DS:buffers:GAUGE:120:0:U", "DS:cached:GAUGE:120:0:U", "DS:swptotal:GAUGE:120:0:U", "DS:swpfree:GAUGE:120:0:U", "DS:swpused:GAUGE:120:0:U", "DS:hdtotal:GAUGE:120:0:U", "DS:hdfree:GAUGE:120:0:U", "DS:hdused:GAUGE:120:0:U", "DS:uptime:GAUGE:120:0:U", "RRA:MIN:0.5:1:1500", "RRA:MIN:0.5:5:600", "RRA:MIN:0.5:30:700", "RRA:MIN:0.5:120:775", "RRA:MIN:0.5:1440:797", "RRA:AVERAGE:0.5:1:1500", "RRA:AVERAGE:0.5:5:600", "RRA:AVERAGE:0.5:30:700", "RRA:AVERAGE:0.5:120:775", "RRA:AVERAGE:0.5:1440:797", "RRA:MAX:0.5:1:1500", "RRA:MAX:0.5:5:600", "RRA:MAX:0.5:30:700", "RRA:MAX:0.5:120:775", "RRA:MAX:0.5:1440:797") unless -e "/var/lib/rrd/sysmon.rrd"; RRDs::update("/var/lib/rrd/sysmon.rrd", "N:$datahash->{total}->{all}:$datahash->{user}->{all}:$datahash->{nice}->{all}:" . "$datahash->{system}->{all}:$datahash->{iowait}->{all}:$datahash->{idle}->{all}:" . "$datahash->{'runq-sz'}:$datahash->{'plist-sz'}:$datahash->{'ldavg-1'}:" . "$datahash->{'ldavg-5'}:$datahash->{memtotal}:$datahash->{memfree}:" . "$datahash->{memused}:$datahash->{buffers}:$datahash->{cached}:$datahash->{swptotal}:" . "$datahash->{swpfree}:$datahash->{swpused}:$datahash->{hdtotal}->{all}:$datahash->{hdfree}->{all}:" . "$datahash->{hdused}->{all}:$datahash->{uptime}"); rename("/var/lib/rrd/sysmon.rrd","/var/lib/rrd/sysmon.bad") if(RRDs::error); print RRDs::error . "\n" if (RRDs::error); foreach my $cpu (keys %{$datahash->{idle}}) { next if $cpu eq 'all'; RRDs::create("/var/lib/rrd/$cpu.rrd","-s","60", "DS:total:GAUGE:120:0:150", "DS:user:GAUGE:120:0:150", "DS:nice:GAUGE:120:0:150", "DS:system:GAUGE:120:0:150", "DS:iowait:GAUGE:120:0:150", "DS:idle:GAUGE:120:0:150", "RRA:MIN:0.5:1:1500", "RRA:MIN:0.5:5:600", "RRA:MIN:0.5:30:700", "RRA:MIN:0.5:120:775", "RRA:MIN:0.5:1440:797", "RRA:AVERAGE:0.5:1:1500", "RRA:AVERAGE:0.5:5:600", "RRA:AVERAGE:0.5:30:700", "RRA:AVERAGE:0.5:120:775", "RRA:AVERAGE:0.5:1440:797", "RRA:MAX:0.5:1:1500", "RRA:MAX:0.5:5:600", "RRA:MAX:0.5:30:700", "RRA:MAX:0.5:120:775", "RRA:MAX:0.5:1440:797") unless -e "/var/lib/rrd/$cpu.rrd"; RRDs::update("/var/lib/rrd/$cpu.rrd", "N:$datahash->{total}->{$cpu}:$datahash->{user}->{$cpu}:$datahash->{nice}->{$cpu}:" . "$datahash->{system}->{$cpu}:$datahash->{iowait}->{$cpu}:$datahash->{idle}->{$cpu}"); rename("/var/lib/rrd/$cpu.rrd","/var/lib/rrd/$cpu.bad") if(RRDs::error); print RRDs::error . "\n" if (RRDs::error); } foreach my $drive (keys %{$datahash->{hdtotal}}) { next if $drive eq 'all'; RRDs::create("/var/lib/rrd/drive_$drive.rrd","-s","60", "DS:hdtotal:GAUGE:120:0:U", "DS:hdfree:GAUGE:120:0:U", "DS:hdused:GAUGE:120:0:U", "RRA:MIN:0.5:1:1500", "RRA:MIN:0.5:5:600", "RRA:MIN:0.5:30:700", "RRA:MIN:0.5:120:775", "RRA:MIN:0.5:1440:797", "RRA:AVERAGE:0.5:1:1500", "RRA:AVERAGE:0.5:5:600", "RRA:AVERAGE:0.5:30:700", "RRA:AVERAGE:0.5:120:775", "RRA:AVERAGE:0.5:1440:797", "RRA:MAX:0.5:1:1500", "RRA:MAX:0.5:5:600", "RRA:MAX:0.5:30:700", "RRA:MAX:0.5:120:775", "RRA:MAX:0.5:1440:797") unless -e "/var/lib/rrd/drive_$drive.rrd"; RRDs::update("/var/lib/rrd/drive_$drive.rrd", "N:$datahash->{hdtotal}->{$drive}:$datahash->{hdfree}->{$drive}:$datahash->{hdused}->{$drive}"); rename("/var/lib/rrd/drive_$drive.rrd","/var/lib/rrd/drive_$drive.bad") if(RRDs::error); print RRDs::error . "\n" if (RRDs::error); } foreach my $iface (keys %{$datahash->{rxkB}}) { next if ($iface =~ /(lo|br\d+|imq\d+)$/); next if ($datahash->{rxkB}->{$iface} == 0); next if ($badifaces =~ /$iface/); RRDs::create("/var/lib/rrd/iface_$iface.rrd","-s","60", "DS:rxkB:" . ($iface =~ /^sw/ ? "COUNTER" : "GAUGE" ) . ":120:0:U", "DS:txkB:" . ($iface =~ /^sw/ ? "COUNTER" : "GAUGE" ) . ":120:0:U", "DS:rxpck:" . ($iface =~ /^sw/ ? "COUNTER" : "GAUGE" ) . ":120:0:U", "DS:txpck:" . ($iface =~ /^sw/ ? "COUNTER" : "GAUGE" ) . ":120:0:U", "RRA:MIN:0.5:1:1500", "RRA:MIN:0.5:5:600", "RRA:MIN:0.5:30:700", "RRA:MIN:0.5:120:775", "RRA:MIN:0.5:1440:797", "RRA:AVERAGE:0.5:1:1500", "RRA:AVERAGE:0.5:5:600", "RRA:AVERAGE:0.5:30:700", "RRA:AVERAGE:0.5:120:775", "RRA:AVERAGE:0.5:1440:797", "RRA:MAX:0.5:1:1500", "RRA:MAX:0.5:5:600", "RRA:MAX:0.5:30:700", "RRA:MAX:0.5:120:775", "RRA:MAX:0.5:1440:797") unless -e "/var/lib/rrd/iface_$iface.rrd"; RRDs::update("/var/lib/rrd/iface_$iface.rrd", "N:$datahash->{rxkB}->{$iface}:$datahash->{txkB}->{$iface}:$datahash->{rxpck}->{$iface}:" . "$datahash->{txpck}->{$iface}"); rename("/var/lib/rrd/iface_$iface.rrd","/var/lib/rrd/iface_$iface.bad") if(RRDs::error); print RRDs::error . "\n" if (RRDs::error); } my $cnt=0; if ( $upsstatus eq 'enabled') { my @upsentries = ('i_voltage', 'u_load', 'b_charge', 'b_runtime', 'b_voltage', 'u_temperature') ; #use File::Slurp qw/ read_file /; my $upslines = read_file('/etc/ups/ups.conf'); my @upses = $upslines =~ m/\[(.*)\]\n/; foreach(@upses) { chomp; my $upsname="$_\@localhost"; $cnt++; my @upsdata = `/usr/bin/upsc $upsname 2> /dev/null`; $upslines="ups $upsname: "; foreach(@upsdata) { if(/^([a-z])[^.]+\.(voltage|load|charge|runtime|temperature|humidity)\s*:\s*([0-9,.]+)/) { my $element = "$1_$2"; $upslines .= "$element=$3, "; $datahash->{ups}->{$cnt}->{$element}=$3; if($element=~/time/i) { $datahash->{ups}->{$cnt}->{$element} /= 60; } } } foreach my $element (@upsentries){ next if exists($datahash->{ups}->{$cnt}->{$element}); $datahash->{ups}->{$cnt}->{$element}=''; $upslines .= "$element=, "; } } } foreach my $ups (keys %{$datahash->{ups}}) { RRDs::create("/var/lib/rrd/ups$ups.rrd","-s","60", (map {"DS:$_:GAUGE:120:0:U"} sort keys %{$datahash->{ups}->{$ups}}), "RRA:MIN:0.5:1:1500", "RRA:MIN:0.5:5:600", "RRA:MIN:0.5:30:700", "RRA:MIN:0.5:120:775", "RRA:MIN:0.5:1440:797", "RRA:AVERAGE:0.5:1:1500", "RRA:AVERAGE:0.5:5:600", "RRA:AVERAGE:0.5:30:700", "RRA:AVERAGE:0.5:120:775", "RRA:AVERAGE:0.5:1440:797", "RRA:MAX:0.5:1:1500", "RRA:MAX:0.5:5:600", "RRA:MAX:0.5:30:700", "RRA:MAX:0.5:120:775", "RRA:MAX:0.5:1440:797") unless -e "/var/lib/rrd/ups$ups.rrd"; RRDs::update("/var/lib/rrd/ups$ups.rrd", "N:".(join ":", map { $datahash->{ups}->{$ups}->{$_} } sort keys %{$datahash->{ups}->{$ups}})); rename("/var/lib/rrd/ups$ups.rrd","/var/lib/rrd/ups$ups.bad") if(RRDs::error); print RRDs::error . "\n" if (RRDs::error); } if( -e '/usr/bin/sensors') { my $check = `/sbin/lsmod 2> /dev/null`; if( $check =~ /i2c_/ ) { my @sensordata = `/usr/bin/sensors -u 2> /dev/null`; foreach(@sensordata) { #pre SME9 if(/(-?[0-9,.]+) \(((?:in|fan|temp|vid|vrm)[0-9]*)\)/) { $datahash->{sensors}->{$2} = $1; print "$2=$1, "} if(/(in|fan|temp|vid|vrm)([0-9])_input: ?(-?[0-9,.]+)/) { $datahash->{sensors}->{"$1$2"} = $3;} #print "sensors:$1$2=$3\n"} } if(defined($datahash->{sensors})) { RRDs::create("/var/lib/rrd/sensors.rrd","-s","60", (map {"DS:$_:GAUGE:120:U:U"} sort keys %{$datahash->{sensors}}), "RRA:MIN:0.5:1:1500", "RRA:MIN:0.5:5:600", "RRA:MIN:0.5:30:700", "RRA:MIN:0.5:120:775", "RRA:MIN:0.5:1440:797", "RRA:AVERAGE:0.5:1:1500", "RRA:AVERAGE:0.5:5:600", "RRA:AVERAGE:0.5:30:700", "RRA:AVERAGE:0.5:120:775", "RRA:AVERAGE:0.5:1440:797", "RRA:MAX:0.5:1:1500", "RRA:MAX:0.5:5:600", "RRA:MAX:0.5:30:700", "RRA:MAX:0.5:120:775", "RRA:MAX:0.5:1440:797") unless -e "/var/lib/rrd/sensors.rrd"; RRDs::update("/var/lib/rrd/sensors.rrd", "N:".(join ":", map { $datahash->{sensors}->{$_} } sort keys %{$datahash->{sensors}})); rename("/var/lib/rrd/sensors.rrd","/var/lib/rrd/sensors.bad") if(RRDs::error); print RRDs::error . "\n" if (RRDs::error); } } } my $inh = gensym; my $outh = gensym; my $errh = gensym; my $gateway = `/sbin/route -n | /bin/egrep '^0\.' | /bin/awk '{ print \$2 }' | /bin/egrep '^[1-9]'` || `/sbin/ifconfig | /bin/sed -ne '/P-t-P/p' | /bin/awk '{ print \$3 }' | /bin/cut -d: -f2` || 'down'; chomp $gateway; my $hosts = db_get_prop(\%conf, 'sysmon', 'hosts') || "gateway"; $hosts =~ s/\bgateway\b/$gateway/g; $hosts =~ s/[,:; ]+/ /g; my @pings = `fping -C 25 -q -B1 -t1000 -r1 -p 500 $hosts 2>&1`; foreach (@pings) { chomp; my @times = split /\s+/; my $ip = shift @times; $ip =~ s/\b$gateway\b/gateway/g; if (':' eq shift @times) { @times = map {sprintf "%.10e", $_ / $pingfactor} sort {$a <=> $b} grep /^\d/, @times; my $median = $times[int($#times/2)] || 'U'; my $loss = 25 - ($#times+1); if ($loss >= 25) { @times = map {'U'} 1..25; } else { splice @times, sprintf("%.0f", int(($#times+1)/2)),0,map {'U'} 1..$loss; } RRDs::create("/var/lib/rrd/host_$ip.rrd","-s","60", "DS:loss:GAUGE:120:0:25", "DS:median:GAUGE:120:0:180", (map {"DS:ping${_}:GAUGE:120:0:180"} 1..25), "RRA:MIN:0.5:1:1500", "RRA:MIN:0.5:5:600", "RRA:MIN:0.5:30:700", "RRA:MIN:0.5:120:775", "RRA:MIN:0.5:1440:797", "RRA:AVERAGE:0.5:1:1500", "RRA:AVERAGE:0.5:5:600", "RRA:AVERAGE:0.5:30:700", "RRA:AVERAGE:0.5:120:775", "RRA:AVERAGE:0.5:1440:797", "RRA:MAX:0.5:1:1500", "RRA:MAX:0.5:5:600", "RRA:MAX:0.5:30:700", "RRA:MAX:0.5:120:775", "RRA:MAX:0.5:1440:797") unless -e "/var/lib/rrd/host_$ip.rrd"; RRDs::update("/var/lib/rrd/host_$ip.rrd", "N:$loss:$median:".(join ':', @times)); rename("/var/lib/rrd/host_$ip.rrd","/var/lib/rrd/host_$ip.bad") if(RRDs::error); print RRDs::error . "\n" if (RRDs::error); } } } sleep(60-time%60); } }