mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-11-04 05:12:30 +00:00 
			
		
		
		
	git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@13467 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
		
			
				
	
	
		
			507 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			507 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
#!/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;
 | 
						|
use xCAT::Utils;
 | 
						|
use xCAT::TableUtils;
 | 
						|
use xCAT::ServiceNodeUtils;
 | 
						|
# 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->getNodeAttribs($current_node,@ppcattribs);
 | 
						|
    my ($fip_ppc_ent) = $ppctab->getNodeAttribs($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::ServiceNodeUtils->get_ServiceNode(\@hcps, $service, "MN");
 | 
						|
        #print Dumper($sn);
 | 
						|
        if( keys(%$sn) == 0 )     {
 | 
						|
            my $reqcopy = {%$req};
 | 
						|
            push @requests, $reqcopy;
 | 
						|
        } 
 | 
						|
      
 | 
						|
 
 | 
						|
        # 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 o ) )) {
 | 
						|
         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->getNodeAttribs( $current_node,@ppcattribs);
 | 
						|
    my ($fip_ppc_ent) = $ppctab->getNodeAttribs( $fip_node,@ppcattribs);
 | 
						|
    my @current_attrs;
 | 
						|
    my @fip_attrs;
 | 
						|
    my $cec;
 | 
						|
    if( $current_ppc_ent->{'parent'} eq $fip_ppc_ent->{'parent'} ) {
 | 
						|
 | 
						|
        my %tabs;
 | 
						|
	$tabs{ppc}=$ppctab;
 | 
						|
	$tabs{vpd}= xCAT::Table->new( 'vpd', -create=>1, -autocommit=>0);
 | 
						|
        unless (  !exists( $tabs{vpd} )  ) {
 | 
						|
	    $rsp->{data}->[0] = "Cannot open vpd table";
 | 
						|
	    xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
	    return 1;
 | 
						|
        }
 | 
						|
 | 
						|
	xCAT::FSPUtils::getHcpAttribs($request, \%tabs);
 | 
						|
	#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 ($request, $cec, \@current_attrs, $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 );
 | 
						|
 | 
						|
    if( ! (exists($opt->{o}))) {
 | 
						|
        $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->getNodeAttribs( $current_node,@nodeposattribs);
 | 
						|
    my $fip_ent     = $nodepostab->getNodeAttribs( $fip_node,@nodeposattribs);
 | 
						|
 | 
						|
    # swap the current ent and the fip ent 
 | 
						|
    $keyhash{'node'}    = $current_node; 
 | 
						|
    $nodepostab->setAttribs( \%keyhash,$fip_ent );
 | 
						|
 | 
						|
    if( ! (exists($opt->{o}))) {
 | 
						|
        $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 ($request,$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 ($request, $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 [-o]";
 | 
						|
    xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
1;
 | 
						|
 |