484 lines
12 KiB
Perl
484 lines
12 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;
|
||
|
|
||
|
# 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;
|
||
|
|