mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-11-03 21:02:34 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			4956 lines
		
	
	
		
			215 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			4956 lines
		
	
	
		
			215 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
#!/usr/bin/perl
 | 
						|
## IBM(c) 2017 EPL license http://www.eclipse.org/legal/epl-v10.html
 | 
						|
 | 
						|
package xCAT_plugin::openbmc;
 | 
						|
 | 
						|
BEGIN
 | 
						|
{
 | 
						|
    $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
 | 
						|
    my $async_path = "/usr/local/share/perl5/";
 | 
						|
    unless (grep { $_ eq $async_path } @INC) {
 | 
						|
        push @INC, $async_path;
 | 
						|
    }
 | 
						|
}
 | 
						|
use lib "$::XCATROOT/lib/perl";
 | 
						|
use strict;
 | 
						|
use warnings "all";
 | 
						|
 | 
						|
use JSON;
 | 
						|
use HTTP::Async;
 | 
						|
use HTTP::Cookies;
 | 
						|
use LWP::UserAgent;
 | 
						|
use File::Basename;
 | 
						|
use File::Spec;
 | 
						|
use File::Copy qw/copy cp mv move/;
 | 
						|
use File::Path;
 | 
						|
use Data::Dumper;
 | 
						|
use Getopt::Long;
 | 
						|
use xCAT::OPENBMC;
 | 
						|
use xCAT::RemoteShellExp;
 | 
						|
use xCAT::Utils;
 | 
						|
use xCAT::Table;
 | 
						|
use xCAT::Usage;
 | 
						|
use xCAT::SvrUtils;
 | 
						|
use xCAT::GlobalDef;
 | 
						|
use xCAT_monitoring::monitorctrl;
 | 
						|
use POSIX qw(WNOHANG);
 | 
						|
use xCAT::Utils qw/natural_sort_cmp/;
 | 
						|
 | 
						|
$::VERBOSE                  = 0;
 | 
						|
# String constants for rbeacon states
 | 
						|
$::BEACON_STATE_OFF         = "off";
 | 
						|
$::BEACON_STATE_ON          = "on";
 | 
						|
# String constants for rpower states
 | 
						|
$::POWER_STATE_OFF          = "off";
 | 
						|
$::POWER_STATE_ON           = "on";
 | 
						|
$::POWER_STATE_ON_HOSTOFF   = "on (Chassis)";
 | 
						|
$::POWER_STATE_POWERING_OFF = "powering-off";
 | 
						|
$::POWER_STATE_POWERING_ON  = "powering-on";
 | 
						|
$::POWER_STATE_QUIESCED     = "quiesced";
 | 
						|
$::POWER_STATE_RESET        = "reset";
 | 
						|
$::POWER_STATE_REBOOT       = "reboot";
 | 
						|
$::UPLOAD_FILE              = "";
 | 
						|
$::UPLOAD_FILE_VERSION      = "";
 | 
						|
$::UPLOAD_PNOR              = "";
 | 
						|
$::UPLOAD_PNOR_VERSION      = "";
 | 
						|
$::UPLOAD_FILE_HASH_ID      = "";
 | 
						|
$::UPLOAD_PNOR_HASH_ID      = "";
 | 
						|
$::RSETBOOT_URL_PATH        = "boot";
 | 
						|
# To improve the output to users, store this value as a global
 | 
						|
$::UPLOAD_AND_ACTIVATE      = 0;
 | 
						|
$::UPLOAD_ACTIVATE_STREAM   = 0;
 | 
						|
$::RFLASH_STREAM_NO_HOST_REBOOT = 0;
 | 
						|
$::NO_ATTRIBUTES_RETURNED   = "No attributes returned from the BMC.";
 | 
						|
$::FAILED_UPLOAD_MSG        = "Failed to upload update file";
 | 
						|
$::FAILED_LOGIN_MSG         = "BMC did not respond. Validate BMC configuration and retry the command.";
 | 
						|
 | 
						|
$::UPLOAD_WAIT_ATTEMPT      = 6;
 | 
						|
$::UPLOAD_WAIT_INTERVAL     = 10;
 | 
						|
$::UPLOAD_WAIT_TOTALTIME    = int($::UPLOAD_WAIT_ATTEMPT*$::UPLOAD_WAIT_INTERVAL);
 | 
						|
 | 
						|
$::RPOWER_CHECK_INTERVAL    = 2;
 | 
						|
$::RPOWER_CHECK_ON_INTERVAL = 12;
 | 
						|
$::RPOWER_ON_MAX_RETRY      = 5;
 | 
						|
$::RPOWER_MAX_RETRY         = 30;
 | 
						|
 | 
						|
$::BMC_MAX_RETRY = 20;
 | 
						|
$::BMC_CHECK_INTERVAL = 15;
 | 
						|
 | 
						|
$::RSPCONFIG_DUMP_INTERVAL  = 15;
 | 
						|
$::RSPCONFIG_DUMP_MAX_RETRY = 20;
 | 
						|
$::RSPCONFIG_DUMP_WAIT_TOTALTIME = int($::RSPCONFIG_DUMP_INTERVAL*$::RSPCONFIG_DUMP_MAX_RETRY);
 | 
						|
$::RSPCONFIG_DUMP_DOWNLOAD_ALL_REQUESTED = 0;
 | 
						|
$::RSPCONFIG_WAIT_VLAN_DONE = 15;
 | 
						|
$::RSPCONFIG_WAIT_IP_DONE   = 3;
 | 
						|
$::RSPCONFIG_DUMP_CMD_TIME  = 0;
 | 
						|
$::RSPCONFIG_CONFIGURED_API_KEY  = -1;
 | 
						|
 | 
						|
$::XCAT_LOG_DIR             = "/var/log/xcat";
 | 
						|
$::RAS_POLICY_TABLE         = "/opt/ibm/ras/lib/policyTable.json";
 | 
						|
$::XCAT_LOG_RFLASH_DIR      = $::XCAT_LOG_DIR . "/rflash/";
 | 
						|
$::XCAT_LOG_DUMP_DIR        = $::XCAT_LOG_DIR . "/dump/";
 | 
						|
 | 
						|
unless (-d $::XCAT_LOG_RFLASH_DIR) {
 | 
						|
    mkpath($::XCAT_LOG_RFLASH_DIR);
 | 
						|
}
 | 
						|
unless (-d $::XCAT_LOG_DUMP_DIR) {
 | 
						|
    mkpath($::XCAT_LOG_DUMP_DIR);
 | 
						|
}
 | 
						|
 | 
						|
# Common logging messages:
 | 
						|
my $usage_errormsg = "Usage error.";
 | 
						|
my $reventlog_no_id_resolved_errormsg = "Provide a comma separated list of IDs to be resolved. Example: 'resolved=x,y,z'";
 | 
						|
 | 
						|
 | 
						|
sub unsupported {
 | 
						|
    my $callback = shift;
 | 
						|
    if (defined($::OPENBMC_DEVEL) && ($::OPENBMC_DEVEL eq "YES")) {
 | 
						|
        return;
 | 
						|
    } else {
 | 
						|
        return ([ 1, "This openbmc related function is not yet supported. Please contact xCAT development team." ]);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  handled_commands
 | 
						|
 | 
						|
  Return list of commands handled by this plugin
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub handled_commands {
 | 
						|
    return {
 | 
						|
        getopenbmccons => 'nodehm:cons',
 | 
						|
        rbeacon        => 'nodehm:mgt',
 | 
						|
        renergy        => 'nodehm:mgt',
 | 
						|
        reventlog      => 'nodehm:mgt',
 | 
						|
        rflash         => 'nodehm:mgt',
 | 
						|
        rinv           => 'nodehm:mgt',
 | 
						|
        rpower         => 'nodehm:mgt',
 | 
						|
        rsetboot       => 'nodehm:mgt',
 | 
						|
        rspconfig      => 'nodehm:mgt',
 | 
						|
        rspreset       => 'nodehm:mgt',
 | 
						|
        rvitals        => 'nodehm:mgt',
 | 
						|
    };
 | 
						|
}
 | 
						|
 | 
						|
my $prefix = "xyz.openbmc_project";
 | 
						|
 | 
						|
my %sensor_units = (
 | 
						|
    "$prefix.Sensor.Value.Unit.DegreesC" => "C",
 | 
						|
    "$prefix.Sensor.Value.Unit.RPMS" => "RPMS",
 | 
						|
    "$prefix.Sensor.Value.Unit.Volts" => "Volts",
 | 
						|
    "$prefix.Sensor.Value.Unit.Meters" => "Meters",
 | 
						|
    "$prefix.Sensor.Value.Unit.Amperes" => "Amps",
 | 
						|
    "$prefix.Sensor.Value.Unit.Watts" => "Watts",
 | 
						|
    "$prefix.Sensor.Value.Unit.Joules" => "Joules"
 | 
						|
);
 | 
						|
my %child_node_map;   # pid => node
 | 
						|
my %fw_tar_files;
 | 
						|
my $http_protocol="https";
 | 
						|
my $openbmc_url = "/org/openbmc";
 | 
						|
my $openbmc_project_url = "/xyz/openbmc_project";
 | 
						|
$::SOFTWARE_URL = "$openbmc_project_url/software";
 | 
						|
$::LOGGING_URL  = "$openbmc_project_url/logging/entry/#ENTRY_ID#/attr/Resolved";
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
# The hash table to store method and url for request,
 | 
						|
# process function for response
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
my %status_info = (
 | 
						|
    LOGIN_REQUEST      => {
 | 
						|
        method         => "POST",
 | 
						|
        init_url       => "/login",
 | 
						|
    },
 | 
						|
    LOGIN_REQUEST_GENERAL  => {
 | 
						|
        method         => "POST",
 | 
						|
        init_url       => "/login",
 | 
						|
    },
 | 
						|
    LOGIN_RESPONSE     => {
 | 
						|
        process        => \&login_response,
 | 
						|
    },
 | 
						|
    LOGIN_RESPONSE_GENERAL => {
 | 
						|
        process        => \&login_response,
 | 
						|
    },
 | 
						|
    RBEACON_ON_REQUEST  => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url/led/groups/enclosure_identify/attr/Asserted",
 | 
						|
        data           => "true",
 | 
						|
    },
 | 
						|
    RBEACON_ON_RESPONSE => {
 | 
						|
        process        => \&rbeacon_response,
 | 
						|
    },
 | 
						|
    RBEACON_OFF_REQUEST  => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url/led/groups/enclosure_identify/attr/Asserted",
 | 
						|
        data           => "false",
 | 
						|
    },
 | 
						|
    RBEACON_OFF_RESPONSE => {
 | 
						|
        process        => \&rbeacon_response,
 | 
						|
    },
 | 
						|
 | 
						|
    REVENTLOG_REQUEST => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/logging/enumerate",
 | 
						|
    },
 | 
						|
    REVENTLOG_RESPONSE => {
 | 
						|
        process        => \&reventlog_response,
 | 
						|
    },
 | 
						|
    REVENTLOG_CLEAR_REQUEST => {
 | 
						|
        method         => "POST",
 | 
						|
        init_url       => "$openbmc_project_url/logging/action/deleteAll",
 | 
						|
        data           => "[]",
 | 
						|
    },
 | 
						|
    REVENTLOG_CLEAR_RESPONSE => {
 | 
						|
        process        => \&reventlog_response,
 | 
						|
    },
 | 
						|
    REVENTLOG_RESOLVED_REQUEST => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$::LOGGING_URL",
 | 
						|
        data           => "1",
 | 
						|
    },
 | 
						|
    REVENTLOG_RESOLVED_RESPONSE => {
 | 
						|
        process        => \&reventlog_response,
 | 
						|
    },
 | 
						|
    REVENTLOG_RESOLVED_RESPONSE_LED => {
 | 
						|
        process        => \&reventlog_response,
 | 
						|
    },
 | 
						|
 | 
						|
    RFLASH_LIST_REQUEST  => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/software/enumerate",
 | 
						|
    },
 | 
						|
    RFLASH_LIST_RESPONSE => {
 | 
						|
        process        => \&rflash_response,
 | 
						|
    },
 | 
						|
    RFLASH_FILE_UPLOAD_REQUEST  => {
 | 
						|
        process        => \&rflash_response,
 | 
						|
    },
 | 
						|
    RFLASH_FILE_UPLOAD_RESPONSE => {
 | 
						|
        process        => \&rflash_response,
 | 
						|
    },
 | 
						|
    RFLASH_UPDATE_ACTIVATE_REQUEST  => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url/software",
 | 
						|
        data           => "xyz.openbmc_project.Software.Activation.RequestedActivations.Active",
 | 
						|
    },
 | 
						|
    RFLASH_UPDATE_HOST_ACTIVATE_REQUEST  => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url/software",
 | 
						|
        data           => "xyz.openbmc_project.Software.Activation.RequestedActivations.Active",
 | 
						|
    },
 | 
						|
    RFLASH_UPDATE_ACTIVATE_RESPONSE => {
 | 
						|
        process        => \&rflash_response,
 | 
						|
    },
 | 
						|
    RFLASH_UPDATE_HOST_ACTIVATE_RESPONSE => {
 | 
						|
        process        => \&rflash_response,
 | 
						|
    },
 | 
						|
    RFLASH_UPDATE_CHECK_STATE_REQUEST  => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/software",
 | 
						|
    },
 | 
						|
    RFLASH_UPDATE_CHECK_STATE_RESPONSE => {
 | 
						|
        process        => \&rflash_response,
 | 
						|
    },
 | 
						|
    RFLASH_UPDATE_CHECK_ID_REQUEST  => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/software/enumerate",
 | 
						|
    },
 | 
						|
    RFLASH_UPDATE_CHECK_ID_RESPONSE => {
 | 
						|
        process        => \&rflash_response,
 | 
						|
    },
 | 
						|
    RFLASH_SET_PRIORITY_REQUEST  => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url/software",
 | 
						|
        data           => "false", # Priority state of 0 sets image to active
 | 
						|
    },
 | 
						|
    RFLASH_SET_PRIORITY_RESPONSE => {
 | 
						|
        process        => \&rflash_response,
 | 
						|
    },
 | 
						|
    RFLASH_DELETE_IMAGE_REQUEST  => {
 | 
						|
        method         => "POST",
 | 
						|
        init_url       => "$openbmc_project_url/software",
 | 
						|
        data           => "[]",
 | 
						|
    },
 | 
						|
    RFLASH_DELETE_IMAGE_RESPONSE => {
 | 
						|
        process        => \&rflash_response,
 | 
						|
    },
 | 
						|
 | 
						|
    RFLASH_DELETE_CHECK_STATE_RESPONSE => {
 | 
						|
        process        => \&rflash_response,
 | 
						|
    },
 | 
						|
 | 
						|
    RINV_REQUEST => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/inventory/enumerate",
 | 
						|
    },
 | 
						|
    RINV_RESPONSE => {
 | 
						|
        process        => \&rinv_response,
 | 
						|
    },
 | 
						|
 | 
						|
    RINV_FIRM_REQUEST => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/software/enumerate",
 | 
						|
    },
 | 
						|
    RINV_FIRM_RESPONSE => {
 | 
						|
        process        => \&rinv_response,
 | 
						|
    },
 | 
						|
 | 
						|
    RPOWER_BMCREBOOT_REQUEST  => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url/state/bmc0/attr/RequestedBMCTransition",
 | 
						|
        data           => "xyz.openbmc_project.State.BMC.Transition.Reboot",
 | 
						|
    },
 | 
						|
    RPOWER_ON_REQUEST  => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url/state/host0/attr/RequestedHostTransition",
 | 
						|
        data           => "xyz.openbmc_project.State.Host.Transition.On",
 | 
						|
    },
 | 
						|
    RPOWER_ON_RESPONSE => {
 | 
						|
        process        => \&rpower_response,
 | 
						|
    },
 | 
						|
    RPOWER_CHECK_ON_RESPONSE => {
 | 
						|
        process        => \&rpower_response,
 | 
						|
    },
 | 
						|
    RPOWER_OFF_REQUEST  => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url/state/chassis0/attr/RequestedPowerTransition",
 | 
						|
        data           => "xyz.openbmc_project.State.Chassis.Transition.Off",
 | 
						|
    },
 | 
						|
    RPOWER_OFF_RESPONSE => {
 | 
						|
        process        => \&rpower_response,
 | 
						|
    },
 | 
						|
    RPOWER_SOFTOFF_REQUEST  => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url/state/host0/attr/RequestedHostTransition",
 | 
						|
        data           => "xyz.openbmc_project.State.Host.Transition.Off",
 | 
						|
    },
 | 
						|
    RPOWER_SOFTOFF_RESPONSE => {
 | 
						|
        process        => \&rpower_response,
 | 
						|
    },
 | 
						|
    RPOWER_RESET_RESPONSE => {
 | 
						|
        process        => \&rpower_response,
 | 
						|
    },
 | 
						|
    RPOWER_STATUS_REQUEST  => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/state/enumerate",
 | 
						|
    },
 | 
						|
    RPOWER_STATUS_RESPONSE => {
 | 
						|
        process        => \&rpower_response,
 | 
						|
    },
 | 
						|
    RPOWER_CHECK_REQUEST  => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/state/enumerate",
 | 
						|
    },
 | 
						|
    RPOWER_CHECK_ON_REQUEST  => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/state/enumerate",
 | 
						|
    },
 | 
						|
    RPOWER_BMC_STATUS_REQUEST  => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/state/enumerate",
 | 
						|
    },
 | 
						|
    RPOWER_BMC_CHECK_REQUEST  => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/state/enumerate",
 | 
						|
    },
 | 
						|
    RPOWER_BMC_STATUS_RESPONSE => {
 | 
						|
        process        => \&rpower_response,
 | 
						|
    },
 | 
						|
    RPOWER_BMC_CHECK_RESPONSE => {
 | 
						|
        process        => \&rpower_response,
 | 
						|
    },
 | 
						|
    RPOWER_CHECK_RESPONSE => {
 | 
						|
        process        => \&rpower_response,
 | 
						|
    },
 | 
						|
 | 
						|
    RSETBOOT_ENABLE_REQUEST => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url/control/host0/boot/one_time/attr/Enabled",
 | 
						|
        data           => '1',
 | 
						|
    },
 | 
						|
    RSETBOOT_ENABLE_RESPONSE => {
 | 
						|
        process        => \&rsetboot_response,
 | 
						|
    },
 | 
						|
    RSETBOOT_SET_REQUEST => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url/control/host0/boot/one_time/attr/BootSource",
 | 
						|
        data           => "xyz.openbmc_project.Control.Boot.Source.Sources.",
 | 
						|
    },
 | 
						|
    RSETBOOT_SET_RESPONSE => {
 | 
						|
        process        => \&rsetboot_response,
 | 
						|
    },
 | 
						|
    RSETBOOT_STATUS_REQUEST  => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/control/host0/enumerate",
 | 
						|
    },
 | 
						|
    RSETBOOT_STATUS_RESPONSE => {
 | 
						|
        process        => \&rsetboot_response,
 | 
						|
    },
 | 
						|
 | 
						|
    RSPCONFIG_GET_REQUEST => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/network/enumerate",
 | 
						|
    },
 | 
						|
    RSPCONFIG_GET_RESPONSE => {
 | 
						|
        process        => \&rspconfig_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_GET_NIC_REQUEST => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/network/enumerate",
 | 
						|
    },
 | 
						|
    RSPCONFIG_GET_NIC_RESPONSE => {
 | 
						|
        process        => \&rspconfig_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_SET_PASSWD_REQUEST => {
 | 
						|
        method         => "POST",
 | 
						|
        init_url       => "/xyz/openbmc_project/user/root/action/SetPassword",
 | 
						|
        data           => "",
 | 
						|
    },
 | 
						|
    "RSPCONFIG_PASSWD_VERIFY" => {
 | 
						|
        process        => \&rspconfig_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_SET_HOSTNAME_REQUEST => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url/network/config/attr/HostName",
 | 
						|
        data           => "[]",
 | 
						|
    },
 | 
						|
    RSPCONFIG_SET_NTPSERVERS_REQUEST => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url/network/#NIC#/attr/NTPServers",
 | 
						|
        data           => "[]",
 | 
						|
    },
 | 
						|
    RSPCONFIG_SET_RESPONSE => {
 | 
						|
        process        => \&rspconfig_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_IPOBJECT_REQUEST => {
 | 
						|
        method         => "POST",
 | 
						|
        init_url       => "$openbmc_project_url/network/#NIC#/action/IP",
 | 
						|
        data           => "",
 | 
						|
    },
 | 
						|
    RSPCONFIG_IPOBJECT_RESPONSE => {
 | 
						|
        process        => \&rspconfig_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_VLAN_REQUEST  => {
 | 
						|
        method         => "POST",
 | 
						|
        init_url       => "$openbmc_project_url/network/action/VLAN",
 | 
						|
        data           => "",
 | 
						|
    },
 | 
						|
    RSPCONFIG_VLAN_RESPONSE => {
 | 
						|
        process        => \&rspconfig_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_CHECK_REQUEST  => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/network/enumerate",
 | 
						|
    },
 | 
						|
    RSPCONFIG_CHECK_RESPONSE => {
 | 
						|
        process        => \&rspconfig_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_DHCP_REQUEST => {
 | 
						|
        method         => "POST",
 | 
						|
        init_url       => "$openbmc_project_url/network/action/Reset",
 | 
						|
        data           => "[]",
 | 
						|
    },
 | 
						|
    RSPCONFIG_DHCP_RESPONSE => {
 | 
						|
        process        => \&rspconfig_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_DHCPDIS_REQUEST => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url/network/#NIC#/attr/DHCPEnabled",
 | 
						|
        data           => 0,
 | 
						|
    },
 | 
						|
    RSPCONFIG_DHCPDIS_RESPONSE => {
 | 
						|
        process        => \&rspconfig_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_DELETE_REQUEST => {
 | 
						|
        method         => "DELETE",
 | 
						|
        init_url       => "",
 | 
						|
    },
 | 
						|
    RSPCONFIG_DELETE_RESPONSE => {
 | 
						|
        process        => \&rspconfig_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_PRINT_BMCINFO => {
 | 
						|
        process        => \&rspconfig_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_SSHCFG_REQUEST => {
 | 
						|
        process        => \&rspconfig_sshcfg_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_SSHCFG_RESPONSE => {
 | 
						|
        process        => \&rspconfig_sshcfg_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_CLEAR_GARD_REQUEST => {
 | 
						|
        method         => "POST",
 | 
						|
        init_url       => "/org/open_power/control/gard/action/Reset",
 | 
						|
        data           => "[]",
 | 
						|
    },
 | 
						|
    RSPCONFIG_CLEAR_GARD_RESPONSE => {
 | 
						|
        process        => \&rspconfig_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_DUMP_LIST_REQUEST => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/dump/enumerate",
 | 
						|
    },
 | 
						|
    RSPCONFIG_DUMP_LIST_RESPONSE => {
 | 
						|
        process        => \&rspconfig_dump_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_DUMP_CHECK_RESPONSE => {
 | 
						|
        process        => \&rspconfig_dump_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_DUMP_CREATE_REQUEST => {
 | 
						|
        method         => "POST",
 | 
						|
        init_url       => "$openbmc_project_url/dump/action/CreateDump",
 | 
						|
        data           => "[]",
 | 
						|
    },
 | 
						|
    RSPCONFIG_DUMP_CREATE_RESPONSE => {
 | 
						|
        process        => \&rspconfig_dump_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_DUMP_CLEAR_REQUEST => {
 | 
						|
        method         => "POST",
 | 
						|
        init_url       => "$openbmc_project_url/dump/entry/#ID#/action/Delete",
 | 
						|
        data           => "[]",
 | 
						|
    },
 | 
						|
    RSPCONFIG_DUMP_CLEAR_ALL_REQUEST => {
 | 
						|
        method         => "POST",
 | 
						|
        init_url       => "$openbmc_project_url/dump/action/DeleteAll",
 | 
						|
        data           => "[]",
 | 
						|
    },
 | 
						|
    RSPCONFIG_DUMP_CLEAR_RESPONSE => {
 | 
						|
        process        => \&rspconfig_dump_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_DUMP_DOWNLOAD_REQUEST => {
 | 
						|
        init_url       => "download/dump/#ID#",
 | 
						|
        process        => \&rspconfig_dump_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_DUMP_DOWNLOAD_RESPONSE => {
 | 
						|
        process        => \&rspconfig_dump_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_DUMP_DOWNLOAD_ALL_RESPONSE => {
 | 
						|
        process        => \&rspconfig_dump_response,
 | 
						|
    },
 | 
						|
    RVITALS_REQUEST => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/sensors/enumerate",
 | 
						|
    },
 | 
						|
    RVITALS_RESPONSE => {
 | 
						|
        process        => \&rvitals_response,
 | 
						|
    },
 | 
						|
    RVITALS_LEDS_REQUEST => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url/led/physical/enumerate",
 | 
						|
    },
 | 
						|
    RVITALS_LEDS_RESPONSE => {
 | 
						|
        process        => \&rvitals_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_API_CONFIG_ON_REQUEST  => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url",
 | 
						|
        data           => "true",
 | 
						|
    },
 | 
						|
    RSPCONFIG_API_CONFIG_ON_RESPONSE => {
 | 
						|
        process        => \&rspconfig_api_config_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_API_CONFIG_OFF_REQUEST  => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url",
 | 
						|
        data           => "false",
 | 
						|
    },
 | 
						|
    RSPCONFIG_API_CONFIG_OFF_RESPONSE => {
 | 
						|
        process        => \&rspconfig_api_config_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_API_CONFIG_ATTR_REQUEST  => {
 | 
						|
        method         => "PUT",
 | 
						|
        init_url       => "$openbmc_project_url",
 | 
						|
        data           => "false",
 | 
						|
    },
 | 
						|
    RSPCONFIG_API_CONFIG_ACTION_ATTR_REQUEST  => {
 | 
						|
        method         => "POST",
 | 
						|
        init_url       => "$openbmc_project_url",
 | 
						|
        data           => "false",
 | 
						|
    },
 | 
						|
    RSPCONFIG_API_CONFIG_ATTR_RESPONSE => {
 | 
						|
        process        => \&rspconfig_api_config_response,
 | 
						|
    },
 | 
						|
    RSPCONFIG_API_CONFIG_ACTION_ATTR_QUERY_REQUEST  => {
 | 
						|
        method         => "POST",
 | 
						|
        init_url       => "$openbmc_project_url",
 | 
						|
        data           => "[]",
 | 
						|
    },
 | 
						|
    RSPCONFIG_API_CONFIG_QUERY_REQUEST  => {
 | 
						|
        method         => "GET",
 | 
						|
        init_url       => "$openbmc_project_url",
 | 
						|
    },
 | 
						|
    RSPCONFIG_API_CONFIG_QUERY_RESPONSE => {
 | 
						|
        process        => \&rspconfig_api_config_response,
 | 
						|
    },
 | 
						|
);
 | 
						|
 | 
						|
# Setup configured subcommand.
 | 
						|
# Currently only rspconfig is supported and only for boolean commands or attribute settings.
 | 
						|
#
 | 
						|
# Usage can also be autogenerated for these commands. However, changes to the xCAT::Usage->usage
 | 
						|
# need to be made to split a single string into its components. Look at "rspconfig" usage as an
 | 
						|
# example.
 | 
						|
#
 | 
						|
# For example: rspconfig <subcommand>
 | 
						|
#              rspconfig <subcommand>=0
 | 
						|
#              rspconfig <subcommand>=1
 | 
						|
#              rspconfig <subcommand>=<attr_value>
 | 
						|
#
 | 
						|
#
 | 
						|
my %api_config_info = (
 | 
						|
    RSPCONFIG_AUTO_REBOOT => {
 | 
						|
        command      => "rspconfig",
 | 
						|
        url          => "/control/host0/auto_reboot",
 | 
						|
        attr_url     => "AutoReboot",
 | 
						|
        display_name => "BMC AutoReboot",
 | 
						|
        instruct_msg => "",
 | 
						|
        type         => "boolean",
 | 
						|
        subcommand   => "autoreboot",
 | 
						|
    },
 | 
						|
    RSPCONFIG_BOOT_MODE => {
 | 
						|
        command      => "rspconfig",
 | 
						|
        url          => "/control/host0/boot",
 | 
						|
        attr_url     => "BootMode",
 | 
						|
        display_name => "BMC BootMode",
 | 
						|
        instruct_msg => "",
 | 
						|
        type         => "attribute",
 | 
						|
        subcommand   => "bootmode",
 | 
						|
        attr_value   => {
 | 
						|
            regular     => "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular",
 | 
						|
            safe        => "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe",
 | 
						|
            setup       => "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup",
 | 
						|
        },
 | 
						|
    },
 | 
						|
    RSPCONFIG_POWERSUPPLY_REDUNDANCY => {
 | 
						|
        command      => "rspconfig",
 | 
						|
        url          => "/sensors/chassis/PowerSupplyRedundancy",
 | 
						|
        attr_url     => "/action/setValue",
 | 
						|
        query_url    => "/action/getValue",
 | 
						|
        display_name => "BMC PowerSupplyRedundancy",
 | 
						|
        instruct_msg => "",
 | 
						|
        type         => "action_attribute",
 | 
						|
        subcommand   => "powersupplyredundancy",
 | 
						|
        attr_value   => {
 | 
						|
            disabled    => "Disabled",
 | 
						|
            enabled     => "Enabled",
 | 
						|
        },
 | 
						|
    },
 | 
						|
    RSPCONFIG_POWERRESTORE_POLICY => {
 | 
						|
        command      => "rspconfig",
 | 
						|
        url          => "/control/host0/power_restore_policy",
 | 
						|
        attr_url     => "PowerRestorePolicy",
 | 
						|
        display_name => "BMC PowerRestorePolicy",
 | 
						|
        instruct_msg => "",
 | 
						|
        type         => "attribute",
 | 
						|
        subcommand   => "powerrestorepolicy",
 | 
						|
        attr_value   => {
 | 
						|
            restore     => "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore",
 | 
						|
            always_on   => "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn",
 | 
						|
            always_off  => "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff",
 | 
						|
        },
 | 
						|
    },
 | 
						|
    RSPCONFIG_TIME_SYNC_METHOD => {
 | 
						|
        command      => "rspconfig",
 | 
						|
        url          => "/time/sync_method",
 | 
						|
        attr_url     => "TimeSyncMethod",
 | 
						|
        display_name => "BMC TimeSyncMethod",
 | 
						|
        instruct_msg => "",
 | 
						|
        type         => "attribute",
 | 
						|
        subcommand   => "timesyncmethod",
 | 
						|
        attr_value   => {
 | 
						|
            ntp         => "xyz.openbmc_project.Time.Synchronization.Method.NTP",
 | 
						|
            manual      => "xyz.openbmc_project.Time.Synchronization.Method.Manual",
 | 
						|
        },
 | 
						|
    },
 | 
						|
);
 | 
						|
 | 
						|
$::RESPONSE_OK                  = "200 OK";
 | 
						|
$::RESPONSE_SERVER_ERROR        = "500 Internal Server Error";
 | 
						|
$::RESPONSE_SERVICE_UNAVAILABLE = "503 Service Unavailable";
 | 
						|
$::RESPONSE_FORBIDDEN           = "403 Forbidden";
 | 
						|
$::RESPONSE_NOT_FOUND           = "404 Not Found";
 | 
						|
$::RESPONSE_METHOD_NOT_ALLOWED  = "405 Method Not Allowed";
 | 
						|
$::RESPONSE_SERVICE_TIMEOUT     = "504 Gateway Timeout";
 | 
						|
 | 
						|
#-----------------------------
 | 
						|
 | 
						|
=head3 %node_info
 | 
						|
 | 
						|
  $node_info = (
 | 
						|
      $node => {
 | 
						|
          bmc        => "x.x.x.x",
 | 
						|
          username   => "username",
 | 
						|
          password   => "password",
 | 
						|
          cur_status => "LOGIN_REQUEST",
 | 
						|
          cur_url    => "",
 | 
						|
          method     => "",
 | 
						|
      },
 | 
						|
  );
 | 
						|
 | 
						|
  'cur_url', 'method' used for path has a trailing-slash
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-----------------------------
 | 
						|
my %node_info = ();
 | 
						|
 | 
						|
my %next_status = ();
 | 
						|
 | 
						|
my %handle_id_node = ();
 | 
						|
 | 
						|
# Store the value format like '<node> => <time>' to manage the green sleep time, used
 | 
						|
# by retry_after and the main loop in process_request only.
 | 
						|
my %node_wait = ();
 | 
						|
 | 
						|
my $wait_node_num;
 | 
						|
 | 
						|
my $async;
 | 
						|
 | 
						|
my $cookie_jar;
 | 
						|
 | 
						|
my $callback;
 | 
						|
 | 
						|
my %allerrornodes = ();
 | 
						|
 | 
						|
my $xcatdebugmode = 0;
 | 
						|
 | 
						|
my $flag_debug = "[openbmc_debug_perl]";
 | 
						|
 | 
						|
my %login_pid_node; # used in process_request, record login fork pid map
 | 
						|
 | 
						|
my $event_mapping = "";
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  preprocess_request
 | 
						|
 | 
						|
  preprocess the command
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub preprocess_request {
 | 
						|
    my $request = shift;
 | 
						|
    $callback  = shift;
 | 
						|
 | 
						|
    if (defined $request->{_xcat_ignore_flag}->[0] and $request->{_xcat_ignore_flag}->[0] eq 'openbmc') {
 | 
						|
        return [];#workaround the bug 3026, to ignore it for openbmc
 | 
						|
    }
 | 
						|
    if (defined $request->{_xcatpreprocessed}->[0] and $request->{_xcatpreprocessed}->[0] == 1) {
 | 
						|
        return [$request];
 | 
						|
    }
 | 
						|
 | 
						|
    ##############################################
 | 
						|
    # Delete this when could be released
 | 
						|
 | 
						|
    if (ref($request->{environment}) eq 'ARRAY' and ref($request->{environment}->[0]->{XCAT_OPENBMC_DEVEL}) eq 'ARRAY') {
 | 
						|
        $::OPENBMC_DEVEL = $request->{environment}->[0]->{XCAT_OPENBMC_DEVEL}->[0];
 | 
						|
    } elsif (ref($request->{environment}) eq 'ARRAY') {
 | 
						|
        $::OPENBMC_DEVEL = $request->{environment}->[0]->{XCAT_OPENBMC_DEVEL};
 | 
						|
    } else {
 | 
						|
        $::OPENBMC_DEVEL = $request->{environment}->{XCAT_OPENBMC_DEVEL};
 | 
						|
    }
 | 
						|
 | 
						|
    if (ref($request->{environment}) eq 'ARRAY' and ref($request->{environment}->[0]->{XCAT_OPENBMC_FIRMWARE}) eq 'ARRAY') {
 | 
						|
        $::OPENBMC_FW = $request->{environment}->[0]->{XCAT_OPENBMC_FIRMWARE}->[0];
 | 
						|
    } elsif (ref($request->{environment}) eq 'ARRAY') {
 | 
						|
        $::OPENBMC_FW = $request->{environment}->[0]->{XCAT_OPENBMC_FIRMWARE};
 | 
						|
    } else {
 | 
						|
        $::OPENBMC_FW = $request->{environment}->{XCAT_OPENBMC_FIRMWARE};
 | 
						|
    }
 | 
						|
 | 
						|
    # Provide a way to turn on and off transition state processing, default to off
 | 
						|
    if (ref($request->{environment}) eq 'ARRAY' and ref($request->{environment}->[0]->{XCAT_OPENBMC_POWER_TRANSITION}) eq 'ARRAY') {
 | 
						|
        $::OPENBMC_PWR = $request->{environment}->[0]->{XCAT_OPENBMC_POWER_TRANSITION}->[0];
 | 
						|
    } elsif (ref($request->{environment}) eq 'ARRAY') {
 | 
						|
        $::OPENBMC_PWR = $request->{environment}->[0]->{XCAT_OPENBMC_POWER_TRANSITION};
 | 
						|
    } else {
 | 
						|
        $::OPENBMC_PWR = $request->{environment}->{XCAT_OPENBMC_POWER_TRANSITION};
 | 
						|
    }
 | 
						|
    ##############################################
 | 
						|
 | 
						|
    my $command   = $request->{command}->[0];
 | 
						|
    if ($request->{command}->[0] eq "getopenbmccons") {
 | 
						|
        my $nodes = $request->{node};
 | 
						|
        my $check = parse_node_info($nodes);
 | 
						|
        foreach my $node (keys %node_info) {
 | 
						|
            my $donargs = [ $node,$node_info{$node}{bmc},$node_info{$node}{username}, $node_info{$node}{password}];
 | 
						|
            getopenbmccons($donargs, $callback);
 | 
						|
        }
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    my ($rc, $msg) = xCAT::OPENBMC->run_cmd_in_perl($command, $request->{environment});
 | 
						|
    if ($rc == 0) { $request = {}; return;}
 | 
						|
    if ($rc < 0) {
 | 
						|
        $request = {};
 | 
						|
        $callback->({ errorcode => [1], data => [$msg] });
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    if ($::XCATSITEVALS{xcatdebugmode}) { $xcatdebugmode = $::XCATSITEVALS{xcatdebugmode} }
 | 
						|
 | 
						|
    if ($xcatdebugmode) {
 | 
						|
        process_debug_info("OpenBMC");
 | 
						|
    }
 | 
						|
 | 
						|
    my $noderange = $request->{node};
 | 
						|
    my $extrargs  = $request->{arg};
 | 
						|
    my @exargs    = ($request->{arg});
 | 
						|
    my @requests;
 | 
						|
    my $usage_string;
 | 
						|
    $::cwd = $request->{cwd}->[0];
 | 
						|
    if (ref($extrargs)) {
 | 
						|
        @exargs = @$extrargs;
 | 
						|
    }
 | 
						|
    # Request usage for openbmc sections only
 | 
						|
    $usage_string = xCAT::Usage->parseCommand($command . ".openbmc", @exargs);
 | 
						|
 | 
						|
    if ($usage_string) {
 | 
						|
        if ($usage_string =~ /cannot be found/) {
 | 
						|
            # Could not find usage for openbmc section, try getting usage for all sections
 | 
						|
            $usage_string = xCAT::Usage->parseCommand($command, @exargs);
 | 
						|
        }
 | 
						|
        #else {
 | 
						|
            # Usage for openbmc section was extracted, append autogenerated usage for
 | 
						|
            # configured commands
 | 
						|
        #    $usage_string .= &build_config_api_usage($callback, $command);
 | 
						|
        #}
 | 
						|
 | 
						|
        $callback->({ data => [$usage_string] });
 | 
						|
        $request = {};
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    #pdu commands will be handled in the pdu plugin
 | 
						|
    if ($command eq "rpower") {
 | 
						|
        my $subcmd = $exargs[0];
 | 
						|
        if(($subcmd eq 'pduoff') || ($subcmd eq 'pduon') || ($subcmd eq 'pdustat') || ($subcmd eq 'pdureset')){
 | 
						|
            return;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    my $parse_result = parse_args($command, $extrargs, $noderange);
 | 
						|
    if (ref($parse_result) eq 'ARRAY') {
 | 
						|
        my $error_data;
 | 
						|
        foreach my $node (@$noderange) {
 | 
						|
            $error_data .= "\n" if ($error_data);
 | 
						|
            $error_data .= "$node: Error: " . "$parse_result->[1]";
 | 
						|
        }
 | 
						|
        $callback->({ errorcode => [$parse_result->[0]], data => [$error_data] });
 | 
						|
        $request = {};
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    my $sn = xCAT::ServiceNodeUtils->get_ServiceNode($noderange, "xcat", "MN");
 | 
						|
    foreach my $snkey (keys %$sn) {
 | 
						|
        my $reqcopy = {%$request};
 | 
						|
        $reqcopy->{node}                   = $sn->{$snkey};
 | 
						|
        $reqcopy->{'_xcatdest'}            = $snkey;
 | 
						|
        $reqcopy->{_xcatpreprocessed}->[0] = 1;
 | 
						|
        push @requests, $reqcopy;
 | 
						|
    }
 | 
						|
 | 
						|
    return \@requests;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  retry_after
 | 
						|
 | 
						|
    The request will be delayed for the given time and then
 | 
						|
    send the reqeust based on the status in the main loop.
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub retry_after {
 | 
						|
    my ($node, $request_status, $timeout) = @_;
 | 
						|
    $node_info{$node}{cur_status} = $request_status;
 | 
						|
    $node_wait{$node} = time() + $timeout;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  retry_check_times
 | 
						|
 | 
						|
    The request will be delayed for the given time and then
 | 
						|
    send the reqeust based on the BMC status after BMCreboot.
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub retry_check_times {
 | 
						|
    my ($node, $request_status, $check_type, $wait_time, $response_status) = @_;
 | 
						|
    if ($node_info{$node}{$check_type} > 0) {
 | 
						|
        $node_info{$node}{$check_type}--;
 | 
						|
        if ($node_info{$node}{wait_start}) {
 | 
						|
            $node_info{$node}{wait_end} = time();
 | 
						|
        } else {
 | 
						|
            $node_info{$node}{wait_start} = time();
 | 
						|
        }
 | 
						|
        my $retry_msg = "Retry BMC state, wait for $wait_time seconds ...";
 | 
						|
        xCAT::MsgUtils->message("I", { data => ["$node: $retry_msg"] }, $callback);
 | 
						|
        if ($response_status ne $::RESPONSE_SERVICE_UNAVAILABLE) {
 | 
						|
            my $login_url = "$http_protocol://$node_info{$node}{bmc}/login";
 | 
						|
            my $content = '[ "' . $node_info{$node}{username} .'", "' . $node_info{$node}{password} . '" ]';
 | 
						|
            $status_info{LOGIN_REQUEST_GENERAL}{data} = $content;
 | 
						|
            $node_info{$node}{cur_status} = "LOGIN_REQUEST_GENERAL";
 | 
						|
            $node_wait{$node} = time() + $wait_time;
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        $node_info{$node}{cur_status} = $request_status;
 | 
						|
        $node_wait{$node} = time() + $wait_time;
 | 
						|
        return;
 | 
						|
   } else {
 | 
						|
        my $wait_time_X = $node_info{$node}{wait_end} - $node_info{$node}{wait_start};
 | 
						|
        my $msg="Error: Sent bmcreboot but state did not change to BMC Ready after waiting $wait_time_X seconds. (State=BMC NotReady).";
 | 
						|
        xCAT::SvrUtils::sendmsg([1, $msg], $callback, $node);
 | 
						|
        $node_info{$node}{cur_status} = "";
 | 
						|
        $wait_node_num--;
 | 
						|
        return;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  process_request
 | 
						|
 | 
						|
  Process the command
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub process_request {
 | 
						|
    my $request = shift;
 | 
						|
    $callback = shift;
 | 
						|
    my $command   = $request->{command}->[0];
 | 
						|
    my $noderange = $request->{node};
 | 
						|
    my $extrargs       = $request->{arg};
 | 
						|
    $::cwd = $request->{cwd}->[0];
 | 
						|
    my @exargs         = ($request->{arg});
 | 
						|
    if (ref($extrargs)) {
 | 
						|
        @exargs = @$extrargs;
 | 
						|
    }
 | 
						|
 | 
						|
    my $check = parse_node_info($noderange);
 | 
						|
    my $rst = parse_command_status($command, \@exargs);
 | 
						|
    return if ($rst);
 | 
						|
 | 
						|
    if ($request->{command}->[0] eq "getopenbmccons") {
 | 
						|
        # This may not be run as "getopenbmccons" is handled in preprocess now
 | 
						|
        # Leave the code here in case some codes just call `process_request`
 | 
						|
        foreach my $node (keys %node_info) {
 | 
						|
            my $donargs = [ $node,$node_info{$node}{bmc},$node_info{$node}{username}, $node_info{$node}{password}];
 | 
						|
            getopenbmccons($donargs, $callback);
 | 
						|
        }
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    if ($::VERBOSE) {
 | 
						|
        xCAT::SvrUtils::sendmsg("Running command in Perl", $callback);
 | 
						|
    }
 | 
						|
 | 
						|
    $cookie_jar = HTTP::Cookies->new({});
 | 
						|
    $async = HTTP::Async->new(
 | 
						|
        slots => 500,
 | 
						|
        cookie_jar => $cookie_jar,
 | 
						|
        timeout => 60,
 | 
						|
        max_request_time => 60,
 | 
						|
        ssl_options => {
 | 
						|
            SSL_verify_mode => 0,
 | 
						|
        },
 | 
						|
    );
 | 
						|
 | 
						|
    my $login_url;
 | 
						|
    my $handle_id;
 | 
						|
    my $content;
 | 
						|
    my @nodes_login = keys %node_info;
 | 
						|
    $wait_node_num = @nodes_login;
 | 
						|
    my $child_num;
 | 
						|
    my %valid_nodes = ();
 | 
						|
 | 
						|
    my $max_child_num = 64;
 | 
						|
    my $for_num = ($wait_node_num < $max_child_num) ? $wait_node_num : $max_child_num;
 | 
						|
    for (my $i = 0; $i < $for_num; $i++) {
 | 
						|
        my $node = shift @nodes_login;
 | 
						|
        my $rst_fork = fork_process_login($node);
 | 
						|
        $child_num++ unless($rst_fork);
 | 
						|
    }
 | 
						|
 | 
						|
    while (1) {
 | 
						|
        last if ($child_num == 0 and !@nodes_login);
 | 
						|
        my $cpid = waitpid(-1, WNOHANG);
 | 
						|
        if ($cpid > 0) {
 | 
						|
            if ($login_pid_node{$cpid}) {
 | 
						|
                $child_num--;
 | 
						|
                my $node = $login_pid_node{$cpid};
 | 
						|
                my $rc = $? >> 8;
 | 
						|
                if ($rc == 0) {
 | 
						|
                    $valid_nodes{$node} = 1;
 | 
						|
                }
 | 
						|
                delete $login_pid_node{$cpid};
 | 
						|
            }
 | 
						|
        } elsif ($cpid == 0) {
 | 
						|
            select(undef, undef, undef, 0.01);
 | 
						|
        } elsif ($cpid < 0 and !@nodes_login) {
 | 
						|
            last;
 | 
						|
        }
 | 
						|
 | 
						|
        if (@nodes_login) {
 | 
						|
            if ($child_num < $max_child_num) {
 | 
						|
                my $node = shift @nodes_login;
 | 
						|
                my $rst_fork = fork_process_login($node);
 | 
						|
                $child_num++ unless($rst_fork);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    foreach my $node (keys %node_info) {
 | 
						|
        if (!$valid_nodes{$node}) {
 | 
						|
            xCAT::SvrUtils::sendmsg([1, $::FAILED_LOGIN_MSG], $callback, $node);
 | 
						|
            $node_info{$node}{rst} = $::FAILED_LOGIN_MSG;
 | 
						|
            $wait_node_num--;
 | 
						|
            next;
 | 
						|
        }
 | 
						|
        if ($next_status{LOGIN_RESPONSE} eq "RSPCONFIG_SET_HOSTNAME_REQUEST" and $status_info{RSPCONFIG_SET_HOSTNAME_REQUEST}{data} =~ /^\*$/) {
 | 
						|
            if ($node_info{$node}{bmc} =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
 | 
						|
                my $info_msg = "Invalid OpenBMC Hostname $node_info{$node}{bmc}, can't set to OpenBMC";
 | 
						|
                xCAT::SvrUtils::sendmsg([1, $info_msg], $callback, $node);
 | 
						|
                $wait_node_num--;
 | 
						|
                next;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        # All options parsed and validated. Now lock upload and activate processing, so that only one
 | 
						|
        # can continue in case multiples are issued for the same node
 | 
						|
        #
 | 
						|
        if (($next_status{LOGIN_RESPONSE} eq "RFLASH_FILE_UPLOAD_REQUEST") or
 | 
						|
            ($next_status{LOGIN_RESPONSE} eq "RFLASH_UPDATE_ACTIVATE_REQUEST") or
 | 
						|
            ($next_status{LOGIN_RESPONSE} eq "RFLASH_UPDATE_HOST_ACTIVATE_REQUEST")) {
 | 
						|
 | 
						|
            my $lock = xCAT::Utils->acquire_lock("rflash_$node", 1);
 | 
						|
            unless ($lock) {
 | 
						|
                my $lock_msg = "Unable to rflash $node. Another process is already flashing this node.";
 | 
						|
                xCAT::SvrUtils::sendmsg([ 1, $lock_msg ], $callback, $node);
 | 
						|
                $node_info{$node}{rst} = $lock_msg;
 | 
						|
                $wait_node_num--;
 | 
						|
                next;
 | 
						|
            }
 | 
						|
            if ($::VERBOSE) {
 | 
						|
                xCAT::SvrUtils::sendmsg("Acquired the lock for upload and activate process", $callback, $node);
 | 
						|
            }
 | 
						|
            $node_info{$node}{rflash_lock} = $lock;
 | 
						|
        }
 | 
						|
 | 
						|
        $login_url = "$http_protocol://$node_info{$node}{bmc}/login";
 | 
						|
        $content = '{ "data": [ "' . $node_info{$node}{username} .'", "' . $node_info{$node}{password} . '" ] }';
 | 
						|
        if ($xcatdebugmode) {
 | 
						|
            my $debug_info = "curl -k -c cjar -H \"Content-Type: application/json\" -d '{ \"data\": [\"$node_info{$node}{username}\", \"xxxxxx\"] }' $login_url";
 | 
						|
            process_debug_info($node, $debug_info);
 | 
						|
        }
 | 
						|
        $handle_id = xCAT::OPENBMC->new($async, $login_url, $content);
 | 
						|
        $handle_id_node{$handle_id} = $node;
 | 
						|
        $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
    }
 | 
						|
 | 
						|
    if ($next_status{LOGIN_RESPONSE} eq "RSPCONFIG_SSHCFG_REQUEST") {
 | 
						|
        my $home = xCAT::Utils->getHomeDir("root");
 | 
						|
        open(FILE, ">$home/.ssh/copy.sh")
 | 
						|
          or die "cannot open file $home/.ssh/copy.sh\n";
 | 
						|
        print FILE "#!/bin/sh
 | 
						|
umask 0077
 | 
						|
userid=\$1
 | 
						|
home=`egrep \"^\$userid:\" /etc/passwd | cut -f6 -d :`
 | 
						|
if [ -n \"\$home\" ]; then
 | 
						|
  dest_dir=\"\$home/.ssh\"
 | 
						|
else
 | 
						|
  home=`su - root -c pwd`
 | 
						|
  dest_dir=\"\$home/.ssh\"
 | 
						|
fi
 | 
						|
mkdir -p \$dest_dir
 | 
						|
cat /tmp/\$userid/.ssh/id_rsa.pub >> \$home/.ssh/authorized_keys 2>&1
 | 
						|
rm -f /tmp/\$userid/.ssh/* 2>&1
 | 
						|
rmdir \"/tmp/\$userid/.ssh\"
 | 
						|
rmdir \"/tmp/\$userid\" \n";
 | 
						|
        close FILE;
 | 
						|
        chmod 0700, "$home/.ssh/copy.sh";
 | 
						|
 | 
						|
        mkdir "$home/.ssh/tmp";
 | 
						|
        # create authorized_keys file to be appended to target
 | 
						|
        if (-f "/etc/xCATMN") {    # if on Management Node
 | 
						|
            copy("$home/.ssh/id_rsa.pub","$home/.ssh/tmp/authorized_keys");
 | 
						|
        } else {
 | 
						|
            copy("$home/.ssh/authorized_keys","$home/.ssh/tmp/authorized_keys");
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    while (1) {
 | 
						|
        unless ($wait_node_num) {
 | 
						|
            if ($event_mapping and (ref($event_mapping) ne "HASH")) {
 | 
						|
                xCAT::SvrUtils::sendmsg("$event_mapping, install the OpenBMC RAS package to obtain more details logging messages.", $callback);
 | 
						|
            }
 | 
						|
            if ($next_status{LOGIN_RESPONSE} eq "RSPCONFIG_SSHCFG_REQUEST") {
 | 
						|
                my $home = xCAT::Utils->getHomeDir("root");
 | 
						|
                unlink "$home/.ssh/copy.sh";
 | 
						|
                File::Path->remove_tree("$home/.ssh/tmp/");
 | 
						|
            }
 | 
						|
            if ($::UPLOAD_AND_ACTIVATE or $next_status{LOGIN_RESPONSE} eq "RFLASH_UPDATE_ACTIVATE_REQUEST") {
 | 
						|
                my %rflash_result = ();
 | 
						|
                foreach my $node (keys %node_info) {
 | 
						|
                    if ($node_info{$node}{rst} =~ /successful/) {
 | 
						|
                        push @{ $rflash_result{success} }, $node;
 | 
						|
                    } else {
 | 
						|
                        # If there is no error in $node_info{$node}{rst} it is probably because fw file
 | 
						|
                        # upload is done in a forked process and data can not be saved in $node_info{$node}{rst}
 | 
						|
                        # In that case check the rflash log file for this node and extract error from there
 | 
						|
                        unless ($node_info{$node}{rst}) {
 | 
						|
                            my $rflash_log_file = xCAT::Utils->full_path($node.".log", $::XCAT_LOG_RFLASH_DIR);
 | 
						|
                            # Extract the upload error from last line in log file
 | 
						|
                            my $upload_error = `tail $rflash_log_file -n1 | grep "$::FAILED_UPLOAD_MSG"`;
 | 
						|
                            if ($upload_error) {
 | 
						|
                                chomp $upload_error;
 | 
						|
                                $node_info{$node}{rst} = $upload_error;
 | 
						|
                            } else {
 | 
						|
                                $node_info{$node}{rst} = "BMC is not ready";
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                        push @{ $rflash_result{fail} }, "$node: $node_info{$node}{rst}";
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                my $total = keys %node_info;
 | 
						|
                # Display summary information but only if there were any nodes to process
 | 
						|
                if ($total > 0) {
 | 
						|
                    xCAT::MsgUtils->message("I", { data => ["-------------------------------------------------------"], host => [1] }, $callback);
 | 
						|
                    my $summary = "Firmware update complete: ";
 | 
						|
                    my $success = 0;
 | 
						|
                    my $fail = 0;
 | 
						|
                    $success = @{ $rflash_result{success} } if (defined $rflash_result{success} and @{ $rflash_result{success} });
 | 
						|
                    $fail = @{ $rflash_result{fail} } if (defined $rflash_result{fail} and @{ $rflash_result{fail} });
 | 
						|
                    $summary .= "Total=$total Success=$success Failed=$fail";
 | 
						|
                    xCAT::MsgUtils->message("I", { data => ["$summary"], host => [1] }, $callback);
 | 
						|
 | 
						|
                    if ($rflash_result{fail}) {
 | 
						|
                        foreach (@{ $rflash_result{fail} }) {
 | 
						|
                            xCAT::MsgUtils->message("I", { data => ["$_"], host => [1] }, $callback);
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    xCAT::MsgUtils->message("I", { data => ["-------------------------------------------------------"], host => [1] }, $callback);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            last;
 | 
						|
        }
 | 
						|
        while (my ($response, $handle_id) = $async->wait_for_next_response) {
 | 
						|
            deal_with_response($handle_id, $response);
 | 
						|
        }
 | 
						|
 | 
						|
        if (%child_node_map) {
 | 
						|
            my $pid_flag = 0;
 | 
						|
            while ((my $cpid = waitpid(-1, WNOHANG)) > 0) {
 | 
						|
                if ($child_node_map{$cpid}) {
 | 
						|
                    $pid_flag = 1;
 | 
						|
                    my $node = $child_node_map{$cpid};
 | 
						|
                    my $rc = $? >> 8;
 | 
						|
                    if ($rc != 0) {
 | 
						|
                        $wait_node_num--;
 | 
						|
                    } else {
 | 
						|
                        if ($status_info{ $node_info{$node}{cur_status} }->{process}) {
 | 
						|
                            $status_info{ $node_info{$node}{cur_status} }->{process}->($node, undef);
 | 
						|
                        } else {
 | 
						|
                            xCAT::SvrUtils::sendmsg([1,"Internal error, check the process handler for current status "
 | 
						|
                                        .$node_info{$node}{cur_status}."."], $callback, $node);
 | 
						|
                            $wait_node_num--;
 | 
						|
                        }
 | 
						|
 | 
						|
                    }
 | 
						|
                    delete $child_node_map{$cpid};
 | 
						|
                }
 | 
						|
            }
 | 
						|
            unless ($pid_flag) {
 | 
						|
                select(undef, undef, undef, 0.01);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        my @del;
 | 
						|
        while (my ($k, $v) = each %node_wait) {
 | 
						|
            if (time() >= $v) {
 | 
						|
                if ($node_info{$k}{method} || $status_info{ $node_info{$k}{cur_status} }{method}) {
 | 
						|
                    gen_send_request($k);
 | 
						|
                } else {
 | 
						|
                    xCAT::SvrUtils::sendmsg([1,"Internal error, check the REST handler for current status "
 | 
						|
                                .$node_info{$k}{cur_status}."."], $callback, $k);
 | 
						|
                    $wait_node_num--;
 | 
						|
                }
 | 
						|
                push(@del, $k);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        foreach my $d (@del) {
 | 
						|
            delete $node_wait{$d};
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    $callback->({ errorcode => [$check] }) if ($check);
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  parse_args
 | 
						|
 | 
						|
  Parse the command line options and operands
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub parse_args {
 | 
						|
    my $command  = shift;
 | 
						|
    my $extrargs = shift;
 | 
						|
    my $noderange = shift;
 | 
						|
    my $check = undef;
 | 
						|
    my $subcommand = undef;
 | 
						|
    my $verbose    = undef;
 | 
						|
    unless (GetOptions(
 | 
						|
        'V|verbose'  => \$verbose,
 | 
						|
    )) {
 | 
						|
        return ([ 1, "Error parsing arguments." ]);
 | 
						|
    }
 | 
						|
 | 
						|
    # If command includes '-V', it must be the last one prarmeter. Or print error message.
 | 
						|
    if ($verbose) {
 | 
						|
        my $option = $$extrargs[-1];
 | 
						|
        return ([ 1, "Error parsing arguments." ]) if ($option !~ /V|verbose/);
 | 
						|
    }
 | 
						|
 | 
						|
    if (scalar(@ARGV) >= 2 and ($command =~ /rpower|rinv|rvitals/)) {
 | 
						|
        return ([ 1, "Only one option is supported at the same time for $command" ]);
 | 
						|
    } elsif (scalar(@ARGV) >= 2 and $command eq "reventlog") {
 | 
						|
        my $option_s;
 | 
						|
        GetOptions( 's' => \$option_s );
 | 
						|
        return ([ 1, "The -s option is not supported for OpenBMC." ]) if ($option_s);
 | 
						|
        if ( "resolved" ~~ @ARGV) {
 | 
						|
            return ([ 1, "$usage_errormsg $reventlog_no_id_resolved_errormsg" ]);
 | 
						|
        }
 | 
						|
        return ([ 1, "Only one option is supported at the same time for $command" ]);
 | 
						|
 | 
						|
    } elsif (scalar(@ARGV) == 0 and $command =~ /rpower|rspconfig|rflash/) {
 | 
						|
        return ([ 1, "No option specified for $command" ]);
 | 
						|
    } else {
 | 
						|
        $subcommand = $ARGV[0];
 | 
						|
    }
 | 
						|
 | 
						|
    if ($command eq "rbeacon") {
 | 
						|
        unless ($subcommand =~ /^on$|^off$|^stat$/) {
 | 
						|
	    return ([ 1, "Only 'on', 'off' or 'stat' are supported for OpenBMC managed nodes."]);
 | 
						|
        }
 | 
						|
    } elsif ($command eq "rpower") {
 | 
						|
        unless ($subcommand =~ /^on$|^off$|^softoff$|^reset$|^boot$|^bmcreboot$|^bmcstate$|^status$|^stat$|^state$/) {
 | 
						|
            return ([ 1, "Unsupported command: $command $subcommand" ]);
 | 
						|
        }
 | 
						|
    } elsif ($command eq "rinv") {
 | 
						|
        $subcommand = "all" if (!defined($ARGV[0]));
 | 
						|
        unless ($subcommand =~ /^model$|^serial$|^firm$|^cpu$|^dimm$|^all$/) {
 | 
						|
            return ([ 1, "Unsupported command: $command $subcommand" ]);
 | 
						|
        }
 | 
						|
    } elsif ($command eq "getopenbmccons") {
 | 
						|
        # command for openbmc rcons
 | 
						|
    } elsif ($command eq "rsetboot") {
 | 
						|
        $subcommand = "stat" if (!defined($ARGV[0]));
 | 
						|
        unless ($subcommand =~ /^net$|^hd$|^cd$|^def$|^default$|^stat$/) {
 | 
						|
            return ([ 1, "Unsupported command: $command $subcommand" ]);
 | 
						|
        }
 | 
						|
    } elsif ($command eq "reventlog") {
 | 
						|
        $subcommand = "all" if (!defined($ARGV[0]));
 | 
						|
        if ($subcommand =~ /^(\w+)=(.*)/) {
 | 
						|
            my $key = $1;
 | 
						|
            my $value = $2;
 | 
						|
            if (not $value) {
 | 
						|
                return ([ 1, "$usage_errormsg $reventlog_no_id_resolved_errormsg" ]);
 | 
						|
            }
 | 
						|
 | 
						|
            my $nodes_num = @$noderange;
 | 
						|
            if (@$noderange > 1) {
 | 
						|
                return ([ 1, "Resolving faults over a xCAT noderange is not recommended." ]);
 | 
						|
            }
 | 
						|
 | 
						|
            xCAT::SvrUtils::sendmsg("Attempting to resolve the following log entries: $value...", $callback);
 | 
						|
        } elsif ($subcommand !~ /^\d$|^\d+$|^all$|^clear$/) {
 | 
						|
            if ($subcommand =~ "resolved") {
 | 
						|
                return ([ 1, "$usage_errormsg $reventlog_no_id_resolved_errormsg" ]);
 | 
						|
            }
 | 
						|
            return ([ 1, "Unsupported command: $command $subcommand" ]);
 | 
						|
        }
 | 
						|
    } elsif ($command eq "rspconfig") {
 | 
						|
        my $num_subcommand = @ARGV;
 | 
						|
        my $setorget;
 | 
						|
        my $all_subcommand = "";
 | 
						|
        foreach $subcommand (@ARGV) {
 | 
						|
            $::RSPCONFIG_CONFIGURED_API_KEY = &is_valid_config_api($subcommand, $callback);
 | 
						|
            if ($::RSPCONFIG_CONFIGURED_API_KEY ne -1) {
 | 
						|
                return ([ 1, "Can not query $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{subcommand} information with other options at the same time" ]) if ($#ARGV > 1);
 | 
						|
                # subcommand defined in the configured API hash, return from here, the RSPCONFIG_CONFIGURED_API_KEY is the key into the hash
 | 
						|
                return;
 | 
						|
            }
 | 
						|
            elsif ($subcommand =~ /^(\w+)=(.*)/) {
 | 
						|
                return ([ 1, "Can not set and query OpenBMC information at the same time" ]) if ($setorget and $setorget eq "get");
 | 
						|
                my $key = $1;
 | 
						|
                my $value = $2;
 | 
						|
                return ([ 1, "Changing ipsrc value is currently not supported." ]) if ($key eq "ipsrc");
 | 
						|
                return ([ 1, "Unsupported command: $command $key" ]) unless ($key =~ /^ip$|^netmask$|^gateway$|^hostname$|^vlan$|^admin_passwd$|^ntpservers$/);
 | 
						|
                return ([ 1, "The option '$key' can not work with other options." ]) if ($key =~ /^hostname$|^admin_passwd$|^ntpservers$/ and $num_subcommand > 1);
 | 
						|
                if ($key eq "admin_passwd") {
 | 
						|
                    my $comma_num = $value =~ tr/,/,/;
 | 
						|
                    return ([ 1, "Invalid parameter for option $key: $value" ]) if ($comma_num != 1);
 | 
						|
                    if ($subcommand =~ /^admin_passwd=(.*),(.*)/) {
 | 
						|
                        return ([ 1, "Invalid parameter for option $key: $value" ]) if ($1 eq "" or $2 eq "");
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                my $nodes_num = @$noderange;
 | 
						|
                return ([ 1, "Invalid parameter for option $key" ]) if (!$value and $key ne ("ntpservers"));
 | 
						|
                return ([ 1, "Invalid parameter for option $key: $value" ]) if (($key eq "netmask") and !xCAT::NetworkUtils->isIpaddr($value));
 | 
						|
                return ([ 1, "Invalid parameter for option $key: $value" ]) if (($key eq "gateway") and ($value !~ "0.0.0.0" and !xCAT::NetworkUtils->isIpaddr($value)));
 | 
						|
                if ($key eq "ip") {
 | 
						|
                    return ([ 1, "Can not configure more than 1 nodes' ip at the same time" ]) if ($nodes_num >= 2 and $value ne "dhcp");
 | 
						|
                    if ($value ne "dhcp" ) {
 | 
						|
                        if (!xCAT::NetworkUtils->isIpaddr($value)) {
 | 
						|
                            return ([ 1, "Invalid parameter for option $key: $value" ]);
 | 
						|
                        } else {
 | 
						|
                            $all_subcommand .= $key . ",";
 | 
						|
                        }
 | 
						|
                    } else {
 | 
						|
                        return ([ 1, "Setting ip=dhcp must be issued without other options." ]) if ($num_subcommand > 1);
 | 
						|
                    }
 | 
						|
                } elsif ($key =~ /^netmask$|^gateway$|^vlan$/) {
 | 
						|
                    $all_subcommand .= $key . ",";
 | 
						|
                }
 | 
						|
                $setorget = "set";
 | 
						|
            } elsif ($subcommand =~ /^ip$|^netmask$|^gateway$|^hostname$|^vlan$|^ipsrc$|^ntpservers$/) {
 | 
						|
                return ([ 1, "Can not set and query OpenBMC information at the same time" ]) if ($setorget and $setorget eq "set");
 | 
						|
                $setorget = "get";
 | 
						|
            } elsif ($subcommand =~ /^sshcfg$/) {
 | 
						|
                return ([ 1, "Configure sshcfg must be issued without other options." ]) if ($num_subcommand > 1);
 | 
						|
                $setorget = ""; # SSH Keys are copied using a RShellAPI, not REST API
 | 
						|
            } elsif ($subcommand eq "gard") {
 | 
						|
                my $option = "";
 | 
						|
                $option = $ARGV[1] if (defined $ARGV[1]);
 | 
						|
                return  ([ 1, "Clear GARD cannot be issued with other options." ]) if ($num_subcommand > 2);
 | 
						|
                return ([ 1, "Invalid parameter for $command $subcommand $option" ]) if ($option !~ /^-c$|^--clear$/);
 | 
						|
                $setorget = "";
 | 
						|
                return;
 | 
						|
            } elsif ($subcommand eq "dump") {
 | 
						|
                my $option = "";
 | 
						|
                $option = $ARGV[1] if (defined $ARGV[1]);
 | 
						|
                if ($option =~ /^-d$|^--download$/) {
 | 
						|
                    return ([ 1, "No dump file ID specified" ]) unless ($ARGV[2]);
 | 
						|
                    return ([ 1, "Invalid parameter for $command $option $ARGV[2]" ]) if ($ARGV[2] !~ /^\d*$/ and $ARGV[2] ne "all");
 | 
						|
                } elsif ($option =~ /^-c$|^--clear$/) {
 | 
						|
                    return ([ 1, "No dump file ID specified. To clear all, specify 'all'." ]) unless ($ARGV[2]);
 | 
						|
                    return ([ 1, "Invalid parameter for $command $option $ARGV[2]" ]) if ($ARGV[2] !~ /^\d*$/ and $ARGV[2] ne "all");
 | 
						|
                } elsif ($option and $option !~ /^-l$|^--list$|^-g$|^--generate$/) {
 | 
						|
                    return ([ 1, "Invalid parameter for $command $option" ]);
 | 
						|
                }
 | 
						|
                return;
 | 
						|
            } else {
 | 
						|
                return ([ 1, "Unsupported command: $command $subcommand" ]);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if ($all_subcommand) {
 | 
						|
            if ($all_subcommand !~ /ip/ or $all_subcommand !~ /netmask/ or $all_subcommand !~ /gateway/) {
 | 
						|
                if ($all_subcommand =~ /vlan/) {
 | 
						|
                    return ([ 1, "VLAN must be configured with IP, netmask and gateway" ]);
 | 
						|
                } else {
 | 
						|
                    return ([ 1, "IP, netmask and gateway must be configured together." ]);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    } elsif ($command eq "rvitals") {
 | 
						|
        $subcommand = "all" if (!defined($ARGV[0]));
 | 
						|
        unless ($subcommand =~ /^leds$|^temp$|^voltage$|^wattage$|^fanspeed$|^power$|^altitude$|^all$/) {
 | 
						|
            return ([ 1, "Unsupported command: $command $subcommand" ]);
 | 
						|
        }
 | 
						|
    } elsif ($command eq "rflash") {
 | 
						|
        my $filename_passed = 0;
 | 
						|
        my $updateid_passed = 0;
 | 
						|
        my $filepath_passed = 0;
 | 
						|
        my $option_flag;
 | 
						|
 | 
						|
        my @tarball_path;
 | 
						|
        my $invalid_options = "";
 | 
						|
        my @flash_arguments;
 | 
						|
 | 
						|
        foreach my $opt (@$extrargs) {
 | 
						|
            # Only files ending on .tar are allowed
 | 
						|
            if ($opt =~ /.*\.tar$/i) {
 | 
						|
                $filename_passed = 1;
 | 
						|
                push (@flash_arguments, $opt);
 | 
						|
                next;
 | 
						|
            }
 | 
						|
            # Check if hex number for the updateid is passed
 | 
						|
            elsif ($opt =~ /^[[:xdigit:]]+$/i) {
 | 
						|
                $updateid_passed = 1;
 | 
						|
                push (@flash_arguments, $opt);
 | 
						|
                next;
 | 
						|
            }
 | 
						|
            # check if option starting with - was passed
 | 
						|
            elsif ($opt =~ /^-/) {
 | 
						|
                # do not add verbose option to the $option_flag in order to preserve arg checks below
 | 
						|
                if ($opt !~ /^-V$|^--verbose$/) {
 | 
						|
                    if ($option_flag) {
 | 
						|
                        $option_flag .= " " . $opt;
 | 
						|
                    } else {
 | 
						|
                        $option_flag .= $opt;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            elsif ($opt =~ /^\//) {
 | 
						|
                $filepath_passed = 1;
 | 
						|
                push (@tarball_path, $opt);
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                my $tmppath = xCAT::Utils->full_path($opt, $::cwd);
 | 
						|
                if (opendir(TDIR, $tmppath)) {
 | 
						|
                    $filepath_passed = 1;
 | 
						|
                    push (@tarball_path, $tmppath);
 | 
						|
                    close(TDIR);
 | 
						|
                } else {
 | 
						|
                    push (@flash_arguments, $opt);
 | 
						|
                    $invalid_options .= $opt . " ";
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        # show options parsed in bypass mode
 | 
						|
        print "DEBUG filename=$filename_passed, updateid=$updateid_passed, options=$option_flag, tar_file_path=@tarball_path, invalid=$invalid_options rflash_arguments=@flash_arguments\n";
 | 
						|
 | 
						|
        if ($option_flag =~ tr{ }{ } > 0) {
 | 
						|
            unless ($verbose or $option_flag =~/^-d --no-host-reboot$/) {
 | 
						|
                return ([ 1, "Multiple options are not supported. Options specified: $option_flag"]);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (scalar @flash_arguments > 1) {
 | 
						|
            if (($option_flag =~ /^-a$|^--activate$|^--delete$/) or ($filename_passed and $option_flag !~ /^-d$/)) {
 | 
						|
                # Handles:
 | 
						|
                #   - Multiple options not supported to activate/delete at the same time
 | 
						|
                #   - Filename passed in and option is not -d for directory
 | 
						|
                return ([1, "More than one firmware specified is not supported."]);
 | 
						|
            } elsif ($option_flag =~ /^-d$/) {
 | 
						|
                return ([1, "More than one directory specified is not supported."]);
 | 
						|
            } else {
 | 
						|
                return ([ 1, "Invalid firmware specified with $option_flag" ]);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if ($filename_passed) {
 | 
						|
            # Filename was passed, check flags allowed with file
 | 
						|
            if ($option_flag !~ /^-c$|^--check$|^-u$|^--upload$|^-a$|^--activate$/) {
 | 
						|
                return ([ 1, "Invalid option specified when a file is provided: $option_flag" ]);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            if ($updateid_passed) {
 | 
						|
                # Updateid was passed, check flags allowed with update id
 | 
						|
                if ($option_flag !~ /^--delete$|^-a$|^--activate$/) {
 | 
						|
                    my $optional_help_msg = "";
 | 
						|
                    if ($option_flag == "-d") {
 | 
						|
                        # For this special case, -d was changed to pass in a directory.
 | 
						|
                        $optional_help_msg = "Did you mean --delete?"
 | 
						|
                    }
 | 
						|
                    return ([ 1, "Invalid option specified when an update id is provided: $option_flag. $optional_help_msg" ]);
 | 
						|
                }
 | 
						|
                my $action = "activate";
 | 
						|
                if ($option_flag =~ /^--delete$/) {
 | 
						|
                    $action = "delete";
 | 
						|
                }
 | 
						|
                xCAT::SvrUtils::sendmsg("Attempting to $action ID=$flash_arguments[0], please wait...", $callback);
 | 
						|
            } elsif ($filepath_passed) {
 | 
						|
                if ($option_flag =~ /^-d|^-d --no-host-reboot$/) {
 | 
						|
                    if (scalar @tarball_path > 1) {
 | 
						|
                        return ([1, "More than one directory specified is not supported"]);
 | 
						|
                    }
 | 
						|
                    if ($invalid_options) {
 | 
						|
                        return ([ 1, "Invalid option specified $invalid_options"]);
 | 
						|
                    }
 | 
						|
                } elsif ($option_flag =~ /^-c$|^--check$|^-u$|^--upload$|^-a$|^--activate$/) {
 | 
						|
                    return ([ 1, "Invalid firmware specified with $option_flag" ]);
 | 
						|
                } else {
 | 
						|
                    return ([ 1, "Invalid option specified" ]);
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
                # Neither Filename nor updateid was not passed, check flags allowed without file or updateid
 | 
						|
                if ($option_flag !~ /^-c$|^--check$|^-l$|^--list$/) {
 | 
						|
                    return ([ 1, "Invalid option specified with $option_flag: $invalid_options" ]);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        return ([ 1, "Command is not supported." ]);
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  parse_command_status
 | 
						|
 | 
						|
  Parse the command to init status machine
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub parse_command_status {
 | 
						|
    my $command     = shift;
 | 
						|
    my $subcommands = shift;
 | 
						|
    my $subcommand;
 | 
						|
 | 
						|
    return if ($command eq "getopenbmccons");
 | 
						|
 | 
						|
    if ($$subcommands[-1] and $$subcommands[-1] =~ /V|verbose/) {
 | 
						|
        $::VERBOSE = 1;
 | 
						|
        pop(@$subcommands);
 | 
						|
    }
 | 
						|
 | 
						|
    $next_status{LOGIN_REQUEST} = "LOGIN_RESPONSE";
 | 
						|
 | 
						|
    if ($command eq "rbeacon") {
 | 
						|
        $subcommand = $$subcommands[0];
 | 
						|
 | 
						|
        if ($subcommand eq "on") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RBEACON_ON_REQUEST";
 | 
						|
            $next_status{RBEACON_ON_REQUEST} = "RBEACON_ON_RESPONSE";
 | 
						|
        } elsif ($subcommand eq "off") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RBEACON_OFF_REQUEST";
 | 
						|
            $next_status{RBEACON_OFF_REQUEST} = "RBEACON_OFF_RESPONSE";
 | 
						|
        } elsif ($subcommand eq "stat") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RVITALS_LEDS_REQUEST";
 | 
						|
            $next_status{RVITALS_LEDS_REQUEST} = "RVITALS_LEDS_RESPONSE";
 | 
						|
            $status_info{RVITALS_LEDS_RESPONSE}{argv} = "compact";
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($command eq "rpower") {
 | 
						|
        $subcommand = $$subcommands[0];
 | 
						|
 | 
						|
        if ($subcommand eq "on") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RPOWER_ON_REQUEST";
 | 
						|
            $next_status{RPOWER_ON_REQUEST} = "RPOWER_ON_RESPONSE";
 | 
						|
        } elsif ($subcommand eq "off") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RPOWER_OFF_REQUEST";
 | 
						|
            $next_status{RPOWER_OFF_REQUEST} = "RPOWER_OFF_RESPONSE";
 | 
						|
        } elsif ($subcommand eq "softoff") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RPOWER_SOFTOFF_REQUEST";
 | 
						|
            $next_status{RPOWER_SOFTOFF_REQUEST} = "RPOWER_SOFTOFF_RESPONSE";
 | 
						|
        } elsif ($subcommand eq "reset") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RPOWER_STATUS_REQUEST";
 | 
						|
            $next_status{RPOWER_STATUS_REQUEST} = "RPOWER_STATUS_RESPONSE";
 | 
						|
            $next_status{RPOWER_STATUS_RESPONSE}{ON} = "RPOWER_OFF_REQUEST";
 | 
						|
            $next_status{RPOWER_OFF_REQUEST} = "RPOWER_OFF_RESPONSE";
 | 
						|
            $next_status{RPOWER_OFF_RESPONSE} = "RPOWER_CHECK_REQUEST";
 | 
						|
            $next_status{RPOWER_CHECK_REQUEST} = "RPOWER_CHECK_RESPONSE";
 | 
						|
            $next_status{RPOWER_CHECK_RESPONSE}{ON} = "RPOWER_CHECK_REQUEST";
 | 
						|
            $next_status{RPOWER_CHECK_RESPONSE}{OFF} = "RPOWER_ON_REQUEST";
 | 
						|
            $next_status{RPOWER_ON_REQUEST} = "RPOWER_ON_RESPONSE";
 | 
						|
            $status_info{RPOWER_ON_RESPONSE}{argv} = "$subcommand";
 | 
						|
        } elsif ($subcommand =~ /^bmcstate$|^status$|^state$|^stat$/) {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RPOWER_STATUS_REQUEST";
 | 
						|
            $next_status{RPOWER_STATUS_REQUEST} = "RPOWER_STATUS_RESPONSE";
 | 
						|
            $status_info{RPOWER_STATUS_RESPONSE}{argv} = "$subcommand";
 | 
						|
        } elsif ($subcommand eq "boot") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RPOWER_OFF_REQUEST";
 | 
						|
            $next_status{RPOWER_OFF_REQUEST} = "RPOWER_OFF_RESPONSE";
 | 
						|
            $next_status{RPOWER_OFF_RESPONSE} = "RPOWER_CHECK_REQUEST";
 | 
						|
            $next_status{RPOWER_CHECK_REQUEST} = "RPOWER_CHECK_RESPONSE";
 | 
						|
            $next_status{RPOWER_CHECK_RESPONSE}{ON} = "RPOWER_CHECK_REQUEST";
 | 
						|
            $next_status{RPOWER_CHECK_RESPONSE}{OFF} = "RPOWER_ON_REQUEST";
 | 
						|
            $next_status{RPOWER_ON_REQUEST} = "RPOWER_ON_RESPONSE";
 | 
						|
            $status_info{RPOWER_ON_RESPONSE}{argv} = "$subcommand";
 | 
						|
        } elsif ($subcommand eq "bmcreboot") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RINV_FIRM_REQUEST";
 | 
						|
            $next_status{RINV_FIRM_REQUEST} = "RINV_FIRM_RESPONSE";
 | 
						|
            $next_status{RINV_FIRM_RESPONSE}{PENDING} = "RSPCONFIG_DUMP_CLEAR_ALL_REQUEST";
 | 
						|
            $next_status{RSPCONFIG_DUMP_CLEAR_ALL_REQUEST} = "RSPCONFIG_DUMP_CLEAR_RESPONSE";
 | 
						|
            $next_status{RSPCONFIG_DUMP_CLEAR_RESPONSE} = "RPOWER_BMCREBOOT_REQUEST";
 | 
						|
            $next_status{RINV_FIRM_RESPONSE}{NO_PENDING} = "RPOWER_BMCREBOOT_REQUEST";
 | 
						|
            $next_status{RPOWER_BMCREBOOT_REQUEST} = "RPOWER_RESET_RESPONSE";
 | 
						|
            $status_info{RPOWER_RESET_RESPONSE}{argv} = "$subcommand";
 | 
						|
            $status_info{RINV_FIRM_RESPONSE}{check} = 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($command eq "rinv") {
 | 
						|
        if (defined($$subcommands[0])) {
 | 
						|
            $subcommand = $$subcommands[0];
 | 
						|
        } else {
 | 
						|
            $subcommand = "all";
 | 
						|
        }
 | 
						|
 | 
						|
        if ($subcommand eq "firm") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RINV_FIRM_REQUEST";
 | 
						|
            $next_status{RINV_FIRM_REQUEST} = "RINV_FIRM_RESPONSE";
 | 
						|
        } elsif ($subcommand eq "all") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RINV_REQUEST";
 | 
						|
            $next_status{RINV_REQUEST} = "RINV_RESPONSE";
 | 
						|
            $status_info{RINV_RESPONSE}{argv} = "$subcommand";
 | 
						|
            $next_status{RINV_RESPONSE} = "RINV_FIRM_REQUEST";
 | 
						|
            $next_status{RINV_FIRM_REQUEST} = "RINV_FIRM_RESPONSE";
 | 
						|
        } else {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RINV_REQUEST";
 | 
						|
            $next_status{RINV_REQUEST} = "RINV_RESPONSE";
 | 
						|
            $status_info{RINV_RESPONSE}{argv} = "$subcommand";
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($command eq "rsetboot") {
 | 
						|
        if ($$subcommands[-1] and $$subcommands[-1] eq "-p") {
 | 
						|
            pop(@$subcommands);
 | 
						|
            $status_info{RSETBOOT_ENABLE_REQUEST}{data} = '0';
 | 
						|
            $status_info{RSETBOOT_SET_REQUEST}{init_url} = "$openbmc_project_url/control/host0/boot/attr/BootSource";
 | 
						|
        }
 | 
						|
 | 
						|
        if (defined($$subcommands[0])) {
 | 
						|
            $subcommand = $$subcommands[0];
 | 
						|
        } else {
 | 
						|
            $subcommand = "stat";
 | 
						|
        }
 | 
						|
        if ($subcommand =~ /^hd$|^net$|^cd$|^default$|^def$/) {
 | 
						|
            if (defined($::OPENBMC_FW) && ($::OPENBMC_FW < 1738)) {
 | 
						|
                #
 | 
						|
                # In 1738, the endpount URL changed.  In order to support the older URL as a work around, allow for a environment
 | 
						|
                # variable to change this value.
 | 
						|
                #
 | 
						|
                $::RSETBOOT_URL_PATH = "boot_source";
 | 
						|
                $status_info{RSETBOOT_SET_REQUEST}{init_url} = "$openbmc_project_url/control/host0/$::RSETBOOT_URL_PATH/attr/BootSource";
 | 
						|
                $status_info{RSETBOOT_STATUS_REQUEST}{init_url} = "$openbmc_project_url/control/host0/$::RSETBOOT_URL_PATH";
 | 
						|
                $next_status{LOGIN_RESPONSE} = "RSETBOOT_SET_REQUEST";
 | 
						|
            } else {
 | 
						|
                $next_status{LOGIN_RESPONSE} = "RSETBOOT_ENABLE_REQUEST";
 | 
						|
                $next_status{RSETBOOT_ENABLE_REQUEST} = "RSETBOOT_ENABLE_RESPONSE";
 | 
						|
                $next_status{RSETBOOT_ENABLE_RESPONSE} = "RSETBOOT_SET_REQUEST";
 | 
						|
            }
 | 
						|
            $next_status{RSETBOOT_SET_REQUEST} = "RSETBOOT_SET_RESPONSE";
 | 
						|
            if ($subcommand eq "net") {
 | 
						|
                $status_info{RSETBOOT_SET_REQUEST}{data} .= "Network";
 | 
						|
            } elsif ($subcommand eq "hd") {
 | 
						|
                $status_info{RSETBOOT_SET_REQUEST}{data} .= "Disk";
 | 
						|
            } elsif ($subcommand eq "cd") {
 | 
						|
                $status_info{RSETBOOT_SET_REQUEST}{data} .= "ExternalMedia";
 | 
						|
            } elsif ($subcommand eq "def" or $subcommand eq "default") {
 | 
						|
                $status_info{RSETBOOT_SET_REQUEST}{data} .= "Default";
 | 
						|
            }
 | 
						|
            $next_status{RSETBOOT_SET_RESPONSE} = "RSETBOOT_STATUS_REQUEST";
 | 
						|
            $next_status{RSETBOOT_STATUS_REQUEST} = "RSETBOOT_STATUS_RESPONSE";
 | 
						|
        } elsif ($subcommand eq "stat") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RSETBOOT_STATUS_REQUEST";
 | 
						|
            $next_status{RSETBOOT_STATUS_REQUEST} = "RSETBOOT_STATUS_RESPONSE";
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($command eq "reventlog") {
 | 
						|
        if (defined($$subcommands[0])) {
 | 
						|
            $subcommand = $$subcommands[0];
 | 
						|
        } else {
 | 
						|
            $subcommand = "all";
 | 
						|
        }
 | 
						|
 | 
						|
        if ($subcommand eq "clear") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "REVENTLOG_CLEAR_REQUEST";
 | 
						|
            $next_status{REVENTLOG_CLEAR_REQUEST} = "REVENTLOG_CLEAR_RESPONSE";
 | 
						|
        } elsif (uc($subcommand) =~ /RESOLVED=LED/) {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "REVENTLOG_REQUEST";
 | 
						|
            $next_status{REVENTLOG_REQUEST} = "REVENTLOG_RESOLVED_RESPONSE_LED";
 | 
						|
        } elsif ($subcommand =~ /resolved=(.+)/) {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "REVENTLOG_RESOLVED_REQUEST";
 | 
						|
            $next_status{REVENTLOG_RESOLVED_REQUEST} = "REVENTLOG_RESOLVED_RESPONSE";
 | 
						|
            my @entries = split(",", $1);
 | 
						|
            my $init_entry = shift @entries;
 | 
						|
            $status_info{REVENTLOG_RESOLVED_REQUEST}{init_url} =~ s/#ENTRY_ID#/$init_entry/g;
 | 
						|
            push @{ $status_info{REVENTLOG_RESOLVED_RESPONSE}{remain_entries} }, @entries;
 | 
						|
        } else {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "REVENTLOG_REQUEST";
 | 
						|
            $next_status{REVENTLOG_REQUEST} = "REVENTLOG_RESPONSE";
 | 
						|
            $status_info{REVENTLOG_RESPONSE}{argv} = "$subcommand";
 | 
						|
            if (-e "$::RAS_POLICY_TABLE") {
 | 
						|
                my $policy_json = `cat $::RAS_POLICY_TABLE`;
 | 
						|
                if ($policy_json) {
 | 
						|
                    my $policy_hash = decode_json $policy_json;
 | 
						|
                    $event_mapping = $policy_hash->{events};
 | 
						|
                } else {
 | 
						|
                    $event_mapping = "No data in $::RAS_POLICY_TABLE";
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
                $event_mapping = "Could not find '$::RAS_POLICY_TABLE'";
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($command eq "rspconfig") {
 | 
						|
        my @options = ();
 | 
						|
        my $num_subcommand = @$subcommands;
 | 
						|
        #Setup chain to process the configured command
 | 
						|
        $subcommand = $$subcommands[0];
 | 
						|
        $::RSPCONFIG_CONFIGURED_API_KEY = &is_valid_config_api($subcommand, $callback);
 | 
						|
        if ($::RSPCONFIG_CONFIGURED_API_KEY ne -1) {
 | 
						|
            # Check if setting or quering
 | 
						|
            if ($subcommand =~ /^(\w+)=(.*)/) {
 | 
						|
                # setting
 | 
						|
                my $subcommand_key = $1;
 | 
						|
                my $subcommand_value = lc $2;
 | 
						|
 | 
						|
                if (($subcommand_value eq "1") && ($api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{type} eq "boolean")) {
 | 
						|
                    # Setup chain for subcommand=1
 | 
						|
                    $next_status{LOGIN_RESPONSE} = "RSPCONFIG_API_CONFIG_ON_REQUEST";
 | 
						|
                    $status_info{RSPCONFIG_API_CONFIG_ON_REQUEST}{init_url} =  $status_info{RSPCONFIG_API_CONFIG_ON_REQUEST}{init_url} . $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{url} . "/attr/" . $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{attr_url};
 | 
						|
                    $next_status{RSPCONFIG_API_CONFIG_ON_REQUEST} = "RSPCONFIG_API_CONFIG_ON_RESPONSE";
 | 
						|
                }
 | 
						|
                elsif (($subcommand_value eq "0") && ($api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{type} eq "boolean")) {
 | 
						|
                    # Setup chain for subcommand=0
 | 
						|
                    $next_status{LOGIN_RESPONSE} = "RSPCONFIG_API_CONFIG_OFF_REQUEST";
 | 
						|
                    $status_info{RSPCONFIG_API_CONFIG_OFF_REQUEST}{init_url} =  $status_info{RSPCONFIG_API_CONFIG_OFF_REQUEST}{init_url} . $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{url} . "/attr/" . $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{attr_url};
 | 
						|
                    $next_status{RSPCONFIG_API_CONFIG_OFF_REQUEST} = "RSPCONFIG_API_CONFIG_OFF_RESPONSE";
 | 
						|
                }
 | 
						|
                elsif (($api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{type} eq "attribute") && (exists $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{attr_value}{$subcommand_value})) {
 | 
						|
                    # Setup chain for subcommand=<attribute key>
 | 
						|
                    $next_status{LOGIN_RESPONSE} = "RSPCONFIG_API_CONFIG_ATTR_REQUEST";
 | 
						|
                    $status_info{RSPCONFIG_API_CONFIG_ATTR_REQUEST}{init_url} =  $status_info{RSPCONFIG_API_CONFIG_ATTR_REQUEST}{init_url} . $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{url} . "/attr/" . $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{attr_url};
 | 
						|
                    $status_info{RSPCONFIG_API_CONFIG_ATTR_REQUEST}{data} =  $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{attr_value}{$subcommand_value};
 | 
						|
                    $next_status{RSPCONFIG_API_CONFIG_ATTR_REQUEST} = "RSPCONFIG_API_CONFIG_ATTR_RESPONSE";
 | 
						|
                }
 | 
						|
                elsif (($api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{type} eq "action_attribute") && (exists $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{attr_value}{$subcommand_value})) {
 | 
						|
                    # Setup chain for subcommand=<attribute key>
 | 
						|
                    $next_status{LOGIN_RESPONSE} = "RSPCONFIG_API_CONFIG_ACTION_ATTR_REQUEST";
 | 
						|
                    $status_info{RSPCONFIG_API_CONFIG_ACTION_ATTR_REQUEST}{init_url} =  $status_info{RSPCONFIG_API_CONFIG_ACTION_ATTR_REQUEST}{init_url} . $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{url} . $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{attr_url};
 | 
						|
                    $status_info{RSPCONFIG_API_CONFIG_ACTION_ATTR_REQUEST}{data} =  "[\"" . $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{attr_value}{$subcommand_value} . "\"]";
 | 
						|
                    $next_status{RSPCONFIG_API_CONFIG_ACTION_ATTR_REQUEST} = "RSPCONFIG_API_CONFIG_ATTR_RESPONSE";
 | 
						|
                }
 | 
						|
                else {
 | 
						|
                    # Everything else is invalid
 | 
						|
                        xCAT::SvrUtils::sendmsg([1, "Invalid value '$subcommand_value' for '$subcommand_key'"], $callback);
 | 
						|
                        my @valid_values = keys %{ $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{attr_value} };
 | 
						|
                        if (!@valid_values) {
 | 
						|
                            if ($api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{type} eq "boolean") {
 | 
						|
                                xCAT::SvrUtils::sendmsg([1, "Valid values: 0,1"], $callback);
 | 
						|
                            }
 | 
						|
                        } else {
 | 
						|
                            xCAT::SvrUtils::sendmsg([1, "Valid values: " . join(",", @valid_values)], $callback);
 | 
						|
                        }
 | 
						|
                        return 1;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                # Setup chain for query subcommand
 | 
						|
                if ($api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{type} eq "action_attribute") {
 | 
						|
                    $next_status{LOGIN_RESPONSE} = "RSPCONFIG_API_CONFIG_ACTION_ATTR_QUERY_REQUEST";
 | 
						|
                    $status_info{RSPCONFIG_API_CONFIG_ACTION_ATTR_QUERY_REQUEST}{init_url} =
 | 
						|
                             $status_info{RSPCONFIG_API_CONFIG_ACTION_ATTR_QUERY_REQUEST}{init_url} .
 | 
						|
                             $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{url} .
 | 
						|
                             $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{query_url};
 | 
						|
                    $next_status{RSPCONFIG_API_CONFIG_ACTION_ATTR_QUERY_REQUEST} = "RSPCONFIG_API_CONFIG_QUERY_RESPONSE";
 | 
						|
                }
 | 
						|
                else {
 | 
						|
                    $next_status{LOGIN_RESPONSE} = "RSPCONFIG_API_CONFIG_QUERY_REQUEST";
 | 
						|
                    $status_info{RSPCONFIG_API_CONFIG_QUERY_REQUEST}{init_url} =  $status_info{RSPCONFIG_API_CONFIG_QUERY_REQUEST}{init_url} . $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{url};
 | 
						|
                    $next_status{RSPCONFIG_API_CONFIG_QUERY_REQUEST} = "RSPCONFIG_API_CONFIG_QUERY_RESPONSE";
 | 
						|
                }
 | 
						|
            }
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
        if ($num_subcommand == 1) {
 | 
						|
            $subcommand = $$subcommands[0];
 | 
						|
            if ($subcommand =~ /^sshcfg$/) {
 | 
						|
                # Special processing to copy ssh keys, currently there is no REST API to do this.
 | 
						|
                $next_status{LOGIN_RESPONSE} = "RSPCONFIG_SSHCFG_REQUEST";
 | 
						|
                $next_status{RSPCONFIG_SSHCFG_REQUEST} = "RSPCONFIG_SSHCFG_RESPONSE";
 | 
						|
                return 0;
 | 
						|
            }
 | 
						|
            if ($subcommand eq "ip=dhcp") {
 | 
						|
                $next_status{LOGIN_RESPONSE} = "RSPCONFIG_DHCP_REQUEST";
 | 
						|
                $next_status{RSPCONFIG_DHCP_REQUEST} = "RSPCONFIG_DHCP_RESPONSE";
 | 
						|
                $next_status{RSPCONFIG_DHCP_RESPONSE} = "RPOWER_BMCREBOOT_REQUEST";
 | 
						|
                $next_status{RPOWER_BMCREBOOT_REQUEST} = "RPOWER_RESET_RESPONSE";
 | 
						|
                $status_info{RPOWER_RESET_RESPONSE}{argv} = "bmcreboot";
 | 
						|
                return 0;
 | 
						|
            }
 | 
						|
            if ($subcommand =~ /^hostname=(.+)/) {
 | 
						|
                $next_status{LOGIN_RESPONSE} = "RSPCONFIG_SET_HOSTNAME_REQUEST";
 | 
						|
                $next_status{RSPCONFIG_SET_HOSTNAME_REQUEST} = "RSPCONFIG_SET_RESPONSE";
 | 
						|
                $next_status{RSPCONFIG_SET_RESPONSE} = "RSPCONFIG_GET_REQUEST";
 | 
						|
                $next_status{RSPCONFIG_GET_REQUEST} = "RSPCONFIG_GET_RESPONSE";
 | 
						|
 | 
						|
                $status_info{RSPCONFIG_SET_HOSTNAME_REQUEST}{data} = $1;
 | 
						|
                $status_info{RSPCONFIG_SET_RESPONSE}{argv} = "Hostname";
 | 
						|
                $status_info{RSPCONFIG_GET_RESPONSE}{argv} = "hostname";
 | 
						|
                return 0;
 | 
						|
            }
 | 
						|
            if ($subcommand =~ /^ntpservers=(.*)/) {
 | 
						|
                $next_status{LOGIN_RESPONSE} = "RSPCONFIG_GET_NIC_REQUEST";
 | 
						|
                $next_status{RSPCONFIG_GET_NIC_REQUEST} = "RSPCONFIG_GET_NIC_RESPONSE";
 | 
						|
                $next_status{RSPCONFIG_GET_NIC_RESPONSE} = "RSPCONFIG_SET_NTPSERVERS_REQUEST";
 | 
						|
                $next_status{RSPCONFIG_SET_NTPSERVERS_REQUEST} = "RSPCONFIG_SET_RESPONSE";
 | 
						|
                $next_status{RSPCONFIG_SET_RESPONSE} = "RSPCONFIG_GET_REQUEST";
 | 
						|
                $next_status{RSPCONFIG_GET_REQUEST} = "RSPCONFIG_GET_RESPONSE";
 | 
						|
 | 
						|
                $status_info{RSPCONFIG_GET_RESPONSE}{argv} = "ntpservers";
 | 
						|
                $status_info{RSPCONFIG_SET_RESPONSE}{argv} = "NTPServers";
 | 
						|
                $status_info{RSPCONFIG_SET_NTPSERVERS_REQUEST}{data} = "[\"$1\"]";
 | 
						|
                return 0;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        $subcommand = $$subcommands[0];
 | 
						|
        if ($subcommand eq "dump") {
 | 
						|
            my $dump_opt = "";
 | 
						|
            $dump_opt = $$subcommands[1] if (defined $$subcommands[1]);
 | 
						|
            if ($dump_opt =~ /-l|--list/) {
 | 
						|
                $next_status{LOGIN_RESPONSE} = "RSPCONFIG_DUMP_LIST_REQUEST";
 | 
						|
                $next_status{RSPCONFIG_DUMP_LIST_REQUEST} = "RSPCONFIG_DUMP_LIST_RESPONSE";
 | 
						|
            } elsif ($dump_opt =~ /-g|--generate/) {
 | 
						|
                $next_status{LOGIN_RESPONSE} = "RSPCONFIG_DUMP_CREATE_REQUEST";
 | 
						|
                $next_status{RSPCONFIG_DUMP_CREATE_REQUEST} = "RSPCONFIG_DUMP_CREATE_RESPONSE";
 | 
						|
            } elsif ($dump_opt =~ /-c|--clear/) {
 | 
						|
                if ($$subcommands[2] eq "all") {
 | 
						|
                    $next_status{LOGIN_RESPONSE} = "RSPCONFIG_DUMP_CLEAR_ALL_REQUEST";
 | 
						|
                    $next_status{RSPCONFIG_DUMP_CLEAR_ALL_REQUEST} = "RSPCONFIG_DUMP_CLEAR_RESPONSE";
 | 
						|
                } else {
 | 
						|
                    $next_status{LOGIN_RESPONSE} = "RSPCONFIG_DUMP_CLEAR_REQUEST";
 | 
						|
                    $next_status{RSPCONFIG_DUMP_CLEAR_REQUEST} = "RSPCONFIG_DUMP_CLEAR_RESPONSE";
 | 
						|
                    $status_info{RSPCONFIG_DUMP_CLEAR_REQUEST}{init_url} =~ s/#ID#/$$subcommands[2]/g;
 | 
						|
                }
 | 
						|
                $status_info{RSPCONFIG_DUMP_CLEAR_RESPONSE}{argv} = $$subcommands[2];
 | 
						|
            } elsif ($dump_opt =~ /-d|--download/) {
 | 
						|
                # Verify directory for download is there
 | 
						|
                unless (-d  $::XCAT_LOG_DUMP_DIR) {
 | 
						|
                    xCAT::SvrUtils::sendmsg([1, "Unable to create directory " . $::XCAT_LOG_DUMP_DIR . " to download dump file, cannot continue."], $callback);
 | 
						|
                    return 1;
 | 
						|
                }
 | 
						|
                $::RSPCONFIG_DUMP_CMD_TIME = time(); #Save time of rspcommand start to use in the dump filename
 | 
						|
                if ($$subcommands[2] eq "all") {
 | 
						|
                    # if "download all" was passed in
 | 
						|
                    $next_status{LOGIN_RESPONSE} = "RSPCONFIG_DUMP_LIST_REQUEST";
 | 
						|
                    $next_status{RSPCONFIG_DUMP_LIST_REQUEST} = "RSPCONFIG_DUMP_LIST_RESPONSE";
 | 
						|
                    $next_status{RSPCONFIG_DUMP_LIST_RESPONSE} = "RSPCONFIG_DUMP_DOWNLOAD_ALL_RESPONSE";
 | 
						|
                    xCAT::SvrUtils::sendmsg("Downloading all dumps...", $callback);
 | 
						|
                    $::RSPCONFIG_DUMP_DOWNLOAD_ALL_REQUESTED = 1; # Set flag to download all dumps
 | 
						|
                } else {
 | 
						|
                    $next_status{LOGIN_RESPONSE} = "RSPCONFIG_DUMP_DOWNLOAD_REQUEST";
 | 
						|
                    $next_status{RSPCONFIG_DUMP_DOWNLOAD_REQUEST} = "RSPCONFIG_DUMP_DOWNLOAD_RESPONSE";
 | 
						|
                    $status_info{RSPCONFIG_DUMP_DOWNLOAD_REQUEST}{init_url} =~ s/#ID#/$$subcommands[2]/g;
 | 
						|
                    $status_info{RSPCONFIG_DUMP_DOWNLOAD_REQUEST}{argv} = $$subcommands[2];
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
                # this section handles the dump support where no options are given and xCAT will
 | 
						|
                # # handle the creation, waiting, and download of the dump across a given noderange
 | 
						|
                # Verify directory for download is there
 | 
						|
                unless (-d  $::XCAT_LOG_DUMP_DIR) {
 | 
						|
                    xCAT::SvrUtils::sendmsg([1, "Unable to find directory " . $::XCAT_LOG_DUMP_DIR . " to download dump file"], $callback);
 | 
						|
                    return 1;
 | 
						|
                }
 | 
						|
                $::RSPCONFIG_DUMP_CMD_TIME = time(); #Save time of rspcommand start to use in the dump filename
 | 
						|
                xCAT::SvrUtils::sendmsg("Capturing BMC Diagnostic information, this will take some time...", $callback);
 | 
						|
                $next_status{LOGIN_RESPONSE} = "RSPCONFIG_DUMP_CREATE_REQUEST";
 | 
						|
                $next_status{RSPCONFIG_DUMP_CREATE_REQUEST} = "RSPCONFIG_DUMP_CREATE_RESPONSE";
 | 
						|
                $next_status{RSPCONFIG_DUMP_CREATE_RESPONSE} = "RSPCONFIG_DUMP_LIST_REQUEST";
 | 
						|
                $next_status{RSPCONFIG_DUMP_LIST_REQUEST} = "RSPCONFIG_DUMP_CHECK_RESPONSE";
 | 
						|
                $next_status{RSPCONFIG_DUMP_CHECK_RESPONSE} = "RSPCONFIG_DUMP_DOWNLOAD_REQUEST";
 | 
						|
                $next_status{RSPCONFIG_DUMP_DOWNLOAD_REQUEST} = "RSPCONFIG_DUMP_DOWNLOAD_RESPONSE";
 | 
						|
            }
 | 
						|
            return 0;
 | 
						|
        } elsif ($subcommand eq "gard") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RSPCONFIG_CLEAR_GARD_REQUEST";
 | 
						|
            $next_status{RSPCONFIG_CLEAR_GARD_REQUEST} = "RSPCONFIG_CLEAR_GARD_RESPONSE";
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($subcommand =~ /^admin_passwd=(.+),(.+)/) {
 | 
						|
            my $currentpasswd = $1;
 | 
						|
            my $newpasswd = $2;
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RSPCONFIG_PASSWD_VERIFY";
 | 
						|
            $next_status{RSPCONFIG_PASSWD_VERIFY} = "RSPCONFIG_SET_PASSWD_REQUEST";
 | 
						|
            $next_status{RSPCONFIG_SET_PASSWD_REQUEST} = "RSPCONFIG_SET_RESPONSE";
 | 
						|
 | 
						|
            $status_info{RSPCONFIG_PASSWD_VERIFY}{argv} = "$currentpasswd";
 | 
						|
            $status_info{RSPCONFIG_SET_PASSWD_REQUEST}{data} = "[\"$newpasswd\"]";
 | 
						|
            $status_info{RSPCONFIG_SET_RESPONSE}{argv} = "Password";
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
 | 
						|
        my $type = "obj";
 | 
						|
        my %tmp_hash = ();
 | 
						|
        foreach $subcommand (@$subcommands) {
 | 
						|
            if ($subcommand =~ /^ip$|^netmask$|^gateway$|^hostname$|^vlan$|^ipsrc$|^ntpservers$/) {
 | 
						|
                $type = "get";
 | 
						|
                push @options, $subcommand;
 | 
						|
            } elsif ($subcommand =~ /^(\w+)=(.+)/) {
 | 
						|
                my $key   = $1;
 | 
						|
                my $value = $2;
 | 
						|
                $type = "vlan" if ($key eq "vlan");
 | 
						|
                $tmp_hash{$key} = $value;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if ($type eq "get") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RSPCONFIG_GET_REQUEST";
 | 
						|
            $next_status{RSPCONFIG_GET_REQUEST} = "RSPCONFIG_GET_RESPONSE";
 | 
						|
            $status_info{RSPCONFIG_GET_RESPONSE}{argv} = join(",", @options);
 | 
						|
        } else {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RSPCONFIG_GET_REQUEST";
 | 
						|
            $next_status{RSPCONFIG_GET_REQUEST} = "RSPCONFIG_GET_RESPONSE";
 | 
						|
            my $prefix = xCAT::NetworkUtils::formatNetmask($tmp_hash{netmask}, 0, 1);
 | 
						|
 | 
						|
            if ($type eq "obj") {
 | 
						|
                $next_status{RSPCONFIG_GET_RESPONSE} = "RSPCONFIG_IPOBJECT_REQUEST";
 | 
						|
                $next_status{RSPCONFIG_IPOBJECT_REQUEST} = "RSPCONFIG_IPOBJECT_RESPONSE";
 | 
						|
 | 
						|
                $status_info{RSPCONFIG_CHECK_RESPONSE}{argv} = "$tmp_hash{ip}-$prefix-$tmp_hash{gateway}";
 | 
						|
                $status_info{RSPCONFIG_PRINT_BMCINFO}{data} = "BMC IP: $tmp_hash{ip},BMC Netmask: $tmp_hash{netmask},BMC Gateway: $tmp_hash{gateway}";
 | 
						|
            } elsif ($type eq "vlan") {
 | 
						|
                $next_status{RSPCONFIG_GET_RESPONSE} = "RSPCONFIG_VLAN_REQUEST";
 | 
						|
                $next_status{RSPCONFIG_VLAN_REQUEST} = "RSPCONFIG_VLAN_RESPONSE";
 | 
						|
                $next_status{RSPCONFIG_VLAN_RESPONSE} = "RSPCONFIG_IPOBJECT_REQUEST";
 | 
						|
                $next_status{RSPCONFIG_IPOBJECT_REQUEST} = "RSPCONFIG_IPOBJECT_RESPONSE";
 | 
						|
 | 
						|
                $status_info{RSPCONFIG_VLAN_REQUEST}{data} = "[\"#NIC#\",\"$tmp_hash{vlan}\"]";
 | 
						|
                $status_info{RSPCONFIG_IPOBJECT_REQUEST}{init_url} =~ s/#NIC#/#NIC#_$tmp_hash{vlan}/g;
 | 
						|
                $status_info{RSPCONFIG_CHECK_RESPONSE}{argv} = "$tmp_hash{vlan}-$tmp_hash{ip}-$prefix-$tmp_hash{gateway}";
 | 
						|
                $status_info{RSPCONFIG_PRINT_BMCINFO}{data} = "BMC IP: $tmp_hash{ip},BMC Netmask: $tmp_hash{netmask},BMC Gateway: $tmp_hash{gateway},BMC VLAN ID: $tmp_hash{vlan}";
 | 
						|
            }
 | 
						|
 | 
						|
            $next_status{RSPCONFIG_IPOBJECT_RESPONSE} = "RSPCONFIG_CHECK_REQUEST";
 | 
						|
            $next_status{RSPCONFIG_CHECK_REQUEST} = "RSPCONFIG_CHECK_RESPONSE";
 | 
						|
            $next_status{RSPCONFIG_CHECK_RESPONSE}{STATIC} = "RSPCONFIG_DELETE_REQUEST";
 | 
						|
            $next_status{RSPCONFIG_DELETE_REQUEST} = "RSPCONFIG_DELETE_RESPONSE";
 | 
						|
            $next_status{RSPCONFIG_CHECK_RESPONSE}{DHCP} = "RSPCONFIG_DHCPDIS_REQUEST";
 | 
						|
            $next_status{RSPCONFIG_DHCPDIS_REQUEST} = "RSPCONFIG_DHCPDIS_RESPONSE";
 | 
						|
            $next_status{RSPCONFIG_DELETE_RESPONSE} = "RSPCONFIG_PRINT_BMCINFO";
 | 
						|
            $next_status{RSPCONFIG_DHCPDIS_RESPONSE} = "RSPCONFIG_PRINT_BMCINFO";
 | 
						|
 | 
						|
            $status_info{RSPCONFIG_GET_RESPONSE}{argv} = "all";
 | 
						|
            $status_info{RSPCONFIG_IPOBJECT_REQUEST}{data} = "[\"xyz.openbmc_project.Network.IP.Protocol.IPv4\",\"$tmp_hash{ip}\",$prefix,\"$tmp_hash{gateway}\"]";
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($command eq "rvitals") {
 | 
						|
        if (defined($$subcommands[0])) {
 | 
						|
            $subcommand = $$subcommands[0];
 | 
						|
        } else {
 | 
						|
            $subcommand = "all";
 | 
						|
        }
 | 
						|
 | 
						|
        if ($subcommand eq "leds") {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RVITALS_LEDS_REQUEST";
 | 
						|
            $next_status{RVITALS_LEDS_REQUEST} = "RVITALS_LEDS_RESPONSE";
 | 
						|
            $status_info{RVITALS_LEDS_RESPONSE}{argv} = "$subcommand";
 | 
						|
        } else {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RVITALS_REQUEST";
 | 
						|
            $next_status{RVITALS_REQUEST} = "RVITALS_RESPONSE";
 | 
						|
            $status_info{RVITALS_RESPONSE}{argv} = "$subcommand";
 | 
						|
            if ($subcommand eq "all") {
 | 
						|
                $next_status{RVITALS_RESPONSE} = "RVITALS_LEDS_REQUEST";
 | 
						|
                $next_status{RVITALS_LEDS_REQUEST} = "RVITALS_LEDS_RESPONSE";
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($command eq "rflash") {
 | 
						|
        my $check_version = 0;
 | 
						|
        my $list = 0;
 | 
						|
        my $delete = 0;
 | 
						|
        my $upload = 0;
 | 
						|
        my $activate = 0;
 | 
						|
        my $update_file;
 | 
						|
        my $streamline = 0;
 | 
						|
        my $nohost_reboot = 0;
 | 
						|
 | 
						|
        foreach $subcommand (@$subcommands) {
 | 
						|
            if ($subcommand =~ /^-c|^--check/) {
 | 
						|
                $check_version = 1;
 | 
						|
            } elsif ($subcommand =~ /^-l|^--list/) {
 | 
						|
                $list = 1;
 | 
						|
            } elsif ($subcommand =~ /^--delete/) {
 | 
						|
                $delete = 1;
 | 
						|
            } elsif ($subcommand =~ /^-u|^--upload/) {
 | 
						|
                $upload = 1;
 | 
						|
            } elsif ($subcommand =~ /^-a|^--activate/) {
 | 
						|
                $activate = 1;
 | 
						|
            } elsif ($subcommand =~ /^-d/) {
 | 
						|
                $streamline = 1;
 | 
						|
            } elsif ($subcommand =~ /^--no-host-reboot/) {
 | 
						|
                $nohost_reboot = 1;
 | 
						|
            } else {
 | 
						|
                $update_file = $subcommand;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        my $file_id = undef;
 | 
						|
        my $grep_cmd = "/usr/bin/grep -a";
 | 
						|
        my $tr_cmd = "/usr/bin/tr";
 | 
						|
        my $sha512sum_cmd = "/usr/bin/sha512sum";
 | 
						|
        my $version_tag = '"^version="';
 | 
						|
        my $purpose_tag = '"purpose="';
 | 
						|
        my $purpose_value;
 | 
						|
        my $version_value;
 | 
						|
        my $tarfile_path;
 | 
						|
        if (defined $update_file) {
 | 
						|
            if ($streamline) {
 | 
						|
                if ($update_file =~ /^\//){
 | 
						|
                    $tarfile_path = $update_file;
 | 
						|
                } else {
 | 
						|
                    $tarfile_path =xCAT::Utils->full_path($update_file, $::cwd);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            # Filename or file id was specified
 | 
						|
            if ($update_file =~ /.*\.tar$/) {
 | 
						|
                # Filename ending on .tar was specified
 | 
						|
                if (File::Spec->file_name_is_absolute($update_file)) {
 | 
						|
                    $::UPLOAD_FILE = $update_file;
 | 
						|
                }
 | 
						|
                else {
 | 
						|
                    # If relative file path was given, convert it to absolute
 | 
						|
                    $::UPLOAD_FILE = xCAT::Utils->full_path($update_file, $::cwd);
 | 
						|
                }
 | 
						|
                # Verify file exists and is readable
 | 
						|
                unless (-r $::UPLOAD_FILE) {
 | 
						|
                    xCAT::SvrUtils::sendmsg([1,"Cannot access $::UPLOAD_FILE. Check the management node and/or service nodes."], $callback);
 | 
						|
                    return 1;
 | 
						|
                }
 | 
						|
                if ($activate) {
 | 
						|
                    # Activate flag was specified together with a update file. We want to
 | 
						|
                    # upload the file and activate it.
 | 
						|
                    $::UPLOAD_AND_ACTIVATE = 1;
 | 
						|
                    $activate = 0;
 | 
						|
                }
 | 
						|
 | 
						|
                if ($check_version | $::UPLOAD_AND_ACTIVATE) {
 | 
						|
                    # Extract Host version for the update file
 | 
						|
                    my $firmware_version_in_file = `$grep_cmd $version_tag $::UPLOAD_FILE`;
 | 
						|
                    my $purpose_version_in_file = `$grep_cmd $purpose_tag $::UPLOAD_FILE`;
 | 
						|
                    chomp($firmware_version_in_file);
 | 
						|
                    chomp($purpose_version_in_file);
 | 
						|
                    (my $purpose_string,$purpose_value) = split("=", $purpose_version_in_file);
 | 
						|
                    (my $version_string,$version_value) = split("=", $firmware_version_in_file);
 | 
						|
                    if ($purpose_value =~ /host/) {
 | 
						|
                        $purpose_value = "Host";
 | 
						|
                    }
 | 
						|
                    $::UPLOAD_FILE_VERSION = $version_value;
 | 
						|
                    if (-x $sha512sum_cmd && -x $tr_cmd) {
 | 
						|
                        # Save hash id this firmware version should resolve to:
 | 
						|
                        # take version string, get rid of newline, run through sha512sum, take first 8 characters
 | 
						|
                        $::UPLOAD_FILE_HASH_ID = substr(`echo $::UPLOAD_FILE_VERSION | $tr_cmd -d '\n' | $sha512sum_cmd`, 0,8);
 | 
						|
                    }
 | 
						|
                    else {
 | 
						|
                        if ($::VERBOSE) {
 | 
						|
                            xCAT::SvrUtils::sendmsg("WARN: No hashing check being done. ($sha512sum_cmd or $tr_cmd commands not found)
 | 
						|
", $callback);
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                if ($check_version) {
 | 
						|
                    # Display firmware version of the specified .tar file
 | 
						|
                    xCAT::SvrUtils::sendmsg("TAR $purpose_value Firmware Product Version\: $version_value", $callback);
 | 
						|
                }
 | 
						|
            } elsif (defined $tarfile_path) {
 | 
						|
                if (!opendir(DIR, $tarfile_path)) {
 | 
						|
                    xCAT::SvrUtils::sendmsg([1,"Can't open directory : $tarfile_path"], $callback);
 | 
						|
                    closedir(DIR);
 | 
						|
                    return 1;
 | 
						|
                }
 | 
						|
                my @tar_files = readdir(DIR);
 | 
						|
                foreach my $file (@tar_files) {
 | 
						|
                    if ($file !~ /.*\.tar$/) {
 | 
						|
                        next;
 | 
						|
                    } else {
 | 
						|
                        my $full_path_file = $tarfile_path."/".$file;
 | 
						|
                        $full_path_file=~s/\/\//\//g;
 | 
						|
                        my $firmware_version_in_file = `$grep_cmd $version_tag $full_path_file`;
 | 
						|
                        my $purpose_version_in_file = `$grep_cmd $purpose_tag $full_path_file`;
 | 
						|
                        chomp($firmware_version_in_file);
 | 
						|
                        chomp($purpose_version_in_file);
 | 
						|
                        if (defined($firmware_version_in_file) and defined($purpose_version_in_file)) {
 | 
						|
                            (my $purpose_string,$purpose_value) = split("=", $purpose_version_in_file);
 | 
						|
                            (my $version_string,$version_value) = split("=", $firmware_version_in_file);
 | 
						|
                            if ($purpose_value =~ /Purpose.BMC$/ and $version_string =~/version/){
 | 
						|
                                $::UPLOAD_FILE = $full_path_file;
 | 
						|
                                $::UPLOAD_FILE_VERSION = $version_value;
 | 
						|
                            } elsif ($purpose_value =~ /Purpose.Host$/ and $version_value =~ /witherspoon/) {
 | 
						|
                                $::UPLOAD_PNOR = $full_path_file;
 | 
						|
                                $::UPLOAD_PNOR_VERSION = $version_value;
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                my $return_code = 0;
 | 
						|
                if (!$::UPLOAD_FILE) {
 | 
						|
                    xCAT::SvrUtils::sendmsg([1,"No BMC tar file found in $update_file"], $callback);
 | 
						|
                    $return_code = 1;
 | 
						|
                }
 | 
						|
                if (!$::UPLOAD_PNOR) {
 | 
						|
                    xCAT::SvrUtils::sendmsg([1,"No Host tar file found in $update_file"], $callback);
 | 
						|
                    $return_code = 1;
 | 
						|
                }
 | 
						|
                if ($return_code) {
 | 
						|
                    return 1;
 | 
						|
                }
 | 
						|
                if ($streamline) {
 | 
						|
                    $::UPLOAD_ACTIVATE_STREAM = 1;
 | 
						|
                    if ($nohost_reboot) {
 | 
						|
                        $::RFLASH_STREAM_NO_HOST_REBOOT = 1;
 | 
						|
                        $nohost_reboot = 0;
 | 
						|
                    }
 | 
						|
                    $streamline = 0;
 | 
						|
                    if (-x $sha512sum_cmd && -x $tr_cmd) {
 | 
						|
                        # Save hash id this firmware version should resolve to:
 | 
						|
                        $::UPLOAD_FILE_HASH_ID = substr(`echo $::UPLOAD_FILE_VERSION | $tr_cmd -d '\n' | $sha512sum_cmd`, 0,8);
 | 
						|
                        $::UPLOAD_PNOR_HASH_ID = substr(`echo $::UPLOAD_PNOR_VERSION | $tr_cmd -d '\n' | $sha512sum_cmd`, 0,8);
 | 
						|
                    }
 | 
						|
                    else {
 | 
						|
                        if ($::VERBOSE) {
 | 
						|
                            xCAT::SvrUtils::sendmsg("WARN: No hashing check being done. ($sha512sum_cmd or $tr_cmd commands not found)
 | 
						|
", $callback);
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                # Check if hex number for the updateid is passed
 | 
						|
                if ($update_file =~ /^[[:xdigit:]]+$/i) {
 | 
						|
                    # Update init_url to include the id of the update
 | 
						|
                    $status_info{RFLASH_UPDATE_ACTIVATE_REQUEST}{init_url}    .= "/$update_file/attr/RequestedActivation";
 | 
						|
                    $status_info{RFLASH_SET_PRIORITY_REQUEST}{init_url}       .= "/$update_file/attr/Priority";
 | 
						|
                    $status_info{RFLASH_UPDATE_CHECK_STATE_REQUEST}{init_url} .= "/$update_file";
 | 
						|
                    $status_info{RFLASH_DELETE_IMAGE_REQUEST}{init_url}       .= "/$update_file/action/Delete";
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        # Check if there are any valid nodes to work on. If none, do not issue these messages
 | 
						|
        if (keys %node_info > 0) {
 | 
						|
            if ($upload or $::UPLOAD_AND_ACTIVATE) {
 | 
						|
                xCAT::SvrUtils::sendmsg("Attempting to upload $::UPLOAD_FILE, please wait...", $callback);
 | 
						|
            } elsif ($::UPLOAD_ACTIVATE_STREAM) {
 | 
						|
                xCAT::SvrUtils::sendmsg("Attempting to upload $::UPLOAD_FILE and $::UPLOAD_PNOR, please wait...", $callback);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if ($check_version) {
 | 
						|
            # Display firmware version on BMC
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RINV_FIRM_REQUEST";
 | 
						|
            $next_status{RINV_FIRM_REQUEST} = "RINV_FIRM_RESPONSE";
 | 
						|
        }
 | 
						|
        if ($list) {
 | 
						|
            # Display firmware update files uploaded to BMC
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RFLASH_LIST_REQUEST";
 | 
						|
            $next_status{RFLASH_LIST_REQUEST} = "RFLASH_LIST_RESPONSE";
 | 
						|
        }
 | 
						|
        if ($delete) {
 | 
						|
            # Request to delete uploaded image from BMC or Host
 | 
						|
            # Firsh check if image is allowed to be deleted
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RFLASH_LIST_REQUEST";
 | 
						|
            $next_status{RFLASH_LIST_REQUEST} = "RFLASH_DELETE_CHECK_STATE_RESPONSE";
 | 
						|
        }
 | 
						|
        if ($upload) {
 | 
						|
            # Upload specified update file to BMC
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RFLASH_FILE_UPLOAD_REQUEST";
 | 
						|
            $next_status{"RFLASH_FILE_UPLOAD_REQUEST"} = "RFLASH_FILE_UPLOAD_RESPONSE";
 | 
						|
        }
 | 
						|
        if ($activate) {
 | 
						|
            # Activation of an update was requested.
 | 
						|
            # First we query the update image for its Activation state. If image is in "Ready" we
 | 
						|
            # need to set "RequestedActivation" attribute to "Active". If image is in "Active" we
 | 
						|
            # need to set "Priority" to 0.
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RFLASH_UPDATE_ACTIVATE_REQUEST";
 | 
						|
            $next_status{"RFLASH_UPDATE_ACTIVATE_REQUEST"} = "RFLASH_UPDATE_ACTIVATE_RESPONSE";
 | 
						|
            $next_status{"RFLASH_UPDATE_ACTIVATE_RESPONSE"} = "RFLASH_UPDATE_CHECK_STATE_REQUEST";
 | 
						|
            $next_status{"RFLASH_UPDATE_CHECK_STATE_REQUEST"} = "RFLASH_UPDATE_CHECK_STATE_RESPONSE";
 | 
						|
 | 
						|
            $next_status{"RFLASH_SET_PRIORITY_REQUEST"} = "RFLASH_SET_PRIORITY_RESPONSE";
 | 
						|
            $next_status{"RFLASH_SET_PRIORITY_RESPONSE"} = "RFLASH_UPDATE_CHECK_STATE_REQUEST";
 | 
						|
        }
 | 
						|
        if ($::UPLOAD_AND_ACTIVATE) {
 | 
						|
            # Upload specified update file to BMC
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RFLASH_FILE_UPLOAD_REQUEST";
 | 
						|
            $next_status{"RFLASH_FILE_UPLOAD_REQUEST"} = "RFLASH_FILE_UPLOAD_RESPONSE";
 | 
						|
            $next_status{"RFLASH_FILE_UPLOAD_RESPONSE"} = "RFLASH_UPDATE_CHECK_ID_REQUEST";
 | 
						|
            $next_status{"RFLASH_UPDATE_CHECK_ID_REQUEST"} = "RFLASH_UPDATE_CHECK_ID_RESPONSE";
 | 
						|
            $next_status{"RFLASH_UPDATE_CHECK_ID_RESPONSE"} = "RFLASH_UPDATE_ACTIVATE_REQUEST";
 | 
						|
            $next_status{"RFLASH_UPDATE_ACTIVATE_REQUEST"} = "RFLASH_UPDATE_ACTIVATE_RESPONSE";
 | 
						|
            $next_status{"RFLASH_UPDATE_ACTIVATE_RESPONSE"} = "RFLASH_UPDATE_CHECK_STATE_REQUEST";
 | 
						|
            $next_status{"RFLASH_UPDATE_CHECK_STATE_REQUEST"} = "RFLASH_UPDATE_CHECK_STATE_RESPONSE";
 | 
						|
            $next_status{"RFLASH_SET_PRIORITY_REQUEST"} = "RFLASH_SET_PRIORITY_RESPONSE";
 | 
						|
            $next_status{"RFLASH_SET_PRIORITY_RESPONSE"} = "RFLASH_UPDATE_CHECK_STATE_REQUEST";
 | 
						|
        }
 | 
						|
        if ($::UPLOAD_ACTIVATE_STREAM) {
 | 
						|
            $next_status{LOGIN_RESPONSE} = "RFLASH_FILE_UPLOAD_REQUEST";
 | 
						|
            $next_status{RFLASH_FILE_UPLOAD_REQUEST} = "RFLASH_FILE_UPLOAD_RESPONSE";
 | 
						|
            $next_status{RFLASH_FILE_UPLOAD_RESPONSE} = "RFLASH_UPDATE_CHECK_ID_REQUEST";
 | 
						|
            $next_status{RFLASH_UPDATE_CHECK_ID_REQUEST} = "RFLASH_UPDATE_CHECK_ID_RESPONSE";
 | 
						|
            $next_status{RFLASH_UPDATE_CHECK_ID_RESPONSE} = "RFLASH_UPDATE_ACTIVATE_REQUEST";
 | 
						|
            $next_status{RFLASH_UPDATE_ACTIVATE_REQUEST} = "RFLASH_UPDATE_ACTIVATE_RESPONSE";
 | 
						|
            $next_status{RFLASH_UPDATE_ACTIVATE_RESPONSE} = "RFLASH_UPDATE_HOST_ACTIVATE_REQUEST";
 | 
						|
            $next_status{RFLASH_UPDATE_HOST_ACTIVATE_REQUEST} = "RFLASH_UPDATE_HOST_ACTIVATE_RESPONSE";
 | 
						|
            $next_status{RFLASH_UPDATE_HOST_ACTIVATE_RESPONSE} = "RFLASH_UPDATE_CHECK_STATE_REQUEST";
 | 
						|
            $next_status{RFLASH_UPDATE_CHECK_STATE_REQUEST} = "RFLASH_UPDATE_CHECK_STATE_RESPONSE";
 | 
						|
            $next_status{RFLASH_SET_PRIORITY_REQUEST} = "RFLASH_SET_PRIORITY_RESPONSE";
 | 
						|
            $next_status{RFLASH_SET_PRIORITY_RESPONSE} = "RFLASH_UPDATE_CHECK_STATE_REQUEST";
 | 
						|
            $next_status{RFLASH_UPDATE_CHECK_STATE_RESPONSE} = "RPOWER_BMCREBOOT_REQUEST";
 | 
						|
            $next_status{RPOWER_BMCREBOOT_REQUEST} = "RPOWER_RESET_RESPONSE";
 | 
						|
            $status_info{RPOWER_RESET_RESPONSE}{argv} = "bmcreboot";
 | 
						|
            $next_status{RPOWER_RESET_RESPONSE} = "RPOWER_BMC_CHECK_REQUEST";
 | 
						|
            $next_status{RPOWER_BMC_CHECK_REQUEST} = "RPOWER_BMC_STATUS_RESPONSE";
 | 
						|
            $next_status{LOGIN_REQUEST_GENERAL} = "LOGIN_RESPONSE_GENERAL";
 | 
						|
            $next_status{LOGIN_RESPONSE_GENERAL} = "RPOWER_BMC_STATUS_REQUEST";
 | 
						|
            $next_status{RPOWER_BMC_STATUS_REQUEST} = "RPOWER_BMC_STATUS_RESPONSE";
 | 
						|
            $status_info{RPOWER_BMC_STATUS_RESPONSE}{argv} = "bmcstate";
 | 
						|
            if (!$::RFLASH_STREAM_NO_HOST_REBOOT) {
 | 
						|
               $next_status{RPOWER_BMC_STATUS_RESPONSE} = "RPOWER_OFF_REQUEST";
 | 
						|
               $next_status{RPOWER_OFF_REQUEST} = "RPOWER_OFF_RESPONSE";
 | 
						|
               $next_status{RPOWER_OFF_RESPONSE} = "RPOWER_CHECK_REQUEST";
 | 
						|
               $next_status{RPOWER_CHECK_REQUEST} = "RPOWER_CHECK_RESPONSE";
 | 
						|
               $next_status{RPOWER_CHECK_RESPONSE}{ON} = "RPOWER_CHECK_REQUEST";
 | 
						|
               $next_status{RPOWER_CHECK_RESPONSE}{OFF} = "RPOWER_ON_REQUEST";
 | 
						|
               $next_status{RPOWER_ON_REQUEST} = "RPOWER_ON_RESPONSE";
 | 
						|
               $status_info{RPOWER_ON_RESPONSE}{argv} = "boot";
 | 
						|
               $next_status{RPOWER_ON_RESPONSE} = "RPOWER_CHECK_ON_REQUEST";
 | 
						|
               $next_status{RPOWER_CHECK_ON_REQUEST} = "RPOWER_CHECK_ON_RESPONSE";
 | 
						|
               $next_status{RPOWER_CHECK_ON_RESPONSE}{OFF} = "RPOWER_ON_REQUEST";
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  fork_process_login
 | 
						|
 | 
						|
  Fork process to login
 | 
						|
  Input:
 | 
						|
        $node: nodename
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub fork_process_login {
 | 
						|
    my $node = shift;
 | 
						|
    my $rst = 0;
 | 
						|
 | 
						|
    my $child = xCAT::Utils->xfork;
 | 
						|
    if (!defined($child)) {
 | 
						|
        xCAT::SvrUtils::sendmsg("Failed to fork child process for login request.", $callback, $node);
 | 
						|
        sleep(1);
 | 
						|
        $rst = 1;
 | 
						|
    } elsif ($child == 0) {
 | 
						|
        exit(login_request($node));
 | 
						|
    } else {
 | 
						|
        $login_pid_node{$child} = $node;
 | 
						|
    }
 | 
						|
 | 
						|
    return $rst;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
#
 | 
						|
#=head3  get_functional_software_ids
 | 
						|
#
 | 
						|
#  Checks if the FW response data contains "functional" which
 | 
						|
#  indicates the actual software version currently running on
 | 
						|
#  the Server.
 | 
						|
#
 | 
						|
#  Returns: reference to hash
 | 
						|
#
 | 
						|
#  =cut
 | 
						|
#
 | 
						|
#-------------------------------------------------------
 | 
						|
sub get_functional_software_ids {
 | 
						|
    my $response = shift;
 | 
						|
    my %functional;
 | 
						|
 | 
						|
    #
 | 
						|
    # Get the functional IDs to accurately mark the active running FW
 | 
						|
    #
 | 
						|
    if (${ $response->{data} }{'/xyz/openbmc_project/software/functional'} ) {
 | 
						|
        my %func_data = %{ ${ $response->{data} }{'/xyz/openbmc_project/software/functional'} };
 | 
						|
        foreach ( @{$func_data{endpoints}} ) {
 | 
						|
            my $fw_id = (split '/', $_)[-1];
 | 
						|
            $functional{$fw_id} = 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return \%functional;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  parse_node_info
 | 
						|
 | 
						|
  Parse the node information: bmc, username, password
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub parse_node_info {
 | 
						|
    my $noderange = shift;
 | 
						|
    my $rst = 0;
 | 
						|
 | 
						|
    my $passwd_table = xCAT::Table->new('passwd');
 | 
						|
    my $passwd_hash = $passwd_table->getAttribs({ 'key' => 'openbmc' }, qw(username password));
 | 
						|
 | 
						|
    my $openbmc_table = xCAT::Table->new('openbmc');
 | 
						|
    my $openbmc_hash = $openbmc_table->getNodesAttribs(\@$noderange, ['bmc', 'username', 'password']);
 | 
						|
 | 
						|
    foreach my $node (@$noderange) {
 | 
						|
        if (defined($openbmc_hash->{$node}->[0])) {
 | 
						|
            if ($openbmc_hash->{$node}->[0]->{'bmc'}) {
 | 
						|
                $node_info{$node}{bmc} = $openbmc_hash->{$node}->[0]->{'bmc'};
 | 
						|
                $node_info{$node}{bmcip} = xCAT::NetworkUtils::getNodeIPaddress($openbmc_hash->{$node}->[0]->{'bmc'});
 | 
						|
            }
 | 
						|
            unless($node_info{$node}{bmc}) {
 | 
						|
                xCAT::SvrUtils::sendmsg("Error: Unable to get attribute bmc", $callback, $node);
 | 
						|
                $rst = 1;
 | 
						|
                next;
 | 
						|
            }
 | 
						|
            unless($node_info{$node}{bmcip}) {
 | 
						|
                xCAT::SvrUtils::sendmsg("Error: Unable to resolved ip address for bmc: $node_info{$node}{bmc}", $callback, $node);
 | 
						|
                delete $node_info{$node};
 | 
						|
                $rst = 1;
 | 
						|
                next;
 | 
						|
            }
 | 
						|
            if ($openbmc_hash->{$node}->[0]->{'username'}) {
 | 
						|
                $node_info{$node}{username} = $openbmc_hash->{$node}->[0]->{'username'};
 | 
						|
            } elsif ($passwd_hash and $passwd_hash->{username}) {
 | 
						|
                $node_info{$node}{username} = $passwd_hash->{username};
 | 
						|
            } else {
 | 
						|
                xCAT::SvrUtils::sendmsg("Error: Unable to get attribute username", $callback, $node);
 | 
						|
                delete $node_info{$node};
 | 
						|
                $rst = 1;
 | 
						|
                next;
 | 
						|
            }
 | 
						|
 | 
						|
            if ($openbmc_hash->{$node}->[0]->{'password'}) {
 | 
						|
                $node_info{$node}{password} = $openbmc_hash->{$node}->[0]->{'password'};
 | 
						|
            } elsif ($passwd_hash and $passwd_hash->{password}) {
 | 
						|
                $node_info{$node}{password} = $passwd_hash->{password};
 | 
						|
            } else {
 | 
						|
                xCAT::SvrUtils::sendmsg("Error: Unable to get attribute password", $callback, $node);
 | 
						|
                delete $node_info{$node};
 | 
						|
                $rst = 1;
 | 
						|
                next;
 | 
						|
            }
 | 
						|
 | 
						|
            $node_info{$node}{cur_status} = "LOGIN_REQUEST";
 | 
						|
            $node_info{$node}{rpower_check_times} = $::RPOWER_MAX_RETRY;
 | 
						|
            $node_info{$node}{rpower_check_on_times} = $::RPOWER_ON_MAX_RETRY;
 | 
						|
            $node_info{$node}{bmc_conn_check_times} = $::BMC_MAX_RETRY;
 | 
						|
            $node_info{$node}{bmcstate_check_times} = $::BMC_MAX_RETRY;
 | 
						|
        } else {
 | 
						|
            xCAT::SvrUtils::sendmsg("Error: Unable to get information from openbmc table", $callback, $node);
 | 
						|
            $rst = 1;
 | 
						|
            next;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return $rst;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  gen_send_request
 | 
						|
 | 
						|
  Generate request's information
 | 
						|
      If the node has method itself, use it as request's method.
 | 
						|
      If not, use method %status_info defined.
 | 
						|
      If the node has cur_url, check whether also has sub_urls.
 | 
						|
      If has, request's url is join cur_url and one in sub_urls(use one at once to check which is needed).
 | 
						|
      If not, use method %status_info defined.
 | 
						|
      use xCAT::OPENBMC->send_request send request
 | 
						|
      store handle_id and mapping node
 | 
						|
  Input:
 | 
						|
      $node: nodename of current node
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub gen_send_request {
 | 
						|
    my $node = shift;
 | 
						|
    my $method;
 | 
						|
    my $request_url;
 | 
						|
    my $content = "";
 | 
						|
 | 
						|
    if ($node_info{$node}{method}) {
 | 
						|
        $method = $node_info{$node}{method};
 | 
						|
    } else {
 | 
						|
        $method = $status_info{ $node_info{$node}{cur_status} }{method};
 | 
						|
    }
 | 
						|
    if (defined($status_info{ $node_info{$node}{cur_status} }{data})) {
 | 
						|
        # Handle boolean values by create the json objects without wrapping with quotes
 | 
						|
        if ($status_info{ $node_info{$node}{cur_status} }{data} =~ /^1$|^true$|^True$|^0$|^false$|^False$/) {
 | 
						|
            $content = '{"data":' . $status_info{ $node_info{$node}{cur_status} }{data} . '}';
 | 
						|
        } elsif ($status_info{ $node_info{$node}{cur_status} }{data} =~ /^\[\]$/) {
 | 
						|
            # Special handling of empty data list
 | 
						|
            $content = '{"data":[]}';
 | 
						|
        } elsif ($status_info{ $node_info{$node}{cur_status} }{data} =~ /^\[.+\]$/) {
 | 
						|
            $content = '{"data":' . $status_info{ $node_info{$node}{cur_status} }{data} . '}';
 | 
						|
        } elsif (($status_info{ $node_info{$node}{cur_status} }{init_url} =~ /config\/attr\/HostName$/) &&
 | 
						|
                 ($status_info{ $node_info{$node}{cur_status} }{data} =~ /^\*$/)) {
 | 
						|
            # Special handling for hostname=*
 | 
						|
            $content = '{"data":"' . $node_info{$node}{bmc} . '"}';
 | 
						|
        } else {
 | 
						|
            $content = '{"data":"' . $status_info{ $node_info{$node}{cur_status} }{data} . '"}';
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_url}) {
 | 
						|
        $request_url = $node_info{$node}{cur_url};
 | 
						|
    } else {
 | 
						|
        $request_url = $status_info{ $node_info{$node}{cur_status} }{init_url};
 | 
						|
    }
 | 
						|
    $request_url = "$http_protocol://" . $node_info{$node}{bmc} . $request_url;
 | 
						|
 | 
						|
    if ($xcatdebugmode) {
 | 
						|
        my $debug_info;
 | 
						|
        if ($method eq "GET") {
 | 
						|
            $debug_info = "curl -k -b cjar -X $method -H \"Content-Type: application/json\" $request_url";
 | 
						|
        } else {
 | 
						|
            if ($::UPLOAD_FILE and !$::UPLOAD_ACTIVATE_STREAM) {
 | 
						|
                # Slightly different debug message when doing a file upload
 | 
						|
                $debug_info = "curl -k -b cjar -X $method -H \"Content-Type: application/json\" -T $::UPLOAD_FILE $request_url";
 | 
						|
            } else {
 | 
						|
                if ($node_info{$node}{cur_status} eq "LOGIN_REQUEST_GENERAL") {
 | 
						|
                    $debug_info = "curl -k -c cjar -H \"Content-Type: application/json\" -d '{ \"data\": [\"$node_info{$node}{username}\", \"xxxxxx\"] }' $request_url";
 | 
						|
                } else {
 | 
						|
                    $debug_info = "curl -k -b cjar -X $method -H \"Content-Type: application/json\" -d '$content' $request_url";
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        process_debug_info($node, $debug_info);
 | 
						|
    }
 | 
						|
    my $handle_id = xCAT::OPENBMC->send_request($async, $method, $request_url, $content);
 | 
						|
    $handle_id_node{$handle_id} = $node;
 | 
						|
    $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  deal_with_response
 | 
						|
 | 
						|
  Check response's status_line and
 | 
						|
  Input:
 | 
						|
        $handle_id: Async return ID with response
 | 
						|
        $response: Async return response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub deal_with_response {
 | 
						|
    my $handle_id = shift;
 | 
						|
    my $response = shift;
 | 
						|
    my $node = $handle_id_node{$handle_id};
 | 
						|
 | 
						|
    delete $handle_id_node{$handle_id};
 | 
						|
 | 
						|
    if ($xcatdebugmode) {
 | 
						|
        my $debug_info = lc ($node_info{$node}{cur_status}) . " " . $response->status_line;
 | 
						|
        process_debug_info($node, $debug_info);
 | 
						|
    }
 | 
						|
 | 
						|
    if ($response->status_line ne $::RESPONSE_OK) {
 | 
						|
        my $error;
 | 
						|
        if (defined $status_info{RPOWER_STATUS_RESPONSE}{argv} and $status_info{RPOWER_STATUS_RESPONSE}{argv} =~ /bmcstate$/) {
 | 
						|
            # Handle the special case to return "NotReady" if the BMC does not return a success response.
 | 
						|
            # If the REST service is not up, it can't return "NotReady" itself, during reboot.
 | 
						|
            $error = "BMC NotReady";
 | 
						|
            xCAT::SvrUtils::sendmsg($error, $callback, $node);
 | 
						|
            $wait_node_num--;
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        if ($node_info{$node}{cur_status} eq "RPOWER_BMC_STATUS_RESPONSE" and defined $status_info{RPOWER_BMC_STATUS_RESPONSE}{argv} and $status_info{RPOWER_BMC_STATUS_RESPONSE}{argv} =~ /bmcstate$/) {
 | 
						|
            retry_check_times($node, "RPOWER_BMC_STATUS_REQUEST", "bmc_conn_check_times", $::BMC_CHECK_INTERVAL, $response->status_line);
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($response->status_line eq $::RESPONSE_SERVICE_UNAVAILABLE) {
 | 
						|
            $error = $::RESPONSE_SERVICE_UNAVAILABLE;
 | 
						|
        } elsif ($response->status_line eq $::RESPONSE_METHOD_NOT_ALLOWED) {
 | 
						|
            if ($node_info{$node}{cur_status} eq "REVENTLOG_RESOLVED_RESPONSE") {
 | 
						|
                $error = "Could not find ID specified.";
 | 
						|
            } else {
 | 
						|
                # Special processing for file upload. At this point we do not know how to
 | 
						|
                # form a proper file upload request. It always fails with "Method not allowed" error.
 | 
						|
                # If that happens, just assume it worked.
 | 
						|
                # TODO remove this block when proper request can be generated
 | 
						|
                $status_info{ $node_info{$node}{cur_status} }->{process}->($node, $response);
 | 
						|
                return;
 | 
						|
            }
 | 
						|
        } elsif ($response->status_line eq $::RESPONSE_SERVICE_TIMEOUT) {
 | 
						|
            if ($node_info{$node}{cur_status} eq "RPOWER_RESET_RESPONSE" and defined $status_info{RPOWER_RESET_RESPONSE}{argv} and $status_info{RPOWER_RESET_RESPONSE}{argv} =~ /bmcreboot$/) {
 | 
						|
                my $infomsg = "BMC $::POWER_STATE_REBOOT";
 | 
						|
                xCAT::SvrUtils::sendmsg($infomsg, $callback, $node);
 | 
						|
                if ($::UPLOAD_ACTIVATE_STREAM) {
 | 
						|
                    retry_after($node, "RPOWER_BMC_CHECK_REQUEST", 15);
 | 
						|
                    return;
 | 
						|
                }else{
 | 
						|
                    $wait_node_num--;
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            $error = $::RESPONSE_SERVICE_TIMEOUT;
 | 
						|
        } else {
 | 
						|
            my $response_info = decode_json $response->content;
 | 
						|
            # Handle 500
 | 
						|
            if ($response->status_line eq $::RESPONSE_SERVER_ERROR) {
 | 
						|
                $error = "[" . $response->code . "] " . $response_info->{'data'}->{'exception'};
 | 
						|
            # Handle 403
 | 
						|
            } elsif ($response->status_line eq $::RESPONSE_FORBIDDEN) {
 | 
						|
                #
 | 
						|
                # For any invalid data that we can detect, provide a better response message
 | 
						|
                #
 | 
						|
                if ($node_info{$node}{cur_status} eq "RFLASH_UPDATE_ACTIVATE_RESPONSE" or $node_info{$node}{cur_status} eq "RFLASH_UPDATE_HOST_ACTIVATE_RESPONSE") {
 | 
						|
                    # If 403 is received for an activation, that means the activation ID is incorrect
 | 
						|
                    $error = "Invalid ID provided to activate. Use the -l option to view valid firmware IDs.";
 | 
						|
                } elsif ($node_info{$node}{cur_status} eq "RSETBOOT_ENABLE_RESPONSE" ) {
 | 
						|
                    # If 403 is received setting boot method, API endpoint changed in 1738 FW, inform the user of work around.
 | 
						|
                    $error = "Invalid endpoint used to set boot method. If running firmware < ibm-v1.99.10-0-r7, 'export XCAT_OPENBMC_FIRMWARE=1736' and retry.";
 | 
						|
                } elsif ($node_info{$node}{cur_status} eq "REVENTLOG_RESOLVED_RESPONSE") {
 | 
						|
                    my $cur_url;
 | 
						|
                    if ($node_info{$node}{cur_url}) {
 | 
						|
                        $cur_url = $node_info{$node}{cur_url};
 | 
						|
                    } else {
 | 
						|
                        $cur_url = $status_info{REVENTLOG_RESOLVED_REQUEST}{init_url};
 | 
						|
                    }
 | 
						|
                    my $log_id = (split ('/', $cur_url))[5];
 | 
						|
                    $error = "Invalid ID=$log_id provided to be resolved. [$::RESPONSE_FORBIDDEN]";
 | 
						|
                } else{
 | 
						|
                    $error = "$::RESPONSE_FORBIDDEN - Requested endpoint does not exist or may indicate function is not yet supported by OpenBMC firmware.";
 | 
						|
                }
 | 
						|
            # Handle 404
 | 
						|
            } elsif ($response->status_line eq $::RESPONSE_NOT_FOUND) {
 | 
						|
                #
 | 
						|
                # For any invalid data that we can detect, provide a better response message
 | 
						|
                #
 | 
						|
                if ($node_info{$node}{cur_status} eq "RFLASH_DELETE_IMAGE_RESPONSE") {
 | 
						|
                    $error = "Invalid ID provided to delete.  Use the -l option to view valid firmware IDs.";
 | 
						|
                } elsif (($node_info{$node}{cur_status} eq "RSPCONFIG_API_CONFIG_QUERY_RESPONSE") ||
 | 
						|
                         ($node_info{$node}{cur_status} eq "RSPCONFIG_API_CONFIG_ATTR_RESPONSE")) {
 | 
						|
                    $error = "$::RESPONSE_NOT_FOUND - Requested endpoint does not exist or may indicate function is not supported on this OpenBMC firmware.";
 | 
						|
                } else {
 | 
						|
                    $error = "[" . $response->code . "] " . $response_info->{'data'}->{'description'};
 | 
						|
                }
 | 
						|
 | 
						|
            } else {
 | 
						|
                $error = "[" . $response->code . "] " . $response_info->{'data'}->{'description'};
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (!($node_info{$node}{cur_status} eq "RSPCONFIG_DUMP_CLEAR_RESPONSE" and $next_status{ $node_info{$node}{cur_status} })) {
 | 
						|
            xCAT::SvrUtils::sendmsg([1, $error], $callback, $node);
 | 
						|
            if ($::UPLOAD_AND_ACTIVATE or $next_status{LOGIN_RESPONSE} eq "RFLASH_UPDATE_ACTIVATE_REQUEST") {
 | 
						|
                $node_info{$node}{rst} = $error;
 | 
						|
                my $rflash_log_file = xCAT::Utils->full_path($node.".log", $::XCAT_LOG_RFLASH_DIR);
 | 
						|
                open (RFLASH_LOG_FILE_HANDLE, ">> $rflash_log_file");
 | 
						|
                print RFLASH_LOG_FILE_HANDLE "$error\n";
 | 
						|
                close (RFLASH_LOG_FILE_HANDLE);
 | 
						|
            }
 | 
						|
            $wait_node_num--;
 | 
						|
            return;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($status_info{ $node_info{$node}{cur_status} }->{process}) {
 | 
						|
        $status_info{ $node_info{$node}{cur_status} }->{process}->($node, $response);
 | 
						|
    } else {
 | 
						|
        xCAT::SvrUtils::sendmsg([1,"Internal error, check the process handler for current status $node_info{$node}{cur_status}"]);
 | 
						|
        $wait_node_num--;
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  process_debug_info
 | 
						|
 | 
						|
  print debug info and add to log
 | 
						|
  Input:
 | 
						|
        $node: nodename which want to process ingo
 | 
						|
        $debug_msg: Info for debug
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub process_debug_info {
 | 
						|
    my $node = shift;
 | 
						|
    my $debug_msg = shift;
 | 
						|
    my $ts_node = localtime() . " " . $node;
 | 
						|
    if (!$debug_msg) {
 | 
						|
        $debug_msg = "";
 | 
						|
    }
 | 
						|
 | 
						|
    xCAT::SvrUtils::sendmsg("$flag_debug $debug_msg", $callback, $ts_node);
 | 
						|
    xCAT::MsgUtils->trace(0, "D", "$flag_debug $node $debug_msg");
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  login_request
 | 
						|
 | 
						|
  Send login request using curl command
 | 
						|
  Input:
 | 
						|
        $node: nodename
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub login_request {
 | 
						|
    my $node = shift;
 | 
						|
 | 
						|
    my $login_url = "$http_protocol://" . $node_info{$node}{bmc} . "/login";
 | 
						|
    my $data = '{ "data": [ "' . $node_info{$node}{username} .'", "' . $node_info{$node}{password} . '" ] }';
 | 
						|
 | 
						|
    my $brower = LWP::UserAgent->new( ssl_opts => { SSL_verify_mode => 0x00, verify_hostname => 0  }, timeout => 20);
 | 
						|
    my $cookie_jar = HTTP::Cookies->new();
 | 
						|
    my $header = HTTP::Headers->new('Content-Type' => 'application/json');
 | 
						|
    $brower->cookie_jar($cookie_jar);
 | 
						|
 | 
						|
    my $login_request = HTTP::Request->new( 'POST', $login_url, $header, $data );
 | 
						|
    my $login_response = $brower->request($login_request);
 | 
						|
 | 
						|
    # Check the return code
 | 
						|
    if ($login_response->code eq 500 or $login_response->code eq 404) {
 | 
						|
        # handle only 404 and 504 in this code, defer to deal_with_response for the rest
 | 
						|
        xCAT::SvrUtils::sendmsg([1 ,"[" . $login_response->code . "] Login to BMC failed: " . $login_response->status_line . "."], $callback, $node);
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  login_response
 | 
						|
 | 
						|
  Deal with response of login
 | 
						|
  Input:
 | 
						|
        $node: nodename of current response
 | 
						|
        $response: Async return response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub login_response {
 | 
						|
    my $node = shift;
 | 
						|
    my $response = shift;
 | 
						|
    if ($next_status{ $node_info{$node}{cur_status} }) {
 | 
						|
        $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
        if ($node_info{$node}{method} || $status_info{ $node_info{$node}{cur_status} }{method}) {
 | 
						|
            gen_send_request($node);
 | 
						|
        } elsif ($status_info{ $node_info{$node}{cur_status} }->{process}) {
 | 
						|
            $status_info{ $node_info{$node}{cur_status} }->{process}->($node, undef);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  rpower_response
 | 
						|
 | 
						|
  Deal with response of rpower command
 | 
						|
  Input:
 | 
						|
        $node: nodename of current response
 | 
						|
        $response: Async return response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub rpower_response {
 | 
						|
    my $node = shift;
 | 
						|
    my $response = shift;
 | 
						|
    my %new_status = ();
 | 
						|
 | 
						|
    my $response_info = decode_json $response->content;
 | 
						|
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RPOWER_ON_RESPONSE") {
 | 
						|
        if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
            if ($status_info{RPOWER_ON_RESPONSE}{argv}) {
 | 
						|
                if (defined($node_info{$node}{power_state_rest}) and ($node_info{$node}{power_state_rest} == 1)) {
 | 
						|
                    xCAT::SvrUtils::sendmsg("$::POWER_STATE_ON", $callback, $node);
 | 
						|
                } else {
 | 
						|
                    $node_info{$node}{power_state_rest} = 1;
 | 
						|
                    xCAT::SvrUtils::sendmsg("$::POWER_STATE_RESET", $callback, $node);
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
                if (defined($::OPENBMC_PWR) and ($::OPENBMC_PWR eq "YES")) {
 | 
						|
                    xCAT::SvrUtils::sendmsg("$::STATUS_POWERING_ON", $callback, $node);
 | 
						|
                } else {
 | 
						|
                    xCAT::SvrUtils::sendmsg("$::POWER_STATE_ON", $callback, $node);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            $new_status{$::STATUS_POWERING_ON} = [$node];
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} =~ /^RPOWER_OFF_RESPONSE$|^RPOWER_SOFTOFF_RESPONSE$/) {
 | 
						|
        if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
            my $power_state = "$::POWER_STATE_OFF";
 | 
						|
            if ($node_info{$node}{cur_status} eq "RPOWER_SOFTOFF_RESPONSE") {
 | 
						|
                $power_state = "$::POWER_STATE_POWERING_OFF";
 | 
						|
            }
 | 
						|
            xCAT::SvrUtils::sendmsg("$power_state", $callback, $node) if (!$next_status{ $node_info{$node}{cur_status} });
 | 
						|
            $new_status{$::STATUS_POWERING_OFF} = [$node];
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RPOWER_RESET_RESPONSE") {
 | 
						|
        if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
            if (defined $status_info{RPOWER_RESET_RESPONSE}{argv} and $status_info{RPOWER_RESET_RESPONSE}{argv} =~ /bmcreboot$/) {
 | 
						|
                xCAT::SvrUtils::sendmsg("BMC $::POWER_STATE_REBOOT", $callback, $node);
 | 
						|
                if ($::UPLOAD_ACTIVATE_STREAM) {
 | 
						|
                    retry_after($node, "RPOWER_BMC_CHECK_REQUEST", 15);
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            $new_status{$::STATUS_POWERING_ON} = [$node];
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    xCAT_monitoring::monitorctrl::setNodeStatusAttributes(\%new_status, 1) if (%new_status);
 | 
						|
 | 
						|
    my $all_status;
 | 
						|
    #get host $all_status for RPOWER_CHECK_ON_RESPONSE
 | 
						|
    if ($node_info{$node}{cur_status} eq "RPOWER_STATUS_RESPONSE" or $node_info{$node}{cur_status} eq "RPOWER_CHECK_RESPONSE" or $node_info{$node}{cur_status} eq "RPOWER_BMC_STATUS_RESPONSE" or $node_info{$node}{cur_status} eq "RPOWER_CHECK_ON_RESPONSE") {
 | 
						|
        my $bmc_state = "";
 | 
						|
        my $bmc_transition_state = "";
 | 
						|
        my $chassis_state = "";
 | 
						|
        my $chassis_transition_state = "";
 | 
						|
        my $host_state = "";
 | 
						|
        my $host_transition_state = "";
 | 
						|
        foreach my $type (keys %{$response_info->{data}}) {
 | 
						|
            if ($type =~ /bmc0/) {
 | 
						|
                $bmc_state = $response_info->{'data'}->{$type}->{CurrentBMCState};
 | 
						|
                $bmc_transition_state = $response_info->{'data'}->{$type}->{RequestedBMCTransition};
 | 
						|
            }
 | 
						|
            if ($type =~ /chassis0/) {
 | 
						|
                $chassis_state = $response_info->{'data'}->{$type}->{CurrentPowerState};
 | 
						|
                $chassis_transition_state = $response_info->{'data'}->{$type}->{RequestedPowerTransition};
 | 
						|
            }
 | 
						|
            if ($type =~ /host0/) {
 | 
						|
                $host_state = $response_info->{'data'}->{$type}->{CurrentHostState};
 | 
						|
                $host_transition_state = $response_info->{'data'}->{$type}->{RequestedHostTransition};
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (defined($::OPENBMC_PWR) and ($::OPENBMC_PWR eq "YES")) {
 | 
						|
            # Print this debug only if testing transition states
 | 
						|
            print "$node: DEBUG State CurrentBMCState=$bmc_state\n";
 | 
						|
            print "$node: DEBUG State RequestedBMCTransition=$bmc_transition_state\n";
 | 
						|
            print "$node: DEBUG State CurrentPowerState=$chassis_state\n";
 | 
						|
            print "$node: DEBUG State RequestedPowerTransition=$chassis_transition_state\n";
 | 
						|
            print "$node: DEBUG State CurrentHostState=$host_state\n";
 | 
						|
            print "$node: DEBUG State RequestedHostTransition=$host_transition_state\n";
 | 
						|
        }
 | 
						|
        if (defined $status_info{RPOWER_STATUS_RESPONSE}{argv} and $status_info{RPOWER_STATUS_RESPONSE}{argv} =~ /bmcstate$/) {
 | 
						|
            my $bmc_short_state = (split(/\./, $bmc_state))[-1];
 | 
						|
            xCAT::SvrUtils::sendmsg("BMC $bmc_short_state", $callback, $node);
 | 
						|
        } elsif ($node_info{$node}{cur_status} eq "RPOWER_BMC_STATUS_RESPONSE" and  (defined $status_info{RPOWER_BMC_STATUS_RESPONSE}{argv}) and $status_info{RPOWER_BMC_STATUS_RESPONSE}{argv} =~ /bmcstate$/) {
 | 
						|
                my $bmc_short_state = (split(/\./, $bmc_state))[-1];
 | 
						|
                if (defined($bmc_state) and $bmc_state !~ /State.BMC.BMCState.Ready$/) {
 | 
						|
                    if ($node_info{$node}{bmcstate_check_times} > 0) {
 | 
						|
                        $node_info{$node}{bmcstate_check_times}--;
 | 
						|
                        if ($node_info{$node}{wait_start}) {
 | 
						|
                            $node_info{$node}{wait_end} = time();
 | 
						|
                        } else {
 | 
						|
                            $node_info{$node}{wait_start} = time();
 | 
						|
                        }
 | 
						|
                        retry_after($node, "RPOWER_BMC_STATUS_REQUEST", $::BMC_CHECK_INTERVAL);
 | 
						|
                        return;
 | 
						|
                    } else {
 | 
						|
                        my $wait_time_X = $node_info{$node}{wait_end} - $node_info{$node}{wait_start};
 | 
						|
                        xCAT::SvrUtils::sendmsg([1, "Error: Sent bmcreboot but state did not change to BMC Ready after waiting $wait_time_X seconds. (State=BMC $bmc_short_state)."], $callback, $node);
 | 
						|
                        $node_info{$node}{cur_status} = "";
 | 
						|
                        $wait_node_num--;
 | 
						|
                        return;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                xCAT::SvrUtils::sendmsg("BMC $bmc_short_state", $callback, $node);
 | 
						|
 | 
						|
        } else {
 | 
						|
            if ($chassis_state =~ /Off$/) {
 | 
						|
                # Chassis state is Off, but check if we can detect transition states
 | 
						|
                if ((defined($::OPENBMC_PWR) and ($::OPENBMC_PWR eq "YES")) and
 | 
						|
                        $host_state =~ /Off$/ and $host_transition_state =~ /On$/) {
 | 
						|
                    xCAT::SvrUtils::sendmsg("$::POWER_STATE_POWERING_ON", $callback, $node);
 | 
						|
                } else {
 | 
						|
                    if (defined $status_info{RPOWER_STATUS_RESPONSE}{argv} and $status_info{RPOWER_STATUS_RESPONSE}{argv} =~ /fw_delete$/) {
 | 
						|
                        # We are here just to check the state of the Host to determine if ok to remove active FW
 | 
						|
                        # The state is Off so FW can be removed
 | 
						|
                        $next_status{"RPOWER_STATUS_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST";
 | 
						|
                        $next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE";
 | 
						|
                        $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
                        gen_send_request($node);
 | 
						|
                        return;
 | 
						|
                    } else {
 | 
						|
                        xCAT::SvrUtils::sendmsg("$::POWER_STATE_OFF", $callback, $node) if (!$next_status{ $node_info{$node}{cur_status} });
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                $all_status = $::POWER_STATE_OFF;
 | 
						|
            } elsif ($chassis_state =~ /On$/) {
 | 
						|
                if ($host_state =~ /Off$/) {
 | 
						|
                    # This is a debug scenario where the chassis is powered on but hostboot is not
 | 
						|
                    xCAT::SvrUtils::sendmsg("$::POWER_STATE_ON_HOSTOFF", $callback, $node) if (!$next_status{ $node_info{$node}{cur_status} });
 | 
						|
                    $all_status = $::POWER_STATE_OFF;
 | 
						|
                } elsif ($host_state =~ /Quiesced$/) {
 | 
						|
                    xCAT::SvrUtils::sendmsg("$::POWER_STATE_QUIESCED", $callback, $node) if (!$next_status{ $node_info{$node}{cur_status} });
 | 
						|
                    $all_status = $::POWER_STATE_ON;
 | 
						|
                } elsif ($host_state =~ /Running$/) {
 | 
						|
                    if ((defined($::OPENBMC_PWR) and ($::OPENBMC_PWR eq "YES")) and
 | 
						|
                           $host_transition_state =~ /Off$/ and $chassis_state =~ /On$/) {
 | 
						|
                        xCAT::SvrUtils::sendmsg("$::POWER_STATE_POWERING_OFF", $callback, $node);
 | 
						|
                    } else {
 | 
						|
                        if (defined $status_info{RPOWER_STATUS_RESPONSE}{argv} and $status_info{RPOWER_STATUS_RESPONSE}{argv} =~ /fw_delete$/) {
 | 
						|
                            xCAT::SvrUtils::sendmsg([1, "Deleting currently active firmware on powered on host is not supported"], $callback, $node);
 | 
						|
                            $wait_node_num--;
 | 
						|
                            return;
 | 
						|
                        }
 | 
						|
                        xCAT::SvrUtils::sendmsg("$::POWER_STATE_ON", $callback, $node) if (!$next_status{ $node_info{$node}{cur_status} });
 | 
						|
                    }
 | 
						|
                    $all_status = $::POWER_STATE_ON;
 | 
						|
                } else {
 | 
						|
                    xCAT::SvrUtils::sendmsg("Unexpected host state=$host_state", $callback, $node) if (!$next_status{ $node_info{$node}{cur_status} });
 | 
						|
                    $all_status = $::POWER_STATE_ON;
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
                xCAT::SvrUtils::sendmsg("Unexpected chassis state=$chassis_state", $callback, $node) if (!$next_status{ $node_info{$node}{cur_status} });
 | 
						|
                $all_status = $::POWER_STATE_ON;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($next_status{ $node_info{$node}{cur_status} }) {
 | 
						|
        if ($node_info{$node}{cur_status} eq "RPOWER_CHECK_RESPONSE") {
 | 
						|
            if ($all_status eq "$::POWER_STATE_OFF") {
 | 
						|
                $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} }{OFF};
 | 
						|
            } else {
 | 
						|
                if ($node_info{$node}{rpower_check_times} > 0) {
 | 
						|
                    $node_info{$node}{rpower_check_times}--;
 | 
						|
                    if ($node_info{$node}{wait_start}) {
 | 
						|
                        $node_info{$node}{wait_end} = time();
 | 
						|
                    } else {
 | 
						|
                        $node_info{$node}{wait_start} = time();
 | 
						|
                    }
 | 
						|
                    retry_after($node, $next_status{ $node_info{$node}{cur_status} }{ON}, $::RPOWER_CHECK_INTERVAL);
 | 
						|
                    return;
 | 
						|
                } else {
 | 
						|
                    my $wait_time_X = $node_info{$node}{wait_end} - $node_info{$node}{wait_start};
 | 
						|
                    xCAT::SvrUtils::sendmsg([1, "Error: Sent power-off command but state did not change to $::POWER_STATE_OFF after waiting $wait_time_X seconds. (State=$all_status)."], $callback, $node);
 | 
						|
                    $node_info{$node}{cur_status} = "";
 | 
						|
                    $wait_node_num--;
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        } elsif ($node_info{$node}{cur_status} eq "RPOWER_STATUS_RESPONSE") {
 | 
						|
            if ($all_status eq "$::POWER_STATE_OFF") {
 | 
						|
                xCAT::SvrUtils::sendmsg("$::POWER_STATE_OFF", $callback, $node);
 | 
						|
                $node_info{$node}{cur_status} = "";
 | 
						|
                $wait_node_num--;
 | 
						|
                return;
 | 
						|
            } else {
 | 
						|
                $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} }{ON};
 | 
						|
            }
 | 
						|
        } elsif ($node_info{$node}{cur_status} eq "RPOWER_CHECK_ON_RESPONSE") {
 | 
						|
            #RPOWER_CHECK_ON_REQUEST and RPOWER_CHECK_ON_RESPONSE are for rflash -d function
 | 
						|
            #in order to make sure host is reboot successfully
 | 
						|
            #if rpower reset host and host state is always off, retry to set RPOWER_CHECK_ON_REQUEST to run rpower on the host
 | 
						|
            #1. if host power state is on, do nothing, and return
 | 
						|
            if ($all_status eq "$::POWER_STATE_ON") {
 | 
						|
                $node_info{$node}{cur_status} = "";
 | 
						|
                $wait_node_num--;
 | 
						|
                return;
 | 
						|
            }else{
 | 
						|
                #2. if host state is always off, retry to set RPOWER_CHECK_ON_REQUEST to run rpower on the host
 | 
						|
                if ($node_info{$node}{rpower_check_on_times} > 0) {
 | 
						|
                    $node_info{$node}{rpower_check_on_times}--;
 | 
						|
                    if ($node_info{$node}{wait_on_start}) {
 | 
						|
                        $node_info{$node}{wait_on_end} = time();
 | 
						|
                    } else {
 | 
						|
                        $node_info{$node}{wait_on_start} = time();
 | 
						|
                    }
 | 
						|
                    #retry to set RPOWER_CHECK_ON_REQUEST after wait for $::RPOWER_CHECK_ON_INTERVAL
 | 
						|
                    retry_after($node, $next_status{ $node_info{$node}{cur_status} }{OFF}, $::RPOWER_CHECK_ON_INTERVAL);
 | 
						|
                    return;
 | 
						|
                } else {
 | 
						|
                    #after retry 5 times, the host is still off, print error and return
 | 
						|
                    my $wait_time_X = $node_info{$node}{wait_on_end} - $node_info{$node}{wait_on_start};
 | 
						|
                    xCAT::SvrUtils::sendmsg([1, "Sent power-on command but state did not change to $::POWER_STATE_ON after waiting $wait_time_X seconds. (State=$all_status)."], $callback, $node);
 | 
						|
                    $node_info{$node}{cur_status} = "";
 | 
						|
                    $wait_node_num--;
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
        }
 | 
						|
        gen_send_request($node);
 | 
						|
    } else {
 | 
						|
        $wait_node_num--;
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  rinv_response
 | 
						|
 | 
						|
  Deal with response of rinv command
 | 
						|
  Input:
 | 
						|
        $node: nodename of current response
 | 
						|
        $response: Async return response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub rinv_response {
 | 
						|
    my $node = shift;
 | 
						|
    my $response = shift;
 | 
						|
 | 
						|
    my $response_info = decode_json $response->content;
 | 
						|
 | 
						|
    my $grep_string;
 | 
						|
    if ($node_info{$node}{cur_status} eq "RINV_FIRM_RESPONSE") {
 | 
						|
        $grep_string = "firm";
 | 
						|
    } else {
 | 
						|
        $grep_string = $status_info{RINV_RESPONSE}{argv};
 | 
						|
    }
 | 
						|
 | 
						|
    my $src;
 | 
						|
    my $content_info;
 | 
						|
    my @sorted_output;
 | 
						|
    my $to_clear_dump = 0;
 | 
						|
 | 
						|
    # Get the functional IDs to accurately mark the active running FW
 | 
						|
    my $functional = get_functional_software_ids($response_info);
 | 
						|
 | 
						|
    foreach my $key_url (keys %{$response_info->{data}}) {
 | 
						|
        my %content = %{ ${ $response_info->{data} }{$key_url} };
 | 
						|
 | 
						|
        if ($grep_string eq "firm") {
 | 
						|
            # This handles the data from the /xyz/openbmc_project/Software endpoint.
 | 
						|
            my $sw_id = (split(/\//, $key_url))[-1];
 | 
						|
            if (defined($content{Version}) and $content{Version}) {
 | 
						|
                my $purpose_value = uc ((split(/\./, $content{Purpose}))[-1]);
 | 
						|
                if ($purpose_value =~ /BMC/) {
 | 
						|
                    $purpose_value = "[B$sw_id]$purpose_value";
 | 
						|
                } else {
 | 
						|
                    $purpose_value = "[H$sw_id]$purpose_value";
 | 
						|
                }
 | 
						|
                my $activation_value = (split(/\./, $content{Activation}))[-1];
 | 
						|
                my $priority_value = -1;
 | 
						|
                if (defined($content{Priority})) {
 | 
						|
                    $priority_value = $content{Priority};
 | 
						|
                }
 | 
						|
 | 
						|
                if ($status_info{RINV_FIRM_RESPONSE}{check}) {
 | 
						|
                    if (($purpose_value =~ /BMC/) and
 | 
						|
                        ($priority_value == 0 and %{$functional} and !exists($functional->{$sw_id}))) {
 | 
						|
                        $to_clear_dump = 1;
 | 
						|
                        last;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                #
 | 
						|
                # For 'rinv firm', only print Active software, unless verbose is specified
 | 
						|
                #
 | 
						|
                if ( (%{$functional} and exists($functional->{$sw_id}) ) or
 | 
						|
                     (!%{$functional} and $activation_value =~ "Active" and $priority_value == 0) or
 | 
						|
                      $::VERBOSE ) {
 | 
						|
                    #
 | 
						|
                    # The space below between "Firmware Product Version:" and $content{Version} is intentional
 | 
						|
                    # to cause the sorting of this line before any additional info lines
 | 
						|
                    #
 | 
						|
                    $content_info = "$purpose_value Firmware Product:   $content{Version} ($activation_value)";
 | 
						|
                    my $indicator = "";
 | 
						|
                    if ($priority_value == 0 and %{$functional} and !exists($functional->{$sw_id})) {
 | 
						|
                        # indicate that a reboot is needed if priority = 0 and it's not in the functional list
 | 
						|
                        $indicator = "+";
 | 
						|
                    } elsif (%{$functional} and exists($functional->{$sw_id})) {
 | 
						|
                        $indicator = "*";
 | 
						|
                    }
 | 
						|
                    $content_info .= $indicator;
 | 
						|
                    push (@sorted_output, $content_info);
 | 
						|
 | 
						|
                    if (defined($content{ExtendedVersion}) and $content{ExtendedVersion} ne "") {
 | 
						|
                        # ExtendedVersion is going to be a comma separated list of additional software
 | 
						|
                        my @versions = split(',', $content{ExtendedVersion});
 | 
						|
                        foreach my $ver (@versions) {
 | 
						|
                            $content_info = "$purpose_value Firmware Product: -- additional info: $ver";
 | 
						|
                            push (@sorted_output, $content_info);
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    next;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            if (! defined $content{Present}) {
 | 
						|
                # If the Present field is not part of the attribute, then it's most likely a callout
 | 
						|
                # Do not print as part of the inventory response
 | 
						|
                next;
 | 
						|
            }
 | 
						|
 | 
						|
            # SPECIAL CASE: If 'serial' or 'model' is specified, only return the system level information
 | 
						|
            if ($grep_string eq "serial" or $grep_string eq "model") {
 | 
						|
                if ($key_url ne "$openbmc_project_url/inventory/system") {
 | 
						|
                    next;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if ($key_url =~ /\/(cpu\d*)\/(\w+)/) {
 | 
						|
                $src = "$1 $2";
 | 
						|
            } else {
 | 
						|
                $src = basename $key_url;
 | 
						|
            }
 | 
						|
 | 
						|
            foreach my $key (keys %content) {
 | 
						|
                # If not all options is specified, check whether the key string contains
 | 
						|
                # the keyword option.  If so, add it to the return data
 | 
						|
                if ($grep_string ne "all" and ((lc($key) !~ m/$grep_string/i) and ($key_url !~ m/$grep_string/i)) ) {
 | 
						|
                    next;
 | 
						|
                }
 | 
						|
                $content_info = uc ($src) . " " . $key . " : " . $content{$key};
 | 
						|
                push (@sorted_output, $content_info); #Save output in array
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    @sorted_output = () if ($status_info{RINV_FIRM_RESPONSE}{check});
 | 
						|
    # If sorted array has any contents, sort it naturally and print it
 | 
						|
    if (scalar @sorted_output > 0) {
 | 
						|
        # sort alpha, then numeric
 | 
						|
        foreach (sort natural_sort_cmp @sorted_output) {
 | 
						|
            #
 | 
						|
            # The firmware output requires the ID to be part of the string to sort correctly.
 | 
						|
            # Remove this ID from the output to the user
 | 
						|
            #
 | 
						|
            $_ =~ s/\[.*?\]//;
 | 
						|
            xCAT::MsgUtils->message("I", { data => ["$node: $_"] }, $callback);
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        if ($status_info{RINV_FIRM_RESPONSE}{check}) {
 | 
						|
            if ($to_clear_dump) {
 | 
						|
                xCAT::MsgUtils->message("I", { data => ["$node: Firmware will be flashed on reboot, deleting all BMC diagnostics..."] }, $callback);
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            xCAT::MsgUtils->message("I", { data => ["$node: $::NO_ATTRIBUTES_RETURNED"] }, $callback);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($next_status{ $node_info{$node}{cur_status} }) {
 | 
						|
        if ($status_info{RINV_FIRM_RESPONSE}{check}) {
 | 
						|
            if ($to_clear_dump) {
 | 
						|
                $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} }{PENDING};
 | 
						|
            } else {
 | 
						|
                $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} }{NO_PENDING}
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
        }
 | 
						|
        gen_send_request($node);
 | 
						|
    } else {
 | 
						|
        $wait_node_num--;
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  getopenbmccons
 | 
						|
 | 
						|
    Process getopenbmccons
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub getopenbmccons {
 | 
						|
    my $argr = shift;
 | 
						|
 | 
						|
    #$argr is [$node,$bmcip,$nodeuser,$nodepass];
 | 
						|
    my $cb = shift;
 | 
						|
 | 
						|
    my $rsp;
 | 
						|
    #my $node=$argr->[0];
 | 
						|
    #my $output = "openbmc, getopenbmccons";
 | 
						|
    #xCAT::SvrUtils::sendmsg($output, $cb, $argr->[0], %allerrornodes);
 | 
						|
 | 
						|
    $rsp = { node => [ { name => [ $argr->[0] ] } ] };
 | 
						|
    $rsp->{node}->[0]->{bmcip}->[0]    = $argr->[1];
 | 
						|
    $rsp->{node}->[0]->{username}->[0]    = $argr->[2];
 | 
						|
    $rsp->{node}->[0]->{passwd}->[0]  = $argr->[3];
 | 
						|
    $cb->($rsp);
 | 
						|
    #return $rsp;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  rsetboot_response
 | 
						|
 | 
						|
  Deal with response of rsetboot command
 | 
						|
  Input:
 | 
						|
        $node: nodename of current response
 | 
						|
        $response: Async return response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub rsetboot_response {
 | 
						|
    my $node = shift;
 | 
						|
    my $response = shift;
 | 
						|
 | 
						|
    my $response_info = decode_json $response->content;
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSETBOOT_STATUS_RESPONSE") {
 | 
						|
        my $one_time_enabled;
 | 
						|
        my $bootsource;
 | 
						|
        if (defined($::OPENBMC_FW) && ($::OPENBMC_FW < 1738)) {
 | 
						|
            $bootsource = $response_info->{'data'}->{BootSource};
 | 
						|
        } else {
 | 
						|
            foreach my $key_url (keys %{$response_info->{data}}) {
 | 
						|
                my %content = %{ ${ $response_info->{data} }{$key_url} };
 | 
						|
                if ($key_url =~ /boot\/one_time/) {
 | 
						|
                    $one_time_enabled = $content{Enabled};
 | 
						|
                    $bootsource = $content{BootSource} if ($one_time_enabled);
 | 
						|
                } elsif ($key_url =~ /\/boot$/) {
 | 
						|
                    $bootsource = $content{BootSource} unless ($one_time_enabled);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if ($bootsource =~ /Disk$/) {
 | 
						|
            xCAT::SvrUtils::sendmsg("Hard Drive", $callback, $node);
 | 
						|
        } elsif ($bootsource =~ /Network$/) {
 | 
						|
            xCAT::SvrUtils::sendmsg("Network", $callback, $node);
 | 
						|
        } elsif ($bootsource =~ /ExternalMedia$/) {
 | 
						|
            xCAT::SvrUtils::sendmsg("CD/DVD", $callback, $node);
 | 
						|
        } elsif ($bootsource =~ /Default$/) {
 | 
						|
            xCAT::SvrUtils::sendmsg("Default", $callback, $node);
 | 
						|
        } else {
 | 
						|
            my $error_msg = "Can not get valid rsetboot status, the data is " . $response_info->{'data'}->{BootSource};
 | 
						|
            xCAT::SvrUtils::sendmsg("$error_msg", $callback, $node);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($next_status{ $node_info{$node}{cur_status} }) {
 | 
						|
        $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
        gen_send_request($node);
 | 
						|
    } else {
 | 
						|
        $wait_node_num--;
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  rbeacon_response
 | 
						|
 | 
						|
  Deal with response of rbeacon command
 | 
						|
  Input:
 | 
						|
        $node: nodename of current response
 | 
						|
        $response: Async return response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub rbeacon_response {
 | 
						|
    my $node = shift;
 | 
						|
    my $response = shift;
 | 
						|
 | 
						|
    my $response_info = decode_json $response->content;
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RBEACON_ON_RESPONSE") {
 | 
						|
        if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
            xCAT::SvrUtils::sendmsg("$::BEACON_STATE_ON", $callback, $node);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RBEACON_OFF_RESPONSE") {
 | 
						|
        if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
            xCAT::SvrUtils::sendmsg("$::BEACON_STATE_OFF", $callback, $node);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($next_status{ $node_info{$node}{cur_status} }) {
 | 
						|
        $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
        gen_send_request($node);
 | 
						|
    } else {
 | 
						|
        $wait_node_num--;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  reventlog_response
 | 
						|
 | 
						|
  Deal with response of reventlog command
 | 
						|
  Input:
 | 
						|
        $node: nodename of current response
 | 
						|
        $response: Async return response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub reventlog_response {
 | 
						|
    my $node = shift;
 | 
						|
    my $response = shift;
 | 
						|
 | 
						|
    my $response_info = decode_json $response->content;
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "REVENTLOG_CLEAR_RESPONSE") {
 | 
						|
        if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
            xCAT::SvrUtils::sendmsg("Logs cleared", $callback, $node);
 | 
						|
        }
 | 
						|
    } elsif ($node_info{$node}{cur_status} eq "REVENTLOG_RESOLVED_RESPONSE") {
 | 
						|
        my $cur_url;
 | 
						|
        if ($node_info{$node}{cur_url}) {
 | 
						|
            $cur_url = $node_info{$node}{cur_url};
 | 
						|
            if ($node_info{$node}{bak_url}) {
 | 
						|
                $node_info{$node}{cur_url} = shift @{ $node_info{$node}{bak_url} };
 | 
						|
            } else {
 | 
						|
                $node_info{$node}{cur_url} = "";
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            $cur_url = $status_info{REVENTLOG_RESOLVED_REQUEST}{init_url};
 | 
						|
        }
 | 
						|
 | 
						|
        if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
            my $log_id = (split ('/', $cur_url))[5];
 | 
						|
            xCAT::SvrUtils::sendmsg("Resolved $log_id.", $callback, $node);
 | 
						|
        }
 | 
						|
 | 
						|
        if ($status_info{REVENTLOG_RESOLVED_RESPONSE}{remain_entries} and !$node_info{$node}{remain_entries}) {
 | 
						|
            foreach my $entry (@{ $status_info{REVENTLOG_RESOLVED_RESPONSE}{remain_entries} }) {
 | 
						|
                my $tmp_url = $::LOGGING_URL;
 | 
						|
                $tmp_url =~ s/#ENTRY_ID#/$entry/g;
 | 
						|
                push @{ $node_info{$node}{bak_url} }, $tmp_url;
 | 
						|
            }
 | 
						|
            $node_info{$node}{cur_url} = shift @{ $node_info{$node}{bak_url} };
 | 
						|
            $node_info{$node}{remain_entries} = $status_info{REVENTLOG_RESOLVED_RESPONSE}{remain_entries};
 | 
						|
        }
 | 
						|
 | 
						|
        if ($node_info{$node}{cur_url}) {
 | 
						|
            $next_status{"REVENTLOG_RESOLVED_RESPONSE"} = "REVENTLOG_RESOLVED_REQUEST";
 | 
						|
        } else {
 | 
						|
            # Break out of this loop if there are no more IDs to resolve
 | 
						|
            $wait_node_num--;
 | 
						|
            return;
 | 
						|
        }
 | 
						|
    } elsif ($node_info{$node}{cur_status} eq "REVENTLOG_RESOLVED_RESPONSE_LED") {
 | 
						|
        # Scan all event log entries and build an array of all that have callout data
 | 
						|
        my @entries;
 | 
						|
        foreach my $key_url (keys %{$response_info->{data}}) {
 | 
						|
            my %content = %{ ${ $response_info->{data} }{$key_url} };
 | 
						|
            next unless ($content{Id});
 | 
						|
            my $event_msg = is_callout_event_data(\%content);
 | 
						|
            push(@entries, $event_msg) if ($event_msg); # Add array entry of log event id
 | 
						|
        }
 | 
						|
 | 
						|
        # If some entries with callout data, send them off to be resolved
 | 
						|
        if (scalar(@entries) > 0) {
 | 
						|
            $next_status{"REVENTLOG_RESOLVED_RESPONSE_LED"} = "REVENTLOG_RESOLVED_REQUEST";
 | 
						|
            $next_status{"REVENTLOG_RESOLVED_REQUEST"} = "REVENTLOG_RESOLVED_RESPONSE";
 | 
						|
 | 
						|
            my $init_entry = shift @entries;
 | 
						|
            $status_info{REVENTLOG_RESOLVED_REQUEST}{init_url} =~ s/#ENTRY_ID#/$init_entry/g;
 | 
						|
            push @{ $status_info{REVENTLOG_RESOLVED_RESPONSE}{remain_entries} }, @entries;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            # Return if there are no entries with callout data
 | 
						|
            xCAT::SvrUtils::sendmsg("There are no event log entries contributing to LED fault", $callback, $node);
 | 
						|
            $wait_node_num--;
 | 
						|
            return;
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        my $entry_string = $status_info{REVENTLOG_RESPONSE}{argv};
 | 
						|
        my $content_info;
 | 
						|
        my %output = ();
 | 
						|
        my $entry_num = 0;
 | 
						|
        $entry_string = "all" if ($entry_string eq "0");
 | 
						|
        $entry_num = 0 + $entry_string if ($entry_string ne "all");
 | 
						|
        my $max_entry = 0;
 | 
						|
 | 
						|
        foreach my $key_url (keys %{$response_info->{data}}) {
 | 
						|
            my %content = %{ ${ $response_info->{data} }{$key_url} };
 | 
						|
            next unless ($content{Id});
 | 
						|
            my $id_num = 0 + $content{Id};
 | 
						|
            my $event_msg = parse_event_data(\%content);
 | 
						|
            $output{$id_num} = $event_msg if ($event_msg);
 | 
						|
            $max_entry = $id_num if ($id_num > $max_entry);
 | 
						|
        }
 | 
						|
 | 
						|
        xCAT::SvrUtils::sendmsg("$::NO_ATTRIBUTES_RETURNED", $callback, $node) if (!%output);
 | 
						|
        # If option is "all", print out all sorted msg. If is a num, print out the last <num> msg (sorted)
 | 
						|
        foreach my $key ( sort { $a <=> $b } keys %output) {
 | 
						|
            xCAT::MsgUtils->message("I", { data => ["$node: $output{$key}"] }, $callback) if ($entry_string eq "all" or $key > ($max_entry - $entry_num));
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($next_status{ $node_info{$node}{cur_status} }) {
 | 
						|
        $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
        gen_send_request($node);
 | 
						|
    } else {
 | 
						|
        $wait_node_num--;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  is_callout_event_data
 | 
						|
 | 
						|
  Parse reventlog data and return entry ID if it has
 | 
						|
   CALLOUT data
 | 
						|
  Input:
 | 
						|
	$content: data for single entry
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub is_callout_event_data {
 | 
						|
    my $content = shift;
 | 
						|
    my $id_num = $$content{Id};
 | 
						|
 | 
						|
    if ($$content{Message}) {
 | 
						|
        if (defined $$content{AdditionalData} and $$content{AdditionalData}) {
 | 
						|
            foreach my $addition (@{ $$content{AdditionalData} }) {
 | 
						|
                if ($addition =~ /CALLOUT/) {
 | 
						|
                    return $id_num;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return "";
 | 
						|
}
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  parse_event_data
 | 
						|
 | 
						|
  Parse reventlog data
 | 
						|
  Input:
 | 
						|
        $content: data for single entry
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub parse_event_data {
 | 
						|
    my $content = shift;
 | 
						|
    my $content_info = "";
 | 
						|
    my $LED_tag      = " [LED]"; # Indicate that the entry contributes to LED fault
 | 
						|
 | 
						|
    my $timestamp = $$content{Timestamp};
 | 
						|
    my $id_num = $$content{Id};
 | 
						|
    if ($$content{Message}) {
 | 
						|
        my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($$content{Timestamp}/1000);
 | 
						|
        $mon += 1;
 | 
						|
        $year += 1900;
 | 
						|
        my $UTC_time = sprintf ("%02d/%02d/%04d %02d:%02d:%02d", $mon, $mday, $year, $hour, $min, $sec);
 | 
						|
        my $message = $$content{Message};
 | 
						|
        my $callout;
 | 
						|
        my $msg_pid;
 | 
						|
        my $i2c_device;
 | 
						|
        my $esel;
 | 
						|
 | 
						|
        if (defined $$content{AdditionalData} and $$content{AdditionalData}) {
 | 
						|
            foreach my $addition (@{ $$content{AdditionalData} }) {
 | 
						|
                if ($addition =~ /CALLOUT_INVENTORY_PATH=(.+)/) {
 | 
						|
                    $callout = $1;
 | 
						|
                }
 | 
						|
                if ($addition =~ /CALLOUT_DEVICE_PATH/) {
 | 
						|
                    $callout = "I2C";
 | 
						|
                    my @info = split("=", $addition);
 | 
						|
                    my $tmp = $info[1];
 | 
						|
                    my @tmp_data = split("/", $tmp);
 | 
						|
                    my $data_num = @tmp_data;
 | 
						|
                    $i2c_device = join("/", @tmp_data[($data_num-4)..($data_num-1)])
 | 
						|
                }
 | 
						|
                if ($addition =~ /ESEL/) {
 | 
						|
                    my @info = split("=", $addition);
 | 
						|
                    $esel = $info[1];
 | 
						|
                    # maybe useful, so leave it here
 | 
						|
                }
 | 
						|
                if ($addition =~ /GPU/) {
 | 
						|
                    my @info = split(" ", $addition);
 | 
						|
                    $callout = "/xyz/openbmc_project/inventory/system/chassis/motherboard/gpu" . $info[-1];
 | 
						|
                }
 | 
						|
                if ($addition =~ /PID=(\d*)/) {
 | 
						|
                    $msg_pid = $1;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        $message .= "||$callout" if ($callout);
 | 
						|
 | 
						|
        if (ref($event_mapping) eq "HASH") {
 | 
						|
            if ($event_mapping->{$message}) {
 | 
						|
                my $event_type = $event_mapping->{$message}{EventType};
 | 
						|
                my $event_message = $event_mapping->{$message}{Message};
 | 
						|
                my $severity = $event_mapping->{$message}{Severity};
 | 
						|
                my $affect = $event_mapping->{$message}{AffectedSubsystem};
 | 
						|
                $content_info = "$UTC_time [$id_num]: $event_type, ($severity) $event_message (AffectedSubsystem: $affect, PID: $msg_pid), Resolved: $$content{Resolved}";
 | 
						|
            } else {
 | 
						|
                $content_info = "$UTC_time [$id_num]: Not found in policy table: $message (PID: $msg_pid), Resolved: $$content{Resolved}";
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            $content_info = "$UTC_time [$id_num]: $message (PID: $msg_pid), Resolved: $$content{Resolved}";
 | 
						|
        }
 | 
						|
        $content_info .= $LED_tag if ($callout);
 | 
						|
    }
 | 
						|
 | 
						|
    return $content_info;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  rspconfig_response
 | 
						|
 | 
						|
  Deal with response of rspconfig command
 | 
						|
  Input:
 | 
						|
        $node: nodename of current response
 | 
						|
        $response: Async return response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub rspconfig_response {
 | 
						|
    my $node = shift;
 | 
						|
    my $response = shift;
 | 
						|
 | 
						|
    my $response_info;
 | 
						|
    $response_info = decode_json $response->content if ($response);
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSPCONFIG_GET_RESPONSE" or $node_info{$node}{cur_status} eq "RSPCONFIG_GET_NIC_RESPONSE") {
 | 
						|
        my $hostname        = "";
 | 
						|
        my $default_gateway = "n/a";
 | 
						|
        my %nicinfo         = ();
 | 
						|
        my $multiple_error = "";
 | 
						|
        my @output;
 | 
						|
        my $grep_string = $status_info{RSPCONFIG_GET_RESPONSE}{argv};
 | 
						|
        foreach my $key_url (keys %{$response_info->{data}}) {
 | 
						|
            my %content = %{ ${ $response_info->{data} }{$key_url} };
 | 
						|
 | 
						|
            if ($key_url =~ /network\/config/) {
 | 
						|
                if (defined($content{DefaultGateway}) and $content{DefaultGateway}) {
 | 
						|
                    $default_gateway = $content{DefaultGateway};
 | 
						|
                }
 | 
						|
                if (defined($content{HostName}) and $content{HostName}) {
 | 
						|
                    $hostname = $content{HostName};
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            my ($path, $adapter_id) = (split(/\/ipv4\//, $key_url));
 | 
						|
 | 
						|
            if ($adapter_id) {
 | 
						|
                if ( (defined($content{Origin}) and $content{Origin} =~ /LinkLocal/) or
 | 
						|
                     (defined($content{Address}) and $content{Address} =~ /^169.254/) ) {
 | 
						|
                    # OpenBMC driver has a interim bug where ZeroConfigIP comes up as DHCP instead of LinkLocal.
 | 
						|
                    # To protect xCAT while the drivers change, check the 169.254 IP also
 | 
						|
                    if ($xcatdebugmode) {
 | 
						|
                        my $debugmsg = "Found LocalLink " . $content{Address} . " for interface " . $key_url . " Ignoring...";
 | 
						|
                        process_debug_info($node, $debugmsg);
 | 
						|
                    }
 | 
						|
                    next;
 | 
						|
                }
 | 
						|
                my $nic = $path;
 | 
						|
                $nic =~ s/(.*\/)//g;
 | 
						|
                unless (defined($nicinfo{$nic}{address})) {
 | 
						|
                    $nicinfo{$nic}{address} = ();
 | 
						|
                    $nicinfo{$nic}{gateway} = ();
 | 
						|
                    $nicinfo{$nic}{ipsrc}   = ();
 | 
						|
                    $nicinfo{$nic}{netmask} = ();
 | 
						|
                    $nicinfo{$nic}{prefix}  = ();
 | 
						|
                    $nicinfo{$nic}{vlan}    = "Disable";
 | 
						|
                }
 | 
						|
 | 
						|
 | 
						|
                if (defined($content{Address}) and $content{Address}) {
 | 
						|
                    if ($content{Address} eq $node_info{$node}{bmcip} and $node_info{$node}{cur_status} eq "RSPCONFIG_GET_NIC_RESPONSE") {
 | 
						|
                        $status_info{RSPCONFIG_SET_NTPSERVERS_REQUEST}{init_url} =~ s/#NIC#/$nic/g;
 | 
						|
                        if ($next_status{"RSPCONFIG_GET_NIC_RESPONSE"}) {
 | 
						|
                            $node_info{$node}{cur_status} = $next_status{"RSPCONFIG_GET_NIC_RESPONSE"};
 | 
						|
                            gen_send_request($node);
 | 
						|
                            return;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    if ($nicinfo{$nic}{address}) {
 | 
						|
                        $multiple_error = "Interfaces with multiple IP addresses are not supported";
 | 
						|
                    }
 | 
						|
                    push @{ $nicinfo{$nic}{address} }, $content{Address};
 | 
						|
                }
 | 
						|
                if (defined($content{Gateway}) and $content{Gateway}) {
 | 
						|
                    push @{ $nicinfo{$nic}{gateway} }, $content{Gateway};
 | 
						|
                }
 | 
						|
                if (defined($content{PrefixLength}) and $content{PrefixLength}) {
 | 
						|
                    push @{ $nicinfo{$nic}{prefix} }, $content{PrefixLength};
 | 
						|
                }
 | 
						|
                if (defined($content{Origin})) {
 | 
						|
                    my $ipsrc_tmp = $content{Origin};
 | 
						|
                    $ipsrc_tmp =~ s/^.*\.(\w+)/$1/;
 | 
						|
                    push @{ $nicinfo{$nic}{ipsrc} }, $ipsrc_tmp;
 | 
						|
                }
 | 
						|
 | 
						|
                if (defined($response_info->{data}->{$path}->{Id})) {
 | 
						|
                    $nicinfo{$nic}{vlan} = $response_info->{data}->{$path}->{Id};
 | 
						|
                }
 | 
						|
 | 
						|
                if (defined($response_info->{data}->{$path}->{NTPServers})) {
 | 
						|
                    $nicinfo{$nic}{ntpservers} = join(",", @{ $response_info->{data}->{$path}->{NTPServers} });
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (scalar (keys %nicinfo) == 0) {
 | 
						|
            my $error = "No valid BMC network information";
 | 
						|
            xCAT::SvrUtils::sendmsg([1, "$error"], $callback, $node);
 | 
						|
            $node_info{$node}{cur_status} = "";
 | 
						|
        } else {
 | 
						|
            my @address = ();
 | 
						|
            my @ipsrc = ();
 | 
						|
            my @netmask = ();
 | 
						|
            my @gateway = ();
 | 
						|
            my @vlan = ();
 | 
						|
            my @ntpservers = ();
 | 
						|
            my $real_ntp_server = 0;
 | 
						|
            my @nics = keys %nicinfo;
 | 
						|
            foreach my $nic (@nics) {
 | 
						|
                my $addon_info = '';
 | 
						|
                if ($#nics > 1) {
 | 
						|
                    $addon_info = " for $nic";
 | 
						|
                }
 | 
						|
 | 
						|
                if ($nicinfo{$nic}{ntpservers}) {
 | 
						|
                    push @ntpservers, "BMC NTP Servers$addon_info: $nicinfo{$nic}{ntpservers}";
 | 
						|
                    $real_ntp_server = 1;
 | 
						|
                } else {
 | 
						|
                    push @ntpservers, "BMC NTP Servers$addon_info: None";
 | 
						|
                }
 | 
						|
 | 
						|
                next if ($multiple_error);
 | 
						|
 | 
						|
                push @address, "BMC IP$addon_info: ${ $nicinfo{$nic}{address} }[0]";
 | 
						|
                push @ipsrc, "BMC IP Source$addon_info: ${ $nicinfo{$nic}{ipsrc} }[0]";
 | 
						|
                if ($nicinfo{$nic}{address}) {
 | 
						|
                    my $mask_shift = 32 - ${ $nicinfo{$nic}{prefix} }[0];
 | 
						|
                    my $decimal_mask = (2 ** ${ $nicinfo{$nic}{prefix} }[0] - 1) << $mask_shift;
 | 
						|
                    push @netmask, "BMC Netmask$addon_info: " . join('.', unpack("C4", pack("N", $decimal_mask)));
 | 
						|
                }
 | 
						|
                push @gateway, "BMC Gateway$addon_info: ${ $nicinfo{$nic}{gateway} }[0] (default: $default_gateway)";
 | 
						|
                push @vlan, "BMC VLAN ID$addon_info: $nicinfo{$nic}{vlan}";
 | 
						|
            }
 | 
						|
            my $mul_out = 0;
 | 
						|
            foreach my $opt (split /,/,$grep_string) {
 | 
						|
                if ($opt eq "hostname") {
 | 
						|
                    push @output, "BMC Hostname: $hostname";
 | 
						|
                } elsif ($opt eq "ntpservers") {
 | 
						|
                    push @output, @ntpservers;
 | 
						|
                    if (($real_ntp_server) && ($status_info{RSPCONFIG_SET_RESPONSE}{argv} =~ "NTPServers")) {
 | 
						|
                        # Display a warning if the host in not powered off
 | 
						|
                        # Time on the BMC is not synced while the host is powered on.
 | 
						|
                        push @output, "Warning: time will not be synchronized until the host is powered off.";
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
                if ($multiple_error and ($opt =~  /^ip$|^ipsrc$|^netmask$|^gateway$|^vlan$/)) {
 | 
						|
                    $mul_out = 1;
 | 
						|
                    next;
 | 
						|
                }
 | 
						|
                if ($opt eq "ip") {
 | 
						|
                    push @output, @address;
 | 
						|
                } elsif ($opt eq "ipsrc") {
 | 
						|
                    push @output, @ipsrc;
 | 
						|
                } elsif ($opt eq "netmask") {
 | 
						|
                    push @output, @netmask;
 | 
						|
                } elsif ($opt eq "gateway") {
 | 
						|
                    push @output, @gateway;
 | 
						|
                } elsif ($opt eq "vlan") {
 | 
						|
                    push @output, @vlan;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            xCAT::SvrUtils::sendmsg("$_", $callback, $node) foreach (@output);
 | 
						|
            if ($multiple_error and $mul_out) {
 | 
						|
                xCAT::SvrUtils::sendmsg([1, "$multiple_error"], $callback, $node);
 | 
						|
                $wait_node_num--;
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            if ($grep_string eq "all") {
 | 
						|
                # If all current values equal the input, just print out message
 | 
						|
                my @checks = split("-", $status_info{RSPCONFIG_CHECK_RESPONSE}{argv});
 | 
						|
                my $check_num = @checks;
 | 
						|
                my $check_vlan;
 | 
						|
                if ($check_num == 4) {
 | 
						|
                    $check_vlan = shift @checks;
 | 
						|
                }
 | 
						|
                my ($check_ip,$check_netmask,$check_gateway) = @checks;
 | 
						|
                my $the_nic_to_config = undef;
 | 
						|
                foreach my $nic (@nics) {
 | 
						|
                    my $address = ${ $nicinfo{$nic}{address} }[0];
 | 
						|
                    my $prefix = ${ $nicinfo{$nic}{prefix} }[0];
 | 
						|
                    my $gateway = ${ $nicinfo{$nic}{gateway} }[0];
 | 
						|
                    if ($check_ip eq $address and $check_netmask eq $prefix and $check_gateway eq $gateway) {
 | 
						|
                        if (($check_vlan and $check_vlan eq $nicinfo{$nic}{vlan}) or !$check_vlan) {
 | 
						|
                            $next_status{ $node_info{$node}{cur_status} } = "RSPCONFIG_PRINT_BMCINFO";
 | 
						|
                            $the_nic_to_config = $nic;
 | 
						|
                            last;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    # Only deal with the nic whose IP matching the BMC IP configured for the node
 | 
						|
                    if ($address eq $node_info{$node}{bmcip}) {
 | 
						|
                        $the_nic_to_config = $nic;
 | 
						|
                        last;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
                if (!defined($the_nic_to_config)) {
 | 
						|
                    xCAT::SvrUtils::sendmsg("Can not find the correct device to configure", $callback, $node);
 | 
						|
                    $wait_node_num--;
 | 
						|
                    return;
 | 
						|
                } else {
 | 
						|
                    my $next_state = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
                    # To create an Object with vlan tag, shall be operated to the eth0
 | 
						|
                    if ($next_state eq "RSPCONFIG_VLAN_REQUEST") {
 | 
						|
                        $the_nic_to_config =~ s/(\_\d*)//g;
 | 
						|
                        $status_info{$next_state}{data} =~ s/#NIC#/$the_nic_to_config/g;
 | 
						|
                    }
 | 
						|
                    $status_info{RSPCONFIG_IPOBJECT_REQUEST}{init_url} =~ s/#NIC#/$the_nic_to_config/g;
 | 
						|
                    $node_info{$node}{nic} = $the_nic_to_config;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    my $origin_type;
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSPCONFIG_CHECK_RESPONSE") {
 | 
						|
        my @checks = split("-", $status_info{RSPCONFIG_CHECK_RESPONSE}{argv});
 | 
						|
        my $check_num = @checks;
 | 
						|
        my $check_vlan;
 | 
						|
        if ($check_num == 4) {
 | 
						|
            $check_vlan = shift @checks;
 | 
						|
        }
 | 
						|
        my ($check_ip,$check_netmask,$check_gateway) = @checks;
 | 
						|
        my $check_result = 0;
 | 
						|
        foreach my $key_url (keys %{$response_info->{data}}) {
 | 
						|
            my %content = %{ ${ $response_info->{data} }{$key_url} };
 | 
						|
            my ($path, $adapter_id) = (split(/\/ipv4\//, $key_url));
 | 
						|
            if ($adapter_id) {
 | 
						|
                if (defined($content{Address}) and $content{Address}) {
 | 
						|
                    if ($content{Address} eq $node_info{$node}{bmcip}) {
 | 
						|
                        if ($content{Origin} =~ /Static/) {
 | 
						|
                            $origin_type = "STATIC";
 | 
						|
                            $status_info{RSPCONFIG_DELETE_REQUEST}{init_url} = "$key_url";
 | 
						|
                        } else {
 | 
						|
                            $origin_type = "DHCP";
 | 
						|
                            my $nic = $path;
 | 
						|
                            $nic =~ s/(.*\/)//g;
 | 
						|
                            $status_info{RSPCONFIG_DHCPDIS_REQUEST}{init_url} =~ s/#NIC#/$nic/g
 | 
						|
                        }
 | 
						|
                    } else {
 | 
						|
                        if (($content{Address} eq $check_ip) and
 | 
						|
                            ($content{PrefixLength} eq $check_netmask) and
 | 
						|
                            ($content{Gateway} eq $check_gateway)) {
 | 
						|
                            if ($check_vlan) {
 | 
						|
                                if (defined($response_info->{data}->{$path}->{Id}) and $response_info->{data}->{$path}->{Id} eq $check_vlan) {
 | 
						|
                                    $check_result = 1;
 | 
						|
                                }
 | 
						|
                            } else {
 | 
						|
                               $check_result = 1;
 | 
						|
                            }
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if (!$check_result or !$origin_type) {
 | 
						|
            xCAT::SvrUtils::sendmsg("Config IP failed", $callback, $node);
 | 
						|
            $next_status{ $node_info{$node}{cur_status} } = "";
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSPCONFIG_PASSWD_VERIFY") {
 | 
						|
        if ($status_info{RSPCONFIG_PASSWD_VERIFY}{argv} ne $node_info{$node}{password}) {
 | 
						|
            xCAT::SvrUtils::sendmsg("Current BMC password is incorrect, cannot set the new password.", $callback, $node);
 | 
						|
            $wait_node_num--;
 | 
						|
            return;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSPCONFIG_SET_RESPONSE") {
 | 
						|
        if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
            if (defined $status_info{RSPCONFIG_SET_RESPONSE}{argv}) {
 | 
						|
                xCAT::SvrUtils::sendmsg("BMC Setting $status_info{RSPCONFIG_SET_RESPONSE}{argv}...", $callback, $node);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSPCONFIG_DHCP_RESPONSE") {
 | 
						|
        if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
            xCAT::SvrUtils::sendmsg("BMC Setting IP to DHCP...", $callback, $node);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSPCONFIG_PRINT_BMCINFO") {
 | 
						|
        if ($status_info{RSPCONFIG_PRINT_BMCINFO}{data}) {
 | 
						|
            my @output = split(",", $status_info{RSPCONFIG_PRINT_BMCINFO}{data});
 | 
						|
            xCAT::SvrUtils::sendmsg($_, $callback, $node) foreach (@output);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSPCONFIG_VLAN_RESPONSE") {
 | 
						|
        if ($xcatdebugmode) {
 | 
						|
             process_debug_info($node, "Wait $::RSPCONFIG_WAIT_VLAN_DONE seconds for interface with VLAN tag be ready");
 | 
						|
        }
 | 
						|
        retry_after($node, $next_status{ $node_info{$node}{cur_status} }, $::RSPCONFIG_WAIT_VLAN_DONE);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSPCONFIG_IPOBJECT_RESPONSE") {
 | 
						|
        if ($xcatdebugmode) {
 | 
						|
             process_debug_info($node, "Wait $::RSPCONFIG_WAIT_IP_DONE seconds for the configuration done");
 | 
						|
        }
 | 
						|
        retry_after($node, $next_status{ $node_info{$node}{cur_status} }, $::RSPCONFIG_WAIT_IP_DONE);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSPCONFIG_CLEAR_GARD_RESPONSE") {
 | 
						|
        if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
            xCAT::SvrUtils::sendmsg("GARD cleared", $callback, $node);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($next_status{ $node_info{$node}{cur_status} }) {
 | 
						|
        if ($node_info{$node}{cur_status} eq "RSPCONFIG_CHECK_RESPONSE") {
 | 
						|
            $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} }{$origin_type};
 | 
						|
        } else {
 | 
						|
            $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
        }
 | 
						|
        if ($node_info{$node}{cur_status} eq "RSPCONFIG_PRINT_BMCINFO") {
 | 
						|
            $status_info{ $node_info{$node}{cur_status} }->{process}->($node, "");
 | 
						|
        } else {
 | 
						|
            gen_send_request($node);
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        $wait_node_num--;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  rspconfig_api_config_response
 | 
						|
 | 
						|
  Deal with response of rspconfig command for configured subcommand
 | 
						|
 | 
						|
  Currently understands only generic boolean setting and query responses
 | 
						|
  Input:
 | 
						|
        $node: nodename of current response
 | 
						|
        $response: Async return response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub rspconfig_api_config_response {
 | 
						|
    my $node = shift;
 | 
						|
    my $response = shift;
 | 
						|
 | 
						|
    my $response_info;
 | 
						|
    my $value = -1;
 | 
						|
    $response_info = decode_json $response->content if ($response);
 | 
						|
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status}) {
 | 
						|
        if ($node_info{$node}{cur_status} eq "RSPCONFIG_API_CONFIG_ON_RESPONSE") {
 | 
						|
            if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
                xCAT::SvrUtils::sendmsg("BMC Setting ". $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{display_name} . "...", $callback, $node);
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                xCAT::SvrUtils::sendmsg("Error setting RSPCONFIG_API_CONFIG_ON_RESPONSE", $callback, $node);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        elsif ($node_info{$node}{cur_status} eq "RSPCONFIG_API_CONFIG_OFF_RESPONSE") {
 | 
						|
            if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
                xCAT::SvrUtils::sendmsg("BMC Setting ". $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{display_name} . "...", $callback, $node);
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                xCAT::SvrUtils::sendmsg("Error unsetting RSPCONFIG_API_CONFIG_OFF_RESPONSE", $callback, $node);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        elsif ($node_info{$node}{cur_status} eq "RSPCONFIG_API_CONFIG_ATTR_RESPONSE") {
 | 
						|
            if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
                xCAT::SvrUtils::sendmsg("BMC Setting ".
 | 
						|
                                        $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{display_name} .
 | 
						|
                                        "... " .
 | 
						|
                                        $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{instruct_msg}, $callback, $node);
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                xCAT::SvrUtils::sendmsg("Error unsetting RSPCONFIG_API_CONFIG_OFF_RESPONSE", $callback, $node);
 | 
						|
            }
 | 
						|
        }
 | 
						|
        elsif ($node_info{$node}{cur_status} eq "RSPCONFIG_API_CONFIG_QUERY_RESPONSE") {
 | 
						|
            if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
                # Sometimes query will return hash, sometimes just a variable data
 | 
						|
                if (ref($response_info->{data}) eq 'HASH') {
 | 
						|
                    # Hash returned in "data"
 | 
						|
                    foreach my $key_url (keys %{$response_info->{data}}) {
 | 
						|
                        if ($key_url eq  $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{attr_url}) {
 | 
						|
                            # Is this the attribute we are looking for ?
 | 
						|
                            $value = $response_info->{data}{$key_url};
 | 
						|
                            last;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                } else {
 | 
						|
                    # "data" is not a hash, field contains the value
 | 
						|
                    $value = $response_info->{data};
 | 
						|
                }
 | 
						|
                if (($value eq "0") || ($value eq "1")) {
 | 
						|
                    # If 0 or 1 display as a boolean value
 | 
						|
                    xCAT::SvrUtils::sendmsg($api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{display_name} . ": $value", $callback, $node);
 | 
						|
                }
 | 
						|
                else {
 | 
						|
                    # If not a boolean value, display the last component of the attribute
 | 
						|
                    # For example "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore"
 | 
						|
                    #    will be displayed as "Restore"
 | 
						|
                    my @attr_value = split('\.', $value);
 | 
						|
                    my $last_component = $attr_value[-1];
 | 
						|
                    my @valid_values = values %{ $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{attr_value} };
 | 
						|
                    if ($value) {
 | 
						|
                        xCAT::SvrUtils::sendmsg($api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{display_name} . " : $last_component", $callback, $node);
 | 
						|
                        my $found = grep(/$value/, @valid_values);
 | 
						|
                        if ($found eq 0) {
 | 
						|
                            # Received data value not expected
 | 
						|
                            xCAT::SvrUtils::sendmsg("WARNING: Unexpected value set: $value", $callback, $node);
 | 
						|
                            xCAT::SvrUtils::sendmsg("WARNING: Valid values: " . join(",", @valid_values), $callback, $node);
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    else {
 | 
						|
                        xCAT::SvrUtils::sendmsg("Unable to query value for " . $api_config_info{$::RSPCONFIG_CONFIGURED_API_KEY}{attr_url}, $callback, $node);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                xCAT::SvrUtils::sendmsg("Error query RSPCONFIG_API_CONFIG_QUERY_RESPONSE", $callback, $node);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($next_status{ $node_info{$node}{cur_status} }) {
 | 
						|
        $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
        if ($node_info{$node}{method} || $status_info{ $node_info{$node}{cur_status} }{method}) {
 | 
						|
            gen_send_request($node);
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        $wait_node_num--;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  rspconfig_sshcfg_response
 | 
						|
 | 
						|
  Deal with request and response of rspconfig command for sscfg subcommand.
 | 
						|
  Input:
 | 
						|
        $node: nodename of current response
 | 
						|
        $response: Async return response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub rspconfig_sshcfg_response {
 | 
						|
    my $node = shift;
 | 
						|
    my $response = shift;
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSPCONFIG_SSHCFG_REQUEST") {
 | 
						|
        my $child = xCAT::Utils->xfork;
 | 
						|
        if (!defined($child)) {
 | 
						|
            xCAT::SvrUtils::sendmsg("Failed to fork child process for rspconfig sshcfg.", $callback, $node);
 | 
						|
            sleep(1)
 | 
						|
        } elsif ($child == 0) {
 | 
						|
            $async->remove_all;
 | 
						|
            exit(sshcfg_process($node))
 | 
						|
        } else {
 | 
						|
            $child_node_map{$child} = $node;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($next_status{ $node_info{$node}{cur_status} }) {
 | 
						|
        $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
        if ($node_info{$node}{method} || $status_info{ $node_info{$node}{cur_status} }{method}) {
 | 
						|
            gen_send_request($node);
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        $wait_node_num--;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  rspconfig_process
 | 
						|
 | 
						|
  Append contents of id_rsa.pub file from management node to
 | 
						|
  the authorized_keys file on BMC
 | 
						|
  Input:
 | 
						|
        $node: nodename of current response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub sshcfg_process {
 | 
						|
    my $node = shift;
 | 
						|
 | 
						|
    my $bmcip = $node_info{$node}{bmc};
 | 
						|
    my $userid = $node_info{$node}{username};
 | 
						|
    my $userpw = $node_info{$node}{password};
 | 
						|
 | 
						|
    #backup the previous $ENV{DSH_REMOTE_PASSWORD},$ENV{'DSH_FROM_USERID'}
 | 
						|
    my $bak_DSH_REMOTE_PASSWORD=$ENV{'DSH_REMOTE_PASSWORD'};
 | 
						|
    my $bak_DSH_FROM_USERID=$ENV{'DSH_FROM_USERID'};
 | 
						|
 | 
						|
    #xCAT::RemoteShellExp->remoteshellexp dependes on environment
 | 
						|
    #variables $ENV{DSH_REMOTE_PASSWORD},$ENV{'DSH_FROM_USERID'}
 | 
						|
    $ENV{'DSH_REMOTE_PASSWORD'}=$userpw;
 | 
						|
    $ENV{'DSH_FROM_USERID'}=$userid;
 | 
						|
 | 
						|
    #send ssh public key from MN to bmc
 | 
						|
    my $rc=xCAT::RemoteShellExp->remoteshellexp("s",$callback,"/usr/bin/ssh",$bmcip,10);
 | 
						|
    if ($rc) {
 | 
						|
        xCAT::SvrUtils::sendmsg("Error copying ssh keys to $bmcip\n", $callback, $node);
 | 
						|
    }else{
 | 
						|
        #check whether the ssh keys has been sent successfully
 | 
						|
        $rc=xCAT::RemoteShellExp->remoteshellexp("t",$callback,"/usr/bin/ssh",$bmcip,10);
 | 
						|
        if ($rc) {
 | 
						|
            xCAT::SvrUtils::sendmsg("Testing the ssh connection to $bmcip failed. Please rerun rspconfig command.", $callback, $node);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            xCAT::SvrUtils::sendmsg("ssh keys copied to $bmcip", $callback, $node);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    #restore env variables
 | 
						|
    $ENV{'DSH_REMOTE_PASSWORD'}=$bak_DSH_REMOTE_PASSWORD;
 | 
						|
    $ENV{'DSH_FROM_USERID'}=$bak_DSH_FROM_USERID;
 | 
						|
 | 
						|
    return $rc;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  rspconfig_dump_response
 | 
						|
 | 
						|
  Deal with request and response of rspconfig command for dump subcommand.
 | 
						|
  Input:
 | 
						|
        $node: nodename of current response
 | 
						|
        $response: Async return response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub rspconfig_dump_response {
 | 
						|
    my $node = shift;
 | 
						|
    my $response = shift;
 | 
						|
 | 
						|
    my $response_info = decode_json $response->content if (defined($response));
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSPCONFIG_DUMP_LIST_RESPONSE" or $node_info{$node}{cur_status} eq "RSPCONFIG_DUMP_CHECK_RESPONSE") {
 | 
						|
        my %dump_info = ();
 | 
						|
        my $gen_check = 0;
 | 
						|
        foreach my $key_url (keys %{$response_info->{data}}) {
 | 
						|
            my %content = %{ ${ $response_info->{data} }{$key_url} };
 | 
						|
            my $id;
 | 
						|
            if (defined $content{Elapsed}) {
 | 
						|
                $id = $key_url;
 | 
						|
                $id =~ s/.*\///g;
 | 
						|
 | 
						|
                if ($node_info{$node}{cur_status} eq "RSPCONFIG_DUMP_CHECK_RESPONSE") {
 | 
						|
                    if ($id eq $node_info{$node}{dump_id}) {
 | 
						|
                        $gen_check = 1;
 | 
						|
                        last;
 | 
						|
                    }
 | 
						|
                    next;
 | 
						|
                }
 | 
						|
 | 
						|
                my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($content{Elapsed});
 | 
						|
                $mon += 1;
 | 
						|
                $year += 1900;
 | 
						|
                my $UTC_time = sprintf ("%02d/%02d/%04d %02d:%02d:%02d", $mon, $mday, $year, $hour, $min, $sec);
 | 
						|
                $dump_info{$id} = "[$id] Generated: $UTC_time, Size: $content{Size}";
 | 
						|
 | 
						|
                if ($::RSPCONFIG_DUMP_DOWNLOAD_ALL_REQUESTED) {
 | 
						|
                    # Save dump info for later, when dump download all
 | 
						|
                    $node_info{$node}{dump_info}{$id} = "[$id] Generated: $UTC_time, Size: $content{Size}";
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        xCAT::SvrUtils::sendmsg("$::NO_ATTRIBUTES_RETURNED", $callback, $node) if (!%dump_info and $node_info{$node}{cur_status} eq "RSPCONFIG_DUMP_LIST_RESPONSE");
 | 
						|
        # If processing the "download all" request, do not print anything now.
 | 
						|
        # Download function dump_download_process() will be
 | 
						|
        # printing the output for each downloaded dump
 | 
						|
        unless ($::RSPCONFIG_DUMP_DOWNLOAD_ALL_REQUESTED) {
 | 
						|
            foreach my $key ( sort { $a <=> $b } keys %dump_info) {
 | 
						|
                xCAT::MsgUtils->message("I", { data => ["$node: $dump_info{$key}"] }, $callback) if ($dump_info{$key});
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (!$gen_check and $node_info{$node}{cur_status} eq "RSPCONFIG_DUMP_CHECK_RESPONSE") {
 | 
						|
            if (!exists($node_info{$node}{dump_wait_attemp})) {
 | 
						|
                $node_info{$node}{dump_wait_attemp} = $::RSPCONFIG_DUMP_MAX_RETRY;
 | 
						|
            }
 | 
						|
            if ( $node_info{$node}{dump_wait_attemp} > 0) {
 | 
						|
                $node_info{$node}{dump_wait_attemp} --;
 | 
						|
                retry_after($node, "RSPCONFIG_DUMP_LIST_REQUEST", $::RSPCONFIG_DUMP_INTERVAL);
 | 
						|
                unless ($node_info{$node}{dump_wait_attemp} % int(8)) { # display message every 8 iterations of the interval
 | 
						|
                    xCAT::SvrUtils::sendmsg("Still waiting for dump $node_info{$node}{dump_id} to be generated...", $callback, $node);
 | 
						|
                }
 | 
						|
                return;
 | 
						|
            } else {
 | 
						|
                xCAT::SvrUtils::sendmsg([1,"Could not find dump $node_info{$node}{dump_id} after waiting $::RSPCONFIG_DUMP_WAIT_TOTALTIME seconds."], $callback, $node);
 | 
						|
                $wait_node_num--;
 | 
						|
                return;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSPCONFIG_DUMP_DOWNLOAD_ALL_RESPONSE") {
 | 
						|
       &dump_download_all_process($node);
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSPCONFIG_DUMP_DOWNLOAD_REQUEST") {
 | 
						|
        my $child = xCAT::Utils->xfork;
 | 
						|
        if (!defined($child)) {
 | 
						|
            xCAT::SvrUtils::sendmsg("Failed to fork child process for rspconfig dump download.", $callback, $node);
 | 
						|
            sleep(1)
 | 
						|
        } elsif ($child == 0) {
 | 
						|
            $async->remove_all;
 | 
						|
            exit(dump_download_process($node))
 | 
						|
        } else {
 | 
						|
            $child_node_map{$child} = $node;
 | 
						|
        }
 | 
						|
        $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSPCONFIG_DUMP_CREATE_RESPONSE") {
 | 
						|
        if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
            if ($response_info->{'data'}) {
 | 
						|
                my $dump_id = $response_info->{'data'};
 | 
						|
                if ($next_status{ $node_info{$node}{cur_status} }) {
 | 
						|
                    $node_info{$node}{dump_id} = $dump_id;
 | 
						|
                    xCAT::SvrUtils::sendmsg("Dump requested. Target ID is $dump_id, waiting for BMC to generate...", $callback, $node);
 | 
						|
                } else {
 | 
						|
                    xCAT::SvrUtils::sendmsg("[$dump_id] success", $callback, $node);
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
                xCAT::SvrUtils::sendmsg([1, "BMC returned $::RESPONSE_OK but no ID was returned.  Verify manually on the BMC."], $callback, $node);
 | 
						|
                $wait_node_num--;
 | 
						|
                return;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RSPCONFIG_DUMP_CLEAR_RESPONSE") {
 | 
						|
        if ($response_info->{'message'} eq $::RESPONSE_OK) {
 | 
						|
            my $dump_id = $status_info{RSPCONFIG_DUMP_CLEAR_RESPONSE}{argv};
 | 
						|
            xCAT::MsgUtils->message("I", { data => ["[$dump_id] clear"] }, $callback) unless ($next_status{ $node_info{$node}{cur_status} });
 | 
						|
        } else {
 | 
						|
            my $error_msg = "Could not clear BMC diagnostics successfully (". $response_info->{'message'} . ")";
 | 
						|
            xCAT::MsgUtils->message("W", { data => ["$node: $error_msg"] }, $callback) if ($next_status{ $node_info{$node}{cur_status} });
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($next_status{ $node_info{$node}{cur_status} }) {
 | 
						|
        $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
        if ($node_info{$node}{method} || $status_info{ $node_info{$node}{cur_status} }{method}) {
 | 
						|
            gen_send_request($node);
 | 
						|
        } elsif ($status_info{ $node_info{$node}{cur_status} }->{process}) {
 | 
						|
            $status_info{ $node_info{$node}{cur_status} }->{process}->($node, undef);
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        $wait_node_num--;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  dump_download_process
 | 
						|
 | 
						|
  Process of download dump tar.xz.
 | 
						|
  Input:
 | 
						|
        $node: nodename of current response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub dump_download_process {
 | 
						|
    my $node = shift;
 | 
						|
 | 
						|
    my $request_url = "$http_protocol://" . $node_info{$node}{bmc};
 | 
						|
    my $content_login = '{ "data": [ "' . $node_info{$node}{username} .'", "' . $node_info{$node}{password} . '" ] }';
 | 
						|
    my $content_logout = '{ "data": [ ] }';
 | 
						|
    my $cjar_id = "/tmp/_xcat_cjar.$node";
 | 
						|
    my $dump_id;
 | 
						|
    $dump_id  = $status_info{RSPCONFIG_DUMP_DOWNLOAD_REQUEST}{argv} if ($status_info{RSPCONFIG_DUMP_DOWNLOAD_REQUEST}{argv});
 | 
						|
    $dump_id = $node_info{$node}{dump_id} if ($node_info{$node}{dump_id});
 | 
						|
    my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime($::RSPCONFIG_DUMP_CMD_TIME);
 | 
						|
    $mon += 1;
 | 
						|
    $year += 1900;
 | 
						|
    my $formatted_time = sprintf ("%04d%02d%02d-%02d%02d", $year, $mon, $mday, $hour, $min);
 | 
						|
    my $file_name = $::XCAT_LOG_DUMP_DIR . $formatted_time . "_$node" . "_dump_$dump_id.tar.xz";
 | 
						|
    my $down_url;
 | 
						|
    $down_url = $status_info{RSPCONFIG_DUMP_DOWNLOAD_REQUEST}{init_url};
 | 
						|
    $down_url =~ s/#ID#/$dump_id/g;
 | 
						|
 | 
						|
    my $curl_login_cmd  = "curl -c $cjar_id -k -H 'Content-Type: application/json' -X POST $request_url/login -d '" . $content_login . "'";
 | 
						|
    my $curl_logout_cmd = "curl -b $cjar_id -k -H 'Content-Type: application/json' -X POST $request_url/logout -d '" . $content_logout . "'";
 | 
						|
    my $curl_dwld_cmd = "curl -J -b $cjar_id -k -H 'Content-Type: application/octet-stream' -X GET $request_url/$down_url -o $file_name";
 | 
						|
 | 
						|
    my $curl_login_result = `$curl_login_cmd -s`;
 | 
						|
    my $h;
 | 
						|
    if (!$curl_login_result) {
 | 
						|
        xCAT::SvrUtils::sendmsg([1, "Did not receive response from OpenBMC after running command '$curl_login_cmd'"], $callback, $node);
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
    eval { $h = from_json($curl_login_result) };
 | 
						|
    if ($@) {
 | 
						|
        xCAT::SvrUtils::sendmsg([1, "Received wrong format response for command '$curl_login_cmd': $curl_login_result)"], $callback, $node);
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
    if ($h->{message} eq $::RESPONSE_OK) {
 | 
						|
        xCAT::SvrUtils::sendmsg("Downloading dump $dump_id to $file_name", $callback, $node);
 | 
						|
        my $curl_dwld_result = `$curl_dwld_cmd -s`;
 | 
						|
        if (!$curl_dwld_result) {
 | 
						|
            if ($xcatdebugmode) {
 | 
						|
                my $debugmsg = "RSPCONFIG_DUMP_DOWNLOAD_REQUEST: CMD: $curl_dwld_cmd";
 | 
						|
                process_debug_info($node, $debugmsg);
 | 
						|
            }
 | 
						|
            `$curl_logout_cmd -s`;
 | 
						|
            # Verify the file actually got downloaded
 | 
						|
            if (-e $file_name) {
 | 
						|
                # Check inside downloaded file, if there is a "Path not found" -> invalid ID
 | 
						|
                my $grep_cmd = "/usr/bin/grep -a";
 | 
						|
                my $path_not_found = "Path not found";
 | 
						|
                my $grep_for_path = `$grep_cmd $path_not_found $file_name`;
 | 
						|
                if ($grep_for_path) {
 | 
						|
                    xCAT::SvrUtils::sendmsg([1, "Invalid dump $dump_id was specified. Use -l option to list."], $callback, $node);
 | 
						|
                    # Remove downloaded file, nothing useful inside of it
 | 
						|
                    unlink $file_name;
 | 
						|
                } else {
 | 
						|
                    xCAT::SvrUtils::sendmsg("Downloaded dump $dump_id to $file_name", $callback, $node) if ($::VERBOSE);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                xCAT::SvrUtils::sendmsg([1, "Failed to download dump $dump_id to $file_name. Verify destination directory exists and has correct access permissions."], $callback, $node);
 | 
						|
                return 1;
 | 
						|
            }
 | 
						|
        } else {
 | 
						|
            xCAT::SvrUtils::sendmsg([1, "Failed to download dump $dump_id :" . $h->{message} . " - " . $h->{data}->{description}], $callback, $node);
 | 
						|
            return 1;
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        xCAT::SvrUtils::sendmsg([1, "Unable to login :" . $h->{message} . " - " . $h->{data}->{description}], $callback, $node);
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  dump_download_all_process
 | 
						|
 | 
						|
  Process to download all dumps
 | 
						|
  Input:
 | 
						|
        $node: nodename of current response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub dump_download_all_process {
 | 
						|
    my $node = shift;
 | 
						|
 | 
						|
    # Call dump_download_process for each dump id in the list
 | 
						|
    foreach my $dump_id (keys %{$node_info{$node}{dump_info}}) {
 | 
						|
        $node_info{$node}{dump_id} = $dump_id;
 | 
						|
        &dump_download_process($node);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  rvitals_response
 | 
						|
 | 
						|
  Deal with response of rvitals command
 | 
						|
  Input:
 | 
						|
        $node: nodename of current response
 | 
						|
        $response: Async return response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub rvitals_response {
 | 
						|
    my $node = shift;
 | 
						|
    my $response = shift;
 | 
						|
 | 
						|
    my $response_info = decode_json $response->content;
 | 
						|
 | 
						|
    my $grep_string;
 | 
						|
    if ($node_info{$node}{cur_status} =~ "RVITALS_LEDS_RESPONSE") {
 | 
						|
        $grep_string = $status_info{RVITALS_LEDS_RESPONSE}{argv};
 | 
						|
    } else {
 | 
						|
        $grep_string = $status_info{RVITALS_RESPONSE}{argv};
 | 
						|
    }
 | 
						|
    my $src;
 | 
						|
    my $content_info;
 | 
						|
    my @sorted_output;
 | 
						|
 | 
						|
    my %leds = ();
 | 
						|
 | 
						|
    foreach my $key_url (keys %{$response_info->{data}}) {
 | 
						|
        my %content = %{ ${ $response_info->{data} }{$key_url} };
 | 
						|
 | 
						|
        my $label = (split(/\//, $key_url))[ -1 ];
 | 
						|
        # replace underscore with space, uppercase the first letter
 | 
						|
        $label =~ s/_/ /g;
 | 
						|
        $label =~ s/\b(\w)/\U$1/g;
 | 
						|
 | 
						|
        my $calc_value = undef;
 | 
						|
 | 
						|
        if ($node_info{$node}{cur_status} =~ "RVITALS_LEDS_RESPONSE") {
 | 
						|
            # Print out Led info
 | 
						|
            $calc_value = (split(/\./, $content{State}))[-1];
 | 
						|
            $content_info = $label . ": " . $calc_value ;
 | 
						|
 | 
						|
            if ($key_url =~ "fan0") { $leds{fan0} = $calc_value; }
 | 
						|
            if ($key_url =~ "fan1") { $leds{fan1} = $calc_value; }
 | 
						|
            if ($key_url =~ "fan2") { $leds{fan2} = $calc_value; }
 | 
						|
            if ($key_url =~ "fan3") { $leds{fan3} = $calc_value; }
 | 
						|
            if ($key_url =~ "front_id") { $leds{front_id} = $calc_value; }
 | 
						|
            if ($key_url =~ "front_fault") { $leds{front_fault} = $calc_value; }
 | 
						|
            if ($key_url =~ "front_power") { $leds{front_power} = $calc_value; }
 | 
						|
            if ($key_url =~ "rear_id") { $leds{rear_id} = $calc_value; }
 | 
						|
            if ($key_url =~ "rear_fault") { $leds{rear_fault} = $calc_value; }
 | 
						|
            if ($key_url =~ "rear_power") { $leds{rear_power} = $calc_value; }
 | 
						|
 | 
						|
        } else {
 | 
						|
            # print out Sensor info
 | 
						|
            #
 | 
						|
            # Skip over attributes that are not asked to be printed
 | 
						|
            #
 | 
						|
            if ($grep_string =~ "temp") {
 | 
						|
                unless ( $content{Unit} =~ "DegreesC") { next; }
 | 
						|
            }
 | 
						|
            if ($grep_string =~ "voltage") {
 | 
						|
                unless ( $content{Unit} =~ "Volts") { next; }
 | 
						|
            }
 | 
						|
            if ($grep_string =~ "wattage") {
 | 
						|
                unless ( $content{Unit} =~ "Watts") { next; }
 | 
						|
            }
 | 
						|
            if ($grep_string =~ "fanspeed") {
 | 
						|
                unless ( $content{Unit} =~ "RPMS") { next; }
 | 
						|
            }
 | 
						|
            if ($grep_string =~ "power") {
 | 
						|
                unless ( $content{Unit} =~ "Amperes" || $content{Unit} =~ "Joules" || $content{Unit} =~ "Watts" ) { next; }
 | 
						|
            }
 | 
						|
            if ($grep_string =~ "altitude") {
 | 
						|
                unless ( $content{Unit} =~ "Meters" ) { next; }
 | 
						|
            }
 | 
						|
 | 
						|
            #
 | 
						|
            # Calculate the adjusted value based on the scale attribute
 | 
						|
            #
 | 
						|
            $calc_value = $content{Value};
 | 
						|
            if (!defined($calc_value)) {
 | 
						|
                # Handle the bug where the keyword in the API is lower case value
 | 
						|
                $calc_value = $content{value};
 | 
						|
            }
 | 
						|
 | 
						|
            if (defined $content{Scale} and $content{Scale} != 0) {
 | 
						|
                $calc_value = ($content{Value} * (10 ** $content{Scale}));
 | 
						|
            }
 | 
						|
 | 
						|
            $content_info = $label . ": " . $calc_value;
 | 
						|
            if (defined($content{Unit})) {
 | 
						|
	        $content_info = $content_info . " " . $sensor_units{ $content{Unit} };
 | 
						|
            }
 | 
						|
            push (@sorted_output, $content_info); #Save output in array
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} =~ "RVITALS_LEDS_RESPONSE") {
 | 
						|
        if ($grep_string =~ "compact") {
 | 
						|
            # Compact output for "rbeacon stat" command
 | 
						|
            $content_info = "Front:$leds{front_id} Rear:$leds{rear_id}";
 | 
						|
            push (@sorted_output, $content_info);
 | 
						|
        } else {
 | 
						|
            # Full output for "rvitals leds" command
 | 
						|
            my @front_rear = ("Front", "Rear");
 | 
						|
            my @led_types = ("Power", "Fault", "Identify");
 | 
						|
            foreach my $i (@front_rear) {
 | 
						|
                foreach my $led_type (@led_types) {
 | 
						|
                    my $tmp_type = lc($led_type);
 | 
						|
                    $tmp_type = "id" if ($led_type eq "Identify");
 | 
						|
                    my $key_type = lc($i) . "_" . $tmp_type;
 | 
						|
                    $content_info = "LEDs $i $led_type: $leds{$key_type}";
 | 
						|
                    push (@sorted_output, $content_info);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            # Fans
 | 
						|
            for (my $i = 0; $i < 4; $i++) {
 | 
						|
                my $tmp_key = "fan" . $i;
 | 
						|
                $content_info = "LEDs Fan$i: $leds{$tmp_key}";
 | 
						|
                push (@sorted_output, $content_info);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # If sorted array has any contents, sort it and print it
 | 
						|
    if (scalar @sorted_output > 0) {
 | 
						|
        # Sort the output, alpha, then numeric
 | 
						|
        xCAT::MsgUtils->message("I", { data => ["$node: $_"] }, $callback) foreach (sort natural_sort_cmp @sorted_output);
 | 
						|
    } else {
 | 
						|
        xCAT::SvrUtils::sendmsg("$::NO_ATTRIBUTES_RETURNED", $callback, $node);
 | 
						|
    }
 | 
						|
 | 
						|
    if ($next_status{ $node_info{$node}{cur_status} }) {
 | 
						|
        $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
        gen_send_request($node);
 | 
						|
    } else {
 | 
						|
        $wait_node_num--;
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  rflash_response
 | 
						|
 | 
						|
  Deal with response of rflash command
 | 
						|
  Input:
 | 
						|
        $node: nodename of current response
 | 
						|
        $response: Async return response
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub rflash_response {
 | 
						|
    my $node = shift;
 | 
						|
    my $response = shift;
 | 
						|
    my $response_info;
 | 
						|
    if (defined($response)) {
 | 
						|
        $response_info = decode_json $response->content;
 | 
						|
    }
 | 
						|
    my $update_id;
 | 
						|
    my $update_activation = "Unknown";
 | 
						|
    my $update_purpose;
 | 
						|
    my $update_version;
 | 
						|
    my $rflash_log_file = xCAT::Utils->full_path($node.".log", $::XCAT_LOG_RFLASH_DIR);
 | 
						|
    open (RFLASH_LOG_FILE_HANDLE, ">> $rflash_log_file");
 | 
						|
    if ($node_info{$node}{cur_status} eq "RFLASH_LIST_RESPONSE") {
 | 
						|
        # Get the functional IDs to accurately mark the active running FW
 | 
						|
        my $functional = get_functional_software_ids($response_info);
 | 
						|
        if (!%{$functional}) {
 | 
						|
            # Inform users that the older firmware levels does not correctly reflect Active version
 | 
						|
            xCAT::SvrUtils::sendmsg("WARNING, The current firmware is unable to detect running firmware version.", $callback, $node);
 | 
						|
        }
 | 
						|
 | 
						|
        # Display "list" option header and data
 | 
						|
        xCAT::SvrUtils::sendmsg("ID       Purpose State      Version", $callback, $node);
 | 
						|
        xCAT::SvrUtils::sendmsg("-" x 55, $callback, $node);
 | 
						|
 | 
						|
        foreach my $key_url (keys %{$response_info->{data}}) {
 | 
						|
            # Initialize values to Unknown for each loop, incase they are not defined in the BMC
 | 
						|
            $update_activation = "Unknown";
 | 
						|
            $update_purpose = "Unknown";
 | 
						|
            $update_version = "Unknown";
 | 
						|
 | 
						|
            my %content = %{ ${ $response_info->{data} }{$key_url} };
 | 
						|
 | 
						|
            $update_id = (split(/\//, $key_url))[ -1 ];
 | 
						|
            if (defined($content{Version}) and $content{Version}) {
 | 
						|
                $update_version = $content{Version};
 | 
						|
            }
 | 
						|
            else {
 | 
						|
                # Entry has no Version attribute, skip listing it
 | 
						|
                next;
 | 
						|
            }
 | 
						|
            if ($xcatdebugmode) {
 | 
						|
                # Only print if xcatdebugmode is set and XCATBYPASS
 | 
						|
                print "\n\n================================= XCATBYPASS DEBUG START =================================\n";
 | 
						|
                print "==> KEY_URL=$key_url\n";
 | 
						|
                print "==> VERSION=$content{Version}\n";
 | 
						|
                print "==> Dump out JSON data:\n";
 | 
						|
                print Dumper(%content);
 | 
						|
                print "================================= XCATBYPASS DEBUG END   =================================\n";
 | 
						|
            }
 | 
						|
            if (defined($content{Activation}) and $content{Activation}) {
 | 
						|
                $update_activation = (split(/\./, $content{Activation}))[ -1 ];
 | 
						|
            }
 | 
						|
            if (defined($content{Purpose}) and $content{Purpose}) {
 | 
						|
                $update_purpose = (split(/\./, $content{Purpose}))[ -1 ];
 | 
						|
            }
 | 
						|
 | 
						|
            my $update_priority = -1;
 | 
						|
            # Just check defined, because priority=0 is a valid value
 | 
						|
            if (defined($content{Priority}))  {
 | 
						|
                $update_priority = (split(/\./, $content{Priority}))[ -1 ];
 | 
						|
            }
 | 
						|
 | 
						|
            # Add indicators to the active firmware
 | 
						|
            if (exists($functional->{$update_id}) ) {
 | 
						|
                #
 | 
						|
                # If the firmware ID exists in the hash, this indicates the really active running FW
 | 
						|
                #
 | 
						|
                $update_activation = $update_activation . "(*)";
 | 
						|
            } elsif ($update_priority == 0) {
 | 
						|
                # Priority attribute of 0 indicates the firmware to be activated on next boot
 | 
						|
                my $indicator = "(+)";
 | 
						|
                if (!%{$functional}) {
 | 
						|
                    # cannot detect, so mark firmware as Active
 | 
						|
                    $indicator = "(*)";
 | 
						|
                }
 | 
						|
                $update_activation = $update_activation . $indicator;
 | 
						|
            }
 | 
						|
            xCAT::SvrUtils::sendmsg(sprintf("%-8s %-7s %-10s %s", $update_id, $update_purpose, $update_activation, $update_version), $callback, $node);
 | 
						|
        }
 | 
						|
        xCAT::SvrUtils::sendmsg("", $callback, $node); #Separate output in case more than 1 endpoint
 | 
						|
    }
 | 
						|
    if ($node_info{$node}{cur_status} eq "RFLASH_DELETE_CHECK_STATE_RESPONSE") {
 | 
						|
        # Verify selected FW ID is not active. If active, display error message,
 | 
						|
        # If not active, proceed to delete
 | 
						|
        my $to_delete_id = (split ('/', $status_info{RFLASH_DELETE_IMAGE_REQUEST}{init_url}))[4];
 | 
						|
        # Get the functional IDs to determint if active running FW can be deleted
 | 
						|
        my $functional = get_functional_software_ids($response_info);
 | 
						|
        if ((!%{$functional}) ||
 | 
						|
           (!exists($functional->{$to_delete_id}))) {
 | 
						|
            # Can not figure out if FW functional, attempt to delete anyway.
 | 
						|
            # Worst case, BMC will not allow FW deletion if we are wrong
 | 
						|
            # OR
 | 
						|
            # FW is not active, it can be deleted. Send the request to do the deletion
 | 
						|
            $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST";
 | 
						|
            $next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE";
 | 
						|
        } else {
 | 
						|
            foreach my $key_url (keys %{$response_info->{data}}) {
 | 
						|
                $update_id = (split(/\//, $key_url))[ -1 ];
 | 
						|
                if ($update_id ne $to_delete_id) {
 | 
						|
                    # Not a match on the id, try next one
 | 
						|
                    next;
 | 
						|
                }
 | 
						|
                # Initialize values to Unknown for each loop, incase they are not defined in the BMC
 | 
						|
                $update_activation = "Unknown";
 | 
						|
                $update_purpose = "Unknown";
 | 
						|
                $update_version = "Unknown";
 | 
						|
 | 
						|
                my %content = %{ ${ $response_info->{data} }{$key_url} };
 | 
						|
 | 
						|
                if (defined($content{Version}) and $content{Version}) {
 | 
						|
                    $update_version = $content{Version};
 | 
						|
                } else {
 | 
						|
                    # Entry has no Version attribute, skip listing it
 | 
						|
                    next;
 | 
						|
                }
 | 
						|
                if (defined($content{Purpose}) and $content{Purpose}) {
 | 
						|
                    $update_purpose = (split(/\./, $content{Purpose}))[ -1 ];
 | 
						|
                }
 | 
						|
                my $update_priority = -1;
 | 
						|
                # Just check defined, because priority=0 is a valid value
 | 
						|
                if (defined($content{Priority}))  {
 | 
						|
                    $update_priority = (split(/\./, $content{Priority}))[ -1 ];
 | 
						|
                }
 | 
						|
 | 
						|
                if ($update_purpose eq "BMC") {
 | 
						|
                    # Active BMC firmware can not be deleted
 | 
						|
                    xCAT::SvrUtils::sendmsg([1, "Deleting currently active BMC firmware is not supported"], $callback, $node);
 | 
						|
                    $wait_node_num--;
 | 
						|
                    return;
 | 
						|
                } elsif ($update_purpose eq "Host") {
 | 
						|
                    # Active Host firmware can NOT be deleted if host is ON
 | 
						|
                    # Active Host firmware can     be deleted if host is OFF
 | 
						|
 | 
						|
                    # Send the request to check Host state
 | 
						|
                    $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RPOWER_STATUS_REQUEST";
 | 
						|
                    $next_status{"RPOWER_STATUS_REQUEST"} = "RPOWER_STATUS_RESPONSE";
 | 
						|
                    # Set special argv to fw_delete if Host is off
 | 
						|
                    $status_info{RPOWER_STATUS_RESPONSE}{argv} = "fw_delete";
 | 
						|
                    last;
 | 
						|
                } else {
 | 
						|
                    xCAT::SvrUtils::sendmsg([1, "Unable to determine the purpose of the firmware to delete"], $callback, $node);
 | 
						|
                    # Can not figure out if Host or BMC, attempt to delete anyway.
 | 
						|
                    # Worst case, BMC will not allow FW deletion if we are wrong
 | 
						|
                    $next_status{"RFLASH_DELETE_CHECK_STATE_RESPONSE"} = "RFLASH_DELETE_IMAGE_REQUEST";
 | 
						|
                    $next_status{"RFLASH_DELETE_IMAGE_REQUEST"} = "RFLASH_DELETE_IMAGE_RESPONSE";
 | 
						|
                    last;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if ($node_info{$node}{cur_status} eq "RFLASH_FILE_UPLOAD_REQUEST") {
 | 
						|
        #
 | 
						|
        # Special processing for file upload
 | 
						|
        #
 | 
						|
        # Unable to form a proper file upload request to the BMC, it fails with: 405 Method Not Allowed
 | 
						|
        # For now, always upload using curl commands.
 | 
						|
        #
 | 
						|
        # TODO: Remove this block when proper request can be generated
 | 
						|
        #
 | 
						|
        if ($::UPLOAD_FILE){
 | 
						|
            $fw_tar_files{$::UPLOAD_FILE}=$::UPLOAD_FILE_VERSION;
 | 
						|
        }
 | 
						|
        if ($::UPLOAD_PNOR){
 | 
						|
            $fw_tar_files{$::UPLOAD_PNOR}=$::UPLOAD_PNOR_VERSION;
 | 
						|
        }
 | 
						|
        if (%fw_tar_files) {
 | 
						|
            my $child = xCAT::Utils->xfork;
 | 
						|
            if (!defined($child)) {
 | 
						|
                xCAT::SvrUtils::sendmsg("Failed to fork child process to upload firmware image.", $callback, $node);
 | 
						|
                sleep(1)
 | 
						|
            } elsif ($child == 0) {
 | 
						|
                $async->remove_all;
 | 
						|
                exit(rflash_upload($node, $callback));
 | 
						|
            } else {
 | 
						|
                $child_node_map{$child} = $node;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if ($node_info{$node}{cur_status} eq "RFLASH_UPDATE_ACTIVATE_RESPONSE") {
 | 
						|
        my $flash_started_msg = "rflash $::UPLOAD_FILE_VERSION started, please wait...";
 | 
						|
        if ($::VERBOSE) {
 | 
						|
            xCAT::SvrUtils::sendmsg("$flash_started_msg", $callback, $node);
 | 
						|
        }
 | 
						|
        print RFLASH_LOG_FILE_HANDLE "$flash_started_msg\n";
 | 
						|
    }
 | 
						|
    if ($node_info{$node}{cur_status} eq "RFLASH_UPDATE_HOST_ACTIVATE_RESPONSE") {
 | 
						|
        my $flash_started_msg = "rflash $::UPLOAD_PNOR_VERSION started, please wait...";
 | 
						|
        if ($::VERBOSE) {
 | 
						|
            xCAT::SvrUtils::sendmsg("$flash_started_msg", $callback, $node);
 | 
						|
        }
 | 
						|
        print RFLASH_LOG_FILE_HANDLE "$flash_started_msg\n";
 | 
						|
    }
 | 
						|
    if ($node_info{$node}{cur_status} eq "RFLASH_SET_PRIORITY_RESPONSE") {
 | 
						|
        print "Update priority has been set";
 | 
						|
    }
 | 
						|
    if ($node_info{$node}{cur_status} eq "RFLASH_UPDATE_CHECK_STATE_RESPONSE") {
 | 
						|
        my %activation_state;
 | 
						|
        my %progress_state;
 | 
						|
        my %priority_state;
 | 
						|
        my %update_ids;
 | 
						|
        my $update_res=0;
 | 
						|
        my $version;
 | 
						|
        foreach my $key_url (keys %{$response_info->{data}}) {
 | 
						|
            if ($::UPLOAD_ACTIVATE_STREAM or $::UPLOAD_AND_ACTIVATE) {
 | 
						|
                my %content = %{${$response_info->{data}}{$key_url}};
 | 
						|
                $version = $content{Version};
 | 
						|
                if (defined($version)) {
 | 
						|
                    if ($version ne $::UPLOAD_FILE_VERSION and $version ne $::UPLOAD_PNOR_VERSION) {
 | 
						|
                        next;
 | 
						|
                    }
 | 
						|
                    # Get values of some attributes to determine activation status
 | 
						|
                    $activation_state{$version} = $content{Activation};
 | 
						|
                    $progress_state{$version} = $content{Progress};
 | 
						|
                    $priority_state{$version} = $content{Priority};
 | 
						|
                    $update_ids{$version} = (split(/\//, $key_url))[ -1 ];
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
                # This is for -a <ID> option
 | 
						|
                $version = "default";
 | 
						|
                if ($key_url eq "Activation") {
 | 
						|
                    $activation_state{$version} = ${ $response_info->{data} }{$key_url};
 | 
						|
                }
 | 
						|
                if ($key_url eq "Progress") {
 | 
						|
                    $progress_state{$version} = ${ $response_info->{data} }{$key_url};
 | 
						|
                }
 | 
						|
                if ($key_url eq "Priority") {
 | 
						|
                    $priority_state{$version} = ${ $response_info->{data} }{$key_url};
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        my $firm_msg;
 | 
						|
        my $version_num = 0;
 | 
						|
        my $rsp;
 | 
						|
        my $length = keys %activation_state;
 | 
						|
        foreach my $firm_version (keys %activation_state) {
 | 
						|
            if ($firm_version eq "default") {
 | 
						|
                $firm_msg = "Firmware";
 | 
						|
            } else {
 | 
						|
                $firm_msg = "Firmware $firm_version";
 | 
						|
            }
 | 
						|
            if ($activation_state{$firm_version} =~ /Software.Activation.Activations.Failed/) {
 | 
						|
                # Activation failed. Report error and exit
 | 
						|
                my $flash_failed_msg = "$firm_msg activation failed.";
 | 
						|
                xCAT::SvrUtils::sendmsg([1,"$flash_failed_msg"], $callback, $node);
 | 
						|
                $update_res = 1;
 | 
						|
                print RFLASH_LOG_FILE_HANDLE "$flash_failed_msg\n";
 | 
						|
                close (RFLASH_LOG_FILE_HANDLE);
 | 
						|
                $node_info{$node}{rst} = "$flash_failed_msg";
 | 
						|
            } elsif ($activation_state{$firm_version} =~ /Software.Activation.Activations.Active/) {
 | 
						|
                if (scalar($priority_state{$firm_version}) == 0) {
 | 
						|
                    $version_num ++;
 | 
						|
                    my $flash_success_msg = "$node: $firm_msg activation successful.";
 | 
						|
                    push @{ $rsp->{data} },$flash_success_msg;
 | 
						|
                    # Activation state of active and priority of 0 indicates the activation has been completed
 | 
						|
                    if ( $length == $version_num ) {
 | 
						|
                        xCAT::MsgUtils->message("I", $rsp, $callback) if ($rsp);
 | 
						|
                        print RFLASH_LOG_FILE_HANDLE "$flash_success_msg\n";
 | 
						|
                        $node_info{$node}{rst} = "$flash_success_msg";
 | 
						|
                        if (!$::UPLOAD_ACTIVATE_STREAM) {
 | 
						|
                            $wait_node_num--;
 | 
						|
                            return;
 | 
						|
                        }
 | 
						|
                        else{
 | 
						|
                            $next_status{ $node_info{$node}{cur_status} } = "RPOWER_BMCREBOOT_REQUEST";
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                } else {
 | 
						|
                    # Activation state of active and priority of non 0 - need to just set priority to 0 to activate
 | 
						|
                    print "$firm_version update is already active, just need to set priority to 0\n";
 | 
						|
                    if ($::UPLOAD_ACTIVATE_STREAM) {
 | 
						|
                         $status_info{RFLASH_SET_PRIORITY_REQUEST}{init_url} =
 | 
						|
                             $::SOFTWARE_URL . "/$update_ids{$firm_version}/attr/Priority";
 | 
						|
                    }
 | 
						|
                    $next_status{ $node_info{$node}{cur_status} } = "RFLASH_SET_PRIORITY_REQUEST";
 | 
						|
                }
 | 
						|
            } elsif ($activation_state{$firm_version} =~ /Software.Activation.Activations.Activating/) {
 | 
						|
                my $activating_progress_msg = "Activating $firm_msg...  $progress_state{$firm_version}\%";
 | 
						|
                if ($::VERBOSE) {
 | 
						|
                    xCAT::SvrUtils::sendmsg("$activating_progress_msg", $callback, $node);
 | 
						|
                }
 | 
						|
                print RFLASH_LOG_FILE_HANDLE "$activating_progress_msg\n";
 | 
						|
                close (RFLASH_LOG_FILE_HANDLE);
 | 
						|
                # Activation still going, sleep for a bit, then print the progress value
 | 
						|
                # Set next state to come back here to chect the activation status again.
 | 
						|
                retry_after($node, "RFLASH_UPDATE_CHECK_STATE_REQUEST", 15);
 | 
						|
                return;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if ($update_res) {
 | 
						|
            close (RFLASH_LOG_FILE_HANDLE);
 | 
						|
            $wait_node_num--;
 | 
						|
            return;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RFLASH_UPDATE_CHECK_ID_RESPONSE") {
 | 
						|
        my $activation_state;
 | 
						|
        my $progress_state;
 | 
						|
        my $priority_state;
 | 
						|
        my $found_match = 0;
 | 
						|
        my $found_pnor_match = 0;
 | 
						|
        my $debugmsg;
 | 
						|
 | 
						|
        if ($xcatdebugmode) {
 | 
						|
            $debugmsg = "CHECK_ID_RESPONSE: Looking for software ID: $::UPLOAD_FILE_VERSION $::UPLOAD_PNOR_VERSION...";
 | 
						|
            process_debug_info($node, $debugmsg);
 | 
						|
        }
 | 
						|
        # Look through all the software entries and find the id of the one that matches
 | 
						|
        # the version of the uploaded file. Once found, set up request/response hash entries
 | 
						|
        # to activate that image.
 | 
						|
        foreach my $key_url (keys %{$response_info->{data}}) {
 | 
						|
            my %content = %{ ${ $response_info->{data} }{$key_url} };
 | 
						|
 | 
						|
            $update_id = (split(/\//, $key_url))[ -1 ];
 | 
						|
            if (defined($content{Version}) and $content{Version}) {
 | 
						|
                $update_version = $content{Version};
 | 
						|
                if ($xcatdebugmode) {
 | 
						|
                    $debugmsg = "CHECK_ID_RESPONSE: key_url=$key_url version=$update_version";
 | 
						|
                    process_debug_info($node, $debugmsg);
 | 
						|
                }
 | 
						|
                if ($update_version eq $::UPLOAD_FILE_VERSION) {
 | 
						|
                    $found_match = 1;
 | 
						|
                    # Found a match of uploaded file version with the image in software/enumerate
 | 
						|
 | 
						|
                    # If we have a saved expected hash ID, compare it to the one just found
 | 
						|
                    if ($::UPLOAD_FILE_HASH_ID && ($::UPLOAD_FILE_HASH_ID ne $update_id)) {
 | 
						|
                        xCAT::SvrUtils::sendmsg([1,"Firmware uploaded but activation cancelled due to hash ID mismatch. $update_id does not match expected $::UPLOAD_FILE_HASH_ID. Verify BMC firmware is at the latest level."], $callback, $node);
 | 
						|
                        $wait_node_num--;
 | 
						|
                        return; # Stop processing for this node, do not activate. Firmware shold be left in "Ready" state.
 | 
						|
                    }
 | 
						|
                    # Set the image id for the activation request
 | 
						|
                    $status_info{RFLASH_UPDATE_ACTIVATE_REQUEST}{init_url} =
 | 
						|
                       $::SOFTWARE_URL . "/$update_id/attr/RequestedActivation";
 | 
						|
                    $status_info{RFLASH_UPDATE_CHECK_STATE_REQUEST}{init_url} =
 | 
						|
                       $::SOFTWARE_URL . "/enumerate";
 | 
						|
                    $status_info{RFLASH_SET_PRIORITY_REQUEST}{init_url} =
 | 
						|
                       $::SOFTWARE_URL . "/$update_id/attr/Priority";
 | 
						|
 | 
						|
                    my $upload_success_msg = "Firmware upload successful. Attempting to activate firmware: $::UPLOAD_FILE_VERSION (ID: $update_id)";
 | 
						|
                    xCAT::SvrUtils::sendmsg("$upload_success_msg", $callback, $node);
 | 
						|
                    print RFLASH_LOG_FILE_HANDLE "$upload_success_msg\n";
 | 
						|
                } elsif ($update_version eq $::UPLOAD_PNOR_VERSION) {
 | 
						|
                    $found_pnor_match = 1;
 | 
						|
                    if ($::UPLOAD_PNOR_HASH_ID && ($::UPLOAD_PNOR_HASH_ID ne $update_id)) {
 | 
						|
                        xCAT::SvrUtils::sendmsg([1,"Firmware uploaded but activation cancelled due to hash ID mismatch. $update_id does not match expected $::UPLOAD_PNOR_HASH_ID. Verify BMC firmware is at the latest level."], $callback, $node);
 | 
						|
                        $wait_node_num--;
 | 
						|
                        return;
 | 
						|
                    }
 | 
						|
                    $status_info{RFLASH_UPDATE_HOST_ACTIVATE_REQUEST}{init_url} =
 | 
						|
                       $::SOFTWARE_URL . "/$update_id/attr/RequestedActivation";
 | 
						|
                    $status_info{RFLASH_UPDATE_CHECK_STATE_REQUEST}{init_url} =
 | 
						|
                       $::SOFTWARE_URL . "/enumerate";
 | 
						|
                    $status_info{RFLASH_SET_PRIORITY_REQUEST}{init_url} =
 | 
						|
                       $::SOFTWARE_URL . "/$update_id/attr/Priority";
 | 
						|
                    my $upload_success_msg = "Firmware upload successful. Attempting to activate firmware: $::UPLOAD_PNOR_VERSION (ID: $update_id)";
 | 
						|
                    xCAT::SvrUtils::sendmsg("$upload_success_msg", $callback, $node);
 | 
						|
                    print RFLASH_LOG_FILE_HANDLE "$upload_success_msg\n";
 | 
						|
                }
 | 
						|
 | 
						|
            }
 | 
						|
        }
 | 
						|
        if ($::UPLOAD_ACTIVATE_STREAM and (!$found_match or !$found_pnor_match) or !$found_match) {
 | 
						|
            if (!exists($node_info{$node}{upload_wait_attemp})) {
 | 
						|
                $node_info{$node}{upload_wait_attemp} = $::UPLOAD_WAIT_ATTEMPT;
 | 
						|
            }
 | 
						|
            my $upload_file_version = "";
 | 
						|
            if (!$found_match) {
 | 
						|
                $upload_file_version = $::UPLOAD_FILE_VERSION;
 | 
						|
            } else {
 | 
						|
                $upload_file_version = $::UPLOAD_PNOR_VERSION;
 | 
						|
            }
 | 
						|
            if($node_info{$node}{upload_wait_attemp} > 0) {
 | 
						|
                $node_info{$node}{upload_wait_attemp} --;
 | 
						|
                my $retry_msg = "Could not find ID for firmware $upload_file_version to activate, waiting $::UPLOAD_WAIT_INTERVAL seconds and retry...";
 | 
						|
                if ($::VERBOSE) {
 | 
						|
                    xCAT::SvrUtils::sendmsg("$retry_msg", $callback, $node);
 | 
						|
                }
 | 
						|
                print RFLASH_LOG_FILE_HANDLE "$retry_msg\n";
 | 
						|
                close (RFLASH_LOG_FILE_HANDLE);
 | 
						|
                retry_after($node, "RFLASH_UPDATE_CHECK_ID_REQUEST", $::UPLOAD_WAIT_INTERVAL);
 | 
						|
                return;
 | 
						|
            } else {
 | 
						|
                my $no_firmware_msg = "Could not find firmware $upload_file_version after waiting $::UPLOAD_WAIT_TOTALTIME seconds.";
 | 
						|
                xCAT::SvrUtils::sendmsg([1,"$no_firmware_msg"], $callback, $node);
 | 
						|
                print RFLASH_LOG_FILE_HANDLE "$no_firmware_msg\n";
 | 
						|
                close (RFLASH_LOG_FILE_HANDLE);
 | 
						|
                $node_info{$node}{rst} = "$no_firmware_msg";
 | 
						|
                $wait_node_num--;
 | 
						|
                return;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if ($node_info{$node}{cur_status} eq "RFLASH_DELETE_IMAGE_RESPONSE") {
 | 
						|
        xCAT::SvrUtils::sendmsg("Firmware removed", $callback, $node);
 | 
						|
    }
 | 
						|
 | 
						|
    close (RFLASH_LOG_FILE_HANDLE);
 | 
						|
 | 
						|
    if ($next_status{ $node_info{$node}{cur_status} }) {
 | 
						|
        $node_info{$node}{cur_status} = $next_status{ $node_info{$node}{cur_status} };
 | 
						|
        if ($node_info{$node}{method} || $status_info{ $node_info{$node}{cur_status} }{method}) {
 | 
						|
            gen_send_request($node);
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        $wait_node_num--;
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
sub rflash_upload {
 | 
						|
    my ($node, $callback) = @_;
 | 
						|
    my $request_url = "$http_protocol://" . $node_info{$node}{bmc};
 | 
						|
    my $content_login = '{ "data": [ "' . $node_info{$node}{username} .'", "' . $node_info{$node}{password} . '" ] }';
 | 
						|
    my $content_logout = '{ "data": [ ] }';
 | 
						|
    my $cjar_id = "/tmp/_xcat_cjar.$node";
 | 
						|
    my %curl_upload_cmds;
 | 
						|
    # curl commands
 | 
						|
    my $curl_login_cmd  = "curl -c $cjar_id -k -H 'Content-Type: application/json' -X POST $request_url/login -d '" . $content_login . "'";
 | 
						|
    my $curl_logout_cmd = "curl -b $cjar_id -k -H 'Content-Type: application/json' -X POST $request_url/logout -d '" . $content_logout . "'";
 | 
						|
     my $curl_check_cpu_dd_cmd = "curl -b $cjar_id -k -H 'Content-Type: application/json' -X GET $request_url/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu0 | grep Version | cut -d: -f2";
 | 
						|
 | 
						|
    if (%fw_tar_files) {
 | 
						|
        foreach my $key (keys %fw_tar_files) {
 | 
						|
            my $curl_upload_cmd = "curl -b $cjar_id -k -H 'Content-Type: application/octet-stream' -X PUT -T " . $key . " $request_url/upload/image/";
 | 
						|
            $curl_upload_cmds{$key}=$curl_upload_cmd;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    my $rflash_log_file = xCAT::Utils->full_path($node.".log", $::XCAT_LOG_RFLASH_DIR);
 | 
						|
    open (RFLASH_LOG_FILE_HANDLE, ">> $rflash_log_file");
 | 
						|
 | 
						|
    # Try to login
 | 
						|
    my $curl_login_result = `$curl_login_cmd -s`;
 | 
						|
    my $h;
 | 
						|
    if (!$curl_login_result) {
 | 
						|
        my $curl_error = "$::FAILED_UPLOAD_MSG. Did not receive response from OpenBMC after running command '$curl_login_cmd'";
 | 
						|
        xCAT::SvrUtils::sendmsg([1, "$curl_error"], $callback, $node);
 | 
						|
        print RFLASH_LOG_FILE_HANDLE "$curl_error\n";
 | 
						|
        $node_info{$node}{rst} = "$curl_error";
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
    eval { $h = from_json($curl_login_result) }; # convert command output to hash
 | 
						|
    if ($@) {
 | 
						|
        my $curl_error = "$::FAILED_UPLOAD_MSG. Received wrong format response for command '$curl_login_cmd': $curl_login_result";
 | 
						|
        xCAT::SvrUtils::sendmsg([1, "$curl_error"], $callback, $node);
 | 
						|
        # Before writing error to log, make it a single line
 | 
						|
        $curl_error =~ tr{\n}{ };
 | 
						|
        print RFLASH_LOG_FILE_HANDLE "$curl_error\n";
 | 
						|
        $node_info{$node}{rst} = "$curl_error";
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
    if ($h->{message} eq $::RESPONSE_OK) {
 | 
						|
        if(%curl_upload_cmds){
 | 
						|
            # Before uploading file, check CPU DD version
 | 
						|
            my $curl_dd_check_result = `$curl_check_cpu_dd_cmd`;
 | 
						|
            if ($curl_dd_check_result =~ "20") {
 | 
						|
                # Display warning the only certain firmware versions are supported on DD 2.0
 | 
						|
                xCAT::SvrUtils::sendmsg("Warning: DD 2.0 processor detected on this node, should not have firmware > ibm-v2.0-0-r13.6 (BMC) and > v1.19_1.94 (Host).", $callback, $node);
 | 
						|
            }
 | 
						|
            if ($curl_dd_check_result =~ "21") {
 | 
						|
                if ($::VERBOSE) {
 | 
						|
                    xCAT::SvrUtils::sendmsg("DD 2.1 processor", $callback, $node);
 | 
						|
                }
 | 
						|
            }
 | 
						|
            while((my $file,my $version)=each(%fw_tar_files)){
 | 
						|
                my $uploading_msg = "Uploading $file ...";
 | 
						|
                my $upload_cmd = $curl_upload_cmds{$file};
 | 
						|
                # Login successfull, upload the file
 | 
						|
                if ($::VERBOSE) {
 | 
						|
                    xCAT::SvrUtils::sendmsg("$uploading_msg", $callback, $node);
 | 
						|
                }
 | 
						|
                print RFLASH_LOG_FILE_HANDLE "$uploading_msg\n";
 | 
						|
 | 
						|
                if ($xcatdebugmode) {
 | 
						|
                    my $debugmsg = "RFLASH_FILE_UPLOAD_RESPONSE: CMD: $upload_cmd";
 | 
						|
                    process_debug_info($node, $debugmsg);
 | 
						|
                }
 | 
						|
                my $curl_upload_result = `$upload_cmd`;
 | 
						|
                if (!$curl_upload_result) {
 | 
						|
                    my $curl_error = "$::FAILED_UPLOAD_MSG. Did not receive response from OpenBMC after running command '$upload_cmd'";
 | 
						|
                    xCAT::SvrUtils::sendmsg([1, "$curl_error"], $callback, $node);
 | 
						|
                    print RFLASH_LOG_FILE_HANDLE "$curl_error\n";
 | 
						|
                    $node_info{$node}{rst} = "$curl_error";
 | 
						|
                    return 1;
 | 
						|
                }
 | 
						|
                eval { $h = from_json($curl_upload_result) }; # convert command output to hash
 | 
						|
                if ($@) {
 | 
						|
                    my $curl_error = "$::FAILED_UPLOAD_MSG. Received wrong format response from command '$upload_cmd': $curl_upload_result";
 | 
						|
                    xCAT::SvrUtils::sendmsg([1, "$curl_error"], $callback, $node);
 | 
						|
                    # Before writing error to log, make it a single line
 | 
						|
                    $curl_error =~ tr{\n}{ };
 | 
						|
                    print RFLASH_LOG_FILE_HANDLE "$curl_error\n";
 | 
						|
                    $node_info{$node}{rst} = "$curl_error";
 | 
						|
                    return 1;
 | 
						|
                }
 | 
						|
                if ($h->{message} eq $::RESPONSE_OK) {
 | 
						|
                    # Upload successful, display message
 | 
						|
                    my $upload_success_msg = "Firmware upload successful. Use -l option to list.";
 | 
						|
                    unless ($::UPLOAD_AND_ACTIVATE or $::UPLOAD_ACTIVATE_STREAM) {
 | 
						|
                        xCAT::SvrUtils::sendmsg("$upload_success_msg", $callback, $node);
 | 
						|
                    }
 | 
						|
                    #Put a delay of 3 seconds to allow time for the BMC to untar the file we just uploaded
 | 
						|
                    if (defined($::UPLOAD_ACTIVATE_STREAM)){
 | 
						|
                        sleep 3;
 | 
						|
                    }
 | 
						|
                    print RFLASH_LOG_FILE_HANDLE "$upload_success_msg\n";
 | 
						|
                    # Try to logoff, no need to check result, as there is nothing else to do if failure
 | 
						|
                } else {
 | 
						|
                    my $upload_fail_msg = $::FAILED_UPLOAD_MSG . " $file :" . $h->{message} . " - " . $h->{data}->{description};
 | 
						|
                    xCAT::SvrUtils::sendmsg("$upload_fail_msg", $callback, $node);
 | 
						|
                    print RFLASH_LOG_FILE_HANDLE "$upload_fail_msg\n";
 | 
						|
                    close (RFLASH_LOG_FILE_HANDLE);
 | 
						|
                    $node_info{$node}{rst} = "$upload_fail_msg";
 | 
						|
                    return 1;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        # Try to logoff, no need to check result, as there is nothing else to do if failure
 | 
						|
        my $curl_logout_result = `$curl_logout_cmd -s`;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        my $unable_login_msg = "Unable to login :" . $h->{message} . " - " . $h->{data}->{description};
 | 
						|
        xCAT::SvrUtils::sendmsg("$unable_login_msg", $callback, $node);
 | 
						|
        print RFLASH_LOG_FILE_HANDLE "$unable_login_msg\n";
 | 
						|
        close (RFLASH_LOG_FILE_HANDLE);
 | 
						|
        $node_info{$node}{rst} = "$unable_login_msg";
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    close (RFLASH_LOG_FILE_HANDLE);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  is_valid_config_api
 | 
						|
 | 
						|
  Verify passed in subcommand is defined in the api_config_info
 | 
						|
  Input:
 | 
						|
        $subcommand: subcommand to verify
 | 
						|
        $callback: callback for message display
 | 
						|
 | 
						|
  Output:
 | 
						|
        returns index into the hash of the $subcommand
 | 
						|
        returns -1 if no match
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub is_valid_config_api {
 | 
						|
    my ($subcommand, $callback) = @_;
 | 
						|
 | 
						|
    my $subcommand_key = $subcommand;
 | 
						|
    my $subcommand_value;
 | 
						|
    if ($subcommand =~ /^(\w+)=(.*)/) {
 | 
						|
        $subcommand_key = $1;
 | 
						|
        $subcommand_value = $2;
 | 
						|
    }
 | 
						|
    foreach my $config_subcommand (keys %api_config_info) {
 | 
						|
        if ($subcommand_key eq $api_config_info{$config_subcommand}{subcommand}) {
 | 
						|
            return $config_subcommand;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  build_config_api_usage
 | 
						|
 | 
						|
  Build usage string from the api_config_info
 | 
						|
  Input:
 | 
						|
        $callback: callback for message display
 | 
						|
        $requested_command:  command for the usage generation
 | 
						|
 | 
						|
  Output:
 | 
						|
        returns usage string
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub build_config_api_usage {
 | 
						|
    my $callback = shift;
 | 
						|
    my $requested_command = shift;
 | 
						|
    my $command = "";
 | 
						|
    my $subcommand = "";
 | 
						|
    my $type = "";
 | 
						|
    my $usage_string = "";
 | 
						|
    my $attr_values = "";
 | 
						|
 | 
						|
    foreach my $config_subcommand (keys %api_config_info) {
 | 
						|
        $command = "";
 | 
						|
        $subcommand = "";
 | 
						|
        $type = "";
 | 
						|
        $attr_values = "";
 | 
						|
        if ($api_config_info{$config_subcommand}{command} eq $requested_command) {
 | 
						|
            $command =  $api_config_info{$config_subcommand}{command};
 | 
						|
            $subcommand =  $api_config_info{$config_subcommand}{subcommand};
 | 
						|
            $type =  $api_config_info{$config_subcommand}{type};
 | 
						|
 | 
						|
            $usage_string .= "       $command <noderange> $subcommand" . "\n";
 | 
						|
 | 
						|
            if ($type eq "boolean") {
 | 
						|
                $usage_string .= "       $command <noderange> $subcommand={0|1}" . "\n";
 | 
						|
            }
 | 
						|
            if (($type eq "attribute") || ($type eq "action_attribute")) {
 | 
						|
                foreach my $attribute_value (keys %{ $api_config_info{$config_subcommand}{attr_value} }) {
 | 
						|
                    $attr_values .= $attribute_value . "|"
 | 
						|
                }
 | 
						|
                chop $attr_values;
 | 
						|
                $usage_string .= "       $command <noderange> $subcommand={" . $attr_values . "}". "\n";
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return $usage_string;
 | 
						|
}
 | 
						|
1;
 |