# 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;

