2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-05 20:47:55 +00:00
Files
xcat-core/xCAT-server/lib/xcat/plugins/energy.pm
T
Vinícius Ferrão 0d6929c427 fix(plugins): mask passwords in plugin log messages
Six modules wrote passwords to their own log and diagnostic messages,
outside the daemon redaction pipeline. The z/VM plugin logged each
smcli command line through printSyslog, with the disk read, write and
multi passwords, the image password, the provision root password and
the page volume parm disk password, passed the real disk passwords to
checkSSH_Rc, which echoes the command to syslog and to the client on
failure, and logged raw directory entries whose USER and MDISK
statements carry the logon and disk passwords. The bmcconfig plugin
logged the BMC password in its attribute report, in syslog and in the
command response. The energy plugin logged the HCP password in a
verbose message, and the CIM utilities dumped the whole HTTP request,
with its basic authorization header, to the verbose callback. The PPC
configuration module logged the HMC, FSP and BPA passwords in its
verbose credential reports.

Mask the passwords in the logged text. The executed commands keep the
real values. The page volume log string is built by operand position,
so a decoy value in another operand cannot divert the mask. The
checkSSH_Rc calls receive the masked command string, as the routine
documentation asks. Add redact_directory_entry to the z/VM utilities.
The routine masks the USER, IDENTITY and IDENT logon password, the
MDISK passwords after the access mode in the range form and in the
DEVNO, V-DISK and T-DISK forms, the APPCPASS statement, and the
keyword password assignments in the short and the full spelling. The
match separators stay on one line, so a record without passwords never
masks the record below it, and one or more comment stars do not hide a
credential record from the rules. The COMMAND statement masks whole,
because it can start any CP command with an inline password. Every directory query sink logs
through it,
and the clone loops redact the query output at the source, because the
failure checker and the retained disk list reuse the text. The
directory helpers keep their raw return value for the callers and hand
a redacted copy to the failure checker. Every error branch that echoes
a fetched record after the output check does so through the redactor,
because a password can spell an error word and trip the check: the
directory fetch, the mini disk keyword fetch, and the four disk list
callers. The CIM dump masks
the authorization header. The bmcconfig report now names the password
state, set or missing, which the report needs for diagnosis.
2026-09-02 01:28:19 -03:00

1191 lines
42 KiB
Perl

#!/usr/bin/perl
# IBM(c) 2014 EPL license http://www.eclipse.org/legal/epl-v10.html
=head3 xCAT_plugin::energy
This plugin module is used to handle the renergy command for:
FSP based Power 8 machine.
1. mgt=fsp, mtm=(p8); 2. mgt=ipmi, arch=ppc64le;
=cut
package xCAT_plugin::energy;
BEGIN
{
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
}
use lib "$::XCATROOT/lib/perl";
use strict;
use warnings "all";
use Getopt::Long;
use IO::Socket;
use Thread qw(yield);
use POSIX "WNOHANG";
use Storable qw(store_fd fd_retrieve);
use xCAT::Usage;
use xCAT::CIMUtils;
use xCAT::MsgUtils;
use xCAT::Table;
use xCAT::FSPUtils;
use xCAT::NetworkUtils;
sub handled_commands {
return {
renergy => 'nodehm:mgt=ipmi|fsp',
}
}
my $parent_fd;
# The hash includes all valid attribute for quering
my %QUERY_ATTRS = (
'savingstatus' => 1,
'dsavingstatus' => 1,
'cappingstatus' => 1,
'cappingmaxmin' => 1,
'cappingvalue' => 1,
'cappingsoftmin' => 1,
'averageAC' => 1,
'averageAChistory' => 1,
'averageDC' => 1,
'averageDChistory' => 1,
'ambienttemp' => 1,
'ambienttemphistory' => 1,
'exhausttemp' => 1,
'exhausttemphistory' => 1,
'CPUspeed' => 1,
'CPUspeedhistory' => 1,
'fanspeed' => 1,
'fanspeedhistory' => 1,
'syssbpower' => 1,
'sysIPLtime' => 1,
# for FFO, only supported when communicating to fsp directly
'ffoMin' => 1,
'ffoVmin' => 1,
'ffoTurbo' => 1,
'ffoNorm' => 1,
'fsavingstatus' => 1,
'ffovalue' => 1,
);
# The hash includes all valid attribute for writting
my %SET_ATTRS = (
'savingstatus' => 1,
'dsavingstatus' => 1,
'cappingstatus' => 1,
'cappingwatt' => 1,
'cappingperc' => 1,
# for FFO
'fsavingstatus' => 1,
'ffovalue' => 1,
);
=head3 parse_args
DESCRIPTION:
Parse the arguments from the command line of renergy command
ARGUMENTS:
The request hash from preprocess_request or process_request
RETURN
First element: rc: 0 -success; 1 - fail
Second element:
1. a string: a message for display;
2. a reference to a hash: {verbose}, {query_list} and {set_pair}.
=cut
sub parse_args {
my $request = shift;
my $opt = ();
my $cmd = $request->{command}->[0];
my $args = $request->{arg};
my $nodes = $request->{node};
my @query_list = (); # The attributes list for query operation
my @set_pair = (); # The attribute need to be set. e.g. savingstatus=on
my $set_flag = (); # Indicate there's setting param in the argv
my $query_flag = (); # Indicate there's param in the argv
# set the usage subroutine
local *usage = sub {
my $add_msg = shift;
my $usage_string = xCAT::Usage->getUsage($cmd);
if ($add_msg) {
return ("$add_msg\n" . $usage_string);
} else {
return ($usage_string);
}
};
# handle the arguments
if ($request->{arg}) {
@ARGV = @{ $request->{arg} };
$Getopt::Long::ignorecase = 0;
Getopt::Long::Configure("bundling");
if (!GetOptions('V' => \$::VERBOSE,
'h|help' => \$::HELP,
'v|version' => \$::VERSION)) {
return (1, &usage());
}
if ($::HELP && $::VERSION) {
return (1, &usage());
}
if ($::HELP) {
return (0, &usage());
}
if ($::VERSION) {
my $version_string = xCAT::Usage->getVersion('renergy');
return (0, $version_string);
}
if ($::VERBOSE) {
$opt->{verbose} = 1;
}
} else {
return (1, &usage());
}
# if the request has node range
if ($nodes) {
# the default option is query all attributes
if ($#ARGV < 0) {
$ARGV[0] = "all";
}
# Check the validity of the parameters of Query and Set
# Forbid to perform both query and set
foreach my $attr (@ARGV) {
my ($set_attr, $set_value) = split(/=/, $attr);
if (defined($set_value)) {
if ($query_flag) {
return (1, &usage("Cannot perform both Query and Set."));
}
# make sure the attribute is valid
if ($SET_ATTRS{$set_attr} != 1) {
return (1, &usage("Invalid attribute."));
}
if ($set_flag) {
return (1, &usage("Only supports to perform one setting at invoke."));
}
# make sure the value for attirbute is valid
if (($set_attr eq "savingstatus" || $set_attr eq "fsavingstatus")
&& ($set_value ne "on" && $set_value ne "off")) {
return (1, &usage("Incorrect Value"));
} elsif ($set_attr eq "dsavingstatus"
&& ($set_value ne "off"
&& $set_value ne "on-norm" && $set_value ne "on-maxp")) {
return (1, &usage("Incorrect Value"));
} elsif ($set_attr eq "cappingstatus"
&& ($set_value ne "on" && $set_value ne "off")) {
return (1, &usage("Incorrect Value"));
} elsif (($set_attr eq "cappingwatt"
|| $set_attr eq "cappingperc" || $set_attr eq "ffovalue")
&& $set_value =~ /\D/) {
return (1, &usage("Incorrect Value"));
}
push @set_pair, $set_attr . "=" . $set_value;
$set_flag = 1;
} else {
if ($set_flag) {
return (1, &usage("Cannot perform both Query and Set."));
}
# replace the 'all' with all valid attribute
if ($attr eq "all") {
foreach my $q_attr (keys %QUERY_ATTRS) {
# do not include 'history' related attributes for all keyword
if ($q_attr =~ /history$/) {
next;
}
if (!grep (/^$q_attr$/, @query_list)) {
push @query_list, $q_attr;
}
}
} else {
# make sure the query attribute is valid
if ($QUERY_ATTRS{$attr} != 1) {
return (1, &usage("Invalid attribute."));
}
if (!grep (/^$attr$/, @query_list)) {
push @query_list, $attr;
}
}
$query_flag = 1;
}
}
} else {
# no noderange, do nothing
return (1, &usage());
}
if (@query_list) {
$opt->{'query_list'} = join(',', @query_list);
} elsif (@set_pair) {
$opt->{'set_pair'} = join(',', @set_pair);
}
return (0, $opt);
}
sub preprocess_request
{
my $req = shift;
my $callback = shift;
# Exit if the packet has been preprocessed
if (defined($req->{_xcatpreprocessed}->[0]) && $req->{_xcatpreprocessed}->[0] == 1) { return [$req]; }
# This plugin only handle the node which is 1. mgt=fsp, mtm=(p8); 2. mgt=ipmi, arch=ppc64le;
# otherwise, make other plugin to handle it
my (@mpnodes, @fspnodes, @bmcnodes, @nohandle);
xCAT::Utils->filter_nodes($req, \@mpnodes, \@fspnodes, \@bmcnodes, \@nohandle);
# Find the nodes which are not handled by mp (@mpnodes), fsp (@fspnodes) and bmc (@bmcnods), and not in @nohandle.
# They are the one of p8_fsp nodes which should be handled by this plugin
my %tmphash = map { $_ => 1 } (@mpnodes, @fspnodes, @bmcnodes, @nohandle);
my @nodes = grep { not $tmphash{$_} } @{ $req->{node} };
# build request array
my @requests;
if (@nodes) {
my ($rc, $args) = parse_args($req);
if ($rc) {
# error or message display happens
xCAT::MsgUtils->message("E", { error => [$args], errorcode => [$rc] }, $callback);
return [];
} else {
unless (ref($args)) {
xCAT::MsgUtils->message("I", { data => [$args] }, $callback);
return [];
}
}
# do nothing if no query or setting required.
unless (defined($args->{query_list}) || defined($args->{set_pair})) {
return [];
}
my $sn = xCAT::ServiceNodeUtils->get_ServiceNode(\@nodes, 'xcat', 'MN');
# Build each request for each service node
foreach my $snkey (keys %$sn) {
my $reqcopy = {%$req};
$reqcopy->{node} = $sn->{$snkey};
$reqcopy->{'_xcatdest'} = $snkey;
$reqcopy->{_xcatpreprocessed}->[0] = 1;
if (defined($args->{verbose})) {
$reqcopy->{verbose} = $args->{verbose};
}
if (defined($args->{query_list})) {
$reqcopy->{query_list} = $args->{query_list};
}
if (defined($args->{set_pair})) {
$reqcopy->{set_pair} = $args->{set_pair};
}
push @requests, $reqcopy;
}
return \@requests;
}
return [];
}
sub process_request {
my $request = shift;
my $callback = shift;
my $subreq = shift;
my $verbose;
my $nodes = $request->{node};
my $args = $request->{arg};
if (defined($request->{verbose})) {
$verbose = $request->{verbose};
}
# get the password for the nodes
my $user_default = "admin";
my $password_default = "admin";
my $ipmi_tab = xCAT::Table->new('ipmi', -create => 0);
my $ipmi_hash;
if ($ipmi_tab) {
$ipmi_hash = $ipmi_tab->getNodesAttribs($request->{node}, [ 'bmc', 'username', 'password' ]);
}
my $ppc_tab = xCAT::Table->new('ppc', -create => 0);
my $ppc_hash;
my @ppc_all_entry;
my $cec2fsp;
if ($ppc_tab) {
$ppc_hash = $ppc_tab->getNodesAttribs($request->{node}, [ 'hcp', 'nodetype' ]);
}
my $nodehm_tab = xCAT::Table->new('nodehm', -create => 0);
my $nodehm_hash;
if ($nodehm_tab) {
$nodehm_hash = $nodehm_tab->getNodesAttribs($request->{node}, ['mgt']);
}
# get the 'fsp' key from the passwd table
my $passwd_tab = xCAT::Table->new('passwd', -create => 0);
my $passwd_hash;
if ($passwd_tab) {
$passwd_hash = $passwd_tab->getAttribs({ key => 'fsp' }, qw(username password));
}
my $ppcdirect_tab = xCAT::Table->new('ppcdirect', -create => 0);
my $children; # The number of child process
my %sp_children; # Record the pid of child process
my $sub_fds = new IO::Select; # Record the parent fd for each child process
# Set the signal handler for ^c
$SIG{TERM} = $SIG{INT} = sub {
foreach (keys %sp_children) {
kill 2, $_;
}
$SIG{ALRM} = sub {
while (wait() > 0) {
yield;
}
exit @_;
};
alarm(1); # wait 1s for grace exit
};
# Set the singal handler for child process finished it's work
$SIG{CHLD} = sub {
my $cpid;
while (($cpid = waitpid(-1, WNOHANG)) > 0) {
if ($sp_children{$cpid}) {
delete $sp_children{$cpid};
$children--;
}
}
};
# Do run each node
foreach my $node (@{ $request->{node} }) {
my $user = $user_default;
my $password = $password_default;
my $hcp_ip;
if (defined($nodehm_hash->{$node}->[0]->{mgt})) {
my $mgt = $nodehm_hash->{$node}->[0]->{mgt};
if ($mgt eq 'fsp') {
# This is Power node which is running in PowerVM mode
unless (@ppc_all_entry) {
@ppc_all_entry = $ppc_tab->getAllNodeAttribs([ 'node', 'parent', 'hcp', 'nodetype' ]);
foreach my $ppcentry (@ppc_all_entry) {
if (defined($ppcentry->{parent}) && defined($ppcentry->{nodetype}) && $ppcentry->{nodetype} =~ /fsp/) {
$cec2fsp->{ $ppcentry->{parent} } .= "$ppcentry->{node},";
}
}
}
$hcp_ip = $cec2fsp->{$node};
# Get the user/password for the node
if ($ppcdirect_tab) {
my $ppcdirect_hash = $ppcdirect_tab->getAttribs({ hcp => $node, username => $user }, 'password');
if ($ppcdirect_hash) {
$password = $ppcdirect_hash->{'password'};
}
}
} elsif ($mgt eq 'ipmi') {
if (defined($ipmi_hash->{$node}->[0]->{bmc})) {
# This is a ipmi managed node. (should be a ppcle)
$hcp_ip = $ipmi_hash->{$node}->[0]->{bmc};
# Get the passwd from passwd table for 'fsp' first, if not the default will be used
if (defined($passwd_hash->{username}) && defined($passwd_hash->{password})) {
$user = $passwd_hash->{username};
$password = $passwd_hash->{password};
}
} else {
xCAT::MsgUtils->message("E", { data => ["$node: Missed attribute [bmc]."] }, $callback);
return 1;
}
} else {
xCAT::MsgUtils->message("E", { data => ["$node: Support the valid mgt [fsp, ipmi]."] }, $callback);
return 1;
}
} else {
xCAT::MsgUtils->message("E", { data => ["$node: Missed important attributes [mgt] to know how to handle this node."] }, $callback);
return 1;
}
unless ($hcp_ip) {
xCAT::MsgUtils->message("E", { data => ["$node: Cannot find HCP"] }, $callback);
return 1;
}
# fork a sub process to handle the communication with service processor
$children++;
my $cfd;
# the $parent_fd will be used by &send_rep() to send response from child process to parent process
socketpair($parent_fd, $cfd, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die "socketpair: $!";
$cfd->autoflush(1);
$parent_fd->autoflush(1);
my $child = xCAT::Utils->xfork;
if ($child == 0) {
close($cfd);
$0 = $0 . " for node [$node]";
$callback = \&send_rep;
foreach my $ip (split(',', $hcp_ip)) {
unless ($ip) { next; }
my $real_ip = xCAT::NetworkUtils->getipaddr($ip);
unless ($real_ip) {
xCAT::MsgUtils->message("E", { error => ["$node: Cannot get ip for $ip"], errorcode => [1] }, $callback);
next;
}
my %args = (
node => $node,
ip => $real_ip,
port => '5989',
method => 'POST',
user => $user,
password => $password);
if ($verbose) {
$args{verbose} = 1;
$args{callback} = $callback;
xCAT::MsgUtils->message("I", { data => ["$node: Access hcp [$ip], user [$user], password [xxxxxxxx]"] }, $callback);
}
# call the cim utils to connect to cim server
my $ret = run_cim($request, $callback, \%args);
# 0 - success; 1 - cim error; 10 - ip is not pingable; 11 - this ip is a standby fsp
unless ($ret == 10 || $ret == 11) {
last;
}
}
exit(0);
} else {
# in the main process, record the created child process and add parent fd for the child process to an IO:Select object
# the main process will check all the parent fd and receive response
$sp_children{$child} = 1;
close($parent_fd);
$sub_fds->add($cfd);
}
}
# receive data from child processes
while ($sub_fds->count > 0 or $children > 0) {
forward_data($callback, $sub_fds);
}
while (forward_data($callback, $sub_fds)) { }
}
=head3 send_rep
DESCRIPTION:
Send date from forked child process to parent process.
This subroutine will be replace the original $callback in the forked child process
ARGUMENTS:
$resp - The response which generated in xCAT::Utils->message();
=cut
sub send_rep {
my $resp = shift;
unless ($resp) { return; }
store_fd($resp, $parent_fd);
}
=head3 forward_data
DESCRIPTION:
Receive data from forked child process and call the original $callback to forward data to xcat client
=cut
sub forward_data {
my $callback = shift;
my $fds = shift;
my @ready_fds = $fds->can_read(1);
my $rfh;
my $rc = @ready_fds;
foreach $rfh (@ready_fds) {
my $data;
my $responses;
eval {
$responses = fd_retrieve($rfh);
};
if ($@ and $@ =~ /^Magic number checking on storable file/) { #this most likely means we ran over the end of available input
$fds->remove($rfh);
close($rfh);
} else {
eval { print $rfh "ACK\n"; }; #Ignore ack loss due to child giving up and exiting, we don't actually explicitly care about the acks
$callback->($responses);
}
}
yield; #Try to avoid useless iterations as much as possible
return $rc;
}
=head3 query_pum
DESCRIPTION:
Query the attribute for instance of FipS_PUMService class
ARGUMENTS:
$http_params - refer to the HTTP_PARAMS in xCAT::CIMUtils.pm
RETURN
$ret - return code and messages
$pum - a hash includes all the attributes
$namepath - the name path of pum instance
=cut
sub query_pum
{
my $http_params = shift;
my %cimargs = (classname => 'FipS_PUMService');
my ($ret, $value, $namepath) = xCAT::CIMUtils->enum_instance($http_params, \%cimargs);
if ($ret->{rc}) {
return ($ret);
}
# parse the return xml to get all the property of pum instance
my $pum;
if ($value && @$value) {
my $instance = $$value[0];
foreach my $pname (keys %{ $instance->{property} }) {
$pum->{$pname} = $instance->{property}->{$pname}->{value};
}
}
return ($ret, $pum, $namepath);
}
=head3 query_cec_drawer
DESCRIPTION:
Query the attribute for instance of FipS_CECDrawer class
ARGUMENTS:
$http_params - refer to the HTTP_PARAMS in xCAT::CIMUtils.pm
RETURN
$ret - return code and messages
$cec_drawer - a hash includes all the attributes
=cut
sub query_cec_drawer
{
my $http_params = shift;
my %cimargs = (classname => 'FipS_CECDrawer');
my ($ret, $value, $namepath) = xCAT::CIMUtils->enum_instance($http_params, \%cimargs);
if ($ret->{rc}) {
return ($ret);
}
# parse the return xml to get all the property of pum instance
my $cec_drawer;
if ($value && @$value) {
my $instance = $$value[0];
foreach my $pname (keys %{ $instance->{property} }) {
$cec_drawer->{$pname} = $instance->{property}->{$pname}->{value};
}
} else {
return ({ rc => 1, msg => "Cannot find instance for FipS_CECDrawer class" });
}
return ($ret, $cec_drawer, $namepath);
}
=head3 query_metric
DESCRIPTION:
Query the attribute for instance of FipS_*metricValue class
ARGUMENTS:
$http_params - refer to the HTTP_PARAMS in xCAT::CIMUtils.pm
$option - the specified operation
RETURN
$ret - return code and messages
$array - a hash includes all the attributes
=cut
sub query_metric
{
my $http_params = shift;
my $classname = shift;
my $matching_string = shift;
my $value_unit = shift;
if (!defined($value_unit)) {
$value_unit = 1;
}
my %cimargs = (classname => "$classname");
my ($ret, $value) = xCAT::CIMUtils->enum_instance($http_params, \%cimargs);
if ($ret->{rc}) {
return $ret;
}
my ($matching_key, $matching_value) = split /:/, $matching_string;
my %instances_hash = ();
foreach my $instance (@$value) {
my $instance_element = undef;
my $timestamp = undef;
if (defined($instance->{property}->{$matching_key}) and $instance->{property}->{$matching_key}->{value} !~ /$matching_value/) {
next;
}
if (defined($instance->{property}->{InstanceID})) {
$instance_element = $instance->{property}->{InstanceID}->{value};
$instance_element =~ s/ .*$//;
}
if (!defined($instance_element)) {
next;
}
if (defined($instance->{property}->{MeasuredElementName})) {
$instances_hash{$instance_element}->{MeasuredElementName} = $instance->{property}->{MeasuredElementName}->{value};
} else {
next;
}
if (defined($instance->{property}->{TimeStamp})) {
$timestamp = $instance->{property}->{TimeStamp}->{value};
$timestamp =~ s/\..*$//;
}
if (defined($instance->{property}->{MetricValue})) {
if (defined($timestamp)) {
$instances_hash{$instance_element}->{MetricValue}->{$timestamp} = $instance->{property}->{MetricValue}->{value} / $value_unit;
}
}
}
return ($ret, \%instances_hash);
}
=head3 query_tmp
DESCRIPTION:
Require the input and output temperature
=cut
sub query_tmp
{
&query_metric(@_, "FipS_ThermalMetricValue", "InstanceID:InletAirTemp|ExhaustAirTemp", 100);
}
=head3 query_cpuspeed
DESCRIPTION:
Require the cpuspeed history
=cut
sub query_cpuspeed
{
&query_metric(@_, "FipS_CPUUsageMetricValue", "InstanceID:AvgCPUUsage");
}
=head3 query_fanspeed
DESCRIPTION:
Require the fanspeed history
=cut
sub query_fanspeed
{
&query_metric(@_, "FipS_FanSpeedMetricValue", "InstanceID:FansSpeed");
}
=head3 query_powermetric
DESCRIPTION:
Require the AC and DC power comsume history
=cut
sub query_powermetric
{
my $http_params = shift;
$http_params->{timeout} = 500;
my ($ret, $return_hash) = &query_metric($http_params, "FipS_PowerMetricValue", "InstanceID:AvgInputPwr");
if ($ret->{rc}) {
return $ret;
}
my %instances = ();
foreach my $ins (keys %$return_hash) {
if ($return_hash->{$ins}->{MeasuredElementName} =~ /Power Supply/) {
foreach my $timestamp (keys %{ $return_hash->{$ins}->{MetricValue} }) {
if (!exists($instances{"averageAC"}->{MetricValue}->{$timestamp})) {
$instances{"averageAC"}->{MetricValue}->{$timestamp} = $return_hash->{$ins}->{MetricValue}->{$timestamp};
} else {
$instances{"averageAC"}->{MetricValue}->{$timestamp} += $return_hash->{$ins}->{MetricValue}->{$timestamp};
}
}
} else {
$instances{"averageDC"}->{MetricValue} = $return_hash->{$ins}->{MetricValue};
}
}
return ($ret, \%instances);
}
=head3 run_cim
DESCRIPTION:
Handle the Query and Setting of Energy via CIM
ARGUMENTS:
$request
$callback
$http_params - refer to the HTTP_PARAMS in xCAT::CIMUtils.pm
RETURN
First element: rc: 0 -success; 1 - cim error; 10 - ip is not pingable; 11 - this ip is a standby fsp
=cut
sub run_cim
{
my $request = shift;
my $callback = shift;
my $http_params = shift;
my $node = $http_params->{node};
my $output;
my $verbose;
my $query_list;
my $set_pair;
if (defined($request->{verbose})) {
$verbose = $request->{verbose};
}
if (defined($request->{query_list})) {
$query_list = $request->{query_list};
}
if (defined($request->{set_pair})) {
$set_pair = $request->{set_pair};
}
# Try to connect CIM Server to Enumerate CEC object;
# If cannot access this ip, return 10 for caller to connect to the next ip
my $cimargs = {
classname => 'fips_cec',
};
$http_params->{timeout} = 5;
my ($ret, $value) = xCAT::CIMUtils->enum_instance($http_params, $cimargs);
if ($ret->{rc}) {
if ($ret->{msg} =~ /(Couldn't connect to server)|(Can't connect to)/) {
xCAT::MsgUtils->message("E", { data => ["$node: Couldn't connect to server [$http_params->{ip}]."] }, $callback);
return 10;
} else {
xCAT::MsgUtils->message("E", { data => ["$node: $ret->{msg}"] }, $callback);
return 1;
}
}
delete $http_params->{timeout};
# ======start to handle the query and setting======
# Pre-query some specific instances since some instances are common for multiple energy attributes
#my $query_pum_capabilities_flag; # set to query the instance for [FipS_PUMServiceCapabilities]
my $query_pum_flag; # set to query the instance for [FipS_PUMService]
my $query_pum_value; # the pre-queried PUM instance
my $namepath_pum; # the name path of PUM instance
my $query_drawer_flag; # set to query the instance for [FipS_CECDrawer]
my $query_drawer_value; # the pre-queried cec drawer instance
my %query_return_hash = (); # the hash store the returned hashes for query functions
my $query_tmp_value; # the requrest for FipS_ThermalMetricValue class
my $query_cpuspeed_value; # the request for FipS_CPUUsageMetricValue class
my $query_fanspeed_value; # the request for FipS_FanSpeedMetricValue class
my $query_powermetric_value; # the request for FipS_PowerMetricValue class
if ($query_list) {
foreach my $attr (split(',', $query_list)) {
if ($attr =~ /^(savingstatus|dsavingstatus|fsavingstatus|ffoMin|ffoVmin|ffoTurbo|ffoNorm|ffovalue)$/) {
$query_pum_flag = 1;
} elsif ($attr =~ /^(syssbpower|sysIPLtime)$/) {
$query_drawer_flag = 1;
} elsif ($attr =~ /^(ambienttemp|exhausttemp)/) {
$query_tmp_value = 1;
} elsif ($attr =~ /^CPUspeed/) {
$query_cpuspeed_value = 1;
} elsif ($attr =~ /^fanspeed/) {
$query_fanspeed_value = 1;
} elsif ($attr =~ /^(averageAC|averageDC)/) {
$query_powermetric_value = 1;
}
}
}
if ($set_pair) {
my ($set_name, $set_value) = split('=', $set_pair);
if ($set_name =~ /^(savingstatus|dsavingstatus|fsavingstatus|ffovalue)$/) {
$query_pum_flag = 1;
}
}
# query the pre required instances
if ($query_pum_flag) {
($ret, $query_pum_value, $namepath_pum) = query_pum($http_params);
if ($ret->{rc}) {
xCAT::MsgUtils->message("E", { data => ["$node: $ret->{msg}"] }, $callback);
return ($ret->{rc});
}
}
if ($query_drawer_flag) {
($ret, $query_drawer_value) = query_cec_drawer($http_params);
if ($ret->{rc}) {
xCAT::MsgUtils->message("E", { data => ["$node: $ret->{msg}"] }, $callback);
return ($ret->{rc});
}
}
if ($query_powermetric_value) {
my ($tmpret, $tmpvalue) = query_powermetric($http_params);
if ($tmpret->{rc}) {
xCAT::MsgUtils->message("E", { data => ["$node: $ret->{msg}"] }, $callback);
return ($tmpret->{rc});
}
$query_return_hash{query_powermetric} = $tmpvalue;
}
if ($query_fanspeed_value) {
$http_params->{timeout} = 200;
my ($tmpret, $tmpvalue) = query_fanspeed($http_params);
if ($tmpret->{rc}) {
xCAT::MsgUtils->message("E", { data => ["$node: $ret->{msg}"] }, $callback);
return ($tmpret->{rc});
}
$query_return_hash{query_fanspeed} = $tmpvalue;
}
if ($query_cpuspeed_value) {
my ($tmpret, $tmpvalue) = query_cpuspeed($http_params);
if ($tmpret->{rc}) {
xCAT::MsgUtils->message("E", { data => ["$node: $ret->{msg}"] }, $callback);
return ($tmpret->{rc});
}
$query_return_hash{query_cpuspeed} = $tmpvalue;
}
if ($query_tmp_value) {
$http_params->{timeout} = 200;
my ($tmpret, $tmpvalue) = query_tmp($http_params);
if ($tmpret->{rc}) {
xCAT::MsgUtils->message("E", { data => ["$node: $ret->{msg}"] }, $callback);
return ($tmpret->{rc});
}
$query_return_hash{query_tmp} = $tmpvalue;
}
# perform the query request
if ($query_list) {
foreach my $attr (split(',', $query_list)) {
# Query the power saving status
if ($attr =~ /^(savingstatus|dsavingstatus|fsavingstatus)$/) {
if ($query_pum_flag) {
if (defined($query_pum_value->{PowerUtilizationMode})) {
# 2 = None; 3 = Dynamic; 4 = Static; 32768 = Dynamic Favor Performance; 32769 = FFO
if ($query_pum_value->{PowerUtilizationMode} eq "2") {
push @{ $output->{$node} }, "$attr: off";
} elsif ($query_pum_value->{PowerUtilizationMode} eq "3") {
if ($attr eq "dsavingstatus") {
push @{ $output->{$node} }, "$attr: on-norm";
} else {
push @{ $output->{$node} }, "$attr: off";
}
} elsif ($query_pum_value->{PowerUtilizationMode} eq "4") {
if ($attr eq "savingstatus") {
push @{ $output->{$node} }, "$attr: on";
} else {
push @{ $output->{$node} }, "$attr: off";
}
} elsif ($query_pum_value->{PowerUtilizationMode} eq "32768") {
if ($attr eq "dsavingstatus") {
push @{ $output->{$node} }, "$attr: on-maxp";
} else {
push @{ $output->{$node} }, "$attr: off";
}
} elsif ($query_pum_value->{PowerUtilizationMode} eq "32769") {
if ($attr eq "fsavingstatus") {
push @{ $output->{$node} }, "$attr: on";
} else {
push @{ $output->{$node} }, "$attr: off";
}
}
} else {
push @{ $output->{$node} }, "$attr: na";
}
} else {
push @{ $output->{$node} }, "$attr: na";
}
}
# Query the FFO settings
if ($attr =~ /^(ffoMin|ffoVmin|ffoTurbo|ffoNorm|ffovalue)$/) {
if ($query_pum_flag) {
if (defined($query_pum_value->{FixedFrequencyPoints}) && defined($query_pum_value->{FixedFrequencyPointValues})) {
my @ffo_point = split(',', $query_pum_value->{FixedFrequencyPoints});
my @ffo_point_value = split(',', $query_pum_value->{FixedFrequencyPointValues});
foreach my $index (0 .. $#ffo_point) {
if ($ffo_point[$index] eq '2' && $attr eq 'ffoNorm') { # Norminal
push @{ $output->{$node} }, "$attr: $ffo_point_value[$index] MHZ";
} elsif ($ffo_point[$index] eq '3' && $attr eq 'ffoTurbo') { # Turbo
push @{ $output->{$node} }, "$attr: $ffo_point_value[$index] MHZ";
} elsif ($ffo_point[$index] eq '4' && $attr eq 'ffoVmin') { # Vmin
push @{ $output->{$node} }, "$attr: $ffo_point_value[$index] MHZ";
} elsif ($ffo_point[$index] eq '5' && $attr eq 'ffoMin') { # Min
push @{ $output->{$node} }, "$attr: $ffo_point_value[$index] MHZ";
}
}
} else {
push @{ $output->{$node} }, "$attr: na";
}
} else {
push @{ $output->{$node} }, "$attr: na";
}
}
# Query the FFO Value
if ($attr eq 'ffovalue') {
if ($query_pum_flag) {
if (defined($query_pum_value->{FixedFrequencyOverrideFreq})) {
if ($query_pum_value->{FixedFrequencyOverrideFreq} eq '4294967295') {
push @{ $output->{$node} }, "$attr: 0 MHZ";
} else {
push @{ $output->{$node} }, "$attr: $query_pum_value->{FixedFrequencyOverrideFreq} MHZ";
}
} else {
push @{ $output->{$node} }, "$attr: na";
}
} else {
push @{ $output->{$node} }, "$attr: na";
}
}
# Query the attribute sysIPLtime and syssbpower
if ($attr =~ /^(syssbpower|sysIPLtime)$/) {
if ($query_drawer_flag) {
if (defined($query_drawer_value->{AverageTimeToIPL}) && $attr eq "sysIPLtime") {
push @{ $output->{$node} }, "$attr: $query_drawer_value->{AverageTimeToIPL} S";
} elsif (defined($query_drawer_value->{StandbyPowerUtilization}) && $attr eq "syssbpower") {
push @{ $output->{$node} }, "$attr: $query_drawer_value->{StandbyPowerUtilization} W";
} else {
push @{ $output->{$node} }, "$attr: na";
}
} else {
push @{ $output->{$node} }, "$attr: na";
}
}
if ($attr =~ /^ambienttemp/) {
my $tmphash = $query_return_hash{query_tmp};
foreach my $ins (keys %$tmphash) {
if ($ins =~ /InletAirTemp/) {
my @times = sort keys %{ $tmphash->{$ins}->{MetricValue} };
if ($attr eq "ambienttemp") {
#push @{$output->{$node}}, "$attr ($tmphash->{$ins}->{MeasuredElementName}): $tmphash->{$ins}->{MetricValue}->{$times[-1]}";
push @{ $output->{$node} }, "$attr: $tmphash->{$ins}->{MetricValue}->{$times[-1]} C";
} else {
foreach my $time (@times) {
#push @{$output->{$node}}, "$attr ($tmphash->{$ins}->{MeasuredElementName}): $tmphash->{$ins}->{MetricValue}->{$time}: $time";
push @{ $output->{$node} }, "$attr: $tmphash->{$ins}->{MetricValue}->{$time} C: $time";
}
}
}
}
} elsif ($attr =~ /^exhausttemp/) {
my $tmphash = $query_return_hash{query_tmp};
foreach my $ins (keys %$tmphash) {
if ($ins =~ /ExhaustAirTemp/) {
my @times = sort keys %{ $tmphash->{$ins}->{MetricValue} };
if ($attr eq "exhausttemp") {
#push @{$output->{$node}}, "$attr ($tmphash->{$ins}->{MeasuredElementName}): $tmphash->{$ins}->{MetricValue}->{$times[-1]}";
push @{ $output->{$node} }, "$attr: $tmphash->{$ins}->{MetricValue}->{$times[-1]} C";
} else {
foreach my $time (@times) {
#push @{$output->{$node}}, "$attr ($tmphash->{$ins}->{MeasuredElementName}): $tmphash->{$ins}->{MetricValue}->{$time}: $time";
push @{ $output->{$node} }, "$attr: $tmphash->{$ins}->{MetricValue}->{$time} C: $time";
}
}
}
}
} elsif ($attr =~ /^CPUspeed/) {
my $tmphash = $query_return_hash{query_cpuspeed};
foreach my $ins (keys %$tmphash) {
if ($ins =~ /AvgCPUUsage/) {
my @times = sort keys %{ $tmphash->{$ins}->{MetricValue} };
if ($attr eq "CPUspeed") {
#push @{$output->{$node}}, "$attr ($tmphash->{$ins}->{MeasuredElementName}): $tmphash->{$ins}->{MetricValue}->{$times[-1]}";
push @{ $output->{$node} }, "$attr: $tmphash->{$ins}->{MetricValue}->{$times[-1]} MHZ";
} else {
foreach my $time (@times) {
#push @{$output->{$node}}, "$attr ($tmphash->{$ins}->{MeasuredElementName}): $tmphash->{$ins}->{MetricValue}->{$time}: $time";
push @{ $output->{$node} }, "$attr: $tmphash->{$ins}->{MetricValue}->{$time} MHZ: $time";
}
}
}
}
} elsif ($attr =~ /^fanspeed/) {
my $tmphash = $query_return_hash{query_fanspeed};
foreach my $ins (keys %$tmphash) {
if ($ins =~ /FansSpeed/) {
my @times = sort keys %{ $tmphash->{$ins}->{MetricValue} };
if ($attr eq "fanspeed") {
push @{ $output->{$node} }, "$attr ($tmphash->{$ins}->{MeasuredElementName}): $tmphash->{$ins}->{MetricValue}->{$times[-1]} RPM";
} else {
foreach my $time (@times) {
push @{ $output->{$node} }, "$attr ($tmphash->{$ins}->{MeasuredElementName}): $tmphash->{$ins}->{MetricValue}->{$time} RPM: $time";
}
}
}
}
$query_fanspeed_value = 1;
} elsif ($attr =~ /^(averageAC|averageDC)/) {
my $tmpattr = $1;
my $tmphash = $query_return_hash{query_powermetric};
my @times = sort keys %{ $tmphash->{$tmpattr}->{MetricValue} };
if ($attr =~ /history$/) {
foreach my $time (@times) {
push @{ $output->{$node} }, "$attr: $tmphash->{$tmpattr}->{MetricValue}->{$time} W: $time";
}
} else {
push @{ $output->{$node} }, "$attr: $tmphash->{$attr}->{MetricValue}->{$times[-1]} W";
}
}
}
}
# Perform the setting request
if ($set_pair) {
my ($set_name, $set_value) = split('=', $set_pair);
if ($set_name =~ /^(savingstatus|dsavingstatus|fsavingstatus|ffovalue)$/) {
if ($query_pum_flag) {
if (defined($query_pum_value->{PowerUtilizationMode})) {
# set the power saving value
my $ps_value;
if ($set_name eq "savingstatus") {
if ($set_value eq 'on') {
$ps_value = '4';
} elsif ($set_value eq 'off') {
$ps_value = '2';
}
} elsif ($set_name eq "dsavingstatus") {
if ($set_value eq 'on-norm') {
$ps_value = '3';
} elsif ($set_value eq 'on-maxp') {
$ps_value = '32768';
} elsif ($set_value eq 'off') {
$ps_value = '2';
}
} elsif ($set_name eq "fsavingstatus") {
if ($set_value eq 'on') {
$ps_value = '32769';
} elsif ($set_value eq 'off') {
$ps_value = '2';
}
}
if ($set_name eq "ffovalue") {
# set ffo value
$cimargs = {
propertyname => 'FixedFrequencyOverrideFreq',
propertyvalue => $set_value,
namepath => $namepath_pum,
};
$ret = xCAT::CIMUtils->set_property($http_params, $cimargs);
if ($ret->{rc}) {
push @{ $output->{$node} }, "Set $set_name failed. [$ret->{msg}]";
} else {
push @{ $output->{$node} }, "Set $set_name succeeded";
}
} else {
# set the power saving
if ($ps_value eq $query_pum_value->{PowerUtilizationMode}) { # do nothing if it already was the correct status
push @{ $output->{$node} }, "Set $set_name succeeded";
} else {
# perform the setting
$cimargs = {
propertyname => 'PowerUtilizationMode',
propertyvalue => $ps_value,
namepath => $namepath_pum,
};
$ret = xCAT::CIMUtils->set_property($http_params, $cimargs);
if ($ret->{rc}) {
push @{ $output->{$node} }, "Set $set_name failed. [$ret->{msg}]";
} else {
push @{ $output->{$node} }, "Set $set_name succeeded";
}
}
}
} else {
push @{ $output->{$node} }, "Set $set_name failed";
}
} else {
push @{ $output->{$node} }, "Set $set_name failed";
}
}
}
# Display the output
foreach my $node (keys(%{$output})) {
my @newoutput;
if ($query_list && $query_list !~ /history/) {
@newoutput = sort (@{ $output->{$node} });
} else {
@newoutput = @{ $output->{$node} };
}
foreach (@newoutput) {
my $rsp;
$rsp->{node}->[0]->{name} = $node;
push @{ $rsp->{node}->[0]->{data}->[0]->{contents} }, $_;
xCAT::MsgUtils->message("N", $rsp, $callback);
}
}
return 0;
}
1;