#!/usr/bin/env perl #IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html package xCAT_monitoring::rrdutil; use strict; use IO::Socket; BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; } #Modules to use: use lib "$::XCATROOT/lib/perl"; use xCAT::Utils; ################################################ #sub start_RRD_server #Description: # FOR AIX: # add "rrdsrv $port/tcp #RRD server" to /etc/services # add "rrdsrv stream tcp no wait root /usr/bin/rrdtool rrdtool - $dir" # to /etc/inetd.conf # restart inetd # FOR LINUX: # add rrdsrv to xinetd # restart xinetd #Input: # $port Port number of RRD server, # $dir directory to save *.rrd #return: # 0 success # !0 fail ################################################ sub start_RRD_server { my ($port, $dir) = @_; if(xCAT::Utils->isAIX()){ my $cmd = undef; my @old = (); my @new = (); my $offset = 0; my $found = 0; @old = xCAT::Utils->runcmd("cat /etc/services", -2); push @new, "rrdsrv $port/tcp #RRD server"; foreach (@old) { if ($_ =~ /rrdsrv/){ if(!$found){ splice(@old, $offset, 1, @new); $found = 1; } else { splice(@old, $offset, 1); } } else { $offset++; } } if(!$found){ push @old, @new; } open FILE, ">/etc/services.new" or return -1; foreach (@old){ print FILE "$_\n" or return -1; } close FILE or return -1; $cmd = "mv -f /etc/services.new /etc/services"; xCAT::Utils->runcmd($cmd, -2); if(! -d $dir){ $cmd = "mkdir -p $dir"; xCAT::Utils->runcmd($cmd, -2); } else { $cmd = "rm -rf $dir/*"; xCAT::Utils->runcmd($cmd, -2); } @old = (); @new = (); @old = xCAT::Utils->runcmd("cat /etc/inetd.conf", -2); $offset = 0; $found = 0; push @new, "rrdsrv stream tcp nowait root /usr/bin/rrdtool rrdtool - $dir"; foreach (@old) { if ($_ =~ /rrdsrv/){ if(!$found){ splice(@old, $offset, 1, @new); $found = 1; } else { splice(@old, $offset, 1); } } else { $offset++; } } if(!$found){ push @old, @new; } open FILE, ">/etc/inetd.conf.new" or return -1; foreach (@old){ print FILE "$_\n" or return -1; } close FILE or return -1; xCAT::Utils->runcmd("mv -f /etc/inetd.conf.new /etc/inetd.conf", -2); xCAT::Utils->runcmd("stopsrc -s inetd", 0); xCAT::Utils->runcmd("startsrc -s inetd", 0); } elsif (xCAT::Utils->isLinux()){ if(-e "/etc/xinetd.d/rrdsrv"){ xCAT::Utils->runcmd("mv -f /etc/xinetd.d/rrdsrv /etc/xinetd.d/.rrdsrv.xcatbak",0) } open FILE, ">/etc/xinetd.d/rrdsrv" or return -1; print FILE "# This is the configuration for the tcp/stream rrdsrv service.\n\n"; print FILE "service rrdsrv\n"; print FILE "{\n"; print FILE "\tdisable = no\n"; print FILE "\tport = 13900\n"; print FILE "\ttype = UNLISTED\n"; print FILE "\twait = no\n"; print FILE "\tsocket_type = stream\n"; print FILE "\tprotocol = tcp\n"; print FILE "\tuser = root\n"; print FILE "\tserver = /usr/bin/rrdtool\n"; print FILE "\tserver_args = - /var/rrd\n"; print FILE "}\n"; close FILE; #xCAT::Utils->runcmd("service xinetd restart", 0); xCAT::Utils->restartservice("xinetd"); } return 0; } ################################################ #sub stop_RRD_server #Description: # FOR AIX: # remove "rrdsrv $port/tcp #RRD server" from /etc/services # remove "rrdsrv stream tcp no wait root /usr/bin/rrdtool rrdtool - $dir" # from /etc/inetd.conf # restart inetd # FOR LINUX: # remove from xinetd # restart xinetd #Input: # None #return: # 0 success # !0 fail ################################################ sub stop_RRD_server { if(xCAT::Utils->isAIX()){ my @old = (); my $offset = 0; @old = xCAT::Utils->runcmd("cat /etc/services", -2); foreach (@old) { if ($_ =~ /rrdsrv/){ splice(@old, $offset, 1); } else { $offset++; } } open FILE, ">/etc/services.new" or return -1; foreach (@old){ print FILE "$_\n" or return -1; } close FILE or return -1; xCAT::Utils->runcmd("mv -f /etc/services.new /etc/services", -1); @old = (); @old = xCAT::Utils->runcmd("cat /etc/inetd.conf", -1); $offset = 0; foreach (@old) { if ($_ =~ /rrdsrv/){ splice(@old, $offset, 1); } else { $offset++; } } open FILE, ">/etc/inetd.conf.new" or return -1; foreach (@old){ print FILE "$_\n" or return -1; } close FILE or return -1; xCAT::Utils->runcmd("mv -f /etc/inetd.conf.new /etc/inetd.conf", -2); xCAT::Utils->runcmd("stopsrc -s inetd", 0); xCAT::Utils->runcmd("startsrc -s inetd", 0); } elsif (xCAT::Utils->isLinux()){ if(-e "/etc/xinetd.d/.rrdsrv.xcatbak"){ xCAT::Utils->runcmd("mv -f /etc/xinetd.d/.rrdsrv.xcatbak /etc/xinetd.d/rrdsrv", 0); } else { xCAT::Utils->runcmd("rm -f /etc/xinetd.d/rrdsrv", 0); } #xCAT::Utils->runcmd("service xinetd restart", 0); xCAT::Utils->restartservice("xinetd"); } return 0; } ################################################ #sub runrrdcmd_remote #Description: # Run the given RRD cmd on remote RRD server, # and return the output in an array. #Input: # $cmd RRD command # $host IP or hostname of RRD server # $port Port number of RRD server, #return: # output of command ################################################ sub runrrdcmd_remote { my($cmd, $host, $port) = @_; my $socket = IO::Socket::INET->new (PeerAddr=>$host, PeerPort=>$port, Proto=>'tcp', Type=>SOCK_STREAM); if(! $socket){ print "ERROR: to connect with $host:$port\n"; return -1; } print $socket "$cmd\n"; my $output = []; my $line = undef; while($line = <$socket>){ push @$output, $line; if($line =~ /(OK|ERROR)/){ last; } } print $socket "quit"; close($socket); return $output; } ################################################ #sub RRD_create #Description: # RRD_create will overwrite a RRdb if it already exists, #Input: # $rrd filename of RRD to create # $sum if $sum != 0 to create a database file for SUMMARY information # $step the base interval in seconds with which data will be fed into the RRD # $start_time the time in seconds when the first value should be added to the RRD # $ds_type ds-name:GAUGE | COUNTER | DERIVE | ABSOLUTE # $data_source the IP or hostname of remote host #return: # 0 sucess # !0 fail ################################################ sub RRD_create { my ($rrd, $sum, $step, $start_time, $ds_type, $data_source) = @_; my $output = []; my $heartbeat = 8 * $step; my $cmd = "create $rrd --start $start_time --step $step DS:sum:$ds_type:$heartbeat:U:U"; if($sum){ $cmd = $cmd." DS:num:$ds_type:$heartbeat:U:U"; } #TODO: Specified custom RR archives here? $cmd = $cmd." RRA:AVERAGE:0.5:1:244 RRA:AVERAGE:0.5:24:244 RRA:AVERAGE:0.5:168:244 RRA:AVERAGE:0.5:672:244 RRA:AVERAGE:0.5:5760:374"; if(defined($data_source)){ $output = &runrrdcmd_remote($cmd, $data_source, 13900); } else { @$output = xCAT::Utils->runcmd("rrdtool $cmd", 0); } my $line = pop(@$output); if($line =~ /ERROR/){ return -1; } else { return 0; } } ################################################ #sub RRD_update #Description: # RRD_update #Input: # $rrd filename of RRD to update # $sum sum of all numeric metrics # $num number of all numeric metrics, should be null for a host metrics # $process_time update time # $data_source the IP or hostname of remote host #return: # 0 sucess # !0 fail ################################################ sub RRD_update { my ($rrd, $sum, $num, $process_time, $data_source) = @_; my $output = []; my $cmd = "update $rrd"; if($num ne "null"){ $cmd = $cmd." $process_time:$sum:$num"; } else { $cmd = $cmd." $process_time:$sum"; } if(defined($data_source)){ $output = &runrrdcmd_remote($cmd, $data_source, 13900); } else { @$output = xCAT::Utils->runcmd("rrdtool $cmd", 0); } my $line = pop(@$output); if($line =~ /ERROR/){ return -1; } else { return 0; } return 0; } ################################################ #sub RRD_fetch #Description: # RRD_fetch #Input: # $rrd filename of RRD to update # $start_time start of time series # $end_time end of time series # $data_source the IP or hostname of remote host #return: # 0 sucess # !0 fail ################################################ sub RRD_fetch { my ($rrd, $start_time, $end_time, $data_source) = @_; my $output = []; my $resolution = undef; my $cmd = undef; $cmd = "fetch $rrd AVERAGE -s $start_time -e $end_time"; if(defined($data_source)){ $output = &runrrdcmd_remote($cmd, $data_source, 13900); } else { @$output = xCAT::Utils->runcmd("rrdtool $cmd", 0); } return $output; } ################################################ #sub push_data_to_rrd #Description: # push_data_to_rrd #Input: # $rrd filename of RRD to update # $sum sum of all numeric metrics # $num number of all numeric metrics, should be null for a host metrics # $step the base interval in seconds with which data will be fed into the RRD # $process_time update time # $ds_type ds-name:GAUGE | COUNTER | DERIVE | ABSOLUTE # $data_source the IP or hostname of remote host #return: # 0 sucess # !0 fail ################################################ sub push_data_to_rrd { my $ret = 0; my($rrd, $sum, $num, $step, $process_time, $ds_type, $data_source) = @_; my $summary = $num eq 'null' ? 0 : 1; if(! -f $rrd){ $ret = RRD_create($rrd, $summary, $step, $process_time-$step, $ds_type, $data_source); if($ret != 0){ return $ret; } } $ret = RRD_update($rrd, $sum, $num, $process_time, $data_source); return $ret; } 1;