implement the swapnodes command for FIP
git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@9144 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
		
							
								
								
									
										483
									
								
								xCAT-server/lib/xcat/plugins/FIP.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										483
									
								
								xCAT-server/lib/xcat/plugins/FIP.pm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,483 @@ | ||||
| #!/usr/bin/env perl -w | ||||
| # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html | ||||
| ##################################################### | ||||
| # | ||||
| #  xCAT plugin package to handle commands that manage the xCAT object | ||||
| #     definitions | ||||
| # | ||||
| ##################################################### | ||||
|  | ||||
| package xCAT_plugin::FIP; | ||||
|  | ||||
| use lib ("/opt/xcat/lib/perl"); | ||||
| use Data::Dumper; | ||||
| use Getopt::Long; | ||||
| use xCAT::MsgUtils; | ||||
| use strict; | ||||
|  | ||||
| # options can be bundled up like -vV | ||||
| Getopt::Long::Configure("bundling"); | ||||
| $Getopt::Long::ignorecase = 0; | ||||
|  | ||||
|  | ||||
| #---------------------------------------------------------------------------- | ||||
|  | ||||
| =head3  handled_commands | ||||
|  | ||||
|         Return a list of commands handled by this plugin | ||||
|  | ||||
| =cut | ||||
|  | ||||
| #----------------------------------------------------------------------------- | ||||
|  | ||||
| sub handled_commands | ||||
| { | ||||
|     return { | ||||
|             swapnodes => "FIP" | ||||
|             }; | ||||
| } | ||||
|  | ||||
|  | ||||
| ########################################################################## | ||||
| # Pre-process request from xCat daemon. Send the request to the the service | ||||
| # nodes of the HCPs. | ||||
| ########################################################################## | ||||
| sub preprocess_request { | ||||
|  | ||||
|     my $req      = shift; | ||||
|     #if ($req->{_xcatdest}) { return [$req]; }    #exit if preprocessed | ||||
|     if ($req->{_xcatpreprocessed}->[0] == 1 ) { return [$req]; } | ||||
|     my $callback = shift; | ||||
|     my $subreq = shift; | ||||
|     my @requests; | ||||
|  | ||||
|     # process the command line | ||||
|     my $rc = &parse_args($req); | ||||
|     if ($rc != 0) | ||||
|     { | ||||
| 	&swapnodes_usage($callback); | ||||
| 	return -1; | ||||
|     } | ||||
|      | ||||
|     ##################################### | ||||
|     # Parse arguments | ||||
|     ##################################### | ||||
|     #my $opt = parse_args( $req, $callback); | ||||
|     #if ( ref($opt) eq 'ARRAY' )  | ||||
|     #{ | ||||
|     #    send_msg( $req, 1, @$opt ); | ||||
|     #    delete($req->{callback}); # if not, it will cause an error --  "Can't encode a value of type: CODE" in hierairchy. | ||||
|     #    return(1); | ||||
|     #} | ||||
|     #delete($req->{callback}); # remove 'callback' => sub { "DUMMY" } in hierairchy. | ||||
|     #$req->{opt} = $opt; | ||||
|  | ||||
|     #if ( exists( $req->{opt}->{V} )) { | ||||
|     #    $req->{verbose} = 1; | ||||
|     #} | ||||
|     my $opt = $req->{opt}; | ||||
|      | ||||
|     my $current_node = $opt->{c}; | ||||
|     my $fip_node = $opt->{f}; | ||||
|     | ||||
|     my @ppcattribs = ('hcp', 'id', 'pprofile', 'parent', 'supernode', 'comments', 'disable'); | ||||
|     my $ppctab  = xCAT::Table->new( 'ppc', -create=>1, -autocommit=>0); | ||||
|     unless ($ppctab ) { | ||||
| 	my $rsp->{data}->[0] = "Cannot open ppc table"; | ||||
| 	xCAT::MsgUtils->message("E", $rsp, $callback); | ||||
| 	return 1; | ||||
|     } | ||||
|  | ||||
|      | ||||
|     my ($current_ppc_ent) = $ppctab->getAttribs({ node=>$current_node},@ppcattribs); | ||||
|     my ($fip_ppc_ent) = $ppctab->getAttribs({ node=>$fip_node},@ppcattribs); | ||||
|     my @current_attrs; | ||||
|     my @fip_attrs; | ||||
|     if( $current_ppc_ent->{'parent'} ne $fip_ppc_ent->{'parent'} ) { | ||||
|         my $reqcopy = {%$req}; | ||||
|         push @requests, $reqcopy; | ||||
|         return \@requests; | ||||
|     } else { | ||||
|      | ||||
|         if($current_ppc_ent->{'hcp'} ne $fip_ppc_ent->{'hcp'} ) { | ||||
|             $callback->({data=>["The two nodes are on the same CEC, but don't have the same hcp"]}); | ||||
| 	    $req = {}; | ||||
| 	    return; | ||||
|         } | ||||
|  | ||||
|         # find service nodes for the HCPs | ||||
|         # build an individual request for each service node | ||||
|         my $service  = "xcat"; | ||||
|         my @hcps=[$current_ppc_ent->{'hcp'}]; | ||||
|         my $sn = xCAT::Utils->get_ServiceNode(\@hcps, $service, "MN"); | ||||
|      | ||||
|         # build each request for each service node | ||||
|         foreach my $snkey (keys %$sn) | ||||
|         {  | ||||
|             #$callback->({data=>["The service node $snkey "]}); | ||||
|             my $reqcopy = {%$req}; | ||||
|             $reqcopy->{'_xcatdest'} = $snkey; | ||||
|             $reqcopy->{_xcatpreprocessed}->[0] = 1; | ||||
|             #my $hcps1=$sn->{$snkey}; | ||||
| 	    #my @nodes=(); | ||||
| 	    #foreach (@$hcps1) {  | ||||
| 	    #    push @nodes, @{$hcp_hash{$_}{nodes}}; | ||||
| 	    #} | ||||
| 	    #@nodes = sort @nodes; | ||||
| 	    #my %hash = map{$_=>1} @nodes; #remove the repeated node for multiple hardware control points | ||||
| 	    #@nodes =keys %hash; | ||||
| 	    #$reqcopy->{node} = \@nodes; | ||||
|             #print "nodes=@nodes\n"; | ||||
|             push @requests, $reqcopy; | ||||
|         } | ||||
|      | ||||
|     } | ||||
|     #print Dumper(\@requests); | ||||
|     return \@requests; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| #---------------------------------------------------------------------------- | ||||
|  | ||||
| =head3   process_request | ||||
|  | ||||
|         Check for xCAT command and call the appropriate subroutine. | ||||
|  | ||||
|         Arguments: | ||||
|  | ||||
|         Returns: | ||||
|                 0 - OK | ||||
|                 1 - error | ||||
|         Globals: | ||||
|  | ||||
|         Error: | ||||
|  | ||||
|         Example: | ||||
|  | ||||
|         Comments: | ||||
| =cut | ||||
|  | ||||
| #----------------------------------------------------------------------------- | ||||
|  | ||||
| sub process_request | ||||
| { | ||||
|  | ||||
|     my $request  = shift; | ||||
|     my $callback = shift; | ||||
|  | ||||
|     my $ret; | ||||
|     my $msg; | ||||
|  | ||||
|     my $command  = $request->{command}->[0]; | ||||
|     my $args     = $request->{arg}; | ||||
|     my $filedata = $request->{stdin}->[0]; | ||||
|  | ||||
|     # figure out which cmd and call the subroutine to process | ||||
|     if ($command eq "swapnodes") | ||||
|     { | ||||
|         ($ret, $msg) = &swapnodes($request, $callback, $args); | ||||
|     } | ||||
|       | ||||
|     my $rsp; | ||||
|     if ($msg) | ||||
|     { | ||||
|         $rsp->{data}->[0] = $msg; | ||||
|         $callback->($rsp); | ||||
|     } | ||||
|  | ||||
|     if ($ret > 0) { | ||||
| 	$rsp->{errorcode}->[0] = $ret; | ||||
|     } | ||||
| } | ||||
|  | ||||
| #---------------------------------------------------------------------------- | ||||
|  | ||||
| =head3   processArgs | ||||
|  | ||||
|         Process the command line. Covers all four commands. | ||||
|  | ||||
| 		Also - Process any input files provided on cmd line. | ||||
|  | ||||
|         Arguments: | ||||
|  | ||||
|         Returns: | ||||
|                 0 - OK | ||||
|                 1 - just print usage | ||||
| 		2 - error | ||||
|         Globals: | ||||
|  | ||||
|         Error: | ||||
|  | ||||
|         Example: | ||||
|  | ||||
|         Comments: | ||||
| =cut | ||||
|  | ||||
| #----------------------------------------------------------------------------- | ||||
|  | ||||
| sub parse_args | ||||
| { | ||||
|     my $request = shift; | ||||
|     my $args = $request->{arg};  | ||||
|     my $gotattrs = 0; | ||||
|     my %opt      =(); | ||||
|  | ||||
|     if (defined(@{$args})) { | ||||
|         @ARGV = @{$args}; | ||||
|     } else { | ||||
|             return 2; | ||||
|     } | ||||
|  | ||||
|     if (scalar(@ARGV) <= 0) { | ||||
|         return 2; | ||||
|     } | ||||
|  | ||||
|     # parse the options - include any option from all 4 cmds | ||||
|     Getopt::Long::Configure("no_pass_through"); | ||||
|     if ( !GetOptions( \%opt, qw(h|help v|version V|verbose c=s f=s ) )) { | ||||
|          return 2; | ||||
|     } | ||||
|  | ||||
|     if ( exists( $opt{v} )) { | ||||
|          return( \$::VERSION ); | ||||
|     } | ||||
|  | ||||
|     if ( exists( $opt{h}) || $opt{help}) { | ||||
|          return 2; | ||||
|     } | ||||
|  | ||||
|     if ( (!exists( $opt{c})) ||(!exists( $opt{f})) ) { | ||||
|          return 2;  | ||||
|     } | ||||
|     | ||||
|     $request->{opt} = \%opt;     | ||||
|      | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| #---------------------------------------------------------------------------- | ||||
|  | ||||
| =head3  swapnodes | ||||
|  | ||||
|         Support for the xCAT chdef command. | ||||
|  | ||||
|         Arguments: | ||||
|         Returns: | ||||
|                 0 - OK | ||||
|                 1 - error | ||||
|         Globals: | ||||
|  | ||||
|         Error: | ||||
|  | ||||
|         Example: | ||||
|  | ||||
|         Comments: | ||||
|  | ||||
| =cut | ||||
|  | ||||
| #----------------------------------------------------------------------------- | ||||
|  | ||||
| sub swapnodes | ||||
| { | ||||
|     my $request = shift; | ||||
|     my $callback = shift; | ||||
|     my $args    = shift; | ||||
| 	 | ||||
|     my $Rc    = 0; | ||||
|     my $error = 0; | ||||
| 	 | ||||
|     my $rsp; | ||||
|     my $action; | ||||
|     my $values; | ||||
|     my $vals; | ||||
|      | ||||
|  | ||||
|     my $opt = $request->{opt}; | ||||
|     #print Dumper($opt); | ||||
|      | ||||
|     my $current_node = $opt->{c}; | ||||
|     my $fip_node = $opt->{f}; | ||||
|     | ||||
|     #check the current_node and fip_node state, they should be in Not Activated state | ||||
|      | ||||
|      | ||||
|     # get the ppc attributes for the two nodes | ||||
|     #swap | ||||
|     #update it | ||||
|     my @ppcattribs = ('hcp', 'id', 'pprofile', 'parent', 'supernode', 'comments', 'disable'); | ||||
|     my $ppctab  = xCAT::Table->new( 'ppc', -create=>1, -autocommit=>0); | ||||
|     unless ($ppctab ) { | ||||
| 	$rsp->{data}->[0] = "Cannot open ppc table"; | ||||
| 	xCAT::MsgUtils->message("E", $rsp, $callback); | ||||
| 	return 1; | ||||
|     } | ||||
|  | ||||
|     my ($current_ppc_ent) = $ppctab->getAttribs({ node=>$current_node},@ppcattribs); | ||||
|     my ($fip_ppc_ent) = $ppctab->getAttribs({ node=>$fip_node},@ppcattribs); | ||||
|     my @current_attrs; | ||||
|     my @fip_attrs; | ||||
|     my $cec; | ||||
|     if( $current_ppc_ent->{'parent'} eq $fip_ppc_ent->{'parent'} ) { | ||||
| 	#the attributes of the current LPAR will be used for fsp_api_action | ||||
|         push @current_attrs, $current_ppc_ent->{'id'}; | ||||
|         push @current_attrs, "0"; | ||||
|         push @current_attrs, $current_ppc_ent->{'parent'}; | ||||
|         push @current_attrs, $current_ppc_ent->{'hcp'};	 | ||||
|         push @current_attrs, "lpar";	 | ||||
|         push @current_attrs, "0"; | ||||
|          | ||||
|         #the attributes of the current LPAR will be used for fsp_api_action | ||||
| 	push @fip_attrs, $fip_ppc_ent->{'id'};	 | ||||
| 	push @fip_attrs, "0";	 | ||||
| 	push @fip_attrs, $fip_ppc_ent->{'parent'};	 | ||||
| 	push @fip_attrs, $fip_ppc_ent->{'hcp'};	 | ||||
| 	push @fip_attrs, "lpar";	 | ||||
| 	push @fip_attrs, "0";	 | ||||
|         | ||||
|         #For the LPARs on the same CEC, we should swap the nodes' attributes and then assign the IO which are assigned to the current LPAR to the FIP LPAR.	 | ||||
| 	$cec = $current_ppc_ent->{'parent'}; | ||||
|         my $type = "lpar"; | ||||
| 	$action = "all_lpars_state"; | ||||
| 	 | ||||
|         my $values =  xCAT::FSPUtils::fsp_state_action ($cec, $type, $action); | ||||
|         my $Rc = shift(@$values); | ||||
| 	if ( $Rc != 0 ) { | ||||
| 	     $rsp->{data}->[0] = $$values[0]; | ||||
| 	     xCAT::MsgUtils->message("E", $rsp, $callback); | ||||
| 	     return -1; | ||||
| 	} | ||||
| 	 | ||||
| 	foreach ( @$values ) { | ||||
|             my ($state,$lparid) = split /,/; | ||||
| 	    if( $lparid eq $current_ppc_ent->{'id'}) { | ||||
| 	         if($state ne "Not Activated") { | ||||
| 		     $rsp->{data}->[0] = "The two LPARs in one same CEC. Please make sure the two LPARs are in Not Activated state before swapping their location information"; | ||||
| 	             xCAT::MsgUtils->message("E", $rsp, $callback); | ||||
| 	             return -1; | ||||
| 		 }    | ||||
| 	    } | ||||
|  | ||||
| 	    if( $lparid eq $fip_ppc_ent->{'id'}) { | ||||
| 	         if($state ne "Not Activated") { | ||||
| 		     $rsp->{data}->[0] = "The two LPARs in one same CEC. Please make sure the two LPARs are in Not Activated state before swapping their location information"; | ||||
| 	             xCAT::MsgUtils->message("E", $rsp, $callback); | ||||
| 	             return -1; | ||||
| 		 }    | ||||
| 	    } | ||||
|         } | ||||
|       	  | ||||
|  | ||||
|     } | ||||
|      | ||||
|     my %keyhash = (); | ||||
|     # swap the current ent and the fip ent  | ||||
|     $keyhash{'node'}    = $current_node;  | ||||
|     $ppctab->setAttribs( \%keyhash,$fip_ppc_ent ); | ||||
|  | ||||
|     $keyhash{'node'}    = $fip_node; | ||||
|     $ppctab->setAttribs( \%keyhash,$current_ppc_ent ); | ||||
|  | ||||
|     $ppctab->commit; | ||||
|     $ppctab->close(); | ||||
|      | ||||
|     #set the variables to be  empty | ||||
|     #$current_ent = (); | ||||
|     #$fip_ent     = (); | ||||
|     %keyhash     =();    | ||||
|      | ||||
|     # get the nodepos attributes for the two nodes | ||||
|     #swap | ||||
|     #update it | ||||
|     my @nodeposattribs =('rack','u','chassis','slot','room','comments','disable');  | ||||
|     my $nodepostab  = xCAT::Table->new( 'nodepos', -create=>1, -autocommit=>0); | ||||
|     unless ($nodepostab ) { | ||||
| 	$rsp->{data}->[0] = "Cannot open nodepos table"; | ||||
| 	xCAT::MsgUtils->message("E", $rsp, $callback); | ||||
| 	return 1; | ||||
|     } | ||||
|  | ||||
|     my $current_ent = $nodepostab->getAttribs({ node=>$current_node},@nodeposattribs); | ||||
|     my $fip_ent     = $nodepostab->getAttribs({ node=>$fip_node},@nodeposattribs); | ||||
|  | ||||
|     # swap the current ent and the fip ent  | ||||
|     $keyhash{'node'}    = $current_node;  | ||||
|     $nodepostab->setAttribs( \%keyhash,$fip_ent ); | ||||
|  | ||||
|     $keyhash{'node'}    = $fip_node; | ||||
|     $nodepostab->setAttribs( \%keyhash,$current_ent ); | ||||
|  | ||||
|     $nodepostab->commit; | ||||
|     $nodepostab->close(); | ||||
|     | ||||
|     # get the slots information from fsp, swap them, and then assign them to the others. | ||||
|     #.... | ||||
|     if( $current_ppc_ent->{'parent'} eq $fip_ppc_ent->{'parent'} ) { | ||||
| 	 | ||||
| 	$action = "get_io_slot_info"; | ||||
| 	$values =  xCAT::FSPUtils::fsp_api_action ($cec, \@current_attrs, $action); | ||||
| 	#$Rc = shift(@$values); | ||||
| 	$Rc = pop(@$values); | ||||
| 	if ( $Rc != 0 ) { | ||||
| 	     $rsp->{data}->[0] = $$values[1]; | ||||
| 	     xCAT::MsgUtils->message("E", $rsp, $callback); | ||||
| 	     return 1; | ||||
| 	}	 | ||||
|         | ||||
| 	$action = "set_io_slot_owner"; | ||||
| 	my $tooltype = 0; | ||||
|         my @data = split(/\n/, $$values[1]); | ||||
| 	foreach my $v (@data) { | ||||
| 	    my ($lpar_id, $busid, $location, $drc_index, $owner_type, $owner, $descr) = split(/,/, $v); | ||||
| 	    if( $lpar_id eq $current_ppc_ent->{'id'} ) { | ||||
| 	        $vals =  xCAT::FSPUtils::fsp_api_action ($fip_node, \@fip_attrs, $action, $tooltype, $drc_index);  | ||||
| 	        $Rc = pop(@$vals); | ||||
| 	        if ( $Rc != 0 ) { | ||||
| 	             $rsp->{data}->[0] = $$vals[1]; | ||||
| 		     xCAT::MsgUtils->message("E", $rsp, $callback); | ||||
| 		     return -1; | ||||
| 		}	 | ||||
| 	    }   | ||||
| 	} | ||||
|     }  | ||||
|  | ||||
|     return ; | ||||
|  | ||||
|      | ||||
| } | ||||
|  | ||||
| #---------------------------------------------------------------------------- | ||||
|  | ||||
| =head3  swapnodes_usage  | ||||
|  | ||||
|         Arguments: | ||||
|         Returns: | ||||
|         Globals: | ||||
|  | ||||
|         Error: | ||||
|  | ||||
|         Example: | ||||
|  | ||||
|         Comments: | ||||
| =cut | ||||
|  | ||||
| #----------------------------------------------------------------------------- | ||||
|  | ||||
| sub swapnodes_usage | ||||
| { | ||||
|     my $callback = shift; | ||||
|     my $rsp; | ||||
|     $rsp->{data}->[0] = | ||||
|       "\nUsage: swapnodes - swap the location info in the db between 2 nodes. If swapping within a cec, it will assign the IO adapters that were assigned to the defective node to the available node\n"; | ||||
|     $rsp->{data}->[1] = "  swapnodes [-h | --help ] \n"; | ||||
|     $rsp->{data}->[2] = "  swapnodes -c current_node -f fip_node"; | ||||
|     xCAT::MsgUtils->message("I", $rsp, $callback); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| 1; | ||||
|  | ||||
		Reference in New Issue
	
	Block a user