# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html

package xCAT::FSPcfg;
use strict;
use Getopt::Long;
use xCAT::Usage;
use xCAT::Utils;
use xCAT::FSPUtils;
use xCAT::TableUtils;
use xCAT::PPCcfg;
#use Data::Dumper;
#use xCAT::PPCcli;
use xCAT::MsgUtils qw(verbose_message);

##########################################
# Globals
##########################################
my %rspconfig = ( 
    frame  => \&frame,
    cec_off_policy  => \&cec_off_policy,
);

my %default_passwd = ( 
    HMC      => "",
    admin   => "admin",
    general => "general",
);

##########################################################################
# Parse the command line for options and operands
##########################################################################
sub array_to_string {
    my $array = shift;
    my $string = "";
    my $i = 0;
    if (!scalar(@$array)) {
        return undef;
    }
    $string .= "\'$array->[0]\'";
    for ($i = 1; $i < scalar(@$array) - 1; $i++) {
        $string .= ", ";
        $string .= "\'$array->[$i]\'";
    }
    if ($i < scalar(@$array)) {
        $string .= " or \'$array->[$i]\'";
    }
    return $string;
}

sub check_command {
    my $cmd = shift;
    my $rsp = shift;
    my @type = ();
    foreach my $tmp_type (keys %$rsp) {
	if (grep (/^$cmd$/, @{$rsp->{$tmp_type}})) {
            push @type, $tmp_type;
	}
    }
    if (!scalar(@type)) {
        return undef;
    } else {
	return &array_to_string(\@type);	
    }
}

sub parse_args {

    my $request = shift;
    my $command = $request->{command};
    my $args    = $request->{arg};
    my %opt     = ();
    my %cmds    = ();
    my @fsp = (
        "HMC_passwd",
        "admin_passwd",
        "general_passwd",
        "*_passwd",
        "resetnet",
        "cec_off_policy"
    );
    my @bpa = (
	"frame",
        "HMC_passwd",
        "admin_passwd",
        "general_passwd",
        "*_passwd",
        "resetnet"
    );
    my @cec = (
        "HMC_passwd",
        "admin_passwd",
        "general_passwd",
        "*_passwd",
        "cec_off_policy",
        "resetnet",
        "sysname",
        "pending_power_on_side",
        "BSR",
        "setup_failover",
        "force_failover",
        "huge_page"
    );
    my @frame = (
	"frame",
        "HMC_passwd",
        "admin_passwd",
        "general_passwd",
        "*_passwd",
        "resetnet",
        "sysname",
        "pending_power_on_side"
    );

    my @blade = (
        "cec_off_policy",
        "pending_power_on_side"
    );

 
    
    my %rsp = (
        fsp   => \@fsp,
        bpa   => \@bpa,
        cec   => \@cec,
        blade   => \@blade,
        frame => \@frame,
    );
    #############################################
    # Get support command list
    #############################################
    #my $typetab  = xCAT::Table->new( 'nodetype' );
    #my $nodes = $request->{node};
    #foreach (@$nodes) {
    #    if ( defined( $typetab )) {      
    #        my ($ent) = $typetab->getAttribs({ node=>$_},'nodetype');
    #        if ( defined($ent) ) {
    #               $request->{hwtype} = $ent->{nodetype};
    #               last;
    #        }
    #
    #    }
    #
    #}
    
    my $nodes = $request->{node};
    my $typehash = xCAT::DBobjUtils->getnodetype($nodes, "ppc");
    foreach my $nn (@$nodes) {
        $request->{hwtype} =$$typehash{$nn};
        last if ($request->{hwtype});
    }
 
    my $supported = $rsp{$request->{hwtype}};
     
    #############################################
    # Responds with usage statement
    #############################################
    local *usage = sub {
        my $usage_string = xCAT::Usage->getUsage($command);
        return( [$_[0], $usage_string] );
    };
    #############################################
    # Process command-line arguments
    #############################################
    if ( !defined( $args )) {
        return(usage( "No command specified" ));
    }
    #############################################
    # Checks case in GetOptions, allows opts
    # to be grouped (e.g. -vx), and terminates
    # at the first unrecognized option.
    #############################################
    @ARGV = @$args;
    $Getopt::Long::ignorecase = 0;
    Getopt::Long::Configure( "bundling" );
    $request->{method} = undef;

    if ( !GetOptions( \%opt, qw(V|verbose resetnet))) {
        return( usage() );
    }
    ####################################
    # Check for "-" with no option
    ####################################
    if ( grep(/^-$/, @ARGV )) {
        return(usage( "Missing option: -" ));
    }
    ####################################
    # Check for "=" with no argument 
    ####################################
    if (my ($c) = grep(/=$/, @ARGV )) {
        return(usage( "Missing argument: $c" ));
    }
    ####################################
    # Check for unsupported commands
    ####################################
    my @arg_array = @ARGV;
    my @fsp_cmds = ();
    my @ppc_cmds = ();
    foreach my $arg ( @arg_array ) {
        my ($command,$value) = split( /=/, $arg );
        if ( !grep( /^$command$/, @$supported) and !$opt{resetnet}) {
            $request->{arg} = [$arg];
            my $res = xCAT::PPCcfg::parse_args($request, @_); 
            if (ref($res) eq 'ARRAY') {
		        my $check_cmd = &check_command($command, \%rsp);
		        if (!defined($check_cmd)) {
                    return $res;
		        } else {
		            return ([$_[0], "'$command' is only supported by type $check_cmd."]);
                }
            } else {
                push @ppc_cmds, $command;
            } 
        } else {
            push @fsp_cmds, $command;
        }
        if ( exists( $cmds{$command} )) {
            return(usage( "Command multiple times: $command" ));
        }
        $cmds{$command} = $value;
    }
    
    $request->{arg} = \@arg_array;
    if (scalar(@fsp_cmds) && scalar(@ppc_cmds)) {
        my $fsp_cmds_string = &array_to_string(\@fsp_cmds);
        my $ppc_cmds_string = &array_to_string(\@ppc_cmds);
        return (usage("Invalid command array: $fsp_cmds_string can not execute with $ppc_cmds_string."));
    } elsif(scalar(@ppc_cmds)) {
        my @enableASMI = xCAT::TableUtils->get_site_attribute("enableASMI");
        if (defined($enableASMI[0])) {
            $enableASMI[0] =~ tr/a-z/A-Z/;    # convert to upper
            if (($enableASMI[0] eq "1") || ($enableASMI[0] eq "YES")) {
                $request->{enableASMI} = 1;
            } 
        } 
        if ($request->{enableASMI} ne '1') {
            return (usage( "You should enable \"ASMI\" first for \'$command\'."));
        }
    }
    ####################################
    # Check command arguments 
    ####################################
    foreach ( keys %cmds ) {
        if ( $cmds{$_} ) {
            my $result = parse_option( $request, $_, $cmds{$_} );
            if ( $result ) {
                return( usage($result) );
            }
        } elsif ($_ =~ /_passwd$/) {
            return( usage("No argument specified for '$_'"));
        } 
    }
    
    ####################################
    # Return method to invoke 
    ####################################
    #if ( $request->{hwtype} =~ /(^hmc|ivm)$/ ) {
    #    $request->{method} = "cfg";
    #    return( \%opt );
    #}
    ####################################
    # Return method to invoke
    ####################################
    if ( exists($cmds{frame}) or exists($cmds{cec_off_policy})) {
        $request->{hcp} = (exists($cmds{frame})) ? "bpa" : "fsp";
        $request->{method} = "cfg"; 
        return( \%opt );
    }

    ####################################
    # Return method to invoke
    ####################################
    if ( $opt{resetnet}  ) {
        $request->{hcp} = "fsp";
        $request->{method} = "resetnet";
        return( \%opt );
    }
    if(exists($cmds{sysname}) or exists($cmds{pending_power_on_side}) or exists($cmds{BSR})
            or exists($cmds{setup_failover}) or exists($cmds{force_failover}) or exists ($cmds{huge_page})) {
        $request->{hcp} = $request->{hwtype} eq 'frame' ? "bpa":"fsp";
        $request->{method} = "do_fspapi_function";
        return (\%opt);
    }
    ####################################
    # Return method to invoke
    ####################################
    if ( exists($cmds{HMC_passwd}) or exists($cmds{general_passwd}) or exists($cmds{admin_passwd}) or exists($cmds{"*_passwd"}) ) {
        $request->{hcp} = "fsp";
        $request->{method} = "passwd";
        return( \%opt );
    }
    $request->{method} = \%cmds;
    return( \%opt );
}


##########################################################################
# Parse the command line optional arguments 
##########################################################################
sub parse_option {

    my $request = shift;
    my $command = shift;
    my $value   = shift;

  
    ####################################
    # Password
    ####################################
    #if ( $command eq 'admin_passwd' or $command eq 'general_passwd' or $command eq "*_passwd"){
    #    my ($passwd,$newpasswd) = split /,/, $value;
    #    if ( !$passwd or !$newpasswd) {
    #        return( "Current password and new password couldn't be empty for user 'admin' and 'general'" );
    #    }
    #}

    if ( $command eq 'HMC_passwd' or $command eq 'admin_passwd' or $command eq 'general_passwd' or $command eq "*_passwd" ) {
        my ($passwd,$newpasswd) = split /,/, $value;
        if ( !$newpasswd ) {
            return( "New password couldn't be empty for user 'HMC', 'admin' or 'general'" );
        }
    }

    if ( $command eq 'frame' ){
        if ( $value !~ /^\d+$/i && $value ne '*' ) { 
            return( "Invalid frame number '$value'" );
        }
    }

    if ( $command eq 'cec_off_policy' ){
        if ( $value !~ /^poweroff$/i && $value !~ /^stayon$/i ) { 
            return( "Invalid cec_off_policy '$value'" );
        }
    }
    if ($command eq 'sysname') {
        if ($value ne '*') {
            if ($value !~ /^[a-zA-Z0-9-_]+$/) {
                return( "Invalid sysname param '$value'" );
            } elsif (scalar(@{$request->{node}}) gt '1') {
                return( "Invalid sysname param '$value'" );
            }
            my $len = rindex $value."\$", "\$";
            if ($len > '31') {
                return ("Invalid sysname param '$value', name is too long, max 31 characters");
            }
        }
    }
    if ($command eq 'pending_power_on_side') {
        if ($value !~ /^(temp|perm)$/) {
            return ("Invalid pending_power_on_side param '$value'");
        }
    }
    if ($command eq 'setup_failover') {
        if ($value !~ /^(enable|disable)$/) {
            return ("Invalid setup_failover param '$value'");
        }
    }
    if ($command =~ /^(BSR|force_failover)$/ ) {
        return ("BSR value can not be set");
    }
    if ($command =~ /^huge_page$/) {
	    if ($value !~ /^[0-9]+$/) {
		    return ("Invalid huge page param '$value'");
	    }
    }
    return undef;
}
sub check_node_info {
	my $hash = shift;
	my $invalid_node = undef;
	while (my ($mtsm, $h) = each (%$hash)) {
		while (my ($name, $d) = each(%$h)) {
			if (@$d[4] !~ /^(cec|frame|blade)$/) {
				$invalid_node = $name;
				last;
			}
		}
	}
	return $invalid_node;
}

my %fspapi_action = (
        sysname => {
            query => {
                cec => "get_cec_name",
                frame => "get_frame_name"
            },
            set => {
                cec => "set_cec_name",
                frame => "set_frame_name"
            }
        },
        pending_power_on_side => {
            query => {
                cec => "list_firmware_level",
                blade => "list_firmware_level",
                frame => "list_firmware_level"
            },
            set => {
                cec => "set_ipl_param",
                blade => "set_ipl_param",
                frame => "set_ipl_param"
            }
        },
        BSR => {
            query => {
                cec => "get_cec_bsr"
            }    
        },
        setup_failover => {
            query => {
                cec => "cec_setup_failover"
            },
            set => {
                cec => "cec_setup_failover"
            }
        },
        force_failover => {
            query => {
                cec => "cec_force_failover"
            }
        },
        huge_page => {
		    query => {
		        cec => "get_huge_page"
		    },
		    set => {
		        cec => "set_huge_page"
		    }
        }
);
sub do_process_query_res {
    my $name = shift;
    my $cmd = shift;
    my $result = shift;
    my $res = shift;
    if (@$res[2] != 0) {
        push @$result, $res;
        return "Error";
    }
    if ($cmd =~ /^sysname$/) {
        push @$result, $res;
    } elsif ($cmd =~ /^pending_power_on_side$/) {
        my @values = split(/\n/, @$res[1]);
        foreach my $v (@values) {
            if ($v =~ /pend_power_on_side_(\w+)=(temp|perm),/) {
                push @$result, [$name, "Pending Power On Side \L\u$1: $2", '0'];
            } else {
                push @$result, [$name, $v, '1'];
                return "Error";
            }
        }
    } elsif ($cmd =~ /^(BSR|huge_page)$/) {
        my @values = split(/\n/, @$res[1]);
        foreach my $v (@values) {
            push @$result, [$name, $v, '0'];
        }
    } else {
        push @$result, $res;
    }
    return undef;
}
sub do_query {
    my $request = shift;
    my $hash = shift;
    my $cmd = shift;
    my @result = ();
    while (my ($mtms, $h) = each(%$hash)) {
        while (my($name, $d) = each(%$h)) {
            my $action = $fspapi_action{$cmd}{query}{@$d[4]};
            xCAT::MsgUtils->verbose_message($request, "rspconfig :$action for node:$name."); 
            my $values = xCAT::FSPUtils::fsp_api_action($request, $name, $d, $action);
            &do_process_query_res($name, $cmd, \@result, $values);
            #my $res = &do_process_query_res($name, $cmd, \@result, $values);
            #if (defined($res)) {
            #    last;
            #}
        }
    }
    return (\@result);
}
sub do_set_get_para {
    my $node_name = shift;
    my $cmd = shift;
    my $value = shift;
    if ($cmd =~ /^sysname$/) {
        return (($value eq '*') ? $node_name : $value);
    } elsif ($cmd =~ /^pending_power_on_side$/){
        return ($value =~ /^perm$/) ? '0' : '1';
    } elsif ($cmd =~ /^setup_failover$/) {
        return ($value =~ /^enable$/) ? '1' : '0';
    } else {
		return $value;
    }
}

sub do_process_set_res {
    my $name = shift;
    my $cmd = shift;
    my $result = shift;
    my $res = shift;
    if (@$res[1] && @$res[1] !~ /success/i) {
        push @$result, $res;
        return "Error";
    } else {
        push @$result, [$name, "Success", 0];
    }
}
sub do_set {
    my $request = shift;
    my $hash = shift;
    my $cmd = shift;
    my $value = shift;
    my @result = ();
    while (my ($mtms, $h) = each(%$hash)) {
        while (my($name, $d) = each(%$h)) {
            my $action = $fspapi_action{$cmd}{set}{@$d[4]};
            xCAT::MsgUtils->verbose_message($request, "rspconfig :$action for node:$name, param:$value."); 
            my $para = &do_set_get_para($name, $cmd, $value);
            my $values = xCAT::FSPUtils::fsp_api_action($request, $name, $d, $action, 0, $para);
#           print Dumper($values);
            &do_process_set_res($name, $cmd, \@result, $values);
            #my $res = &do_process_set_res($name, $cmd, \@result, $values);
            #if (defined($res)) {
            #    last;
            #}
        }
    }
    return (\@result);
}
sub do_fspapi_function {
    my $request = shift;
    my $hash = shift;
    my $exp = shift;
    my @ret = ();
    my $res;
    my $args = $request->{arg};
    my @fspapi_array = qw/sysname pending_power_on_side BSR setup_failover force_failover huge_page/;
    my $invalid_node = &check_node_info($hash);
    if (defined($invalid_node)) {
        return ([[$invalid_node, "Node must be CEC or Frame", '1']]);
    }
    foreach my $arg (@$args) {
        my ($cmd, $value) = split /=/, $arg;
	    if (!grep(/^$cmd$/, @fspapi_array)) {
            my $fspapi_array_string = &array_to_string(\@fspapi_array);
	        return ([["Error", "'$cmd' can not execute with $fspapi_array_string", '1']]);
	    }
        if ($value) {
            $res = &do_set($request, $hash, $cmd, $value)
        } else {
            $res = &do_query($request, $hash, $cmd);
        }
        push @ret, @$res;
    }
    return \@ret;
}
##########################################################################
# Update passwords for different users on FSP/BPA
##########################################################################
sub passwd {

    my $request = shift;
    my $hash    = shift;
    my $exp     = shift;
    my $args    = $request->{arg};
    my $user    = ();
    my $users   = ();
    my @output  = ();
    my $default;

	foreach my $arg ( @$args ) {
        my ($user,$value) = split /=/, $arg;
	if ($user !~ /_passwd$/) {
	    return ([["Error", "'$user' can not execute with '*_passwd' commands", '1']]);
	}
        my ($passwd,$newpasswd) = split /,/, $value;
        $user =~ s/_passwd$//;
        #$user =~ s/^HMC$/access/g;
        
        if( !$passwd) {
            $default = 1;    
        }
         
        if ( $user eq "*" ) {
            push @$users, "HMC";
            push @$users, "admin";
            push @$users, "general";
        } else {
            push @$users, $user;
        }

        foreach my $usr ( @$users ) {
	       if( $default == 1 ) {
	           $passwd = $default_passwd{$usr};
	       }
                
        	while ( my ($cec,$h) = each(%$hash) ) {
           			while ( my ($node,$d) = each(%$h) ) {
               			my $type = @$d[4];
				my $fsp_api    = ($::XCATROOT) ? "$::XCATROOT/sbin/fsp-api" : "/opt/xcat/sbin/fsp-api";
                                xCAT::MsgUtils->verbose_message($request, "rspconfig :modify password of $usr for node:$node.");
				my $cmd = xCAT::FSPcfg::fsp_api_passwd ($request, $node, $d, $usr, $passwd, $newpasswd);
                		my $Rc = @$cmd[2];
				my $data = @$cmd[1];
                		my $usr_back = $usr;
                		$usr_back =~ s/^access$/HMC/g;
				push @output,[$node,"$usr_back: $data",$Rc];


                		##################################
                		# Write the new password to table
                		##################################
                		if ( $Rc == 0 ) {
                                    xCAT::MsgUtils->verbose_message($request, "rspconfig :update xCATdb for node:$node,ID:$usr.");
                		    xCAT::PPCdb::update_credentials( $node, $type, $usr, $newpasswd );
                		}
            			}
        		}
		}
	}
 
    return( \@output );
}

##########################################################################
# Handles all PPC rspconfig commands
##########################################################################
sub cfg {

    my $request = shift;
    my $hash    = shift;
    my $exp     = shift;
    my $args    = $request->{arg};
    my $result;

    foreach ( @$args ) {
        ##################################
        # Ignore switches in command-line
        ##################################
        unless ( /^-/ ) {
            my ($cmd,$value) = split /=/;
	    if ($cmd !~ /(frame|cec_off_policy)/) {
		return ([["Error", "'$cmd' can not execute with 'frame' or 'cec_off_policy'", '1']]);		
	    }

            no strict 'refs';
            $result = $rspconfig{$cmd}( $request, $value, $hash );
            use strict;
        }
    }
    return( $result );
}

sub frame {
    my $request = shift;
    my $value   = shift;
    my $hash    = shift;
    my $arg     = $request->{arg};

    foreach ( @$arg ) {
        my $result;
        my $Rc;
        my $data;

        my ($cmd, $value) = split /=/, $_;
        if ( $cmd ne "frame" ) {
            return( [["Error","Multiple option $cmd and frame is not accepted", -1]] );
        }

        #################################
        # Open xCAT database to sync with
        # the frame number between hcp
        # and database
        #################################
        my $tab = xCAT::Table->new( "ppc" );
        
        while ( my ($cec,$h) = each(%$hash) ) {
            while ( my ($node,$d) = each(%$h) ) {
                if ( !defined($value) ) {

                    #################################
                    # Get frame number
                    #################################
		    #$data = xCAT::PPCcli::lssyscfg( $exp, @$d[4], @$d[2], 'frame_num' );
                    xCAT::MsgUtils->verbose_message($request, "rspconfig :get_frame_number for node:$node.");
		    $data = xCAT::FSPUtils::fsp_api_action( $request, $node, $d, "get_frame_number");
                    $Rc = pop(@$data);

                    #################################
                    # Return error
                    #################################
                    if ( $Rc != 0 || @$data[1] =~ /Error/ ) {
                        return( [[$node,"@$data[1]. If just set the frame number, please wait for 5-10 minutes. Otherwise, maybe other problems cause this failure.",$Rc]] );
                    }

                    push @$result, [$node,@$data[1], 0];

                    #################################
                    # Set frame number to database
                    #################################
                    $tab->setNodeAttribs( $node, { id=>@$data[1] } );

                } elsif ( $value eq '*' ) {
                    #################################
                    # Set frame number
                    # Read the settings from database 
                    #################################
                    my $ent=$tab->getNodeAttribs( $node,['id'] );

                    #################################
                    # Return error
                    #################################
                    if ( !defined($ent) or !defined($ent->{id}) ) {
                        return( [[$node,"Cannot find frame num in database", -1]] );
                    }
		    #$data = xCAT::PPCcli::chsyscfg( $exp, "bpa", $d, "frame_num=".$ent->{id} );
                    xCAT::MsgUtils->verbose_message($request, "rspconfig :set_frame_number for node:$node,id:$ent->{id}.");
		    $data = xCAT::FSPUtils::fsp_api_action( $request, $node, $d, "set_frame_number", 0, $ent->{id});
                    $Rc = pop(@$data);

                    #################################
                    # Return error
                    #################################
                    if ( $Rc != 0 ) {
                        return( [[$node,@$data[1],$Rc]] );
                    }

                    push @$result, [$node,@$data[1], 0];
                    push @$result, [$node,"It will take several minutes to complete. So please wait for 5-10 minutes, then the other operations could be done. Otherwise, the other operation will fail.", 0];

                } else {
                    #################################
                    # Set frame number
                    # Read the frame number from opt
                    #################################
		    #$data = xCAT::PPCcli::chsyscfg( $exp, "bpa", $d, "frame_num=$value" );
                    xCAT::MsgUtils->verbose_message($request, "rspconfig :set_frame_number for node:$node,id:$value.");
                    $data = xCAT::FSPUtils::fsp_api_action( $request, $node, $d, "set_frame_number", 0, $value);
		    $Rc = pop(@$data);

                    #################################
                    # Return error
                    #################################
                    if ( $Rc != 0 ) {
                        return( [[$node,@$data[1],$Rc]] );
                    }

                    push @$result, [$node,@$data[1],0];
                    push @$result, [$node,"It will take several minutes to complete. So please wait for several minutes, then the other operations could be done. Otherwise, the other operation will fail.", 0];

                    #################################
                    # Set frame number to database
                    #################################
                    $tab->setNodeAttribs( $node, { id=>$value } );
                }
            }

            return( [@$result] );
        }  
    }
}

sub cec_off_policy {
    my $request = shift;
    my $value   = shift;
    my $hash    = shift;
    my $arg     = $request->{arg};
    
    foreach ( @$arg ) {
        my $result;
        my $Rc;
        my $data;

        my ($cmd, $value) = split /=/, $_;
        if ( $cmd ne "cec_off_policy" ) {
            return( [["Error","Multiple option $cmd and cec is not accepted", -1]] );
        }

        while ( my ($cec,$h) = each(%$hash) ) {
            while ( my ($node,$d) = each(%$h) ) {
                if ( !defined($value) ) {

                    #################################
                    # Get platform IPL parameters 
                    #################################
                    xCAT::MsgUtils->verbose_message($request, "rspconfig :get_phyp_cfg_power_off_policy for node:$node.");
		    $data = xCAT::FSPUtils::fsp_api_action( $request, $node, $d, "get_phyp_cfg_power_off_policy");
                    $Rc = pop(@$data);

                    #################################
                    # Return error
                    #################################
                    if ( $Rc != 0 ) {
                        return( [[$node,@$data[1],$Rc]] );
                    }
                     
                    @$data[1] =~ /cec_off_policy=(\w*);/;                    

                    push @$result, [$node, $1, 0];


                 } else {
                    #################################
                    # Set cec off policy 
                    #################################
                    xCAT::MsgUtils->verbose_message($request, "rspconfig :set power_off_policy for node:$node,policy:$value.");
		    if( $value eq "poweroff") {
		        $value = "cec_off_policy_poweroff";
		    } else {
		        $value = "cec_off_policy_stayon";
		    }
                    $data = xCAT::FSPUtils::fsp_api_action( $request, $node, $d, $value);
		    $Rc = pop(@$data);

                    #################################
                    # Return error
                    #################################
                    if ( $Rc != 0 ) {
                        return( [[$node,@$data[1],$Rc]] );
                    }

                    push @$result, [$node,"Success",0];

                }
            }

            return( [@$result] );
        }  
    }
}









##########################################################################
# Invoke fsp_api to change the passwords and store updated passwd in db
##########################################################################
sub fsp_api_passwd {
    my $request  = shift;
    my $node_name  = shift;
    my $attrs      = shift;
    my $user       = shift;
    my $passwd     = shift;
    my $newpasswd  = shift;
    my $id         = 1;
    my $fsp_name   = ();
    my $fsp_ip     = ();
    my $type = (); # fsp|lpar -- 0. BPA -- 1
    my @result;
    my $Rc = 0 ;
    my %outhash = ();
    my $res = 0 ;
    my $fsp_api    = ($::XCATROOT) ? "$::XCATROOT/sbin/fsp-api" : "/opt/xcat/sbin/fsp-api";

    $id = $$attrs[0];
    $fsp_name = $$attrs[3];

    ############################
    # Set type for FSP or BPA
    ############################
    if($$attrs[4] =~ /^fsp$/ || $$attrs[4] =~ /^lpar$/ ||  $$attrs[4] =~ /^cec$/) {
        $type = 0;
    } else {
        $type = 1;
    }

    ############################
    # Get IP address
    ############################
    #$fsp_ip = xCAT::NetworkUtils::get_hdwr_ip($fsp_name);
    #$fsp_ip = xCAT::NetworkUtils::getNodeIPaddress($fsp_name);
    #$fsp_ip = xCAT::Utils::getIPaddress($fsp_name);
    $fsp_ip = xCAT::FSPUtils::getIPaddress($request, $$attrs[4], $fsp_name );
    if(!defined($fsp_ip) or ($fsp_ip == -3)) {
        $res = "Failed to get IP address for $fsp_name.";
        return ([$node_name, $res, -1]);
    }

    #################################
    # Create command and run command
    #################################
    my $cmd;
    if( $passwd ne "" ) {
        $cmd = "$fsp_api -a set_fsp_pw -u $user -p $passwd -P $newpasswd -t $type:$fsp_ip:$id:$node_name: ";
    } else {
        $cmd = "$fsp_api -a set_fsp_pw -u $user -P $newpasswd -t $type:$fsp_ip:$id:$node_name: "; 
    }
    $SIG{CHLD} = ();
    $res = xCAT::Utils->runcmd($cmd, -1);
    $Rc = $::RUNCMD_RC;

    if($Rc == 0) {
        $res = "Success";
    }


    ##################
    # output the prompt
    ##################
    #$outhash{ $node_name } = $res;

    return( [$node_name,$res, $Rc] );

}


##########################################################################
# Do resetnet 
##########################################################################
sub resetnet {
    my $request = shift;
    xCAT::PPCcfg::doresetnet($request);
    return 0;
}
1;