#!/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 Sys::Hostname; 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; $::RPOWER_CHECK_ON_TIME = 1; $::RPOWER_RESET_SLEEP_INTERVAL = 13; $::BMC_MAX_RETRY = 20; $::BMC_CHECK_INTERVAL = 15; $::BMC_REBOOT_DELAY = 180; $::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 => "0", # 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_PSR_REQUEST => { method => "GET", init_url => "$openbmc_project_url/control/power_supply_redundancy", }, RSPCONFIG_GET_PSR_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 # rspconfig =0 # rspconfig =1 # rspconfig = # # 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 ' =>