# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html #------------------------------------------------------- =head 1 xCAT plugin package to handle webrun command =cut #------------------------------------------------------- package xCAT_plugin::web; use strict; require xCAT::Utils; require xCAT::MsgUtils; use Getopt::Long; use Data::Dumper; use LWP::Simple; use xCAT::Table; use xCAT::NodeRange; sub handled_commands { return { webrun => "web",}; } #sub preprocess_request #{ #} sub process_request { my $request = shift; my $callback = shift; my $sub_req = shift; my %authorized_cmds = ( #command => function 'pping' => \&web_pping, 'update'=> \&web_update, 'chtab'=> \&web_chtab, 'lscondition'=> \&web_lscond, 'lsresponse'=> \&web_lsresp, 'lscondresp' => \&web_lscondresp, 'mkcondresp' => \&web_mkcondresp, 'startcondresp' => \&web_startcondresp, 'stopcondresp' => \&web_stopcondresp, 'lsrsrc' => \&web_lsrsrc, 'lsrsrcdef-api' => \&web_lsrsrcdef, 'gettab' => \&web_gettab, 'lsevent' => \&web_lsevent, 'lsdef' => \&web_lsdef, 'unlock' => \&web_unlock, 'rmcstart' => \&web_rmcmonStart, 'rmcshow' => \&web_rmcmonShow, #'xdsh' => \&web_xdsh, #THIS list needs to be updated ); #to check whether the request is authorized or not split ' ', $request->{arg}->[0]; my $cmd = $_[0]; if(grep { $_ eq $cmd } keys %authorized_cmds) { my $func = $authorized_cmds{$cmd}; $func->($request, $callback, $sub_req); } else { $callback->({error=>"$cmd is not authorizied!\n",errorcode=>[1]}); } } sub web_lsdef { my ($request, $callback, $sub_req) = @_; print Dumper($request); #TODO: web_lsdef works only for "lsdef -i nodetype" my $ret = `$request->{arg}->[0]`; my @lines = split '\n', $ret; split '=', $lines[2]; my $ntype = $_[1]; $callback->({data=>"$ntype"}); } sub web_lsevent { my ($request, $callback, $sub_req) = @_; my @ret = `$request->{arg}->[0]`; #print Dumper(\@ret); #please refer the manpage for the output format of "lsevent" my %data = (); my %record = (); my $i = 0; my $j = 0; foreach my $item (@ret) { if($item ne "\n") { chomp $item; my ($key, $value) = split("=", $item); $record{$key} = $value; $j ++; if($j == 3) { $i++; $j = 0; while (my ($k, $v) = each %record) { $data{$i}{$k} = $v; } %record = (); } } } #print Dumper(\%data); while (my ($key, $value) = each %data) { $callback->({data => $value}); } } sub web_lsrsrcdef { my ($request, $callback, $sub_req) = @_; my $ret = `$request->{arg}->[0]`; my @lines = split '\n', $ret; shift @lines; print Dumper(\@lines); my $data = join("=", @lines); $callback->({data=>"$data"}); } sub web_lsrsrc { my ($request, $callback, $sub_req) = @_; my $ret = `$request->{arg}->[0]`; my @classes; my @lines = split '\n', $ret; shift @lines; foreach my $line(@lines) { my $index = index($line, '"', 1); push @classes, substr($line, 1, $index-1); } my $data = join("=",@classes); $callback->({data=>"$data"}); } sub web_mkcondresp { my ($request, $callback, $sub_req) = @_; print Dumper($request->{arg}->[0]);#debug my $ret = system($request->{arg}->[0]); #there's no output for "mkcondresp" #TODO if($ret) { #failed } } sub web_startcondresp { my ($request, $callback, $sub_req) = @_; print Dumper($request->{arg}->[0]);#debug my $ret = system($request->{arg}->[0]); if($ret) { #to handle the failure } } sub web_stopcondresp { my ($request, $callback, $sub_req) = @_; print Dumper($request->{arg}->[0]);#debug my $ret = system($request->{arg}->[0]); if($ret) { #to handle the failure } } sub web_lscond { my ($request, $callback, $sub_req) = @_; my $ret = `lscondition`; my @lines = split '\n', $ret; shift @lines; shift @lines; foreach my $line (@lines) { $callback->({data=>$line}); } } sub web_lsresp { my ($request, $callback, $sub_req) = @_; my $ret = `lsresponse`; my @resps; my @lines = split '\n', $ret; shift @lines; shift @lines; foreach my $line (@lines) { $callback->({data=>$line}); } } sub web_lscondresp { my ($request, $callback, $sub_req) = @_; my @ret = `lscondresp`; shift @ret; shift @ret; foreach my $line (@ret) { chomp $line; $callback->({data=>$line}); } } # currently, web_chtab only handle chtab for the table "monitoring" sub web_chtab { my ($request, $callback, $sub_req) = @_; split ' ', $request->{arg}->[0]; my $tmp_str = $_[2]; split '\.', $tmp_str; my $table = $_[0]; #get the table name if($table == "monitoring") { system("$request->{arg}->[0]"); }else { $callback->({error=>"the table $table is not authorized!\n",errorcode=>[1]}); } } sub web_gettab { #right now, gettab only support the monitoring table my ($request, $callback, $sub_req) = @_; split ' ', $request->{arg}->[0]; my $tmp_str = $_[2]; split '\.', $tmp_str; my $table = $_[0]; if($table == "monitoring") { my $val = `$request->{arg}->[0]`; chomp $val; $callback->({data=>$val}); }else { $callback->( {error=>"The table $table is not authorized to get!\n", errorcode=>[1]}); } } sub web_pping { my ($request, $callback, $sub_req) = @_; #treat the argument as the commandline, run it and get the return message my $ret = `$request->{arg}->[0]`; #parse the message, and use $callback to send back to the web interface #the message is like this: # xcat_n02: ping # xcat_n03: ping # xcat_n51: ping # xcat_n52: noping my @total_stat = split '\n', $ret; my $str; foreach $str(@total_stat) { #TODO split ':', $str; $callback->({node=>[{name=>[$_[0]],data=>[{contents=>[$_[1]]}]}]}); } } #------------------------------------------------------- =head3 web_update Description : Update the xCAT associate RPM on manangement node Arguments : RPM Name Repository address Returns : Nothing =cut #------------------------------------------------------- sub web_update { my ($request, $callback, $sub_req) = @_; my $os = "unknow"; my $RpmNames = $request->{arg}->[1]; my $repository = $request->{arg}->[2]; my $FileHandle; my $cmd; my $ReturnInfo; my $WebpageContent = undef; my $RemoteRpmFilePath = undef; my $LocalRpmFilePath = undef; my @temp = undef; if (xCAT::Utils->isLinux()) { $os = xCAT::Utils->osver(); #suse linux if ($os =~ /sles.*/) { $RpmNames =~ s/,/ /g; #create zypper command $cmd = "zypper -t package -r " . $repository . $RpmNames; } #redhat else { #check the yum config file, and delect it if exist. if (-e "/tmp/xCAT_update.yum.conf") { unlink("/tmp/xCAT_update.yum.conf"); } #create file, return error if failed. unless ( open ($FileHandle, '>>', "/tmp/xCAT_update.yum.conf")) { $callback->({error=>"Create temp file eror!\n",errorcode=>[1]}); return; } #write the rpm path into config file. print $FileHandle "[xcat_temp_update]\n"; print $FileHandle "name=temp prepository\n"; $repository = "baseurl=" . $repository . "\n"; print $FileHandle $repository; print $FileHandle "enabled=1\n"; print $FileHandle "gpgcheck=0\n"; close($FileHandle); #use system to run the cmd "yum -y -c config-file update rpm-names" $RpmNames =~ s/,/ /g; $cmd = "yum -y -c /tmp/xCAT_update.yum.conf update " . $RpmNames . " 2>&1"; } #run the command and return the result $ReturnInfo = readpipe($cmd); @temp = split(/\n/, $ReturnInfo); $callback->({info=>$temp[-1]}); } #AIX else { #open the rpmpath(may be error), and read the page's content $WebpageContent = LWP::Simple::get($repository); unless (defined($WebpageContent)) { $callback->({error=>"open $repository error, please check!!", errorcode=>[1]}); return; } #must support for updating several rpms. foreach (split (/,/, $RpmNames)) { #find out rpms' corresponding rpm href on the web page $WebpageContent =~ m/href="($_-.*?[ppc64|noarch].rpm)/i; unless(defined($1)) { next; } $RemoteRpmFilePath = $repository . $1; $LocalRpmFilePath = '/tmp/' . $1; #download rpm package to temp unless(-e $LocalRpmFilePath) { $cmd = "wget -O " . $LocalRpmFilePath . " " . $RemoteRpmFilePath; if(0 != system($cmd)) { $ReturnInfo = $ReturnInfo . "update " . $_ . " failed: can not download the rpm\n"; $callback->({error=>$ReturnInfo, errorcode=>[1]}); return; } } #update rpm by rpm packages. $cmd = "rpm -U " . $LocalRpmFilePath . " 2>&1"; $ReturnInfo = $ReturnInfo . readpipe($cmd); } $callback->({info=>$ReturnInfo}); } } #------------------------------------------------------- =head3 web_unlock Description : Unlock a node by setting up the SSH keys Arguments : Node Password Returns : Nothing =cut #------------------------------------------------------- sub web_unlock { my ( $request, $callback, $sub_req ) = @_; my $node = $request->{arg}->[1]; my $password = $request->{arg}->[2]; my $out = `DSH_REMOTE_PASSWORD=$password xdsh $node -K`; $callback->( { data => $out } ); } #------------------------------------------------------- =head3 web_rmcStart Description : Start the RMC monitoring on management node Arguments : Nothing Returns : Nothing =cut #------------------------------------------------------- sub web_rmcmonStart{ my ( $request, $callback, $sub_req ) = @_; my $nodeRange = $request->{arg}->[1]; my $table; my $retData = ""; my $output; #check the running status $table = xCAT::Table->new('monitoring'); my $rmcWorkingStatus = $table->getAttribs({name => 'rmcmon'}, 'disable'); $table.close(); #the rmc monitoring is running so return directly if($rmcWorkingStatus){ if ($rmcWorkingStatus->{disable} =~ /0|No|no|NO|N|n/){ $callback->({info=>'RMC Monitoring is running now.'}); return; } } $retData .= "RMC is not running, start it now.\n"; #check the monsetting table rmc's montype contains "performance" $table = xCAT::Table->new('monsetting'); my $rmcmonType = $table->getAttribs({name=>'rmcmon', key=>'montype'}, 'value'); $table.close(); #the rmc monitoring is not configure right we should configure it again #there is no rmcmon in monsetting table if (!$rmcmonType){ $output = xCAT::Utils->runcmd('monadd rmcmon -s [montype=perf]', -1, 1); foreach (@$output){ $retData .= ($_ . "\n"); }; $retData .= "Add the rmcmon to monsetting table complete.\n"; } #configure before but there is not performance monitoring, so change the table else { if (!($rmcmonType->{value} =~ /perf/)){ $output = xCAT::Utils->runcmd('chtab name=rmcmon,key=montype monsetting.value=perf', -1, 1); foreach (@$output){ $retData .= ($_ . "\n"); }; $retData .= "Change the rmcmon configure in monsetting table finish.\n"; } } #run the rmccfg command to add all nodes into local RMC configuration $output = xCAT::Utils->runcmd("moncfg rmcmon $nodeRange", -1, 1); foreach (@$output){ $retData .= ($_ . "\n"); }; #run the rmccfg command to add all nodes into remote RMC configuration $output = xCAT::Utils->runcmd("moncfg rmcmon $nodeRange -r", -1, 1); foreach (@$output){ $retData .= ($_ . "\n"); }; #check the monfiguration #use lsrsrc -a IBM.Host Name. compare the command's return and the noderange, then decide witch node should be refrsrc #start the rmc monitor $output = xCAT::Utils->runcmd("monstart rmcmon", -1, 1); foreach (@$output){ $retData .= ($_ . "\n"); }; $callback->({info=>$retData}); return; #configure the rmc monitoring } sub web_rmcmonShow(){ my ( $request, $callback, $sub_req ) = @_; my $nodeRange = $request->{arg}->[1]; my @nodes; my $retInfo; my $retHash = {}; my $output; my @activeNodes; my @rmcNodes; my $tempNodes; my $temp = ""; #only get the system rmc info #like this PctTotalTimeIdle=>"10.0000, 20.0000, 12.0000, 30.0000" if ('summary' eq $nodeRange){ $output = xCAT::Utils->runcmd("monshow rmcmon -s -t 10 -a PctTotalTimeIdle,PctTotalTimeWait,PctTotalTimeUser,PctTotalTimeKernel,PctRealMemFree", -1, 1); foreach $temp (@$output){ #the attribute name if ($temp =~ /Pct/){ $temp =~ s/ //g; #the first one if ("" eq $retInfo){ $retInfo .= ($temp . ':'); } else{ $retInfo =~ s/,$/;/; $retInfo .= ($temp . ':'); } next; } #the content of the attribute $temp =~ m/\s+(\d+\.\d{4})/; if (defined($1)){ $retInfo .= ($1 . ','); } } #return the rmc info $retInfo =~ s/,$//; $callback->({info=>$retInfo}); return; } if ('lpar' eq $nodeRange){ #get nodes detail containt @nodes = xCAT::NodeRange::noderange($nodeRange); if ((@nodes)&& (@nodes > 0)) { #get all the active nodes $temp= join(' ', @nodes); $output =`fping -a $temp 2> /dev/null`; chomp($output); @activeNodes = split(/\n/, $output); #get all the inactive nodes by substracting the active nodes from all. my %temp2; foreach(@activeNodes) { $temp2{$_}=1; } foreach(@nodes) { if (!$temp2{$_}) { push(@{$retHash->{node}},{name=>$_, data=>'NA'}); } } } if (@activeNodes < 1){ $callback->($retHash); return; } $tempNodes = join(',', @activeNodes); $output = xCAT::Utils->runcmd("xdsh $tempNodes rpm -q rsct.core", -1, 1); #non-installed foreach(@$output){ my @temp = split(/:/, $_); if(@temp[1] =~ /not installed/){ push(@{$retHash->{node}},{name=>@temp[0], data=>'NI'}); } else{ push(@rmcNodes, @temp[0]); } } #there are not rmc nodes, so we should return directly if (@rmcNodes < 1){ $callback->($retHash); return; } $tempNodes = join(',', @rmcNodes); $output = xCAT::Utils->runcmd("xdsh $tempNodes \"/bin/ps -ef | /bin/grep rmcd | /bin/grep -v grep\" | /bin/awk '{print \$1\$9}'", -1, 1); foreach(@$output){ my @temp = split(/:/, $_); if(@temp[1] =~ /rmcd/){ push(@{$retHash->{node}},{name=>@temp[0], data=>'OK'}); } #not running else{ push(@{$retHash->{node}},{name=>@temp[0], data=>'NR'}); } } $callback->($retHash); return; } my $attrName = ""; my @attrValue = (); $output = xCAT::Utils->runcmd("monshow rmcmon $nodeRange -t 60 -a PctTotalTimeIdle,PctTotalTimeWait,PctTotalTimeUser,PctTotalTimeKernel,PctRealMemFree", -1, 1); foreach(@$output){ $temp = $_; if ($temp =~ /\t/){ $temp =~ s/\t/ /g; chomp($temp); } #the attribute name if ($temp =~ m/\s+(Pct.*)\s+/){ $temp = $1; #the first one if ("" ne $attrName){ push(@{$retHash->{node}}, {name=>$attrName, data=>join(',', @attrValue)}); $attrName = ""; @attrValue = (); } $attrName = $temp; next; } #the content of the attribute $temp =~ m/\s+(\d+\.\d{4})\s*$/; if (defined($1)){ push(@attrValue, $1); } } #push the last attribute name and values. push(@{$retHash->{node}}, {name=>$attrName, data=>join(',', @attrValue)}); $callback->($retHash); }