mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 19:32:31 +00:00 
			
		
		
		
	git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@16234 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
		
			
				
	
	
		
			1942 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1942 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env perl
 | |
| # 
 | |
| # © Copyright 2009 Hewlett-Packard Development Company, L.P.
 | |
| # EPL license http://www.eclipse.org/legal/epl-v10.html
 | |
| #
 | |
| # Revision history:
 | |
| #   July, 2010    vallard@sumavi.com comments added.
 | |
| #   August, 2009	blade.pm adapted to generate hpblade.pm
 | |
| #
 | |
| package xCAT_plugin::hpblade;
 | |
| BEGIN
 | |
| {
 | |
| 	$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
 | |
| }
 | |
| use lib "$::XCATROOT/lib/perl";
 | |
| 
 | |
| use strict;
 | |
| use xCAT::Table;
 | |
| use xCAT::Utils;
 | |
| use xCAT::TableUtils;
 | |
| use xCAT::ServiceNodeUtils;
 | |
| use xCAT::Usage;
 | |
| use IO::Socket;
 | |
| use Thread 'yield';
 | |
| use Storable qw(freeze thaw);
 | |
| use XML::Simple;
 | |
| use Net::SSLeay qw(die_now die_if_ssl_error);
 | |
| 
 | |
| 
 | |
| use Data::Dumper;
 | |
| use POSIX "WNOHANG";
 | |
| use Getopt::Long;
 | |
| #use xCAT::hpoa;	# require this dynamically below instead
 | |
| 
 | |
| sub handled_commands {
 | |
| 	return {
 | |
| 		findme => 'blade',
 | |
| 		getmacs => 'nodehm:getmac,mgt',
 | |
| 		rscan => 'nodehm:mgt',
 | |
| 		rpower => 'nodehm:power,mgt',
 | |
| 		gethpbladecons => 'hpblade',
 | |
| 		getrvidparms => 'nodehm:mgt',
 | |
| 		rvitals => 'nodehm:mgt',
 | |
| 		rinv => 'nodehm:mgt',
 | |
| 		rbeacon => 'nodehm:mgt',
 | |
| 		rspreset => 'nodehm:mgt',
 | |
| 		rspconfig => 'nodehm:mgt',
 | |
| 		rbootseq => 'nodehm:mgt',
 | |
| 		reventlog => 'nodehm:mgt',
 | |
| 		switchblade => 'nodehm:mgt',
 | |
| 	};
 | |
| }
 | |
| 
 | |
| my $hpoa;
 | |
| my $activeOABay;
 | |
| my $slot;
 | |
| my ($username, $password);
 | |
| my %mm_comm_pids;
 | |
| my %macmap; #Store responses from rinv for discovery
 | |
| my $macmaptimestamp; #reflect freshness of cache
 | |
| my %oahash;
 | |
| my $curn;
 | |
| my $oa;
 | |
| my $getBladeStatusResponse;  # Make this a global here so we can re-use the result
 | |
| my $status_noop="XXXno-opXXX";
 | |
| my $eventHash;
 | |
| my $globalDebug = 0;
 | |
| my $ctx;
 | |
| my @cfgtext;
 | |
| 
 | |
| my %bootdevices = (
 | |
| 	0 => 'IPL_NO_OP',
 | |
| 	1 => 'CD',
 | |
| 	2 => 'FLOPPY',
 | |
| 	3 => 'USB',
 | |
| 	4 => 'HDD',
 | |
| 	5 => 'PXE_NIC1',
 | |
| 	6 => 'PXE_NIC2' ,
 | |
| 	7 => 'PXE_NIC3',
 | |
| 	8 => 'PXE_NIC4'
 | |
| );
 | |
| 
 | |
| my %bootnumbers = (
 | |
| 	'none' => 0,
 | |
| 	'c' => 1,
 | |
| 	'cd' => 1,
 | |
| 	'dvd' => 1,
 | |
| 	'cdrom' => 1,
 | |
| 	'dvdrom' => 1,
 | |
| 	'f' => 2,
 | |
| 	'floppy' => 2,
 | |
| 	'usb' => 3,
 | |
| 	'h' => 4,
 | |
| 	'hd' => 4,
 | |
| 	'hdd' => 4,
 | |
| 	'harddisk' => 4,
 | |
| 	'eth0' => 5,
 | |
| 	'nic1' => 5,
 | |
| 	'pxe_nic1' => 5,
 | |
| 	'eth1' => 6,
 | |
| 	'nic2' => 6,
 | |
| 	'pxe_nic2' => 6,
 | |
| 	'eth2' => 7,
 | |
| 	'nic3' => 7,
 | |
| 	'pxe_nic3' => 7,
 | |
| 	'eth3' => 8,
 | |
| 	'nic4' => 8,
 | |
| 	'pxe_nic4' => 8
 | |
| );
 | |
| 
 | |
| my @rscan_attribs = qw(nodetype name id mtm serial mpa groups mgt);
 | |
| my @rscan_header = (
 | |
| ["type",          "%-8s" ],
 | |
| ["name",          "" ],
 | |
| ["id",            "%-8s" ],
 | |
| ["type-model",    "%-12s" ],
 | |
| ["serial-number", "%-15s" ],
 | |
| ["address",       "%s\n" ]);
 | |
| 
 | |
| sub waitforack {
 | |
|     my $sock = shift;
 | |
|     my $select = new IO::Select;
 | |
|     $select->add($sock);
 | |
|     my $str;
 | |
|     if ($select->can_read(10)) { # Continue after 10 seconds, even if not acked...
 | |
|         if ($str = <$sock>) {
 | |
|         } else {
 | |
| 			$select->remove($sock); #Block until parent acks data
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| # Login to the OA using credentials found in the database.
 | |
| sub oaLogin {
 | |
| 	my $oaName = shift;
 | |
| 	my $result = "";
 | |
| 	my $hopa = "";
 | |
| 	my $errHash;
 | |
| 	
 | |
| 	# we need to get the info on the OA. If the specfied OA is NOT the
 | |
| 	# ACTIVE OA then we return failure because we can't get the desired
 | |
| 	# info from a STANDBY OA.
 | |
| 	
 | |
| 	my ($username, $passwd, $encinfo);
 | |
| 
 | |
| 	my $mpatab = xCAT::Table->new('mpa');
 | |
| 	my $ent;
 | |
| 	if(defined($mpatab)) {
 | |
| 		($ent) = $mpatab->getAttribs({'mpa'=>$oaName}, 'username', 'password');
 | |
| 		if (defined($ent->{password})) {$password = $ent->{password}; }
 | |
| 		if (defined($ent->{username})) {$username = $ent->{username}; }
 | |
| 	}
 | |
| 	
 | |
| 	
 | |
| 	$hpoa = xCAT::hpoa->new('oaAddress' => $oaName);
 | |
| 	my $loginResponse = $hpoa->userLogIn('username' => $username, 'password' => $password);
 | |
| 	if($loginResponse->fault) {
 | |
| 		$errHash = $loginResponse->fault;
 | |
| 		print Dumper($errHash);
 | |
| 		$result = $loginResponse->oaErrorText;
 | |
| 		if($loginResponse->fault) {
 | |
| 			return(1, "Error on login attempt");
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	my $response = $hpoa->getEnclosureInfo();
 | |
| 	if($response->fault) {
 | |
| 		return(1, "Error on get Enclosure Info call");
 | |
| 	}
 | |
| 	my $numOABays = $response->result->{oaBays};
 | |
| 		
 | |
| 	# OK We now know how many oaBays we have in this enclosure. Ask the OAs in each bay
 | |
| 	# if they are active. If they are not, then leave since we can't get what we want 
 | |
| 	# from a standby OA
 | |
| 	$activeOABay = 0;
 | |
| 		
 | |
| 	for (my $oaBay = 1; $oaBay <= $numOABays; $oaBay++) {
 | |
| 		$response = $hpoa->getOaInfo(bayNumber=>$oaBay);
 | |
| 		if(!defined $response->result() || $response->result()->{oaRole} eq "OA_ABSENT" || 
 | |
| 			$response->result->{youAreHere} eq "false") {
 | |
| 			# either there is no OA here or this is not the one I am currently
 | |
| 			# communicating with
 | |
| 			next;
 | |
| 		} elsif ($response->result->{youAreHere} eq "true") {
 | |
| 			$activeOABay = $oaBay;
 | |
| 			last;
 | |
| 		}
 | |
| 	}
 | |
| 		
 | |
| 	if(! $activeOABay ) {
 | |
| 		return(1, "Cannot determine active OnBoard Administrator");
 | |
| 	}
 | |
| 		
 | |
| 	# Last thing. Need to determine if this is the active OA. If not, then we 
 | |
| 	# just tell the caller, and they can make the decision as to what they want
 | |
| 	# to do.
 | |
| 			
 | |
| 	$response = $hpoa->getOaStatus(bayNumber=>$activeOABay);
 | |
| 	if($response->result->{oaRole} ne "ACTIVE") {
 | |
| 		return (-1);
 | |
| 	}
 | |
| 		
 | |
| 	return ($hpoa);
 | |
| }
 | |
| 	
 | |
| sub oaLogout
 | |
| {
 | |
| 	my $hpoa = shift;
 | |
| 	
 | |
| 	my $response = $hpoa->userLogOut();
 | |
| }
 | |
| 
 | |
| sub convertSlot {
 | |
| 	my $origSlot = shift;
 | |
| 	
 | |
| 	if($origSlot =~ /\D/) {
 | |
| 		my $slotNum = $origSlot;
 | |
| 		my $slotAlpha = $slotNum;
 | |
| 		
 | |
| 		$slotNum =~ s/\D//;
 | |
| 		$slotAlpha =~ s/\d//;
 | |
| 		
 | |
| 		my $side;
 | |
| 		if ($slotAlpha eq "a" or $slotAlpha eq "A") {
 | |
| 			$side = 1;
 | |
| 		} elsif ($slotAlpha eq "b" or $slotAlpha eq "B") {
 | |
| 			$side = 2;
 | |
| 		} else {
 | |
| 			return(-1);
 | |
| 		}
 | |
| 		
 | |
| 		my $returnSlot = $side * 16 + $slotNum;
 | |
| 		return($returnSlot);
 | |
| 	}
 | |
| 	return($origSlot);
 | |
| }
 | |
| 	
 | |
| sub gethpbladecons {
 | |
| 	my $noderange = shift;
 | |
| 	my $callback=shift;
 | |
| 	my $mpatab = xCAT::Table->new('mpa');
 | |
| 	my $passtab = xCAT::Table->new('passwd');
 | |
| 	my $tmp;
 | |
| 	my $user="USERID";
 | |
| 
 | |
| 	if ($passtab) {
 | |
| 		($tmp)=$passtab->getAttribs({'key'=>'blade'},'username');
 | |
| 		if (defined($tmp)) {
 | |
| 			$user = $tmp->{username};
 | |
| 		}
 | |
| 	}
 | |
| 	my $mptab=xCAT::Table->new('mp');
 | |
| 	my $mptabhash = $mptab->getNodesAttribs($noderange,['mpa','id']);
 | |
| 	foreach my $node (@$noderange) {
 | |
| 		my $rsp = {node=>[{name=>[$node]}]};
 | |
| 		my $ent=$mptabhash->{$node}->[0]; #$mptab->getNodeAttribs($node,['mpa', 'id']);
 | |
| 		if (defined($ent->{mpa})) { 
 | |
| 			$oa = $ent->{mpa};
 | |
| 			$slot = convertSlot($ent->{id});
 | |
| 			if($slot == 0) { # want to open a console on the OA
 | |
| 				$rsp->{node}->[0]->{mm} = $oa;
 | |
| 			} else {
 | |
| 				$hpoa = oaLogin($oa);
 | |
| 				my $mpInfoResp = $hpoa->getBladeMpInfo("bayNumber"=>$slot);
 | |
| 				if($mpInfoResp->fault) {
 | |
| 					$rsp->{node}->[0]->{error}= ["Error getting MP info"];
 | |
| 					$rsp->{node}->[0]->{errorcode} = [1];
 | |
| 					$callback->($rsp);
 | |
| 					next;
 | |
| 				}
 | |
| 				my $ipaddress = $mpInfoResp->result->{ipAddress};
 | |
| 				$rsp->{node}->[0]->{mm} = $ipaddress;
 | |
| 			}
 | |
| 			($tmp) = $mpatab->getAttribs({'mpa'=>$oa}, 'username');
 | |
| 			$user = [$tmp->{username}];
 | |
| 			$rsp->{node}->[0]->{username} = $user;
 | |
| 		} else { 
 | |
| 			$rsp->{node}->[0]->{error}=["no mpa defined"];
 | |
| 			$rsp->{node}->[0]->{errorcode}=[1];
 | |
| 			$callback->($rsp);
 | |
| 			next;
 | |
| 		}
 | |
| 		if (defined($ent->{id})) { 
 | |
| 			$rsp->{node}->[0]->{slot}=$ent->{id};
 | |
| 		} else { 
 | |
| 			$rsp->{node}->[0]->{slot}="";
 | |
| 		}
 | |
| 		
 | |
| 		$callback->($rsp);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 	
 | |
| sub preprocess_request { 
 | |
| 	my $request = shift;
 | |
| 	#if ($request->{_xcatdest}) { return [$request]; }    #exit if preprocessed
 | |
|         if (   (defined($request->{_xcatpreprocessed}))
 | |
|         && ($request->{_xcatpreprocessed}->[0] == 1))
 | |
|         {
 | |
|            return [$request];
 | |
|         }
 | |
| 
 | |
| 	my $callback=shift;
 | |
| 	my @requests;
 | |
| 		
 | |
| 	#display usage statement if -h is present or no noderage is specified
 | |
| 	my $noderange = $request->{node}; #Should be arrayref
 | |
| 	my $command = $request->{command}->[0];
 | |
| 	my $extrargs = $request->{arg};
 | |
| 	my @exargs=($request->{arg});
 | |
| 	if (ref($extrargs)) {
 | |
| 		@exargs=@$extrargs;
 | |
| 	}
 | |
| 		
 | |
| 	my $usage_string=xCAT::Usage->parseCommand($command, @exargs);
 | |
| 	if ($usage_string) {
 | |
| 		$callback->({data=>$usage_string});
 | |
| 		$request = {};
 | |
| 		return;
 | |
| 	}
 | |
| 		
 | |
| 	if (!$noderange) {
 | |
| 		$usage_string=xCAT::Usage->getUsage($command);
 | |
| 		$callback->({data=>$usage_string});
 | |
| 		$request = {};
 | |
| 		return;
 | |
| 	}   
 | |
| 
 | |
| 	# require SOAP::Lite for hpoa.pm so we can do it dynamically
 | |
| 	my $soapsupport = eval { require SOAP::Lite; };
 | |
| 	unless ($soapsupport) { #Still no SOAP::Lite module
 | |
|       $callback->({error=>"SOAP::Lite perl module missing.  Install perl-SOAP-Lite before running HP blade commands.",errorcode=>[42]});
 | |
|       return [];
 | |
| 	}
 | |
| 	require xCAT::hpoa;
 | |
| 		
 | |
| 	#get the MMs for the nodes for the nodes in order to figure out which service nodes to send the requests to
 | |
| 	my $mptab = xCAT::Table->new("mp");
 | |
| 	unless ($mptab) { 
 | |
| 		$callback->({data=>["Cannot open mp table"]});
 | |
| 		$request = {};
 | |
| 		return;
 | |
| 	}
 | |
| 	my %mpa_hash=();
 | |
| 	my $mptabhash = $mptab->getNodesAttribs($noderange,['mpa','id']);
 | |
| 	if ($request->{command}->[0] eq "gethpbladecons") { #Can handle it here and now
 | |
| 		gethpbladecons($noderange,$callback);
 | |
| 		return ();
 | |
| 	}
 | |
| 		
 | |
| 		
 | |
| 	foreach my $node (@$noderange) {
 | |
| 		my $ent=$mptabhash->{$node}->[0]; #$mptab->getNodeAttribs($node,['mpa', 'id']);
 | |
| 		if (defined($ent->{mpa})) { push @{$mpa_hash{$ent->{mpa}}{nodes}}, $node;}
 | |
| 		else { 
 | |
| 			$callback->({data=>["no mpa defined for node $node"]});
 | |
| 			$request = {};
 | |
| 			return;
 | |
| 		}
 | |
| 		my $tempid;
 | |
| 		if (defined($ent->{id})) {
 | |
| 			#if the ide is defined, we need to see if there is a letter embedded in it. If there is,
 | |
| 			#then we need to convert the id to the correct slot
 | |
| 			$tempid = convertSlot($ent->{id});
 | |
| 			push @{$mpa_hash{$ent->{mpa}}{ids}}, $tempid;
 | |
| 		} else { 
 | |
| 			push @{$mpa_hash{$ent->{mpa}}{ids}}, ""; 
 | |
| 		}
 | |
| 	}
 | |
| 		
 | |
| 	# find service nodes for the MMs
 | |
| 	# build an individual request for each service node
 | |
| 	my $service  = "xcat";
 | |
| 	my @mms=keys(%mpa_hash);
 | |
| 	my $sn = xCAT::ServiceNodeUtils->get_ServiceNode(\@mms, $service, "MN");
 | |
| 		
 | |
| 	# build each request for each service node
 | |
| 	foreach my $snkey (keys %$sn)
 | |
| 	{
 | |
| 		#print "snkey=$snkey\n";
 | |
| 		my $reqcopy = {%$request};
 | |
| 		$reqcopy->{'_xcatdest'} = $snkey;
 | |
| 		my $mms1=$sn->{$snkey};
 | |
| 		my @moreinfo=();
 | |
| 		my @nodes=();
 | |
| 		foreach (@$mms1) { 
 | |
| 			push @nodes, @{$mpa_hash{$_}{nodes}};
 | |
| 			push @moreinfo, "\[$_\]\[" . join(',',@{$mpa_hash{$_}{nodes}}) ."\]\[" . join(',',@{$mpa_hash{$_}{ids}}) . "\]";
 | |
| 		}
 | |
| 		$reqcopy->{node} = \@nodes;
 | |
| 		#print "nodes=@nodes\n";
 | |
| 		$reqcopy->{moreinfo}=\@moreinfo;
 | |
| 		push @requests, $reqcopy;
 | |
| 	}
 | |
| 	return \@requests;
 | |
| }
 | |
| 	
 | |
| sub build_more_info{
 | |
| 	my $noderange=shift;
 | |
| 	my $callback=shift;
 | |
| 	my $mptab = xCAT::Table->new("mp");
 | |
| 	my @moreinfo=();
 | |
| 	unless ($mptab) { 
 | |
| 	$callback->({data=>["Cannot open mp table"]});
 | |
| 			return @moreinfo;
 | |
| 	}
 | |
| 	my %mpa_hash=();
 | |
| 	my $mptabhash = $mptab->getNodesAttribs($noderange,['mpa','id']);
 | |
| 	foreach my $node (@$noderange) {
 | |
| 		my $ent=$mptabhash->{$node}->[0]; #$mptab->getNodeAttribs($node,['mpa', 'id']);
 | |
| 		if (defined($ent->{mpa})) { push @{$mpa_hash{$ent->{mpa}}{nodes}}, $node;}
 | |
| 		else { 
 | |
| 			$callback->({data=>["no mpa defined for node $node"]});
 | |
| 			return @moreinfo;;
 | |
| 		}
 | |
| 		if (defined($ent->{id})) { push @{$mpa_hash{$ent->{mpa}}{ids}}, $ent->{id};}
 | |
| 		else { push @{$mpa_hash{$ent->{mpa}}{ids}}, "";} 
 | |
| 	}
 | |
| 	
 | |
| 	foreach (keys %mpa_hash) {
 | |
| 		push @moreinfo, "\[$_\]\[" . join(',',@{$mpa_hash{$_}{nodes}}) ."\]\[" . join(',',@{$mpa_hash{$_}{ids}}) . "\]";
 | |
| 			
 | |
| 	}
 | |
| 		
 | |
| 	return \@moreinfo;
 | |
| }
 | |
| 
 | |
| sub handle_depend {
 | |
| 	my $request = shift;
 | |
| 	my $callback = shift;
 | |
| 	my $doreq = shift;
 | |
| 	my $dp = shift;
 | |
| 	my %node = ();
 | |
| 	my $dep = @$dp[0];
 | |
| 	my $dep_hash = @$dp[1];
 | |
| 	
 | |
| 	# send all dependencies (along w/ those dependent on nothing)
 | |
| 	# build moreinfo for dependencies 
 | |
| 	my %mpa_hash = ();
 | |
| 	my @moreinfo=();
 | |
| 	my $reqcopy = {%$request};
 | |
| 	my @nodes=();
 | |
| 	
 | |
| 	foreach my $node (keys %$dep) {
 | |
| 		my $mpa = @{$dep_hash->{$node}}[0];
 | |
| 		push @{$mpa_hash{$mpa}{nodes}},$node;
 | |
| 		push @{$mpa_hash{$mpa}{ids}},  @{$dep_hash->{$node}}[1];
 | |
| 	}
 | |
| 	foreach (keys %mpa_hash) {
 | |
| 		push @nodes, @{$mpa_hash{$_}{nodes}};
 | |
| 		push @moreinfo, "\[$_\]\[" . join(',',@{$mpa_hash{$_}{nodes}}) ."\]\[" . join(',',@{$mpa_hash{$_}{ids}}) . "\]";
 | |
| 	}
 | |
| 	$reqcopy->{node} = \@nodes;
 | |
| 	$reqcopy->{moreinfo}=\@moreinfo;
 | |
| 	process_request($reqcopy,$callback,$doreq,1); 
 | |
| 	
 | |
| 	my $start = Time::HiRes::gettimeofday();
 | |
|     
 | |
| 	# build list of dependent nodes w/delays
 | |
| 	while(my ($name,$h) = each(%$dep) ) {
 | |
| 		foreach ( keys %$h ) { 
 | |
| 			if ( $h->{$_} =~ /(^\d+$)/ ) {
 | |
| 				$node{$_} = $1/1000.0;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	# send each dependent node as its delay expires
 | |
| 	while (%node) {
 | |
| 		my @noderange = ();
 | |
| 		my $delay = 0.1;
 | |
| 		my $elapsed = Time::HiRes::gettimeofday()-$start;
 | |
| 		
 | |
| 		# sort in ascending delay order
 | |
| 		foreach (sort {$node{$a} <=> $node{$b}} keys %node) {
 | |
| 			if ($elapsed < $node{$_}) {
 | |
| 				$delay = $node{$_}-$elapsed;
 | |
| 				last;
 | |
| 			}
 | |
| 			push @noderange,$_;
 | |
| 			delete $node{$_};
 | |
| 		}
 | |
| 		if (@noderange) {
 | |
| 			%mpa_hash=();
 | |
| 			foreach my $node (@noderange) {
 | |
| 				my $mpa = @{$dep_hash->{$node}}[0];
 | |
| 				push @{$mpa_hash{$mpa}{nodes}},$node;
 | |
| 				push @{$mpa_hash{$mpa}{ids}},  @{$dep_hash->{$node}}[1];
 | |
| 			}
 | |
| 			
 | |
| 			@moreinfo=();
 | |
| 			$reqcopy = {%$request};
 | |
| 			@nodes=();
 | |
| 			
 | |
| 			foreach (keys %mpa_hash) {
 | |
| 				push @nodes, @{$mpa_hash{$_}{nodes}};
 | |
| 				push @moreinfo, "\[$_\]\[" . join(',',@{$mpa_hash{$_}{nodes}}) ."\]\[" . join(',',@{$mpa_hash{$_}{ids}}) . "\]";
 | |
| 			}
 | |
| 			$reqcopy->{node} = \@nodes;
 | |
| 			$reqcopy->{moreinfo}=\@moreinfo;
 | |
| 			
 | |
| 			# clear global hash variable
 | |
| 			%oahash = ();
 | |
| 			process_request($reqcopy,$callback,$doreq,1);
 | |
| 		}
 | |
| 		# millisecond sleep
 | |
| 		Time::HiRes::sleep($delay);
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| sub build_depend {
 | |
| 	my $noderange = shift;
 | |
| 	my $exargs = shift;
 | |
| 	my $depstab  = xCAT::Table->new('deps');
 | |
| 	my $mptab    = xCAT::Table->new('mp');
 | |
| 	my %dp    = ();
 | |
| 	my %no_dp = ();
 | |
| 	my %mpa_hash;
 | |
| 	
 | |
| 	if (!defined($depstab)) {
 | |
| 		return([\%dp]);
 | |
| 	}
 | |
| 	unless ($mptab) {
 | |
| 		return("Cannot open mp table");
 | |
| 	}
 | |
| 	
 | |
| 	my $depset = $depstab->getNodesAttribs($noderange,[qw(nodedep msdelay cmd)]);
 | |
| 	foreach my $node (@$noderange) {
 | |
| 		my $delay = 0;
 | |
| 		my $dep;
 | |
| 		
 | |
| 		my @ent = @{$depset->{$node}}; #$depstab->getNodeAttribs($node,[qw(nodedep msdelay cmd)]);
 | |
| 		foreach my $h ( @ent ) {
 | |
| 			if ( grep(/^@$exargs[0]$/, split /,/, $h->{cmd} )) {
 | |
| 				if (exists($h->{nodedep})) { $dep=$h->{nodedep}; }
 | |
| 				if (exists($h->{msdelay})) { $delay=$h->{msdelay}; }
 | |
| 				last;
 | |
| 			}
 | |
| 		}
 | |
| 		if (!defined($dep)) {
 | |
| 			$no_dp{$node} = 1;
 | |
| 		}
 | |
| 		else {
 | |
| 			foreach my $n (split /,/,$dep ) {
 | |
| 				if ( !grep( /^$n$/, @$noderange )) {
 | |
| 					return( "Missing dependency on command-line: $node -> $n" );
 | |
| 				} elsif ( $n eq $node ) {
 | |
| 					next;  # ignore multiple levels
 | |
| 				}
 | |
| 				$dp{$n}{$node} = $delay;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	# if there are dependencies, add any non-dependent nodes
 | |
| 	if (scalar(%dp)) {
 | |
| 		foreach (keys %no_dp) {
 | |
| 			if (!exists( $dp{$_} )) {
 | |
| 				$dp{$_}{$_} = -1;
 | |
| 			}
 | |
| 		}
 | |
| 		# build hash of all nodes in preprocess_request() format
 | |
| 		my @namelist = keys %dp;
 | |
| 		my $mphash = $mptab->getNodesAttribs(\@namelist,['mpa','id']);
 | |
| 		while(my ($name,$h) = each(%dp) ) {
 | |
| 			my $ent=$mphash->{$name}->[0]; #$mptab->getNodeAttribs($name,['mpa', 'id']);
 | |
| 			if (!defined($ent->{mpa})) {
 | |
| 				return("no mpa defined for node $name");
 | |
| 			}
 | |
| 			my $id = (defined($ent->{id})) ? $ent->{id} : "";
 | |
| 			push @{$mpa_hash{$name}},$ent->{mpa};
 | |
| 			push @{$mpa_hash{$name}},$id;
 | |
| 			
 | |
| 			@namelist = keys %$h;
 | |
| 			my $mpsubhash = $mptab->getNodesAttribs(\@namelist,['mpa','id']);
 | |
| 			foreach ( keys %$h ) {
 | |
| 				if ( $h->{$_} =~ /(^\d+$)/ ) {
 | |
| 					my $ent=$mpsubhash->{$_}->[0]; #$mptab->getNodeAttribs($_,['mpa', 'id']);
 | |
| 					if (!defined($ent->{mpa})) {
 | |
| 						return("no mpa defined for node $_");
 | |
| 					}
 | |
| 					my $id = (defined($ent->{id})) ? $ent->{id} : "";
 | |
| 					push @{$mpa_hash{$_}},$ent->{mpa};
 | |
| 					push @{$mpa_hash{$_}},$id;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return( [\%dp,\%mpa_hash] );
 | |
| }
 | |
| 
 | |
| 
 | |
| sub process_request { 
 | |
| 	$SIG{INT} = $SIG{TERM} = sub { 
 | |
| 		foreach (keys %mm_comm_pids) {
 | |
| 			kill 2, $_;
 | |
| 		}
 | |
| 		exit 0;
 | |
| 	};
 | |
| 		
 | |
| 	my $request = shift;
 | |
| 	my $callback = shift;
 | |
| 	my $doreq = shift;
 | |
| 	my $level = shift;
 | |
| 	my $noderange = $request->{node};
 | |
| 	my $command = $request->{command}->[0];
 | |
| 	my @exargs;
 | |
| 	unless ($command) {
 | |
| 		return; #Empty request
 | |
| 	}
 | |
| 
 | |
| 	# require SOAP::Lite for hpoa.pm so we can do it dynamically
 | |
| 	my $soapsupport = eval { require SOAP::Lite; };
 | |
| 	unless ($soapsupport) { #Still no SOAP::Lite module
 | |
|       $callback->({error=>"SOAP::Lite perl module missing.  Install perl-SOAP-Lite before running HP blade commands.",errorcode=>[42]});
 | |
|       return [];
 | |
| 	}
 | |
| 	require xCAT::hpoa;
 | |
| 
 | |
| 	if (ref($request->{arg})) {
 | |
| 		@exargs = @{$request->{arg}};
 | |
| 	} else {
 | |
| 		@exargs = ($request->{arg});
 | |
| 	}
 | |
| 		
 | |
| 	my $moreinfo;
 | |
| 	if ($request->{moreinfo}) { $moreinfo=$request->{moreinfo}; }
 | |
| 	else {  $moreinfo=build_more_info($noderange,$callback);} 
 | |
| 		
 | |
| 	if ($command eq "rpower" and grep(/^on|off|boot|reset|cycle$/, @exargs)) {
 | |
| 			
 | |
| 		if ( my ($index) = grep($exargs[$_]=~ /^--nodeps$/, 0..$#exargs )) {
 | |
| 			splice(@exargs, $index, 1);
 | |
| 		} else {
 | |
| 			# handles 1 level of dependencies only
 | |
| 			if (!defined($level)) {
 | |
| 				my $dep = build_depend($noderange,\@exargs);
 | |
| 				if ( ref($dep) ne 'ARRAY' ) {
 | |
| 					$callback->({data=>[$dep],errorcode=>1});
 | |
| 					return;
 | |
| 				}
 | |
| 				if (scalar(%{@$dep[0]})) {
 | |
| 					handle_depend( $request, $callback, $doreq, $dep );
 | |
| 					return 0;
 | |
| 				} 
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	# only 1 node when changing textid to something other than '*'
 | |
| 	if ($command eq "rspconfig" and grep(/^textid=[^*]/,@exargs)) {
 | |
| 		if ( @$noderange > 1 ) {
 | |
| 			$callback->({data=>["Single node required when changing textid"],
 | |
| 			errorcode=>1});
 | |
| 			return;
 | |
| 		}
 | |
| 	}
 | |
| 	my $bladeuser = 'USERID';
 | |
| 	my $bladepass = 'PASSW0RD';
 | |
| 	my $blademaxp = 64;
 | |
| 	#my $sitetab = xCAT::Table->new('site');
 | |
| 	my $mpatab = xCAT::Table->new('mpa');
 | |
| 	my $mptab = xCAT::Table->new('mp');
 | |
| 	my $tmp;
 | |
| 	#if ($sitetab) {
 | |
| 		#($tmp)=$sitetab->getAttribs({'key'=>'blademaxp'},'value');
 | |
|                 my @entries =  xCAT::TableUtils->get_site_attribute("blademaxp");
 | |
|                 my $t_entry = $entries[0];
 | |
| 		if (defined($t_entry)) { $blademaxp=$t_entry; }
 | |
| 	#}
 | |
| 	my $passtab = xCAT::Table->new('passwd');
 | |
| 	if ($passtab) {
 | |
| 		($tmp)=$passtab->getAttribs({'key'=>'blade'},'username','password');
 | |
| 		if (defined($tmp)) {
 | |
| 			$bladeuser = $tmp->{username};
 | |
| 			$bladepass = $tmp->{password};
 | |
| 		}
 | |
| 	}
 | |
| 	if ($request->{command}->[0] eq "findme") {
 | |
| 		my $mptab = xCAT::Table->new("mp");
 | |
| 		unless ($mptab) { return 2; }
 | |
| 		my @bladents = $mptab->getAllNodeAttribs([qw(node)]);
 | |
| 		my @blades;
 | |
| 		foreach (@bladents) {
 | |
| 			push @blades,$_->{node};
 | |
| 		}
 | |
| 		my %invreq;
 | |
| 		$invreq{node} = \@blades;
 | |
| 		$invreq{arg} = ['mac'];
 | |
| 		$invreq{command} = ['rinv'];
 | |
| 		my $mac;
 | |
| 		my $ip = $request->{'_xcat_clientip'};
 | |
| 		my $arptable;
 | |
|                 if ( -x "/usr/sbin/arp") {
 | |
|                     $arptable = `/usr/sbin/arp -n`;
 | |
|                 }
 | |
|                 else{
 | |
|                     $arptable = `/sbin/arp -n`;
 | |
|                 }
 | |
| 		my @arpents = split /\n/,$arptable;
 | |
| 		foreach  (@arpents) {
 | |
| 			if (m/^($ip)\s+\S+\s+(\S+)\s/) {
 | |
| 				$mac=$2;
 | |
| 				last;
 | |
| 			}
 | |
| 		}
 | |
| 		unless ($mac) { return };
 | |
| 			
 | |
| 		#Only refresh the the cache when the request permits and no useful answer
 | |
| 		if ($macmaptimestamp < (time() - 300)) { #after five minutes, invalidate cache
 | |
| 			%macmap = ();
 | |
| 		}
 | |
| 			
 | |
| 		unless ($request->{cacheonly}->[0] or $macmap{$mac} or $macmaptimestamp > (time() - 20)) { #do not refresh cache if requested not to, if it has an entry, or is recent
 | |
| 			%macmap = ();
 | |
| 			$macmaptimestamp=time();
 | |
| 			foreach (@{preprocess_request(\%invreq,\&fillresps)}) {
 | |
| 				%invreq = %$_;
 | |
| 				process_request(\%invreq,\&fillresps);
 | |
| 			}
 | |
| 		}
 | |
| 		unless ($macmap{$mac}) { 
 | |
| 			return 1; #failure
 | |
| 		}
 | |
| 		my $mactab = xCAT::Table->new('mac',-create=>1);
 | |
| 		$mactab->setNodeAttribs($macmap{$mac},{mac=>$mac});
 | |
| 		$mactab->close();
 | |
| 		#my %request = (
 | |
| 		#  command => ['makedhcp'],
 | |
| 		#  node => [$macmap{$mac}]
 | |
| 		#  );
 | |
| 		#$doreq->(\%request);
 | |
| 		$request->{command}=['discovered'];
 | |
| 		$request->{noderange} = [$macmap{$mac}];
 | |
| 		$doreq->($request);
 | |
| 		%{$request}=(); #Clear request. it is done
 | |
| 		undef $mactab;
 | |
| 		return 0;
 | |
| 	}
 | |
| 		
 | |
| 		
 | |
| 	my $children = 0;
 | |
| 	$SIG{CHLD} = sub { my $cpid; while ($cpid = waitpid(-1, WNOHANG) > 0) { delete $mm_comm_pids{$cpid}; $children--; } };
 | |
| 	my $inputs = new IO::Select;;
 | |
| 	foreach my $info (@$moreinfo) {
 | |
| 		$info=~/^\[(.*)\]\[(.*)\]\[(.*)\]/;
 | |
| 		my $mpa=$1;
 | |
| 		my @nodes=split(',', $2);
 | |
| 		my @ids=split(',', $3);
 | |
| 		#print "mpa=$mpa, nodes=@nodes, ids=@ids\n";
 | |
| 		my $user=$bladeuser;
 | |
| 		my $pass=$bladepass;
 | |
| 		my $ent;
 | |
| 		if (defined($mpatab)) {
 | |
| 			($ent)=$mpatab->getAttribs({'mpa'=>$mpa},'username','password');
 | |
| 			if (defined($ent->{password})) { $pass = $ent->{password}; }
 | |
| 			if (defined($ent->{username})) { $user = $ent->{username}; }
 | |
| 		}
 | |
| 		$oahash{$mpa}->{username} = $user;
 | |
| 		$oahash{$mpa}->{password} = $pass;
 | |
| 		for (my $i=0; $i<@nodes; $i++) {
 | |
| 			my $node=$nodes[$i];;
 | |
| 			my $nodeid=$ids[$i];
 | |
| 			$oahash{$mpa}->{nodes}->{$node}=$nodeid;
 | |
| 
 | |
| 		
 | |
| 		}
 | |
| 	}
 | |
| 	my $sub_fds = new IO::Select;
 | |
| 	foreach $oa (sort (keys %oahash)) {
 | |
| 		while ($children > $blademaxp) { forward_data($callback,$sub_fds); }
 | |
| 		$children++;
 | |
| 		my $cfd;
 | |
| 		my $pfd;
 | |
| 		socketpair($pfd, $cfd,AF_UNIX,SOCK_STREAM,PF_UNSPEC) or die "socketpair: $!";
 | |
| 		$cfd->autoflush(1);
 | |
| 		$pfd->autoflush(1);
 | |
| 		my $cpid = xCAT::Utils->xfork;
 | |
| 		unless (defined($cpid)) { die "Fork error"; }
 | |
| 		unless ($cpid) {
 | |
| 			close($cfd);
 | |
| 			eval {
 | |
| 				doblade($pfd,$oa,\%oahash,$command,-args=>\@exargs);
 | |
| 				exit(0);
 | |
| 			};
 | |
| 			if ($@) { die "$@"; }
 | |
| 			die "blade plugin encountered a general error while communication with $oa";
 | |
| 		}
 | |
| 		$mm_comm_pids{$cpid} = 1;
 | |
| 		close ($pfd);
 | |
| 		$sub_fds->add($cfd);
 | |
| 	}
 | |
| 	while ($sub_fds->count > 0 or $children > 0) {
 | |
| 		forward_data($callback,$sub_fds);
 | |
| 	}
 | |
| 	while (forward_data($callback,$sub_fds)) {}
 | |
| }
 | |
| 	
 | |
| my $IMPORT_SSH_KEY_HEADER = '
 | |
| <LOCFGVERSION="2.21"/>
 | |
| <RIBCL VERSION="2.0">
 | |
| <LOGIN USER_LOGIN="AdMiNnAmE" PASSWORD="PaSsWoRd">
 | |
| <RIB_INFO MODE="write">
 | |
| <IMPORT_SSH_KEY>
 | |
| -----BEGIN SSH KEY-----
 | |
| ';
 | |
| 
 | |
| my $IMPORT_SSH_KEY_FOOTER = '
 | |
| -----END SSH KEY-----
 | |
| </IMPORT_SSH_KEY>
 | |
| </RIB_INFO>
 | |
| </LOGIN>
 | |
| </RIBCL>';
 | |
| 
 | |
| my $MOD_NETWORK_SETTINGS_HEADER = '
 | |
| <LOCFGVERSION="2.21"/>
 | |
| <RIBCL VERSION="2.0">
 | |
| <LOGIN USER_LOGIN="AdMiNnAmE" PASSWORD="PaSsWoRd">
 | |
| <RIB_INFO MODE="write">
 | |
| <MOD_NETWORK_SETTINGS>
 | |
| ';
 | |
| 
 | |
| my $MOD_NETWORK_SETTINGS_FOOTER = '
 | |
| </MOD_NETWORK_SETTINGS>
 | |
| </RIB_INFO>
 | |
| <LOGIN>
 | |
| </RIBCL>';
 | |
| 
 | |
| my $GET_NETWORK_SETTINGS = '
 | |
| <LOCFGVERSION="2.21"/>
 | |
| <RIBCL VERSION="2.0">
 | |
| <LOGIN USER_LOGIN="AdMiNnAmE" PASSWORD="PaSsWoRd">
 | |
| <RIB_INFO MODE="read">
 | |
| <GET_NETWORK_SETTINGS/>
 | |
| </RIB_INFO>
 | |
| </LOGIN>
 | |
| </RIBCL>';
 | |
| 
 | |
| 
 | |
| Net::SSLeay::load_error_strings();
 | |
| Net::SSLeay::SSLeay_add_ssl_algorithms();
 | |
| Net::SSLeay::randomize();
 | |
| #
 | |
| # opens an ssl connection to port 443 of the passed host
 | |
| #
 | |
| sub openSSLconnection($)
 | |
| {
 | |
| 	my $host = shift;
 | |
| 	my ($ssl, $sin, $ip, $nip);
 | |
| 	if (not $ip = inet_aton($host))
 | |
| 	{
 | |
| 		print "$host is a DNS Name, performing lookup\n" if $globalDebug;
 | |
| 		$ip = gethostbyname($host) or die "ERROR: Host $host notfound. \n";
 | |
| 	}
 | |
| 	$nip = inet_ntoa($ip);
 | |
| 	#print STDERR "Connecting to $nip:443\n";
 | |
| 	$sin = sockaddr_in(443, $ip);
 | |
| 	socket (S, &AF_INET, &SOCK_STREAM, 0) or die "ERROR: socket: $!";
 | |
| 	connect (S, $sin) or die "connect: $!";
 | |
| 	$ctx = Net::SSLeay::CTX_new() or die_now("ERROR: Failed to create SSL_CTX $! ");
 | |
| 	
 | |
| 	Net::SSLeay::CTX_set_options($ctx, &Net::SSLeay::OP_ALL);
 | |
| 	die_if_ssl_error("ERROR: ssl ctx set options");
 | |
| 	$ssl = Net::SSLeay::new($ctx) or die_now("ERROR: Failed to create SSL $!");
 | |
| 	
 | |
| 	Net::SSLeay::set_fd($ssl, fileno(S));
 | |
| 	Net::SSLeay::connect($ssl) and die_if_ssl_error("ERROR: ssl connect");
 | |
| 	#print STDERR 'SSL Connected ';
 | |
| 	print 'Using Cipher: ' . Net::SSLeay::get_cipher($ssl) if $globalDebug;
 | |
| 	#print STDERR "\n\n";
 | |
| 	return $ssl;
 | |
| }
 | |
| 
 | |
| sub closeSSLconnection($)
 | |
| {
 | |
| 	my $ssl = shift;
 | |
| 	
 | |
| 	Net::SSLeay::free ($ssl);		# Tear down connection
 | |
| 	Net::SSLeay::CTX_free ($ctx);	
 | |
| 	close S;
 | |
| }
 | |
| 
 | |
| # usage: sendscript(host, script)
 | |
| # sends the xmlscript script to host, returns reply
 | |
| sub sendScript($$)
 | |
| {
 | |
| 	my $host = shift;
 | |
| 	my $script = shift;
 | |
| 	my ($ssl, $reply, $lastreply, $res, $n);
 | |
| 	$ssl = openSSLconnection($host);
 | |
| 	# write header
 | |
| 	$n = Net::SSLeay::ssl_write_all($ssl, '<?xml version="1.0"?>'."\r\n");
 | |
| 	print "Wrote $n\n" if $globalDebug;
 | |
| 	$n = Net::SSLeay::ssl_write_all($ssl, '<LOCFG version="2.21"/>'."\r\n");
 | |
| 	print "Wrote $n\n" if $globalDebug;
 | |
| 	
 | |
| 	# write script
 | |
| 	$n = Net::SSLeay::ssl_write_all($ssl, $script);
 | |
| 	print "Wrote $n\n$script\n" if $globalDebug;
 | |
| 	$reply = "";
 | |
| 	$lastreply = "";
 | |
| 	my $reply2return = "";
 | |
| READLOOP:
 | |
| 	while(1) {
 | |
| 		$n++;
 | |
| 		$lastreply = Net::SSLeay::read($ssl);
 | |
| 		die_if_ssl_error("ERROR: ssl read");
 | |
| 		if($lastreply eq "") {
 | |
| 			sleep(2); # wait 2 sec for more text.
 | |
| 			$lastreply = Net::SSLeay::read($ssl);
 | |
| 			die_if_ssl_error("ERROR: ssl read");
 | |
| 			last READLOOP if($lastreply eq "");
 | |
| 		}
 | |
| 		$reply .= $lastreply;
 | |
| 		print "lastreply  $lastreply \b" if $globalDebug;
 | |
| 		
 | |
| 		# Check response to see if a error was returned.
 | |
| 		if($lastreply =~ m/STATUS="(0x[0-9A-F]+)"[\s]+MESSAGE='(.*)'[\s]+\/>[\s]*(([\s]|.)*?)<\/RIBCL>/) {
 | |
| 			if($1 eq "0x0000") {
 | |
| 				#print STDERR "$3\n" if $3;
 | |
| 			} else {
 | |
| 				$reply2return = "ERROR: STATUS: $1, MESSAGE: $2";
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	print "READ: $lastreply\n" if $globalDebug;
 | |
| 	if($lastreply =~ m/STATUS="(0x[0-9A-F]+)"[\s]+MESSAGE='(.*)'[\s]+\/>[\s]*(([\s]|.)*?)<\/RIBCL>/) {
 | |
| 		if($1 eq "0x0000") {
 | |
| 			#Sprint STDERR "$3\n" if $3;
 | |
| 		} else {
 | |
| 			$reply2return = "ERROR: STATUS: $1, MESSAGE: $2";
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	closeSSLconnection($ssl);
 | |
| 	return $reply2return;
 | |
| }
 | |
| 
 | |
| sub extractValue {
 | |
| 	my $inputString = shift;
 | |
| 	my $testString = shift;
 | |
| 	
 | |
| 	$testString = "<"."$testString"." VALUE=";
 | |
| 	
 | |
| 	my $start = index ($inputString, $testString) + length $testString;
 | |
| 	my $end = index $inputString, "\"", ($start + 1);
 | |
| 	return(substr($inputString, ($start + 1), ($end - $start - 1)));
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| sub iloconfig {
 | |
| 	
 | |
| 	my $oa=shift;
 | |
| 	my $user=shift;
 | |
| 	my $pass=shift;
 | |
| 	my $node=shift;
 | |
| 	my $nodeid=shift;
 | |
| 	my $parameter;
 | |
| 	my $value;
 | |
| 	my $assignment;
 | |
| 	my $returncode=0;
 | |
| 	my $textid=0;
 | |
| 	@cfgtext=();
 | |
| 	
 | |
| 	# Before we get going, lets get the info on the MP (iLO)
 | |
| 	$slot = convertSlot($nodeid);
 | |
| 	my $mpInfoResp = $hpoa->getBladeMpInfo("bayNumber"=>$slot);
 | |
| 	if($mpInfoResp->fault) {
 | |
| 		my $errorText ="Error getting MP info";
 | |
| 		next;
 | |
| 	}
 | |
| 	my $ipaddress = $mpInfoResp->result->{ipAddress};
 | |
| 	
 | |
| 	foreach $parameter (@_) {
 | |
| 		$assignment = 0;
 | |
| 		$value = undef;
 | |
| 		if ($parameter =~ /=/) {
 | |
| 			$assignment = 1;
 | |
| 			($parameter,$value) = split /=/,$parameter,2;
 | |
| 		}
 | |
| 		if ($parameter =~ /^sshcfg$/) {
 | |
| 			my $fname = "/root/.ssh/id_dsa.pub";
 | |
| 			if ( ! -s $fname ) {
 | |
| 				# Key file specified does not exist. Error!
 | |
| 				push @cfgtext,"rspconfig:key file does not exist";
 | |
| 				next;
 | |
| 			}
 | |
| 			open (KEY, "$fname");
 | |
| 			my $key = readline(KEY);
 | |
| 			close(KEY);
 | |
| 			my $script = "$IMPORT_SSH_KEY_HEADER"."$key"."$IMPORT_SSH_KEY_FOOTER";
 | |
| 			$script =~ s/AdMiNnAmE/$user/;
 | |
| 			$script =~ s/PaSsWoRd/$pass/;
 | |
| 			my $reply = sendScript($ipaddress, $script);
 | |
| 			push @cfgtext,$reply;
 | |
| 			next;
 | |
| 		}
 | |
| 		if ($parameter =~ /^network$/) {
 | |
| 			if($value) {
 | |
| 				# If value is set, then the user wans us to set these values
 | |
| 				my ($newip,$newhostname,$newgateway,$newmask) = split /,/,$value;
 | |
| 				my $script = "$MOD_NETWORK_SETTINGS_HEADER";
 | |
| 				$script = $script."<IP_ADDRESS VALUE=\"$newip\"\/>" if ($newip);
 | |
| 				$script = $script."<GATEWAY_IP_ADDRESS VALUE=\"$newgateway\"\/>" if($newgateway);
 | |
| 				$script = $script."<SUBNET_MASK VALUE=\"$newmask\"\/>" if($newmask);
 | |
| 				$script = $script."$MOD_NETWORK_SETTINGS_FOOTER";
 | |
| 				$script =~ s/AdMiNnAmE/$user/;
 | |
| 				$script =~ s/PaSsWoRd/$pass/;
 | |
| 				my $reply = sendScript($ipaddress, $script);
 | |
| 				if ($newip)     { push @cfgtext,"iLO IP: $newip"; }
 | |
| 				if ($newgateway){ push @cfgtext,"Gateway: $newgateway"; }
 | |
| 				if ($newmask)   { push @cfgtext,"Subnet Mask: $newmask"; }
 | |
| 				push @cfgtext, $reply;
 | |
| 				
 | |
| 			} else {
 | |
| 				my $script = "$GET_NETWORK_SETTINGS";
 | |
| 				$script =~ s/AdMiNnAmE/$user/;
 | |
| 				$script =~ s/PaSsWoRd/$pass/;
 | |
| 				my $reply = sendScript($ipaddress, $script);
 | |
| 				my $readipaddress = extractValue($reply, "IP_ADDRESS");
 | |
| 				my $gateway = extractValue($reply, "GATEWAY_IP_ADDRESS");
 | |
| 				my $netmask = extractValue($reply, "SUBNET_MASK");
 | |
| 				push @cfgtext,"iLO IP: $readipaddress";
 | |
| 				push @cfgtext, "Gateway: $gateway";
 | |
| 				push @cfgtext, "Subnet mask: $netmask";
 | |
| 				push @cfgtext, $reply;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return 0, @cfgtext;
 | |
| }
 | |
| 			
 | |
| sub getmacs
 | |
| {
 | |
| 	(my $code,my @macs)=inv('mac');
 | |
| 	my $mkey;
 | |
| 	my $nic2Find;
 | |
| 	my $nrtab = xCAT::Table->new('noderes');
 | |
| 	if ($nrtab) {
 | |
| 		my $nent = $nrtab->getNodeAttribs($curn,['primarynic','installnic']);
 | |
| 		if ($nent) {
 | |
| 			if (defined $nent->{installnic}) { #Prefer the install nic
 | |
| 				$mkey="installnic";
 | |
| 			} elsif (defined $nent->{primarynic}) { #see if primary nic was set
 | |
| 				$mkey="primarynic";
 | |
| 			}
 | |
| 			$nic2Find = $nent->{$mkey};
 | |
| 		}
 | |
| 	}
 | |
| 	# We now have the nic2Find, so we need to convert this to the NIC format
 | |
| 	# Strip away the "eth"
 | |
| 	my $interface = $nic2Find;
 | |
| 	$nic2Find =~ s/eth//;
 | |
| 	my $numberPxeNic = $nic2Find + 1;
 | |
| 	my $pxeNic = "NIC ".$numberPxeNic;
 | |
| 	
 | |
| 	if ($code==0) {
 | |
| 		my $mac;
 | |
| 		my @allmacs;
 | |
| 		foreach my $macEntry (@macs) {
 | |
| 			if ($macEntry =~ /MAC ADDRESS $pxeNic/) {
 | |
| 				$mac = $macEntry;
 | |
| 				$mac =~ s/MAC ADDRESS $pxeNic: //;
 | |
| 				$mac = lc $mac;
 | |
| 				last;
 | |
| 			}
 | |
| 		}
 | |
| 		if (! $mac) {
 | |
| 			return 1,"Unable to retrieve MAC address for interface $pxeNic from OnBoard Administrator";
 | |
| 		} 
 | |
| 				
 | |
| 		my $mactab = xCAT::Table->new('mac',-create=>1);
 | |
| 		$mactab->setNodeAttribs($curn,{mac=>$mac},{interface=>$interface});
 | |
| 		$mactab->close;
 | |
| 		return 0,":mac.mac set to $mac";
 | |
| 	} else {
 | |
| 		return $code,$macs[0];
 | |
| 	}
 | |
| }
 | |
| 	
 | |
| sub inv {
 | |
| 	my @invitems;
 | |
| 	my @output;
 | |
| 	foreach (@_) {
 | |
| 		push @invitems, split( /,/,$_);
 | |
| 	}
 | |
| 	my $item;
 | |
| 	unless(scalar(@invitems)) {
 | |
| 		@invitems = ("all");
 | |
| 	}
 | |
| 	
 | |
| 	# Before going off to handle the items, issue a getBladeInfo, getBladeMpInfo, and getOaInfo 
 | |
| 	my $getBladeInfoResult = $hpoa->getBladeInfo("bayNumber" => $slot);
 | |
| 	if($getBladeInfoResult->fault) {
 | |
| 		return(1, "getBladeInfo on node $curn failed");
 | |
| 	}
 | |
| 	my $getBladeMpInfoResult = $hpoa->getBladeMpInfo("bayNumber" => $slot);
 | |
| 	if($getBladeMpInfoResult->fault) {
 | |
| 		return(1, "getBladeMpInfo on node $curn fault");
 | |
| 	}
 | |
| 	my $getOaInfoResult = $hpoa->getOaInfo("bayNumber" => $activeOABay);
 | |
| 	if($getOaInfoResult->fault) {
 | |
| 		my $errHash = $getOaInfoResult->fault;
 | |
| 		return(1, "getOaInfo failed");
 | |
| 	}
 | |
| 		
 | |
| 	while (my $item = shift @invitems) {
 | |
| 		if($item =~ /^all/) {
 | |
| 			push @invitems,(qw(mtm serial mac firm));
 | |
| 			next;
 | |
| 		}
 | |
| 			
 | |
| 		if($item =~ /^firm/) {
 | |
| 			push @invitems,(qw(bladerom mprom oarom));
 | |
| 		}	
 | |
| 		if($item =~ /^bladerom/)  {
 | |
| 			push @output,"BladeFW: ". $getBladeInfoResult->result->{romVersion};
 | |
| 		}
 | |
| 		if($item =~ /^mprom/) {
 | |
| 			push @output, "iLOFW: ". $getBladeMpInfoResult->result->{fwVersion};
 | |
| 		}
 | |
| 		if($item =~ /~oarom/) {
 | |
| 			push @output, "OA FW: ". $getOaInfoResult->result->{fwVersion};
 | |
| 		}
 | |
| 					
 | |
| 		if($item =~ /^model/ or $item =~ /^mtm/ ) {
 | |
| 			push @output,"Machine Type/Model: ". $getBladeInfoResult->result->{partNumber};
 | |
| 		}
 | |
| 		if($item =~ /^serial/) {
 | |
| 			push @output, "Serial Number: ". $getBladeInfoResult->result->{serialNumber};
 | |
| 		}
 | |
| 		if($item =~ /^mac/) {
 | |
| 			my $numberOfNics = $getBladeInfoResult->result->{numberOfNics};
 | |
| 			for (my $i = 0; $i < $numberOfNics; $i++) {
 | |
| 				my $mac = $getBladeInfoResult->result->{nics}->{bladeNicInfo}[$i]->{macAddress};
 | |
| 				my $port = $getBladeInfoResult->result->{nics}->{bladeNicInfo}[$i]->{port};
 | |
| 				push @output, "MAC ADDRESS ".$port.": ".$mac;
 | |
| 				#push@output, "MAC Address ".($_+1).": ".$getBladeInfoResult->result->{nics}->{bladeNicInfo}[$i]->{macAddress};
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return(0, @output);
 | |
| }
 | |
| 
 | |
| 
 | |
| sub CtoF {
 | |
| 	my $Ctemp = shift;
 | |
| 	return((($Ctemp * 9) / 5) + 32);
 | |
| }
 | |
| 
 | |
| my %chassiswidevitals;
 | |
| sub vitals {
 | |
| 	my @output;
 | |
| 	my $tmp;
 | |
| 	my @vitems;
 | |
| 	
 | |
| 	if ( $#_ == 0 && $_[0] eq '' ) { pop @_; push @_,"all" }	#-- default is all if no argument given
 | |
| 	
 | |
| 	if ( defined $slot and $slot > 0 ) { 	#-- blade query
 | |
| 		foreach (@_) {
 | |
| 			if ($_ eq 'all') {
 | |
| 				# push @vitems,qw(temp voltage wattage summary fan);
 | |
| 				push @vitems,qw(cpu_temp memory_temp system_temp ambient_temp summary fanspeed);
 | |
| 				push @vitems,qw(led power);;
 | |
| 			} elsif ($_ =~ '^led') {
 | |
| 				push @vitems,qw(led);
 | |
| 			} else {
 | |
| 				push @vitems,split( /,/,$_);
 | |
| 			}
 | |
| 		}
 | |
| 	} else {		#-- chassis query
 | |
| 		foreach (@_) {
 | |
| 			if ($_ eq 'all') {
 | |
| 				# push @vitems,qw(voltage wattage power summary);
 | |
| 				push @vitems,qw(cpu_temp memory_temp system_temp ambient_temp summary fanspeed);
 | |
| 				# push @vitems,qw(errorled beaconled infoled templed);
 | |
| 				push @vitems,qw(led power);
 | |
| 			} elsif ($_ =~ '^led') {
 | |
| 				push @vitems,qw(led);
 | |
| 			} elsif ($_ =~ '^cool') {
 | |
| 				push @vitems,qw(fanspeed);
 | |
| 			} elsif ($_ =~ '^temp') {
 | |
| 				push @vitems,qw(ambient_temp);
 | |
| 			} else {
 | |
| 				push @vitems,split( /,/,$_);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	my @vitals;
 | |
| 	if ( defined $slot and $slot > 0) {	#-- querying some blade
 | |
| 		if (grep /temp/, @vitems) {
 | |
| 			my $tempResponse = $hpoa->getBladeThermalInfoArray("bayNumber" => $slot);
 | |
| 
 | |
| 			if($tempResponse->fault) {
 | |
| 				push @output, "Request to get Temperature info on slot $slot failed";
 | |
| 			}
 | |
| 			elsif (! $tempResponse->result) {
 | |
| 				# If is the case then the temperature data is not yet available.
 | |
| 				push @output, "Temperature data not available.";
 | |
| 			} else {
 | |
| 				# We have data so go process it....
 | |
| 				my @tempdata =  $tempResponse->result->{bladeThermalInfo};
 | |
| 				my $lastElement = $tempResponse->result->{bladeThermalInfo}[-1]->{sensorNumber};
 | |
| 				if(grep /cpu_temp/, @vitems) {
 | |
| 					my $index = -1;
 | |
| 					do {
 | |
| 						$index++;
 | |
| 						if(grep /CPU/, $tempResponse->result->{bladeThermalInfo}[$index]->{description}) {
 | |
| 							my $Ctemp = $tempResponse->result->{bladeThermalInfo}[$index]->{temperatureC};
 | |
| 							my $desc = $tempResponse->result->{bladeThermalInfo}[$index]->{description};
 | |
| 							my $Ftemp = CtoF($Ctemp);
 | |
| 							push @output , "$desc Temperature: $Ctemp C \( $Ftemp F \)";
 | |
| 						}
 | |
| 					} until $tempResponse->result->{bladeThermalInfo}[$index]->{sensorNumber} eq $lastElement;
 | |
| 				}
 | |
| 				if(grep /memory_temp/, @vitems) {
 | |
| 					my $index = -1;
 | |
| 					do {
 | |
| 						$index++;
 | |
| 						if(grep /Memory/, $tempResponse->result->{bladeThermalInfo}[$index]->{description}) {
 | |
| 							my $Ctemp = $tempResponse->result->{bladeThermalInfo}[$index]->{temperatureC};
 | |
| 							my $desc = $tempResponse->result->{bladeThermalInfo}[$index]->{description};
 | |
| 							my $Ftemp = CtoF($Ctemp);
 | |
| 							push @output , "$desc Temperature: $Ctemp C \( $Ftemp F \)";
 | |
| 						}
 | |
| 					} until $tempResponse->result->{bladeThermalInfo}[$index]->{sensorNumber} eq $lastElement;
 | |
| 				}
 | |
| 				if(grep /system_temp/, @vitems) {
 | |
| 					my $index = -1;
 | |
| 					do {
 | |
| 						$index++;
 | |
| 						if(grep /System/, $tempResponse->result->{bladeThermalInfo}[$index]->{description}) {
 | |
| 							my $Ctemp = $tempResponse->result->{bladeThermalInfo}[$index]->{temperatureC};
 | |
| 							my $desc = $tempResponse->result->{bladeThermalInfo}[$index]->{description};
 | |
| 							my $Ftemp = CtoF($Ctemp);
 | |
| 							push @output , "$desc Temperature: $Ctemp C \( $Ftemp F \)";
 | |
| 						}
 | |
| 					} until $tempResponse->result->{bladeThermalInfo}[$index]->{sensorNumber} eq $lastElement;
 | |
| 				}
 | |
| 				if(grep /ambient_temp/, @vitems) {
 | |
| 					my $index = -1;
 | |
| 					do {
 | |
| 						$index++;
 | |
| 						if(grep /Ambient/, $tempResponse->result->{bladeThermalInfo}[$index]->{description}) {
 | |
| 							my $Ctemp = $tempResponse->result->{bladeThermalInfo}[$index]->{temperatureC};
 | |
| 							my $desc = $tempResponse->result->{bladeThermalInfo}[$index]->{description};
 | |
| 							my $Ftemp = CtoF($Ctemp);
 | |
| 							push @output , "$desc Temperature: $Ctemp C \( $Ftemp F \)";
 | |
| 						}
 | |
| 					} until $tempResponse->result->{bladeThermalInfo}[$index]->{sensorNumber} eq $lastElement;	
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		
 | |
| 		if(grep /fanspeed/, @vitems) {
 | |
| 			my $fanInfoResponse = $hpoa->getFanInfo("bayNumber" => $slot);
 | |
| 			if($fanInfoResponse->fault) {
 | |
| 				push @output, "Request to get Fan Info from slot $slot failed ";
 | |
| 			} elsif (! $fanInfoResponse->result ) {
 | |
| 				push @output, "No Fan Information";
 | |
| 			} else {
 | |
| 				my $fanStatus = $fanInfoResponse->result->{operationalStatus};
 | |
| 				my $fanMax = $fanInfoResponse->result->{maxFanSpeed};
 | |
| 				my $fanCur = $fanInfoResponse->result->{fanSpeed};
 | |
| 				my $fanPercent = ($fanCur / $fanMax) * 100;
 | |
| 				push @output, "Fan status: $fanStatus  Percent of max: $fanPercent\%";
 | |
| 			}
 | |
| 		}
 | |
| 		
 | |
| 		if(grep /led/, @vitems) {
 | |
| 			my $currstat = $getBladeStatusResponse->result->{uid};
 | |
| 
 | |
| 			if ($currstat eq "UID_ON") {
 | |
| 				push @output, "Current UID Status On";
 | |
| 			} elsif ($currstat eq "UID_OFF") {
 | |
| 				push @output, "Current UID Status Off";
 | |
| 			} elsif ($currstat eq "UID_BLINK") {
 | |
| 				push @output, "Current UID Status Blinking";
 | |
| 			}
 | |
| 		}
 | |
| 		
 | |
| 		if(grep /power/, @vitems) {
 | |
| 			my $currPowerStat = $getBladeStatusResponse->result->{powered};
 | |
| 			if($currPowerStat eq "POWER_ON") {
 | |
| 				push @output , "Current Power Status On";
 | |
| 			} elsif ($currPowerStat eq "POWER_OFF") {
 | |
| 				push @output,"Current Power Status Off";
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	return(0, @output);
 | |
| }
 | |
| 
 | |
| sub buildEventHash {
 | |
| 	my $logText = shift;
 | |
| 	my $eventLogFound = 0;
 | |
| 	my $eventFound = 0;
 | |
| 	my $eventNumber = 0;
 | |
| 
 | |
| 	my @lines = split /^/, $logText;
 | |
| 	foreach my $line (@lines){
 | |
| 		if(! $eventLogFound ) {
 | |
| 			if(! $line =~ m/EVENT_LOG/) {
 | |
| 				next;
 | |
| 			} elsif ($line =~ m/EVENT_LOG/) {
 | |
| 				$eventLogFound = 1;
 | |
| 				next;
 | |
| 			}
 | |
| 		}
 | |
| 		
 | |
| 		if(! $eventFound && $line =~ m/\<EVENT/) {
 | |
| 			$eventFound = 1;
 | |
| 			next;
 | |
| 		} elsif ($eventFound && $line =~ m/\/\>/) {
 | |
| 			$eventNumber++;
 | |
| 			$eventFound = 0;
 | |
| 			next;
 | |
| 		}
 | |
| 		
 | |
| 		# We have a good line. Need to split it up and build the hash.
 | |
| 		my ($desc, $value) = split /=/, $line;
 | |
| 		for ($desc) {
 | |
| 			s/^\s+//;
 | |
| 			s/\s+$//;
 | |
| 			s/\"//g;
 | |
| 			s/\\n//;
 | |
| 		}
 | |
| 		for ($value) {
 | |
| 			s/^\s+//;
 | |
| 			s/\"//g;
 | |
| 			s/\s+$//;
 | |
| 			s/\\n//;
 | |
| 		}
 | |
| 		$eventHash->{event}->{$eventNumber}->{$desc} = $value;
 | |
| 		next;
 | |
| 	}
 | |
| 	return $eventNumber;
 | |
| }
 | |
| 
 | |
| sub eventlog {
 | |
| 	my $subcommand= shift;
 | |
| 	
 | |
| 	my @output;
 | |
|  
 | |
| 	$subcommand = "all" if $subcommand eq "";
 | |
|  
 | |
| 	if ($subcommand eq "all" or $subcommand =~ /\d+/) {
 | |
| 		my $mpEventLogResponse = $hpoa->getBladeMpEventLog("bayNumber"=>$slot, "maxsize"=>640000);
 | |
| 		if($mpEventLogResponse->fault) {
 | |
| 			return(1, "Attempt to retrieve Event Log faulted");
 | |
| 		}
 | |
| 		my $logText = $mpEventLogResponse->result->{logContents};
 | |
| 		my $numEvents = buildEventHash($logText);
 | |
| 
 | |
| 		my $recCount = 0;
 | |
| 		$eventHash->{'event'} = {
 | |
| 			map {
 | |
| 				$recCount++ => $_->[1]
 | |
| 			} sort {
 | |
| 				$a->[0] <=> $b->[0]
 | |
| 			} map {
 | |
| 				(defined $_->{LAST_UPDATE} && $_->{LAST_UPDATE} ne '[NOT SET]')
 | |
| 				? [ &extractDate($_->{LAST_UPDATE}), $_]
 | |
| 				: [ $_->{SELID}, $_ ]
 | |
| 			} map {
 | |
| 				$eventHash->{'event'}{$_}{SELID} = $_;
 | |
| 				$eventHash->{'event'}{$_};
 | |
| 			} grep {
 | |
| 				defined $eventHash->{'event'}{$_}
 | |
| 			} keys %{$eventHash->{'event'}}
 | |
| 		};
 | |
| 		
 | |
| 		my $limitEvents = ($subcommand eq "all" ? $recCount : $subcommand);
 | |
| 
 | |
| 		for (my $index = 0; $index < $limitEvents; $index++) {
 | |
| 			--$recCount;
 | |
| 
 | |
| 			my $class = $eventHash->{event}->{$recCount}->{CLASS};
 | |
| 			my $severity = $eventHash->{event}->{$recCount}->{SEVERITY};
 | |
| 			my $dateTime = $eventHash->{event}->{$recCount}->{LAST_UPDATE};
 | |
| 			my $desc = $eventHash->{event}->{$recCount}->{DESCRIPTION};
 | |
| 			unshift @output,"$class $severity:$dateTime $desc";
 | |
| 		}
 | |
| 		return(0, @output);
 | |
| 	} elsif ($subcommand eq "clear") {
 | |
| 		return(1, "Command not supported");
 | |
| 	} else {
 | |
| 		return(1, "Command '$subcommand' not supported");
 | |
| 	}
 | |
| }
 | |
| 			
 | |
| 
 | |
| sub rscan {
 | |
| 	my $args = shift;
 | |
| 	my @values;
 | |
| 	my $result;
 | |
| 	my %opt;
 | |
| 	
 | |
| 	@ARGV = @$args;
 | |
| 	$Getopt::Long::ignorecase = 0;
 | |
| 	Getopt::Long::Configure("bundling");
 | |
| 	
 | |
| 	local *usage = sub {
 | |
| 		my $usage_string=xCAT::Usage->getUsage("rscan");
 | |
| 		return( join('',($_[0],$usage_string)));
 | |
| 	};
 | |
| 	
 | |
| 	if ( !GetOptions(\%opt,qw(V|Verbose w x z))){
 | |
| 		return(1,usage());
 | |
| 	}
 | |
| 	if ( defined($ARGV[0]) ) {
 | |
| 		return(1,usage("Invalid argument: @ARGV\n"));
 | |
| 	}
 | |
| 	if (exists($opt{x}) and exists($opt{z})) {
 | |
| 		return(1,usage("-x and -z are mutually exclusive\n"));
 | |
| 	} 
 | |
| 
 | |
| 	my $encInfo = $hpoa->getEnclosureInfo();
 | |
| 	if( $encInfo->fault) {
 | |
| 		return(1, "Attempt tp get enclosure information has failed");
 | |
| 	}
 | |
| 			
 | |
| 	my $numBays = $encInfo->result->{bladeBays};
 | |
| 	my $calcBladeBays = $numBays * 3;  # Need to worry aboyt casmir blades
 | |
| 			
 | |
| 	my $encName = $encInfo->result->{enclosureName};
 | |
| 	my $enctype = $encInfo->result->{name};
 | |
| 	my $encmodel = $encInfo->result->{partNumber};
 | |
| 	my $encserial = $encInfo->result->{serialNumber};
 | |
| 	
 | |
| 	push @values,join(",","hpoa",$encName,0,"$enctype-$encmodel",$encserial,$oa);
 | |
| 	my $max = length($encName);
 | |
| 	
 | |
| 	for( my $i = 1; $i <= $calcBladeBays; $i++) {
 | |
| 		my $bayInfo = $hpoa->getBladeInfo("bayNumber"=>$i);
 | |
| 		if($bayInfo->fault) {
 | |
| 			return(1, "Attempt to get blade info from bay $i has failed");
 | |
| 		}
 | |
| 		if($bayInfo->result->{presence} eq "ABSENT"  ) {
 | |
| 			# no blade in the bya
 | |
| 			next;
 | |
| 		}
 | |
| 		
 | |
| 		my $name = $bayInfo->result->{serverName};
 | |
| 		my $bayNum = $i;
 | |
| 		my $type = $bayInfo->result->{bladeType};
 | |
| 		my $model = $bayInfo->result->{name};
 | |
| 		my $serial = $bayInfo->result->{serialNumber};
 | |
| 			
 | |
| 		push @values, join (",", "hpblade", $name, $bayNum, "$type-$model", $serial, "");
 | |
| 	}
 | |
| 	
 | |
| 	my $format = sprintf "%%-%ds",($max+2);
 | |
| 	$rscan_header[1][1] = $format;
 | |
| 		
 | |
| 	if (exists($opt{x})) {
 | |
| 		$result = rscan_xml($oa,\@values); 
 | |
| 	} 
 | |
| 	elsif ( exists( $opt{z} )) {
 | |
| 		$result = rscan_stanza($oa,\@values); 
 | |
| 	} 
 | |
| 	else {
 | |
| 		foreach ( @rscan_header ) {
 | |
| 			$result .= sprintf @$_[1],@$_[0];
 | |
| 		}
 | |
| 		foreach (@values ){
 | |
| 			my @data = split /,/;
 | |
| 			my $i = 0;
 | |
| 				
 | |
| 			foreach (@rscan_header) {
 | |
| 				$result .= sprintf @$_[1],$data[$i++];
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	if (!exists( $opt{w})) {
 | |
| 		return(0,$result);
 | |
| 	}
 | |
| 	my @tabs = qw(mp nodehm nodelist);
 | |
| 	my %db   = ();
 | |
| 		
 | |
| 	foreach (@tabs) {
 | |
| 		$db{$_} = xCAT::Table->new( $_, -create=>1, -autocommit=>0 );
 | |
| 		if ( !$db{$_} ) {
 | |
| 			return(1,"Error opening '$_'" );
 | |
| 		}
 | |
| 	}
 | |
| 	foreach (@values) {
 | |
| 		my @data = split /,/;
 | |
| 		my $name = $data[1];
 | |
| 			
 | |
| 		my ($k1,$u1);
 | |
| 		$k1->{node} = $name;
 | |
| 		$u1->{mpa}  = $oa;
 | |
| 		$u1->{id}   = $data[2];
 | |
| 		$db{mp}->setAttribs($k1,$u1);
 | |
| 		$db{mp}{commit} = 1;
 | |
| 			
 | |
| 		my ($k2,$u2);
 | |
| 		$k2->{node} = $name;
 | |
| 		$u2->{mgt}  = "hpblade";
 | |
| 		$db{nodehm}->setAttribs($k2,$u2);
 | |
| 		$db{nodehm}{commit} = 1;
 | |
| 			
 | |
| 		my ($k3,$u3);
 | |
| 		$k3->{node}   = $name;
 | |
| 		$u3->{groups} = "blade,all";
 | |
| 		$db{nodelist}->setAttribs($k3,$u3);
 | |
| 		$db{nodelist}{commit} = 1;
 | |
| 	}
 | |
| 	foreach ( @tabs ) {
 | |
| 		if ( exists( $db{$_}{commit} )) {
 | |
| 			$db{$_}->commit;
 | |
| 		}
 | |
| 	}
 | |
| 	return (0,$result);
 | |
| }
 | |
| 	
 | |
| sub rscan_xml {
 | |
| 		
 | |
| 	my $mpa = shift;
 | |
| 	my $values = shift;
 | |
| 	my $xml;
 | |
| 		
 | |
| 	foreach (@$values) {
 | |
| 		my @data = split /,/;
 | |
| 		my $i = 0;
 | |
| 			
 | |
| 		my $href = {
 | |
| 			Node => { }
 | |
| 		};
 | |
| 		foreach ( @rscan_attribs ) {
 | |
| 			my $d = $data[$i++];
 | |
| 			my $type = $data[0];
 | |
| 				
 | |
| 			if ( /^name$/ ) {
 | |
| 				next;
 | |
| 			} elsif ( /^nodetype$/ ) {
 | |
| 				$d = $type;
 | |
| 			} elsif ( /^groups$/ ) {
 | |
| 				$d = "$type,all";
 | |
| 			} elsif ( /^mgt$/ ) {
 | |
| 				$d = "blade";
 | |
| 			} elsif ( /^mpa$/ ) {
 | |
| 				$d = $mpa;
 | |
| 			}
 | |
| 			$href->{Node}->{$_} = $d;
 | |
| 		}
 | |
| 		$xml.= XMLout($href,NoAttr=>1,KeyAttr=>[],RootName=>undef);
 | |
| 	}
 | |
| 	return( $xml );
 | |
| }
 | |
| 	
 | |
| sub rscan_stanza {
 | |
| 		
 | |
| 	my $mpa = shift;
 | |
| 	my $values = shift;
 | |
| 	my $result;
 | |
| 		
 | |
| 	foreach (@$values) {
 | |
| 		my @data = split /,/;
 | |
| 		my $i = 0; 
 | |
| 		my $type = $data[0];
 | |
| 		$result .= "$data[1]:\n\tobjtype=node\n";
 | |
| 			
 | |
| 		foreach ( @rscan_attribs ) {
 | |
| 			my $d = $data[$i++];
 | |
| 				
 | |
| 			if ( /^name$/ ) {
 | |
| 				next; 
 | |
| 			} elsif ( /^nodetype$/ ) {
 | |
| 				$d = $type;
 | |
| 			} elsif ( /^groups$/ ) {
 | |
| 				$d = "$type,all";
 | |
| 			} elsif ( /^mgt$/ ) {
 | |
| 				$d = "blade"; 
 | |
| 			} elsif ( /^mpa$/ ) {
 | |
| 				$d = $mpa;
 | |
| 			}
 | |
| 			$result .= "\t$_=$d\n";
 | |
| 		}
 | |
| 	}
 | |
| 	return( $result );
 | |
| }
 | |
| 	
 | |
| 	
 | |
| 	
 | |
| 					
 | |
| sub beacon {
 | |
| 	my $subcommand = shift;
 | |
| 	
 | |
| 	if($subcommand eq "stat" ) {
 | |
| 		my $currstat = $getBladeStatusResponse->result->{uid};
 | |
| 		if ($currstat eq "UID_ON") {
 | |
| 			return(0, "on");
 | |
| 		} elsif ($currstat eq "UID_OFF") {
 | |
| 			return(0, "off");
 | |
| 		} elsif ($currstat eq "UID_BLINK") {
 | |
| 			return(0, "blink");
 | |
| 		}
 | |
| 	}
 | |
| 	my $response;
 | |
| 	if($subcommand eq "on") {
 | |
| 		$response =$hpoa->setBladeUid('bayNumber' => $slot, 'uid' => "UID_CMD_ON");
 | |
| 		if($response->fault) {
 | |
| 			my $errHash = $response->fault;
 | |
| 			my $result = $response->oaErrorText;
 | |
| 			print "result is $result \n";
 | |
| 			return("1", "Uid On failed");
 | |
| 		} else {
 | |
| 			return("0", "");
 | |
| 		}
 | |
| 	} elsif ($subcommand eq "off") {
 | |
| 		$response = $hpoa->setBladeUid('bayNumber' => $slot ,'uid' => "UID_CMD_OFF");
 | |
| 		if($response->fault) {
 | |
| 			my $errHash = $response->fault;
 | |
| 			my $result = $response->oaErrorText;
 | |
| 			print "result is $result \n";
 | |
| 			return("1", "Uid Off failed");
 | |
| 		} else {
 | |
| 			return("0", "");
 | |
| 		}
 | |
| 	} elsif ($subcommand eq "blink") {
 | |
| 		$response = $hpoa->setBladeUid('bayNumber' => $slot, 'uid' => "UID_CMD_BLINK");
 | |
| 		if($response->fault) {
 | |
| 			my $errHash = $response->fault;
 | |
| 			my $result = $response->oaErrorText;
 | |
| 			print "result is $result \n";
 | |
| 			return("1", "Uid Blink failed");
 | |
| 		} else {
 | |
| 			return("0", "");
 | |
| 		}
 | |
| 	} else {
 | |
| 		return(1, "subcommand unsupported");
 | |
| 	}
 | |
| 
 | |
| 	return(1, "subcommand unsupported");
 | |
| }
 | |
| 
 | |
| sub bootseq {
 | |
| 	my @args=@_;
 | |
| 	my $data;
 | |
| 	my @order=();
 | |
| 	
 | |
| 	if ($args[0] eq "list" or $args[0] eq "stat") {
 | |
| 		# Before going off to handle the items, issue a getBladeInfo and getOaInfo 
 | |
| 		my $getBladeBootInfoResult = $hpoa->getBladeBootInfo("bayNumber"=> $slot);
 | |
| 		if($getBladeBootInfoResult->fault) {
 | |
| 			return(1, "getBladeBootInfo on node $curn failed");
 | |
| 		}
 | |
| 		# Go through the the IPL Array from the last call to GetBladeStatus
 | |
| 		my $numberOfIpls = $getBladeBootInfoResult->result->{numberOfIpls};
 | |
| 		foreach (my $i = 0; $i < $numberOfIpls; $i++) { 
 | |
| 			foreach (my $j = 0; $j <= 7; $j++) {
 | |
| 				if($getBladeBootInfoResult->result->{ipls}->{ipl}[$j]->{bootPriority} eq ($i + 1)) {
 | |
| 					push(@order, $getBladeBootInfoResult->result->{ipls}->{ipl}[$j]->{iplDevice});
 | |
| 					last;
 | |
| 				}
 | |
| 			}	
 | |
| 		}
 | |
| 					
 | |
| 		return (0, lc join(',',@order));
 | |
| 	} else {
 | |
| 		foreach (@args) {
 | |
| 			my @neworder=(split /,/,$_);
 | |
| 			push @order,@neworder;
 | |
| 		}
 | |
| 		my $number=@order;
 | |
| 		if ($number > 5) {
 | |
| 			return (1,"Only five boot sequence entries allowed");
 | |
| 		}
 | |
| 		my $nonespecified=0;
 | |
| 		my $foundnic = 0;
 | |
| 		foreach (@order) {
 | |
| 			if(($bootnumbers{$_} > 4)) {
 | |
| 				if($foundnic == 1) {
 | |
| 					# only one nic allowed. error out
 | |
| 					return(1, "Only one Eth/Nic device permitted.");
 | |
| 				} else {
 | |
| 					$foundnic = 1;
 | |
| 				}
 | |
| 			}
 | |
| 			unless (defined($bootnumbers{$_})) { return (1,"Unsupported device $_"); }
 | |
| 			unless ($bootnumbers{$_}) { $nonespecified = 1; }
 | |
| 			if ($nonespecified and $bootnumbers{$_}) { return (1,"Error: cannot specify 'none' before a device"); }
 | |
| 		}
 | |
| 		unless ($bootnumbers{$order[0]}) {
 | |
| 			return (1,"Error: cannot specify 'none' as first device");
 | |
| 		}
 | |
| 		
 | |
| 		# Build array to be sent to the blade here
 | |
| 		my @ipl;
 | |
| 		my $i = 1;
 | |
| 		foreach my $dev (@order) {
 | |
| 			push @ipl, {"bootPriority"=>"$i", "iplDevice" => "$bootdevices{$bootnumbers{$order[$i - 1]}}"};
 | |
| 			$i++;
 | |
| 		}
 | |
| 
 | |
| 		my $setiplResponse = $hpoa->setBladeIplBootPriority("bladeIplArray" => ['ipl', \@ipl, "" ], "bayNumber" => $slot);
 | |
| 		if($setiplResponse->fault) {
 | |
| 			my $errHash = $setiplResponse->fault;
 | |
| 			my $result = $setiplResponse->oaErrorText;
 | |
| 			print "result is $result \n";
 | |
| 			return(1, "Error on slot $slot setting ipl");
 | |
| 		}
 | |
| 		
 | |
| 		return bootseq('list');
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 	
 | |
| sub power {
 | |
| 	my $subcommand = shift;
 | |
| 	my $command2Send;
 | |
| 	my $currPowerStat;
 | |
| 	my $returnState;
 | |
| 	
 | |
| 	$returnState = "";
 | |
| 	$currPowerStat = $getBladeStatusResponse->result->{powered};
 | |
| 	
 | |
| 	if($subcommand eq "stat" || $subcommand eq "state") {
 | |
| 		if($currPowerStat eq "POWER_ON") {
 | |
| 			return(0, "on");
 | |
| 		} elsif ($currPowerStat eq "POWER_OFF") {
 | |
| 			return(0, "off");
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	if ($subcommand eq "on") {
 | |
| 		if($currPowerStat eq "POWER_OFF") {
 | |
| 			$command2Send = "MOMENTARY_PRESS";
 | |
| 			$returnState = "on";
 | |
| 		} else {
 | |
| 			return(0, "on");
 | |
| 		}
 | |
| 	} elsif ($subcommand eq "off") {
 | |
| 		if($currPowerStat eq "POWER_ON") {
 | |
| 			$command2Send = "PRESS_AND_HOLD";
 | |
| 			$returnState = "off";
 | |
| 		} else {
 | |
| 			return(0, "off");
 | |
| 		}
 | |
| 	} elsif ($subcommand eq "reset") {
 | |
| 		$command2Send = "RESET";
 | |
| 	} elsif ($subcommand eq "cycle") {
 | |
| 		if($currPowerStat eq "POWER_ON") {
 | |
| 			power("off");
 | |
| 		}
 | |
| 		$command2Send = "MOMENTARY_PRESS";
 | |
| 	} elsif ($subcommand eq "boot") {
 | |
| 		if($currPowerStat eq "POWER_OFF") {
 | |
| 			$command2Send = "MOMENTARY_PRESS";
 | |
| 			$returnState = "off on";
 | |
| 		} else {
 | |
| 			$command2Send = "COLD_BOOT";
 | |
| 			$returnState = "on reset";
 | |
| 		}
 | |
| 	} elsif ($subcommand eq "softoff") {
 | |
| 		if($currPowerStat eq "POWER_ON") {
 | |
| 			$command2Send = "MOMENTARY_PRESS";
 | |
| 		}
 | |
| 	}
 | |
| 		
 | |
| 	#If we got here with a command to send, do it, otherwise just return
 | |
| 	if($command2Send) {
 | |
| 		my $pwrResult = $hpoa->setBladePower('bayNumber' => $slot, 'power' => $command2Send);
 | |
| 		if($pwrResult->fault) {
 | |
| 			return(1, "Node $curn - Power command failed");
 | |
| 		}
 | |
| 		return(0, $returnState);
 | |
| 	}
 | |
| }
 | |
| 	
 | |
| 		
 | |
| 
 | |
| sub bladecmd {
 | |
| 	my $oa = shift;
 | |
| 	my $node = shift;
 | |
| 	$slot = shift;
 | |
| 	my $user = shift;
 | |
| 	my $pass = shift;
 | |
| 	my $command = shift;
 | |
| 	my @args = @_;
 | |
| 	my $error;
 | |
| 	if ($slot > 0) {
 | |
| 		$getBladeStatusResponse = $hpoa->getBladeStatus('bayNumber' => $slot);
 | |
| 		if($getBladeStatusResponse->fault) {
 | |
| 			my $errHash = $getBladeStatusResponse->fault;
 | |
| 			my $result = $getBladeStatusResponse->oaErrorText;
 | |
| 		}
 | |
| 		if ($getBladeStatusResponse->result->{presence} ne "PRESENT") {
 | |
| 			return (1, "Target bay empty");
 | |
| 		}
 | |
| 	}
 | |
| 		
 | |
| 	if ($command eq "rbeacon") {
 | |
| 		return beacon(@args);
 | |
| 	} elsif ($command eq "rpower") {
 | |
| 		return power(@args);
 | |
| 	} elsif ($command eq "rvitals") {
 | |
| 		return vitals(@args);
 | |
| 	} elsif ($command =~ /r[ms]preset/) {
 | |
| 		return resetmp(@args);
 | |
| 	} elsif ($command eq "rspconfig") {
 | |
| 		return iloconfig($oa,$user,$pass,$node,$slot,@args);
 | |
| 	} elsif ($command eq "rbootseq") {
 | |
| 		return bootseq(@args);
 | |
| 	} elsif ($command eq "switchblade") {
 | |
| 		return switchblade(@args);
 | |
| 	} elsif ($command eq "getmacs") {
 | |
| 		return getmacs(@args);
 | |
| 	} elsif ($command eq "rinv") {
 | |
| 		return inv(@args);
 | |
| 	} elsif ($command eq "reventlog") {
 | |
| 		return eventlog(@args);
 | |
| 	} elsif ($command eq "rscan") {
 | |
| 		return rscan(\@args);
 | |
| 	}
 | |
| 		
 | |
| 	return (1,"$command not a supported command by blade method");
 | |
| }
 | |
| 
 | |
| 
 | |
| sub forward_data {
 | |
| 	my $callback = shift;
 | |
| 	my $fds = shift;
 | |
| 	my @ready_fds = $fds->can_read(1);
 | |
| 	my $rfh;
 | |
| 	my $rc = @ready_fds;
 | |
| 	foreach $rfh (@ready_fds) {
 | |
| 		my $data;
 | |
| 		if ($data = <$rfh>) {
 | |
| 			while ($data !~ /ENDOFFREEZE6sK4ci/) {
 | |
| 				$data .= <$rfh>;
 | |
| 			}
 | |
| 			print $rfh "ACK\n";
 | |
| 			my $responses=thaw($data);
 | |
| 			foreach (@$responses) {
 | |
| 				$callback->($_);
 | |
| 			}
 | |
| 		} else {
 | |
| 			$fds->remove($rfh);
 | |
| 			close($rfh);
 | |
| 		}
 | |
| 	}
 | |
| 	yield; #Try to avoid useless iterations as much as possible
 | |
| 	return $rc;
 | |
| }
 | |
| 
 | |
| 	
 | |
| 	
 | |
| sub doblade {
 | |
| 	my $out = shift;
 | |
| 	$oa = shift;
 | |
| 	my $oahash = shift;
 | |
| 	my $command = shift;
 | |
| 	my %namedargs = @_;
 | |
| 	my @exargs = @{$namedargs{-args}};
 | |
| 	my $node;
 | |
| 	my $args = \@exargs;
 | |
| 	
 | |
| 	$hpoa = oaLogin($oa);
 | |
| 		
 | |
| 	# We are now logged into the OA and have a pointer to the OA session. Process
 | |
| 	# the command.
 | |
| 	
 | |
| 	#get new node status
 | |
| 	my %nodestat=();
 | |
| 	my $check=0;
 | |
| 	my $nsh={};
 | |
| 		
 | |
| 	foreach $node (sort (keys %{$oahash->{$oa}->{nodes}})) {
 | |
| 		$curn = $node;
 | |
| 		my ($rc, @output) = bladecmd($oa, $node, $oahash->{$oa}->{nodes}->{$node}, $oahash->{$oa}->{username}, $oahash->{$oa}->{password}, $command, @$args);
 | |
| 		
 | |
| 		foreach(@output) {
 | |
| 			my %output;
 | |
| 				
 | |
| 			if ( $command eq "rscan" ) { 
 | |
| 				$output{errorcode}=$rc;
 | |
| 				$output{data} = [$_];
 | |
| 			}
 | |
| 			else {
 | |
| 				(my $desc,my $text) = split (/:/,$_,2);
 | |
| 				unless ($text) {
 | |
| 					$text=$desc;
 | |
| 				} else {
 | |
| 					$desc =~ s/^\s+//;
 | |
| 					$desc =~ s/\s+$//;
 | |
| 					if ($desc) {
 | |
| 						$output{node}->[0]->{data}->[0]->{desc}->[0]=$desc;
 | |
| 					}
 | |
| 				}
 | |
| 				$text =~ s/^\s+//;
 | |
| 				$text =~ s/\s+$//;
 | |
| 				$output{node}->[0]->{errorcode} = $rc;
 | |
| 				$output{node}->[0]->{name}->[0]=$node;
 | |
| 				$output{node}->[0]->{data}->[0]->{contents}->[0]=$text;
 | |
| 			}
 | |
| 			print $out freeze([\%output]);
 | |
| 			print $out "\nENDOFFREEZE6sK4ci\n";
 | |
| 			yield;
 | |
| 			waitforack($out);
 | |
| 		}
 | |
| 		yield;
 | |
| 	}
 | |
| 		
 | |
| 	#update the node status to the nodelist.status table
 | |
| 	if ($check) {
 | |
| 		my %node_status=();
 | |
| 			
 | |
| 		#foreach (keys %nodestat) { print "node=$_,status=" . $nodestat{$_} ."\n"; } #Ling:remove
 | |
| 			
 | |
| 		foreach my $node (keys %nodestat) {
 | |
| 			my $stat=$nodestat{$node};
 | |
| 			if ($stat eq "no-op") { next; }
 | |
| 			if (exists($node_status{$stat})) {
 | |
| 				my $pa=$node_status{$stat};
 | |
| 				push(@$pa, $node);
 | |
| 			}
 | |
| 			else {
 | |
| 				$node_status{$stat}=[$node];
 | |
| 			}
 | |
| 		}
 | |
| 		xCAT_monitoring::monitorctrl::setNodeStatusAttributes(\%node_status, 1);
 | |
| 			
 | |
| 	}
 | |
| 	#my $msgtoparent=freeze(\@outhashes); # = XMLout(\%output,RootName => 'xcatresponse');
 | |
| 	#print $out $msgtoparent; #$node.": $_\n";
 | |
| }
 | |
| 
 | |
| sub extractDate {
 | |
| 	use Time::Local;
 | |
| 	my $date = shift;
 | |
| 
 | |
| 	return 0 unless $date =~ m/(\d{1,2})\/(\d{1,2})\/(\d{4}) (\d{1,2}):(\d{1,2})/;
 | |
| 
 | |
| 	return timegm(0,$5,$4,$2,$1,$3);
 | |
| }
 | |
| 
 | |
| 1;
 |