mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 03:12:30 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			443 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			443 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head1
 | |
|   xCAT plugin package to handle pdu 
 | |
| 
 | |
|    Supported command:
 | |
|         rpower 
 | |
|         rinv
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| package xCAT_plugin::pdu;
 | |
| 
 | |
| BEGIN {
 | |
|     $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/opt/xcat' : '/usr';
 | |
| }
 | |
| use lib "$::XCATROOT/lib/perl";
 | |
| 
 | |
| use xCAT::Table;
 | |
| use xCAT::Utils;
 | |
| use xCAT::FifoPipe;
 | |
| use xCAT::MsgUtils;
 | |
| use xCAT::State;
 | |
| use xCAT::SvrUtils;
 | |
| use xCAT::Usage;
 | |
| use xCAT::NodeRange;
 | |
| use Data::Dumper;
 | |
| use Getopt::Long;
 | |
| use File::Path;
 | |
| use Term::ANSIColor;
 | |
| use Time::Local;
 | |
| use strict;
 | |
| use Class::Struct;
 | |
| use XML::Simple;
 | |
| use Storable qw(dclone);
 | |
| use SNMP;
 | |
| 
 | |
| my $VERBOSE = 0;
 | |
| my %allerrornodes = ();
 | |
| my $callback;
 | |
| my $pdutab;
 | |
| my @pduents;
 | |
| my $pdunodes;
 | |
| 
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3  handled_commands
 | |
| 
 | |
| Return list of commands handled by this plugin
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| sub handled_commands
 | |
| {
 | |
|     return {
 | |
|        rpower => ["nodehm:mgt","pduoutlet:pdu=\.\*"],
 | |
|        rinv   => ["nodehm:mgt"],
 | |
|        nodeset => ["nodehm:mgt"],
 | |
|     };
 | |
| }
 | |
| 
 | |
| #--------------------------------------------------------------------------------
 | |
| =head3   preprocess_request
 | |
| 
 | |
| Parse the arguments and display the usage or the version string.
 | |
| 
 | |
| =cut
 | |
| #--------------------------------------------------------------------------------
 | |
| sub preprocess_request {
 | |
|     my $req = shift;
 | |
|     if ($req->{_xcatpreprocessed}->[0] == 1) { return [$req]; }
 | |
|     my $callback=shift;
 | |
|     my @requests;
 | |
| 
 | |
|     my $command = $req->{command}->[0];
 | |
|     my $noderange = $req->{node};           #Should be arrayref
 | |
|     my $extrargs = $req->{arg};
 | |
|     my @exargs=($req->{arg});
 | |
|     if (ref($extrargs)) {
 | |
|         @exargs=@$extrargs;
 | |
|     }
 | |
|     my $usage_string=xCAT::Usage->parseCommand($command, @exargs);
 | |
|     if ($usage_string) {
 | |
|         $callback->({data=>[$usage_string]});
 | |
|         $req = {};
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     if (!$noderange) {
 | |
|         $usage_string = xCAT::Usage->getUsage($command);
 | |
|         $callback->({ data => $usage_string });
 | |
|         $req = {};
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     my @result = ();
 | |
|     my $mncopy = {%$req};
 | |
|     push @result, $mncopy;
 | |
|     return \@result;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3  process_request
 | |
| 
 | |
|   Process the command.
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub process_request
 | |
| {
 | |
|     my $request  = shift;
 | |
|     my $callback = shift;
 | |
|     my $subreq   = shift;
 | |
|     my $command  = $request->{command}->[0];
 | |
|     my $noderange = $request->{node};           #Should be arrayref
 | |
|     my $extrargs  = $request->{arg};
 | |
|     my @exargs    = ($request->{arg});
 | |
| 
 | |
|     if (ref($extrargs)) {
 | |
|         @exargs = @$extrargs;
 | |
|     }
 | |
| 
 | |
|     #fill in the total outlet count for each pdu
 | |
|     $pdutab = xCAT::Table->new('pdu');
 | |
|     @pduents = $pdutab->getAllNodeAttribs(['node', 'outlet']);
 | |
|     fill_outletCount(\@pduents, $callback);
 | |
| 
 | |
|     if( $command eq "rinv") {
 | |
|         #for higher performance, handle node in batch
 | |
|         return powerstat($noderange, $callback);
 | |
|     }elsif ($command eq "rpower") {
 | |
|         my $subcmd = $exargs[0];
 | |
|         if (($subcmd eq 'pduoff') || ($subcmd eq 'pduon') || ($subcmd eq 'pdustat')|| ($subcmd eq 'pdureset') ){
 | |
|             #if one day, pdu node have pdu attribute, handle in this section too
 | |
|             return powerpduoutlet($noderange, $subcmd, $callback);
 | |
|         } else {
 | |
|             #-------------------------------------------
 | |
|             #there are 2 cases will enter this block
 | |
|             #one is if node's mgt is pdu
 | |
|             #another is if node has pdu attribute but mgt isn't pdu
 | |
|             #if the node has pdu attribute but mgt isn't pdu, 
 | |
|             #should do nothing for this node, let other plugin to hanle this node 
 | |
|             #-------------------------------------------
 | |
|             my @allpdunodes=();
 | |
|             my $nodehm = xCAT::Table->new('nodehm');
 | |
|             my $nodehmhash = $nodehm->getNodesAttribs($noderange, ['mgt']);
 | |
|             foreach my $node (@$noderange) { 
 | |
|                 if($nodehmhash->{$node}->[0]->{mgt} eq 'pdu'){
 | |
|                     push @allpdunodes, $node;
 | |
|                 }
 | |
|             }
 | |
|             if(@allpdunodes) {
 | |
|                 if(($subcmd eq 'on') || ($subcmd eq 'off') || ($subcmd eq 'stat') || ($subcmd eq 'state') || ($subcmd eq 'reset') ){
 | |
|                     return powerpdu(\@allpdunodes, $subcmd, $callback);
 | |
|                 } else {
 | |
|                     my $pdunode = join (",", @allpdunodes);
 | |
|                     $callback->({ errorcode => [1],error => "The option $subcmd is not support for pdu node(s) $pdunode."});
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }elsif($command eq "nodeset") {
 | |
|         $callback->({ errorcode => [1],error => "The input $command is not support for pdu"});
 | |
|     }else{
 | |
|         #reserve for other new command in future
 | |
|     }
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| sub fill_outletCount {
 | |
|     my $pduentries = shift;
 | |
|     my $callback = shift;
 | |
|     my $outletoid = ".1.3.6.1.4.1.2.6.223.8.2.1.0";
 | |
|     my $pdutab = xCAT::Table->new('pdu');
 | |
| 
 | |
|     foreach my $pdu (@$pduentries) {
 | |
|         my $cur_pdu = $pdu->{node};
 | |
|         my $count = $pdu->{outlet};
 | |
|         #get total outlet number for the pdu
 | |
|         if (!$count) {
 | |
|             my $session = connectTopdu($cur_pdu,$callback);
 | |
|             #will not log this error to output
 | |
|             if (!$session) {
 | |
|                 next;
 | |
|             }
 | |
|             $count = $session->get("$outletoid");
 | |
|             if ($count) {
 | |
|                 $pdutab->setNodeAttribs($cur_pdu, {outlet => $count});
 | |
|             }
 | |
|         }
 | |
|         $pdunodes->{$cur_pdu}->{outlet}=$count;
 | |
|     }
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3  powerpdu 
 | |
| 
 | |
|     Process power command (stat/off/on) for pdu/pdus
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub powerpdu {
 | |
|     my $noderange = shift;
 | |
|     my $subcmd = shift;
 | |
|     my $callback = shift;
 | |
| 
 | |
|     if (($subcmd eq "stat") || ($subcmd eq "state")){
 | |
|         return powerstat($noderange, $callback);
 | |
|     }
 | |
| 
 | |
|     foreach my $node (@$noderange) {
 | |
|         my $session = connectTopdu($node,$callback);
 | |
|         if (!$session) {
 | |
|             $callback->({ errorcode => [1],error => "Couldn't connect to $node"});
 | |
|             next;
 | |
|         }
 | |
|         my $count = $pdunodes->{$node}->{outlet};
 | |
|         my $value;
 | |
|         my $statstr;
 | |
|         if ($subcmd eq "off") {
 | |
|             $value = 0;
 | |
|             $statstr = "off";
 | |
|         } elsif ( $subcmd eq "on") {
 | |
|             $value = 1;
 | |
|             $statstr = "on";
 | |
|         } else  {
 | |
|             $value = 2;
 | |
|             $statstr = "reset";
 | |
|         }
 | |
| 
 | |
|         for (my $outlet =1; $outlet <= $count; $outlet++)
 | |
|         {
 | |
|             outletpower($session, $outlet, $value);
 | |
|             if ($session->{ErrorStr}) { 
 | |
|                 $callback->({ errorcode => [1],error => "Failed to get outlet status for $node"});
 | |
|             } else {
 | |
|                 my $output = " outlet $outlet is $statstr"; 
 | |
|                 xCAT::SvrUtils::sendmsg($output, $callback, $node, %allerrornodes);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3  powerpduoutlet 
 | |
| 
 | |
|     Process power command (pdustat/pduoff/pduon) for compute nodes,
 | |
|     the pdu attribute needs to be set 
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub powerpduoutlet {
 | |
|     my $noderange = shift;
 | |
|     my $subcmd = shift;
 | |
|     my $callback = shift;
 | |
|     my $output;
 | |
|     my $value;
 | |
|     my $statstr;
 | |
| 
 | |
|     my $oid = ".1.3.6.1.4.1.2.6.223.8.2.2.1.11";
 | |
|     my $type = "INTEGER";
 | |
|     my $tmpnodestr = join(",", @$noderange);
 | |
| 
 | |
|     my $nodetab = xCAT::Table->new('pduoutlet');
 | |
|     my $nodepdu = $nodetab->getNodesAttribs($noderange,['pdu']);
 | |
|     foreach my $node (@$noderange) {
 | |
|         # the pdu attribute needs to be set
 | |
|         if(! $nodepdu->{$node}->[0]->{pdu}){
 | |
|             $callback->({ error => "$node: without pdu attribute"});
 | |
|             next;
 | |
|         }
 | |
| 
 | |
|         my @pdus = split /,/, $nodepdu->{$node}->[0]->{pdu};
 | |
|         foreach my $pdu_outlet (@pdus) {
 | |
|             my ($pdu, $outlet) = split /:/, $pdu_outlet;
 | |
|             my $session = connectTopdu($pdu,$callback);
 | |
|             if (!$session) {
 | |
|                 $callback->({ errorcode => [1],error => "Couldn't connect to $pdu"});
 | |
|                 next;
 | |
|             }
 | |
|             if ($outlet > $pdunodes->{$pdu}->{outlet} ) {
 | |
|                 $callback->({ errorcode => [1],error => "outlet number $outlet is invalid for $pdu"});
 | |
|                 next;
 | |
|             }
 | |
|             my $cmd;
 | |
|             if ($subcmd eq "pdustat") {
 | |
|                 $statstr=outletstat($session, $outlet);
 | |
|             } elsif ($subcmd eq "pduoff") {
 | |
|                 $value = 0;
 | |
|                 $statstr = "off";
 | |
|                 outletpower($session, $outlet, $value);
 | |
|             } elsif ($subcmd eq "pduon") {
 | |
|                 $value = 1;
 | |
|                 $statstr = "on";
 | |
|                 outletpower($session, $outlet, $value);
 | |
|             } elsif ($subcmd eq "pdureset") {
 | |
|                 $value = 2;
 | |
|                 $statstr = "reset";
 | |
|                 outletpower($session, $outlet, $value);
 | |
|             } else {
 | |
|                 $callback->({ error => "$subcmd is not support"});
 | |
|             } 
 | |
|     
 | |
|             if ($session->{ErrorStr}) { 
 | |
|                 $callback->({ errorcode => [1],error => "$session->{ErrorStr} for $pdu outlet $outlet"});
 | |
|             } else {
 | |
|                 $output = "$pdu outlet $outlet is $statstr"; 
 | |
|                 xCAT::SvrUtils::sendmsg($output, $callback, $node, %allerrornodes);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3  outletpower 
 | |
| 
 | |
|     Process power command for one pdu outlet,
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub outletpower {
 | |
|     my $session = shift;
 | |
|     my $outlet = shift;
 | |
|     my $value = shift;
 | |
| 
 | |
|     my $oid = ".1.3.6.1.4.1.2.6.223.8.2.2.1.11";
 | |
|     my $type = "INTEGER";
 | |
| 
 | |
|     my $varbind = new SNMP::Varbind([ $oid, $outlet, $value, $type ]);
 | |
|     return $session->set($varbind);
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3  powerstat 
 | |
| 
 | |
|     Process command to query status of pdu
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub powerstat {
 | |
|     my $noderange = shift;
 | |
|     my $callback = shift;
 | |
|     my $output;
 | |
| 
 | |
|     foreach my $pdu (@$noderange) {
 | |
|         my $session = connectTopdu($pdu,$callback);
 | |
|         if (!$session) {
 | |
|             $callback->({ errorcode => [1],error => "Couldn't connect to $pdu"});
 | |
|             next;
 | |
|         }
 | |
|         my $count = $pdunodes->{$pdu}->{outlet};
 | |
|         for (my $outlet =1; $outlet <= $count; $outlet++)
 | |
|         {
 | |
|             my $statstr = outletstat($session, $outlet);
 | |
|             my $msg = " outlet $outlet is $statstr";
 | |
|             xCAT::SvrUtils::sendmsg($msg, $callback, $pdu, %allerrornodes);
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3  outletstat 
 | |
| 
 | |
|     Process command to query status of one pdu outlet
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub outletstat {
 | |
|     my $session = shift;
 | |
|     my $outlet = shift;
 | |
|  
 | |
|     my $oid = ".1.3.6.1.4.1.2.6.223.8.2.2.1.11";
 | |
|     my $output;
 | |
|     my $statstr;
 | |
| 
 | |
|     $output = $session->get("$oid.$outlet");
 | |
|     if ($output eq 1) {
 | |
|         $statstr = "on";
 | |
|     } elsif ($output eq 0) {
 | |
|         $statstr = "off";
 | |
|     } else {
 | |
|         return;
 | |
|     }
 | |
|     return $statstr;
 | |
| }
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3  connectTopdu 
 | |
| 
 | |
|    connect pdu via snmp session 
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub connectTopdu {
 | |
|     my $pdu = shift;
 | |
|     my $callback = shift;
 | |
| 
 | |
|     my $snmpver = "1";
 | |
|     my $community = "public";
 | |
|     my $session;
 | |
|     my $msg = "connectTopdu";
 | |
| 
 | |
|     $session = new SNMP::Session(
 | |
|         DestHost       => $pdu,
 | |
|         Version        => $snmpver,
 | |
|         Community      => $community,
 | |
|         UseSprintValue => 1,
 | |
|     );
 | |
|     unless ($session) {
 | |
|         return;
 | |
|     }
 | |
|     return $session;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 1;
 |