#!/usr/bin/env perl # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html package xCAT_monitoring::rmcmetrix; #Modules to use: #use threads; #use threads::shared; BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; } use lib "$::XCATROOT/lib/perl"; use xCAT::Table; use xCAT::Utils; use xCAT_monitoring::rrdutil; 1; #metrix{Attr}{NodeNameList}{Name} = value #NodeNameList could be NodeNameList | summary | number #Attr could be Attribute | summary | number %metrix={}; ###################################### #sub print_metrix #Description: # to print all content of %metrix, for debug #Input: # None #Return: # None ##################################### sub print_metrix { my $key1; my $key2; my $key3; my $value; while(($key1, $key2) = each %metrix){ if(! exists($metrix{$key1}{$key2})){ print "$key1=>$key2\n"; next; } while(($key2, $key3) = each %{$metrix{$key1}}){ if(! exists($metrix{$key1}{$key2}{$key3})){ print "$key1.$key2=>$key3\n"; } while(($key3, $value) = each %{$metrix{$key1}{$key2}}){ print "$key1.$key2.$key3=>$value\n"; } } } } ####################################### #sub update_metrix2rrd #Description: # update RRDtool database based on content of %metrix, # all statistic be stored as GAUGE in RRDtool, #Input: # $step the base interval in seconds with which data will be fed into the RRD #Return: # None ##################################### sub update_metrix2rrd { my $step = shift @_; my $ret = 0; my $attr; my $nnlist; my $name; my $value; my $rmcrrdroot = "/var/rrd"; my $rrddir = undef; my $rrd = undef; my $process_time = xCAT::Utils->runcmd("date +%s", 0); $process_time = (int $process_time/$step)*$step; my $temp = undef; while(($attr, $nnlist) = each %metrix){ while(($nnlist, $name) = each %{$metrix{$attr}}){ if($nnlist eq 'number'){ next; } $rrddir = "$rmcrrdroot/$nnlist"; if(! -d $rrddir){ xCAT::Utils->runcmd("mkdir -p $rrddir"); } if($nnlist eq 'summary'){ $rrd = "$rrddir/"."$attr.rrd"; $temp = $metrix{$attr}{summary}/$metrix{$attr}{number}; $ret = xCAT_monitoring::rrdutil::push_data_to_rrd($rrd, $temp, $metrix{$attr}{number}, $step, $process_time, 'GAUGE'); if($ret != 0){ return ($ret, "Can't push data to $rrd\n"); } } else { while(($name, $value) = each %{$metrix{$attr}{$nnlist}}){ if($name eq 'number'){ next; } if($name eq 'summary'){ $rrd = "$rrddir/$attr.rrd"; $temp = $metrix{$attr}{$nnlist}{summary}/$metrix{$attr}{$nnlist}{number}; $ret = xCAT_monitoring::rrdutil::push_data_to_rrd($rrd, $temp, $metrix{$attr}{$nnlist}{number}, $step, $process_time, 'GAUGE'); if($ret != 0){ return($ret, "Can't push data to $rrd\n"); } } else { $rrd = "$rrddir/$attr"."_$name.rrd"; xCAT_monitoring::rrdutil::push_data_to_rrd($rrd, $metrix{$attr}{$nnlist}{$name}, 'null', $step, $process_time, 'GAUGE'); if($ret != 0){ return($ret, "Can't push data to $rrd\n"); } } } } } } return (0, "Success"); } ###################################### #sub parse_lsrsrc_output #Description: # parse the output of lsrsrc and store the information to %metrix #Input: # resource class # array of attributes # array of output of lsrsrc command #Return: # 0 Success # !0 Fail ##################################### sub parse_lsrsrc_output { my ($rsrc, $pattr, $output) = @_; my $nnlist = undef; my $name = undef; my $line = undef; my $attr = undef; my @value = (); my $i = undef; my %count = {}; foreach $line (@$output){ if ($line =~ /^ERROR/) { next;} #skip the lines with error @value = split /::/, $line; $name = $value[0]; $name =~ s/[^A-Za-z0-9]+/'.'/; if($name eq ''){ $name = 'null'; } $value[1] =~ /{(\w+)}/; $nnlist = $1; $i = 2; foreach $attr (@$pattr){ if($rsrc eq 'IBM.Processor'){ $metrix{$attr}{$nnlist}{$name} += $value[$i]; } else { $metrix{$attr}{$nnlist}{$name} = $value[$i]; } $metrix{$attr}{$nnlist}{summary} += $value[$i]; $metrix{$attr}{$nnlist}{number} += 1; $i++; } if($rsrc eq 'IBM.Processor'){ $count{$nnlist}{$name} += 1; } } if($rsrc eq 'IBM.Processor'){ foreach $nnlist (keys %count){ foreach $name (keys %{$count{$nnlist}}){ if ($count{$nnlist}{$name} > 1) { foreach $attr (@$pattr){ $metrix{$attr}{$nnlist}{$name} /= $count{$nnlist}{$name}; } } } } } return 0; } ###################################### #sub getmetrix #Description: # Get %metrix using lsrsrc-api, and store to RRD #Input: # $rsrc the resource class of RMC, such as "IBM.EthernetDevice" # $rname the resource name of resouce class, if ($rname eq "__ALL__") then all # resource name will be monitoring # $attrlist the list of attributes of the monitoring resource # $minute the interval to collect data in minute #Return: # 0 Success # !0 Fail ##################################### sub getmetrix { my ($rsrc, $rname, $attrlist, $minute) = @_; my @attrs = (); my $attr = undef; my $nnlist = undef; my @names = (); my $name = undef; my @output = (); my $rrd = undef; my $line = undef; my $ret = 0; my $msg = undef; my $cmd = undef; @attrs = split /,/, $attrlist; $attr = join '::', @attrs; # if(xCAT::Utils->isMN()){ # if($rname eq "__ALL__"){ # $cmd = "CT_MANAGEMENT_SCOPE=1 lsrsrc-api -i -s $rsrc"."::::Name::NodeNameList::$attr"; # @output = xCAT::Utils->runcmd($cmd, 0); # if($::RUNCMD_RC != 0){ # $line = join '', @output; # return ($::RUNCMD_RC, $line); # } # &parse_lsrsrc_output($rsrc, \@attrs, \@output); # } else { # @names = split /,/, $rname; # foreach $name (@names){ # $cmd = "CT_MANAGEMENT_SCOPE=1 lsrsrc-api -i -s $rsrc"."::\'Name==\"$name\"\'::Name::NodeNameList::$attr"; # @output = xCAT::Utils->runcmd($cmd, 0); # if($::RUNCMD_RC != 0){ # $line = join '', @output; # return ($::RUNCMD_RC, $line); # } # &parse_lsrsrc_output($rsrc, \@attrs, \@output); # } # } # } if($rname eq "__ALL__"){ $cmd = "CT_MANAGEMENT_SCOPE=3 lsrsrc-api -i -s $rsrc"."::::Name::NodeNameList::$attr"; @output = xCAT::Utils->runcmd($cmd, -1); #if($::RUNCMD_RC != 0){ # $line = join '', @output; # return ($::RUNCMD_RC, $line); #} #print "+++++ rsrc=$rsrc\nattrs=@attrs\noutput=@output\n"; &parse_lsrsrc_output($rsrc, \@attrs, \@output); } else { @names = split /,/, $rname; foreach $name (@names){ $cmd = "CT_MANAGEMENT_SCOPE=3 lsrsrc-api -i -s $rsrc"."::\'Name==\"$name\"\'::Name::NodeNameList::$attr"; @output = xCAT::Utils->runcmd($cmd, -1); #if($::RUNCMD_RC){ # $line = join '', @output; # return ($::RUNCMD_RC, $line); #} #print "--- rsrc=$rsrc\nattrs=@attrs\noutput=@output\n"; &parse_lsrsrc_output($rsrc, \@attrs, \@output); } } foreach $attr (keys %metrix){ foreach $nnlist (keys %{$metrix{$attr}}){ if(($nnlist ne 'summary') && ($nnlist ne 'number')){ $metrix{$attr}{summary} += $metrix{$attr}{$nnlist}{summary}; $metrix{$attr}{number} += $metrix{$attr}{$nnlist}{number}; } } } my $step = $minute * 60; ($ret, $msg) = &update_metrix2rrd($step); return ($ret, $msg); } ###################################### #sub get_metrix_conf #Description: # Get configure for table monsetting, and return an array #Input: # None; #Return: # an array of configuration (rsrc0, attrlist0, minute0, rsrc1, attrlist1,minute1, ...) ##################################### sub get_metrix_conf { my @conf = (); my @tmp = (); my $rsrc = undef; my $namelist = undef; my $attrlist = undef; my $minute = undef; my $key = undef; my $value = undef; my $conftable = xCAT::Table->new('monsetting'); if($conftable){ @tmp = $conftable->getAttribs({'name'=>'rmcmon'}, ('key','value')); foreach (@tmp) { $key = $_->{key}; $value = $_->{value}; if($key =~ /^rmetrics_(\S+)/){ push @conf, $1; if($value =~ /\]/){ ($namelist, $value) = split /\]/, $value; $namelist =~ s/\[//; } else { $namelist = "__ALL__"; } push @conf, $namelist; ($attrlist, $minute) = split /:/, $value; push @conf, $attrlist; push @conf, $minute; } } $conftable->close; } return @conf; } ###################################### #sub get_sum_metrix #Description: # Consolidates data collected by SNs and MN and stores to local RRD #Input: # $attrlist the list of attributes of the monitoring resource #Return: # 0 Success # !0 Fail ##################################### sub get_sum_metrix { my $code = undef; my $msg = undef; my ($attrlist, $minute) = @_; my $result = undef; my @rmc_nodes = (); my @svc_nodes = (); my $node = undef; my $temp = undef; # my @threads = (); # my $current_thread = 0; my $i = undef; # my %summary:shared; #summary{$attr}{$node} my %summary = {}; my @attributes = (); my $attribute = undef; my $nodename = undef; my $time = undef; # my $end:shared; my %summetrix = {}; my $end = undef; $end = xCAT::Utils->runcmd("date +%s", 0); # my $step:shared; my $step = undef; $step = $minute * 60; #to share %summary @attributes = split /,/, $attrlist; # foreach $attribute (@attributes){ # $summary{$attribute} = &share({}); # } $result = `lsrsrc-api -s IBM.MngNode::::Name 2>&1`; chomp($result); @rmc_nodes=split(/\n/, $result); foreach $node (@rmc_nodes){ if(xCAT::Utils->isSN($node)){ push @svc_nodes, $node; } } $node = `hostname`; chomp($node); push @svc_nodes, $node; foreach $node (@svc_nodes){ # $threads[$current_thread] = threads->new(\&getsum, $attrlist, $node); # $current_thread++; &getsum($attrlist, $node); } sub getsum{ my ($attrs, $n) = @_; my @attr = split /,/,$attrs; my $a = undef; my $start = undef; my $result = undef; my $timestamp = undef; my $sum = undef; my $num = undef; my $localhost = `hostname`; chomp($localhost); foreach $a (@attr){ if(-f "/var/rrd/cluster/$a.rrd"){ $start = `rrdtool last /var/rrd/cluster/$a.rrd`; chomp($start); } else { $start = ((int $end/$step) - 244)*$step; } if($n eq $localhost){ $result = xCAT_monitoring::rrdutil::RRD_fetch("/var/rrd/summary/$a.rrd",$start, $end); } else { $result = xCAT_monitoring::rrdutil::RRD_fetch("summary/$a.rrd",$start, $end, $n); } my $line = pop(@$result); if($line =~ /ERROR/){ return (-1, $line); } else { push @$result, $line; } # $summary{$a}{$n} = &share({}); foreach $line (@$result){ if($line =~ /[NaNQ|nan]/){ next; } elsif ($line =~ /^(\d+): (\S+) (\S+)/){ $timestamp = $1; $sum = $2; $num = $3; # $summary{$a}{$n}{$timestamp} = &share({}); # $summary{$a}{$n}{$timestamp}{sum} = &share({}); # $summary{$a}{$n}{$timestamp}{num} = &share({}); $summetrix{$a}{$timestamp}{sum} += $sum * $num; $summetrix{$a}{$timestamp}{num} += $num; } } } return (0, 'Success'); } # for($i=0; $i<$current_thread; $i++){ # ($code, $msg) = $threads[$i]->join(); # if($code != 0){ # warn("$msg\n"); # } # } # my %summetrix = {}; # foreach $attribute (keys %summary){ # foreach $nodename (keys %{$summary{$attribute}}){ # foreach $time (keys %{$summary{$attribute}{$nodename}}){ # print "$attribute.$nodename.$time $summary{$attribute}{$nodename}{$time}{sum} $summary{$attribute}{$nodename}{$time}{num}\n"; # $temp = $summary{$attribute}{$nodename}{$time}{sum} * $summary{$attribute}{$nodename}{$time}{num}; # $summetrix{$attribute}{$time}{sum} += $temp; # $summetrix{$attribute}{$time}{num} += $summary{$attribute}{$nodename}{$time}{num}; # } # } # } my $rrdcluster = "/var/rrd/cluster"; if(! -d $rrdcluster){ system("mkdir -p $rrdcluster"); } foreach $attribute (keys %summetrix){ my @times = keys(%{$summetrix{$attribute}}); my @sorttimes = sort @times; foreach $time (@sorttimes){ $temp = $summetrix{$attribute}{$time}{sum}/$summetrix{$attribute}{$time}{num}; $code = xCAT_monitoring::rrdutil::push_data_to_rrd("$rrdcluster/$attribute.rrd", $temp, $summetrix{$attribute}{$time}{num}, $step, $time, 'GAUGE'); if($code != 0){ return($code, "Can't push data to $rrdcluster/$attribute.rrd"); } } } return (0, 'Success'); }