diff --git a/perl-xCAT/xCAT/CIMUtils.pm b/perl-xCAT/xCAT/CIMUtils.pm
new file mode 100644
index 000000000..1c49f0102
--- /dev/null
+++ b/perl-xCAT/xCAT/CIMUtils.pm
@@ -0,0 +1,462 @@
+#! /usr/bin/env perl
+# IBM(c) 2014 EPL license http://www.eclipse.org/legal/epl-v10.html
+
+# This package offers subroutines to access CIM server
+
+package xCAT::CIMUtils;
+
+use strict;
+use warnings;
+
+use HTTP::Headers;
+use HTTP::Request;
+use LWP::UserAgent;
+
+use XML::LibXML;
+use Data::Dumper;
+
+=head1 HTTP_PARAMS
+
+ A hash which includes all the parameters for accessing HTTP server. The valid parameter:
+ ip: The IP address of the HTTP server
+ user: The user to access HTTP server.
+ password: The password for the user.
+ method: The http method. (GET, PUT, POST, DELETE). Default is GET
+ protocol: The protocol which will be used to access HTTP server. (http/https). Default is https
+ format: The format of payload. Default is xml
+ payload: The payload of http
+
+ Example:
+ my %http_params = ( ip => '192.168.1.1',
+ port => '5989',
+ user => 'HMC',
+ password => 'admin',
+ method => 'POST',
+ protocol => 'https');
+
+=cut
+
+=head1 enum_instance ()
+ Description:
+ Enumerate CIM instances.
+
+ Arguments:
+ http_params: A reference to HTTP_PARAMS
+ cim_params: The CIM parameters
+ classname - a mandatory param to specify the class that enumerate will target to.
+
+ Return:
+ 1 - A hash reference. The valid key includes:
+ rc - The return code. 0 - success. > 0 - fail.
+ cim_rc - The return code from CIM server.
+ msg - Output message.
+
+ 2 - Array of instances, each instance is a hash contains lots of properties.
+
+ 3 - The name path of instance
+=cut
+
+
+sub enum_instance
+{
+ my $http_params = shift;
+ unless (ref($http_params)) {
+ $http_params = shift;
+ }
+
+ my $cim_params = shift;
+
+ # This is a mandatory parameter
+ unless ($cim_params->{classname}) {
+ return ({rc => 1, msg => "Missed the classname"});
+ }
+
+ unless ($cim_params->{namespace}) {
+ $cim_params->{namespace} = "ibmsd";
+ }
+
+ # prepare the CIM payload
+ my $tmpnode;
+
+ # create a new doc
+ my $doc = XML::LibXML->createDocument('1.0','UTF-8');
+
+ # create and add the root element
+ my $root = $doc->createElement("CIM");
+ $root->setAttribute("CIMVERSION", "2.0");
+ $root->setAttribute("DTDVERSION", "2.0");
+
+ $doc->setDocumentElement($root);
+
+ # create and add the MESSAGE element
+ my $message = $doc->createElement("MESSAGE");
+ $message->setAttribute("ID", "1000");
+ $message->setAttribute("PROTOCOLVERSION", "1.0");
+
+ $root->addChild($message);
+
+ # add a SIMPLE REQUEST
+ my $simple_request = $doc->createElement("SIMPLEREQ");
+ $message->addChild($simple_request);
+
+ # add an IMETHOD CALL
+ my $imethod_call = $doc->createElement("IMETHODCALL");
+ $imethod_call->setAttribute("NAME", "EnumerateInstances");
+
+ $simple_request->addChild($imethod_call);
+
+ # add the local name space path
+ my $localnamespacepath = $doc->createElement("LOCALNAMESPACEPATH");
+ $tmpnode = $doc->createElement("NAMESPACE");
+ $tmpnode->setAttribute("NAME", "root");
+ $localnamespacepath->addChild($tmpnode);
+
+ $tmpnode = $doc->createElement("NAMESPACE");
+ $tmpnode->setAttribute("NAME", $cim_params->{namespace});
+ $localnamespacepath->addChild($tmpnode);
+
+ $imethod_call->addChild($localnamespacepath);
+
+ # add the target class name
+ my $param_classname = $doc->createElement("IPARAMVALUE");
+ $param_classname->setAttribute("NAME", "ClassName");
+ $imethod_call->addChild($param_classname);
+
+ my $classname = $doc->createElement("CLASSNAME");
+ $classname->setAttribute("NAME", $cim_params->{classname});
+ $param_classname->addChild($classname);
+
+ # add several common parameters
+ $imethod_call->appendWellBalancedChunk('TRUEFALSEFALSETRUE');
+
+ my $payload = $doc->toString();
+
+ # generate http request
+ my $ret = gen_http_request($http_params, $payload);
+
+ if ($ret->{rc}) {
+ return $ret;
+ }
+
+ # send request to http server
+ $ret = send_http_request($http_params, $ret->{request});
+ if ($ret->{rc}) {
+ return $ret;
+ }
+
+ # parse the http response
+ my $ret_value;
+ my $parser = XML::LibXML->new();
+ my $resp_doc = $parser->parse_string($ret->{payload});
+
+ # check the error message from CIM
+ my $error_node = $resp_doc->getElementsByTagName("ERROR");
+ if ($error_node) {
+ my $msg = $error_node->[0]->getAttribute("DESCRIPTION");
+ my $errorcode = $error_node->[0]->getAttribute("CODE");
+ return ({rc => 1, cim_rc => $errorcode, msg => $error_node->[0]->getAttribute("DESCRIPTION")." [cim return code: $errorcode]"});
+ }
+
+ # get the name path of the instance, which is used to set property
+ my @namepath = $resp_doc->getElementsByTagName("INSTANCENAME");
+ my $namepath_string;
+ if (@namepath) {
+ $namepath_string = $namepath[0]->toString();
+ }
+
+ # get all the instance elements
+ my @instances = $resp_doc->getElementsByTagName("VALUE.NAMEDINSTANCE");
+ foreach my $instance (@instances) {
+ # get all the property element for each instance
+ my @properties = $instance->getElementsByTagName("PROPERTY");
+ if (my @property_arrays = $instance->getElementsByTagName("PROPERTY.ARRAY")) {
+ push @properties, @property_arrays;
+ }
+ my $ins_value;
+ foreach my $property (@properties) {
+ # get name, vlaue and type for each property. (only the one which has value)
+ if (my $pname = $property->getAttribute("NAME")) {
+ if (my $pvalue = $property->getAttribute("TYPE")) {
+ $ins_value->{property}->{$pname}->{type} = $pvalue;
+ }
+ if ($property->getElementsByTagName("VALUE.ARRAY")) {
+ my @nodelist = $property->getElementsByTagName("VALUE");
+ my @value_array = ();
+ foreach my $n (@nodelist) {
+ push @value_array, $n->textContent;
+ }
+ $ins_value->{property}->{$pname}->{value} = join(',',@value_array);
+ } elsif (my $node = $property->getElementsByTagName("VALUE")) {
+ $ins_value->{property}->{$pname}->{value} = $node->[0]->textContent;
+ }
+ }
+ }
+ push @{$ret_value}, $ins_value;
+ }
+
+ return ({rc =>0}, $ret_value, $namepath_string);
+}
+
+=head1 set_property ()
+ Description:
+ Set the property for an instance.
+
+ Arguments:
+ http_params: A reference to HTTP_PARAMS
+ cim_params: The CIM parameters
+ namepath - a mandatory param to specify the path of the instance.
+ It should be returned from 'enum_instance' subroutine.
+
+ Return:
+ 1 - A hash reference. The valid key includes:
+ rc - The return code. 0 - success. > 0 - fail.
+ cim_rc - The return code from CIM server.
+ msg - Output message.
+=cut
+sub set_property
+{
+ my $http_params = shift;
+ unless (ref($http_params)) {
+ $http_params = shift;
+ }
+
+ my $cim_params = shift;
+
+ # This is a mandatory parameter
+ unless ($cim_params->{namepath}) {
+ return ({rc => 1, msg => "Missed the name path for the instance"});
+ }
+
+ unless ($cim_params->{namespace}) {
+ $cim_params->{namespace} = "ibmsd";
+ }
+
+ # prepare the CIM payload
+ my $tmpnode;
+
+ # create a new doc
+ my $doc = XML::LibXML->createDocument('1.0','UTF-8');
+
+ # create and add the root element
+ my $root = $doc->createElement("CIM");
+ $root->setAttribute("CIMVERSION", "2.0");
+ $root->setAttribute("DTDVERSION", "2.0");
+
+ $doc->setDocumentElement($root);
+
+ # create and add the MESSAGE element
+ my $message = $doc->createElement("MESSAGE");
+ $message->setAttribute("ID", "1000");
+ $message->setAttribute("PROTOCOLVERSION", "1.0");
+
+ $root->addChild($message);
+
+ # add a SIMPLE REQUEST
+ my $simple_request = $doc->createElement("SIMPLEREQ");
+ $message->addChild($simple_request);
+
+ # add an IMETHOD CALL
+ my $imethod_call = $doc->createElement("IMETHODCALL");
+ $imethod_call->setAttribute("NAME", "SetProperty");
+
+ $simple_request->addChild($imethod_call);
+
+ # add the local name space path
+ my $localnamespacepath = $doc->createElement("LOCALNAMESPACEPATH");
+ $tmpnode = $doc->createElement("NAMESPACE");
+ $tmpnode->setAttribute("NAME", "root");
+ $localnamespacepath->addChild($tmpnode);
+
+ $tmpnode = $doc->createElement("NAMESPACE");
+ $tmpnode->setAttribute("NAME", $cim_params->{namespace});
+ $localnamespacepath->addChild($tmpnode);
+
+ $imethod_call->addChild($localnamespacepath);
+
+ # add the target property name
+ my $param_propertyname = $doc->createElement("IPARAMVALUE");
+ $param_propertyname->setAttribute("NAME", "PropertyName");
+ $imethod_call->addChild($param_propertyname);
+
+ $tmpnode = $doc->createElement("VALUE");
+ $tmpnode->appendTextNode($cim_params->{propertyname});
+ $param_propertyname->addChild($tmpnode);
+
+ # add the target property value
+ my $param_newvaluename = $doc->createElement("IPARAMVALUE");
+ $param_newvaluename->setAttribute("NAME", "NewValue");
+ $imethod_call->addChild($param_newvaluename);
+
+ $tmpnode = $doc->createElement("VALUE");
+ $tmpnode->appendTextNode($cim_params->{propertyvalue});
+ $param_newvaluename->addChild($tmpnode);
+
+ # add parameters of instance name path
+ my $param_namepath = $doc->createElement("IPARAMVALUE");
+ $param_namepath->setAttribute("NAME", "InstanceName");
+ $param_namepath->appendWellBalancedChunk($cim_params->{namepath});
+ $imethod_call->addChild($param_namepath);
+
+ my $payload = $doc->toString();
+
+ # generate http request
+ my $ret = gen_http_request($http_params, $payload);
+
+ if ($ret->{rc}) {
+ return $ret;
+ }
+
+ # send request to http server
+ $ret = send_http_request($http_params, $ret->{request});
+ if ($ret->{rc}) {
+ return $ret;
+ }
+
+ # parse the http response
+ my $ret_value;
+ my $parser = XML::LibXML->new();
+ my $resp_doc = $parser->parse_string($ret->{payload});
+
+ # check the error message from CIM
+ my $error_node = $resp_doc->getElementsByTagName("ERROR");
+ if ($error_node) {
+ my $msg = $error_node->[0]->getAttribute("DESCRIPTION");
+ my $errorcode = $error_node->[0]->getAttribute("CODE");
+ return ({rc => 1, cim_rc => $errorcode, msg => $error_node->[0]->getAttribute("DESCRIPTION")." [cim return code: $errorcode]"});
+ }
+
+
+ # if no http and cim error, the setting was succeeded
+ return ($ret);
+}
+
+=head1 gen_http_request ()
+ Description:
+ Generate a http request.
+
+ Arguments:
+ http_params: A reference to HTTP_PARAMS
+ payload: The payload for the http request. It can be null if the payload has been set in http_params.
+
+ Return:
+ A hash reference. The valid key includes:
+ rc - The return code. 0 - success. > 0 - fail.
+ msg - Output message
+ request - The generated HTTP::Request object
+=cut
+
+sub gen_http_request
+{
+ my $http_params = shift;
+ my $http_payload = shift;
+
+ # check the mandatory parameters
+ unless (defined ($http_params->{ip}) && defined ($http_params->{port}) && defined($http_params->{user}) && defined($http_params->{password})) {
+ return ({rc => 1, msg => "Missed the mandatory parameters: ip, port, user or password"});
+ }
+
+ # set the default value for parameters
+ unless (defined ($http_params->{protocol})) {
+ $http_params->{protocol} = 'https';
+ }
+ unless (defined ($http_params->{format})) {
+ $http_params->{format} = 'xml';
+ }
+ unless (defined ($http_params->{method})) {
+ $http_params->{method} = 'GET';
+ }
+
+ my $payload = '';
+ if (defined ($http_params->{payload})) {
+ $payload = $http_params->{payload};
+ }
+ if (defined ($http_payload)) {
+ unless (ref($http_payload)) { #Todo: support payloasd to be a hash
+ $payload = $http_payload;
+ }
+ }
+
+ # create the http head
+ my $header = HTTP::Headers->new('content-type' => "application/$http_params->{format}",
+ 'Accept' => "application/$http_params->{format}",
+ 'User-Agent' => "xCAT/2",
+ 'Host' => "$http_params->{ip}:$http_params->{port}");
+
+ # set the user & password
+ $header->authorization_basic($http_params->{user}, $http_params->{password});
+
+ # set the length of payload
+ my $plen = length($payload);
+ $header->push_header('Content-Length' => $plen);
+
+ # create the URL
+ my $url = "$http_params->{protocol}://$http_params->{ip}:$http_params->{port}";
+ my $request = HTTP::Request->new($http_params->{method}, $url, $header, $payload);
+
+ # set the http version
+ $request->protocol('HTTP/1.1');
+
+ return ({rc => 0, request => $request});
+}
+
+
+=head1 send_http_request ()
+ Description:
+ Send http request to http server and waiting for the response.
+
+ Arguments:
+ http_params: A reference to HTTP_PARAMS
+ http_request: A HTTP::Request object
+
+ Return:
+ A hash reference. The valid key includes:
+ rc - The return code. 0 - success. > 0 - fail.
+ http_rc - The return code of http. 200, 400 ...
+ msg - Output message
+ payload - The http response from http server
+=cut
+
+sub send_http_request
+{
+ my $http_params = shift;
+ my $http_request = shift;
+
+ # Load the library LWP::Protocol::https for https support
+ if ($http_params->{protocol} eq 'https') {
+ eval { require LWP::Protocol::https};
+ if ($@) {
+ return ({rc => 1, msg => "Failed to load perl library LWP::Protocol::https"});
+ }
+ }
+
+ # create a new HTTP User Agent Object
+ my $ua = LWP::UserAgent->new(ssl_opts => { verify_hostname => 0, SSL_verify_mode => 0});
+ if ($http_params->{timeout}) {
+ $ua->timeout($http_params->{timeout});
+ } else {
+ $ua->timeout(10); # the default timeout is 10s
+ }
+
+ if (defined($http_params->{verbose}) && defined ($http_params->{callback})) {
+ $http_params->{callback}({data => ["\n========CIM Request Start========", $http_request->as_string(), "=======CIM Request End======="]});
+ }
+
+ # send request and receive the response
+ my $response = $ua->request($http_request);
+
+ if (defined($http_params->{verbose}) && defined ($http_params->{callback}) && defined ($response->{_content})) {
+ $http_params->{callback}({data => ["\n========CIM Response Start========", $response->{_content}, "=======CIM Response End======="]});
+ }
+
+ # check the http response
+ if (defined ($response) && defined ($response->{_rc}) && defined ($response->{_msg})) {
+ if ($response->{_rc} eq "200" && $response->{_msg} eq "OK") {
+ return ({rc => 0, http_rc => $response->{_rc}, msg => "$response->{_msg} [http return code: $response->{_rc}]", payload => $response->{_content}});
+ }
+ }
+
+ return ({rc => 1, http_rc => $response->{_rc}, msg => $response->{_msg}});
+}
+
+
+1;
diff --git a/perl-xCAT/xCAT/Usage.pm b/perl-xCAT/xCAT/Usage.pm
index 9ef3b006b..6cbcaa4f9 100644
--- a/perl-xCAT/xCAT/Usage.pm
+++ b/perl-xCAT/xCAT/Usage.pm
@@ -333,12 +333,16 @@ my %usage = (
renergy [-v | --version]
Power 6 server specific :
- renergy noderange [-V] { all | { [savingstatus] [cappingstatus] [cappingmaxmin] [cappingvalue] [cappingsoftmin] [averageAC] [averageDC] [ambienttemp] [exhausttemp] [CPUspeed] } }
- renergy noderange [-V] { {savingstatus}={on | off} | {cappingstatus}={on | off} | {cappingwatt}=watt | {cappingperc}=percentage }
+ renergy noderange [-V] { all | { [savingstatus] [cappingstatus] [cappingmaxmin] [cappingvalue] [cappingsoftmin] [averageAC] [averageDC] [ambienttemp] [exhausttemp] [CPUspeed] } }
+ renergy noderange [-V] { {savingstatus}={on | off} | {cappingstatus}={on | off} | {cappingwatt}=watt | {cappingperc}=percentage }
Power 7 server specific :
- renergy noderange [-V] { all | { [savingstatus] [dsavingstatus] [cappingstatus] [cappingmaxmin] [cappingvalue] [cappingsoftmin] [averageAC] [averageDC] [ambienttemp] [exhausttemp] [CPUspeed] [syssbpower] [sysIPLtime] [fsavingstatus] [ffoMin] [ffoVmin] [ffoTurbo] [ffoNorm] [ffovalue] } }
- renergy noderange [-V] { {savingstatus}={on | off} | {dsavingstatus}={on-norm | on-maxp | off} | {fsavingstatus}={on | off} | {ffovalue}=MHZ | {cappingstatus}={on | off} | {cappingwatt}=watt | {cappingperc}=percentage }
+ renergy noderange [-V] { all | { [savingstatus] [dsavingstatus] [cappingstatus] [cappingmaxmin] [cappingvalue] [cappingsoftmin] [averageAC] [averageDC] [ambienttemp] [exhausttemp] [CPUspeed] [syssbpower] [sysIPLtime] [fsavingstatus] [ffoMin] [ffoVmin] [ffoTurbo] [ffoNorm] [ffovalue] } }
+ renergy noderange [-V] { {savingstatus}={on | off} | {dsavingstatus}={on-norm | on-maxp | off} | {fsavingstatus}={on | off} | {ffovalue}=MHZ | {cappingstatus}={on | off} | {cappingwatt}=watt | {cappingperc}=percentage }
+
+ Power 8 server specific :
+ renergy noderange [-V] { all | [savingstatus] [dsavingstatus] [averageAC] [averageAChistory] [averageDC] [averageDChistory] [ambienttemp] [ambienttemphistory] [exhausttemp] [exhausttemphistory] [fanspeed] [fanspeedhistory] [CPUspeed] [CPUspeedhistory] [syssbpower] [sysIPLtime] [fsavingstatus] [ffoMin] [ffoVmin] [ffoTurbo] [ffoNorm] [ffovalue]}
+ renergy noderange [-V] { savingstatus={on | off} | dsavingstatus={on-norm | on-maxp | off} | fsavingstatus={on | off} | ffovalue=MHZ }
BladeCenter specific :
For Management Modules:
diff --git a/perl-xCAT/xCAT/Utils.pm b/perl-xCAT/xCAT/Utils.pm
index 8eb1e0050..8a9e5e8fc 100755
--- a/perl-xCAT/xCAT/Utils.pm
+++ b/perl-xCAT/xCAT/Utils.pm
@@ -3298,13 +3298,68 @@ sub noderangecontainsMn
return; # if no MN in the noderange, return nothing
}
+
+# the MTM of P6 and P7 machine
+my %MTM_P6P7 = (
+ # P6 systems
+ '7998-60X' => 1,
+ '7998-61X' => 1,
+ '7778-23X' => 1,
+ '8203-E4A' => 1,
+ '8204-E8A' => 1,
+ '8234-EMA' => 1,
+ '9117-MMA' => 1,
+ '9119-FHA' => 1,
+
+ # P7 systems
+ '8406-70Y' => 1,
+ '8406-71Y' => 1,
+ '7891-73X' => 1,
+ '7891-74X' => 1,
+ '8231-E2B' => 1,
+ '8202-E4B' => 1,
+ '8231-E2B' => 1,
+ '8205-E6B' => 1,
+ '8233-E8B' => 1,
+ '8236-E8C' => 1,
+ '9117-MMB' => 1,
+ '9179-MHB' => 1,
+ '9119-FHB' => 1,
+);
+
+#-----------------------------------------------------------------------------
+
+=head3 isP6P7
+
+ Check whether a MTM is a P6 or P7 machine
+ Parameter: MTM of Power machine
+
+=cut
+
+#-------------------------------------------------------------------------------
+sub isP6P7
+{
+ my $class = shift;
+ my $mtm = shift;
+
+ if ($class !~ /Utils/) {
+ $mtm = $class;
+ }
+
+ if (defined $MTM_P6P7{$mtm} && $MTM_P6P7{$mtm} == 1) {
+ return 1;
+ }
+
+ return 0;
+}
+
=head3 filter_nodes
##########################################################################
# Fliter the nodes to specific groups
# For specific command, figure out the node lists which should be handled by blade.pm, fsp.pm or ipmi.pm
-# mp group: the nodes will be handled by blade.pm
-# fsp group: the nodes will be handled by fsp.pm
-# bmc group: the nodes will be handled by ipmi.pm
+# mp group (argument: $mpnodes): the nodes will be handled by blade.pm
+# fsp group (argument: $fspnodes): the nodes will be handled by fsp.pm
+# bmc group (argument: $bmcnodes): the nodes will be handled by ipmi.pm
# For rspconfig network, the NGP ppc blade will be included in the group of mp, othewise in the fsp group
# For getmacs -D, the NGP ppc blade will be included in the group of common fsp, otherwise in the mp group
# For renergy command, NGP blade will be moved to mp group
@@ -3346,13 +3401,29 @@ sub filter_nodes{
if ($ipmitab) {
$ipmitabhash = $ipmitab->getNodesAttribs(\@nodes,['bmc']);
}
+
+ # get the node attributes from the nodehm table
my $nodehmhash;
my $nodehmtab = xCAT::Table->new("nodehm");
if ($nodehmtab) {
$nodehmhash = $nodehmtab->getNodesAttribs(\@nodes,['mgt']);
}
- my (@mp, @ngpfsp, @ngpbmc, @commonfsp, @commonbmc, @unknow);
+ # get the node attributes from the nodetype table
+ my $nodetypehash;
+ my $nodetypetab = xCAT::Table->new("nodetype");
+ if ($nodetypetab) {
+ $nodetypehash = $nodetypetab->getNodesAttribs(\@nodes, ['arch']);
+ }
+
+ # get the node attributes from the vpd table
+ my $vpdhash,
+ my $vpdtab = xCAT::Table->new("vpd");
+ if ($vpdtab) {
+ $vpdhash = $vpdtab->getNodesAttribs(\@nodes, ['mtm']);
+ }
+
+ my (@mp, @ngpfsp, @ngpbmc, @commonfsp, @commonbmc, @unknow, @nonppcle, @p6p7);
# if existing in both 'mpa' and 'ppc', a ngp power blade
# if existing in both 'mpa' and 'ipmi', a ngp x86 blade
@@ -3386,9 +3457,21 @@ sub filter_nodes{
} elsif (defined ($ppctabhash->{$_}->[0]) && defined ($ppctabhash->{$_}->[0]->{'hcp'})) {
# common power node
push @commonfsp, $_;
+ # whether is a Power 8 or higher with FSP
+ if (defined ($vpdhash->{$_}->[0]) && defined ($vpdhash->{$_}->[0]->{'mtm'})) {
+ if (isP6P7($vpdhash->{$_}->[0]->{'mtm'})) {
+ push @p6p7, $_;
+ }
+ }
} elsif (defined ($ipmitabhash->{$_}->[0]) && defined ($ipmitabhash->{$_}->[0]->{'bmc'})) {
# common bmc node
push @commonbmc, $_;
+ # whether is a Power 8 or higher with FSP
+ if (defined ($nodetypehash->{$_}->[0]) && defined ($nodetypehash->{$_}->[0]->{'arch'})) {
+ if ($nodetypehash->{$_}->[0]->{'arch'} ne "ppc64le") {
+ push @nonppcle, $_;
+ }
+ }
} else {
push @unknow, $_;
}
@@ -3422,6 +3505,16 @@ sub filter_nodes{
push @{$mpnodes}, @ngpfsp;
}
} elsif ($cmd eq "renergy") {
+ # for renergy command, only the p6,p7 get to the general fsp.pm
+ # P8 and higher will get in the energy.pm
+ @{$fspnodes} = ();
+ push @{$fspnodes}, @p6p7;
+
+ # for rnergy command, only the non-ppcle nodes get to the general ipmi.pm
+ # ppcle of P8 and higher will get in the energy.pm
+ @{$bmcnodes} = ();
+ push @{$bmcnodes}, @nonppcle;
+
if (grep /^(relhistogram)/, @args) {
push @{$bmcnodes}, @ngpbmc;
} else {
diff --git a/xCAT-client/pods/man1/renergy.1.pod b/xCAT-client/pods/man1/renergy.1.pod
index aec573f92..c036e9148 100644
--- a/xCAT-client/pods/man1/renergy.1.pod
+++ b/xCAT-client/pods/man1/renergy.1.pod
@@ -27,17 +27,34 @@ B
=over 2
+B I [-V] { all | [savingstatus] [dsavingstatus]
+[cappingstatus] [cappingmaxmin] [cappingvalue] [cappingsoftmin]
+[averageAC] [averageDC] [ambienttemp] [exhausttemp] [CPUspeed]
+[syssbpower] [sysIPLtime] [fsavingstatus] [ffoMin] [ffoVmin]
+[ffoTurbo] [ffoNorm] [ffovalue]}
+
+B I [-V] { savingstatus={on | off}
+| dsavingstatus={on-norm | on-maxp | off}
+| fsavingstatus={on | off} | ffovalue=MHZ
+| cappingstatus={on | off} | cappingwatt=watt
+| cappingperc=percentage }
+
+=back
+
+B
+
+=over 2
+
B I [-V] { all | [savingstatus] [dsavingstatus]
-[cappingstatus] [cappingmaxmin] [cappingvalue] [cappingsoftmin]
-[averageAC] [averageDC] [ambienttemp] [exhausttemp] [CPUspeed]
+[averageAC] [averageAChistory] [averageDC] [averageDChistory]
+[ambienttemp] [ambienttemphistory] [exhausttemp] [exhausttemphistory]
+[fanspeed] [fanspeedhistory] [CPUspeed] [CPUspeedhistory]
[syssbpower] [sysIPLtime] [fsavingstatus] [ffoMin] [ffoVmin]
[ffoTurbo] [ffoNorm] [ffovalue]}
B I [-V] { savingstatus={on | off}
| dsavingstatus={on-norm | on-maxp | off}
-| fsavingstatus={on | off} | ffovalue=MHZ
-| cappingstatus={on | off} | cappingwatt=watt
-| cappingperc=percentage }
+| fsavingstatus={on | off} | ffovalue=MHZ }
=back
@@ -127,10 +144,11 @@ user can query and set the power saving and power capping status, and also can
query the average consumed energy, the ambient and exhaust temperature,
the processor frequency for a server.
-B command supports IBM POWER6 and POWER7 rack-mounted servers,
+B command supports IBM POWER6, POWER7 and POWER8 rack-mounted servers,
BladeCenter management modules, blade servers, and iDataPlex servers.
-For system p rack-mounted servers, the following specific hardware types are supported:
+For I and I rack-mounted servers, the following specific hardware types are supported:
I<8203-E4A>, I<8204-E8A>, I<9125-F2A>, I<8233-E8B>, I<8236-E8C>.
+For I server, there's no hardware type restriction.
The parameter I needs to be specified for the B command to
get the target servers. The I should be a list of CEC node names, blade
@@ -234,11 +252,13 @@ will get response immediately.
=head1 B
-For the system p nodes, the B command depends
+For the I and I nodes, the B command depends
on the Energy Management Plugin B to
communicate with server. B can be downloaded from the IBM web site:
http://www.ibm.com/support/fixcentral/. (Other Software -> EM)
+NOTE: I nodes don't need this specific energy management package.
+
For iDataPlex nodes, the B command depends
on the Energy Management Plugin B to
communicate with server. This plugin must be requested from IBM.
@@ -262,12 +282,14 @@ Display the version information.
Verbose output.
-
=item B
Query all energy attributes which supported by the specific
type of hardware.
+For I machines, will not display the attributes
+for historical records.
+
=item B
Query all energy attributes of the power domain 1 for blade
@@ -282,6 +304,10 @@ management module node.
Query the current ambient temperature. (Unit is centigrade)
+=item B
+
+Query the historical records which were generated in last one hour for B.
+
=item B
Query the total DC power available for the entire blade center chassis.
@@ -298,10 +324,18 @@ averageAC is the total AC power being consumed by all modules
in the chassis. It also includes power consumed by the Chassis
Cooling Devices for BCH chassis.
+=item B
+
+Query the historical records which were generated in last one hour for B.
+
=item B
Query the average power consumed (Output). (Unit is watt)
+=item B
+
+Query the historical records which were generated in last one hour for B.
+
=item B
Query the Power Capabilities of the blade server.
@@ -380,6 +414,10 @@ guaranteed.
Query the effective processor frequency. (Unit is MHz)
+=item B
+
+Query the historical records which were generated in last one hour for B
+
=item B
Query the dynamic power saving status. The result should
@@ -410,6 +448,21 @@ B is in turn off status.
Query the current exhaust temperature. (Unit is centigrade)
+=item B
+
+Query the historical records which were generated in last one hour for B
+
+=item B
+
+Query the fan speed for all the fans which installed in this node. (Unit is RPM - Rotations Per Minute))
+
+If there are multiple fans for a node, multiple lines will be output. And a fan name in bracket will be
+appended after B attribute name.
+
+=item B
+
+Query the historical records which were generated in last one hour for B.
+
=item B
Query the minimum cpu frequency which can be set for FFO. (Fixed
@@ -455,7 +508,7 @@ The ffovalue setting operation needs about 1 minute to take effect.
Query the status of FFO. The result should be 'on' or 'off'.
'on' - enable; 'off' - disable.
-=item B={B │ B}
+=item B={B | B}
Set the status of FFO. The value must be 'on' or 'off'.
@@ -574,7 +627,7 @@ Query the time used from FSP standby to OS standby.
=item B
Query the system power consumed prior to power on.
-(Unit is MHz)
+(Unit is Watt)
=item B
@@ -595,7 +648,7 @@ center chassis.
=item 1
-Query all the attributes which CEC1,CEC2 supported.
+Query all attributes which CEC1,CEC2 supported.
B CEC1,CEC2 all
@@ -629,6 +682,43 @@ The output of the query operation:
=item 2
+Query the B attribute for Power8 CEC.
+
+B CEC1 fanspeed
+
+The output of the query operation:
+
+ CEC1: fanspeed (Fan U78CB.001.WZS00MA-A1 00002101): 5947 RPM
+ CEC1: fanspeed (Fan U78CB.001.WZS00MA-A2 00002103): 6081 RPM
+ CEC1: fanspeed (Fan U78CB.001.WZS00MA-A3 00002105): 6108 RPM
+ CEC1: fanspeed (Fan U78CB.001.WZS00MA-A4 00002107): 6000 RPM
+ CEC1: fanspeed (Fan U78CB.001.WZS00MA-A5 00002109): 6013 RPM
+ CEC1: fanspeed (Fan U78CB.001.WZS00MA-A6 0000210B): 6013 RPM
+ CEC1: fanspeed (Fan U78CB.001.WZS00MA-E1 0000210C): 4992 RPM
+ CEC1: fanspeed (Fan U78CB.001.WZS00MA-E2 0000210D): 5016 RPM
+
+=item 3
+
+Query the historical records for the B attribute. (Power8 CEC)
+
+B CEC1 CPUspeedhistory
+
+The output of the query operation:
+
+ CEC1: CPUspeedhistory: 2027 MHZ: 20141226042900
+ CEC1: CPUspeedhistory: 2027 MHZ: 20141226042930
+ CEC1: CPUspeedhistory: 2244 MHZ: 20141226043000
+ CEC1: CPUspeedhistory: 2393 MHZ: 20141226043030
+ CEC1: CPUspeedhistory: 2393 MHZ: 20141226043100
+ CEC1: CPUspeedhistory: 2393 MHZ: 20141226043130
+ CEC1: CPUspeedhistory: 2393 MHZ: 20141226043200
+ CEC1: CPUspeedhistory: 2393 MHZ: 20141226043230
+ CEC1: CPUspeedhistory: 2393 MHZ: 20141226043300
+ CEC1: CPUspeedhistory: 2393 MHZ: 20141226043330
+ ...
+
+=item 4
+
Query all the attirbutes for management module node MM1. (For chassis)
B MM1 all
@@ -658,7 +748,7 @@ The output of the query operation:
in this power domain.
mm1: thermaloutput: 9717.376000 BTU/hour
-=item 3
+=item 5
Query all the attirbutes for blade server node blade1.
@@ -674,7 +764,7 @@ The output of the query operation:
blade1: maxCPUspeed: 4204MHZ
blade1: savingstatus: off
-=item 4
+=item 6
Query the attributes savingstatus, cappingstatus
and CPUspeed for server CEC1.
@@ -687,7 +777,7 @@ The output of the query operation:
CEC1: cappingstatus: on
CEC1: CPUspeed: 3621 MHz
-=item 5
+=item 7
Turn on the power saving function of CEC1.
@@ -698,7 +788,7 @@ The output of the setting operation:
CEC1: Set savingstatus succeeded.
CEC1: This setting may need some minutes to take effect.
-=item 6
+=item 8
Set the power capping value base on the percentage of the
max-min capping value. Here, set it to 50%.
diff --git a/xCAT-server/lib/xcat/plugins/energy.pm b/xCAT-server/lib/xcat/plugins/energy.pm
new file mode 100644
index 000000000..c17b10371
--- /dev/null
+++ b/xCAT-server/lib/xcat/plugins/energy.pm
@@ -0,0 +1,1027 @@
+#!/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 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',
+ }
+}
+
+# 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;
+ }
+ }
+
+ # 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]; }
+
+ 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 [];
+ }
+
+ # 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 $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']);
+ }
+
+ my $ppcdirect_tab = xCAT::Table->new('ppcdirect', -create=>0);
+
+ 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})) {
+ $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};
+ if (defined ($ipmi_hash->{$node}->[0]->{username})){
+ $user = $ipmi_hash->{$node}->[0]->{username};
+ $password = $ipmi_hash->{$node}->[0]->{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;
+ }
+ 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], passowrd [$password]"]}, $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;
+ }
+ }
+ }
+
+}
+
+=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/) {
+ xCAT::MsgUtils->message("E", data => ["$node: Couldn not 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};
+ # check whether the primary ip of fsp is the IP we are accessing
+ if (defined ($value->[0]->{property}->{PrimaryFSP_IP}->{value}) && $value->[0]->{property}->{PrimaryFSP_IP}->{value} ne $http_params->{ip}) {
+ # run against the standby fsp, do the next one
+ return 11;
+ }
+
+
+ # ======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
+ my $rsp;
+ if ($query_list && $query_list !~ /history/) {
+ push @{$rsp->{data}}, sort (@output);
+ } else {
+ push @{$rsp->{data}}, @output;
+ }
+ xCAT::MsgUtils->message("I", $rsp, $callback);
+
+ return 0;
+}
+
+
+1;
diff --git a/xCAT-server/lib/xcat/plugins/fsp.pm b/xCAT-server/lib/xcat/plugins/fsp.pm
index 605bc82af..9726685b6 100644
--- a/xCAT-server/lib/xcat/plugins/fsp.pm
+++ b/xCAT-server/lib/xcat/plugins/fsp.pm
@@ -81,7 +81,7 @@ sub preprocess_request {
my (@fspnodes, @nohandle);
xCAT::Utils->filter_nodes($arg1, undef, \@fspnodes, undef, \@nohandle);
if (@fspnodes) {
- $arg1->{noderange} = \@fspnodes;
+ $arg1->{node} = \@fspnodes;
} else {
return [];
}
diff --git a/xCAT-server/xCAT-server.spec b/xCAT-server/xCAT-server.spec
index 46fe1c6ee..17bc22eab 100644
--- a/xCAT-server/xCAT-server.spec
+++ b/xCAT-server/xCAT-server.spec
@@ -25,7 +25,7 @@ AutoReqProv: no
# also need to fix Requires for AIX
%ifos linux
BuildArch: noarch
-Requires: perl-IO-Socket-SSL perl-XML-Simple perl-XML-Parser perl-Digest-SHA1
+Requires: perl-IO-Socket-SSL perl-XML-Simple perl-XML-Parser perl-Digest-SHA1 perl(LWP::Protocol::https)
Obsoletes: atftp-xcat
%endif