2009-09-21 11:30:05 +00:00
# IBM(c) 2009 EPL license http://www.eclipse.org/legal/epl-v10.html
2009-09-21 06:33:27 +00:00
package xCAT::PPCenergy ;
use strict ;
use Getopt::Long ;
use xCAT::Usage ;
use xCAT::NodeRange ;
2011-01-26 13:27:25 +00:00
use xCAT::DBobjUtils ;
2009-09-21 06:33:27 +00:00
% ::QUERY_ATTRS = (
'savingstatus' = > 1 ,
2010-01-30 14:35:01 +00:00
'dsavingstatus' = > 1 ,
2009-09-21 06:33:27 +00:00
'cappingstatus' = > 1 ,
'cappingmaxmin' = > 1 ,
'cappingvalue' = > 1 ,
'cappingsoftmin' = > 1 ,
'averageAC' = > 1 ,
'averageDC' = > 1 ,
'ambienttemp' = > 1 ,
'exhausttemp' = > 1 ,
2010-01-30 14:35:01 +00:00
'CPUspeed' = > 1 ,
'syssbpower' = > 1 ,
'sysIPLtime' = > 1 ,
) ;
2009-09-21 06:33:27 +00:00
% ::SET_ATTRS = (
'savingstatus' = > 1 ,
2010-01-30 14:35:01 +00:00
'dsavingstatus' = > 1 ,
2009-09-21 06:33:27 +00:00
'cappingstatus' = > 1 ,
'cappingwatt' = > 1 ,
'cappingperc' = > 1 ,
) ;
$ ::CIM_CLIENT_PATH = "$::XCATROOT/sbin/xCAT_cim_client" ;
# Parse the arguments of the command line for renergy command
sub parse_args {
my $ request = shift ;
my % opt = ( ) ;
my $ cmd = $ request - > { command } ;
my $ args = $ request - > { arg } ;
my $ nodes = $ request - > { node } ;
my $ query_attrs = ( ) ; # 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 $ argv_flag = ( ) ; # Indicate there's param in the argv
my @ notfspnodes = ( ) ; # The nodes list which are not fsp
# set the usage subroutine
local * usage = sub {
my $ usage_string = xCAT::Usage - > getUsage ( $ cmd ) ;
2010-01-30 14:35:01 +00:00
return ( [ $ _ [ 0 ] , $ usage_string ] ) ;
2009-09-21 06:33:27 +00:00
} ;
if ( $ request - > { arg } ) {
@ ARGV = @ { $ request - > { arg } } ;
$ Getopt:: Long:: ignorecase = 0 ;
Getopt::Long:: Configure ( "bundling" ) ;
if ( $ nodes ) {
if ( ! GetOptions ( 'V' = > \ $ ::VERBOSE ) ) {
return ( & usage ( ) ) ;
}
if ( $ ::VERBOSE ) {
$ opt { verbose } = 1 ;
}
if ( $# ARGV < 0 ) {
return ( & usage ( ) ) ;
}
# Check the validity of the parameters of Query and Set
foreach my $ attr ( @ ARGV ) {
my ( $ set_attr , $ set_value ) = split ( /=/ , $ attr ) ;
2010-01-30 14:35:01 +00:00
if ( defined ( $ set_value ) ) {
2009-09-21 06:33:27 +00:00
if ( $ argv_flag ) {
return ( & usage ( ) ) ;
}
if ( $ ::SET_ATTRS { $ set_attr } != 1 ) {
return ( & usage ( ) ) ;
}
if ( $ set_attr eq "savingstatus"
&& ( $ set_value ne "on" && $ set_value ne "off" ) ) {
return ( & usage ( ) ) ;
2010-01-30 14:35:01 +00:00
} elsif ( $ set_attr eq "dsavingstatus"
&& ( $ set_value ne "off"
&& $ set_value ne "on-norm" && $ set_value ne "on-maxp" ) ) {
return ( & usage ( ) ) ;
2009-09-21 06:33:27 +00:00
} elsif ( $ set_attr eq "cappingstatus"
&& ( $ set_value ne "on" && $ set_value ne "off" ) ) {
return ( & usage ( ) ) ;
} elsif ( ( $ set_attr eq "cappingwatt"
|| $ set_attr eq "cappingperc" )
&& $ set_value =~ /\D/ ) {
return ( & usage ( ) ) ;
}
$ set_pair = $ set_attr . "=" . $ set_value ;
$ set_flag = 1 ;
} else {
if ( $ set_flag ) {
return ( & usage ( ) ) ;
}
}
$ argv_flag = 1 ;
}
if ( ! $ set_flag ) {
my @ query_list = @ ARGV ;
2010-01-30 14:35:01 +00:00
2009-09-21 06:33:27 +00:00
if ( $ query_list [ 0 ] eq "all" and $# query_list == 0 ) {
2010-01-30 14:35:01 +00:00
$ query_attrs = "all" ;
2009-09-21 06:33:27 +00:00
} else {
my @ no_dup_query_list = ( ) ;
foreach my $ q_attr ( @ query_list ) {
chomp ( $ q_attr ) ;
2010-01-30 14:35:01 +00:00
2009-09-21 06:33:27 +00:00
if ( $ ::QUERY_ATTRS { $ q_attr } != 1 ) {
return ( & usage ( ) ) ;
}
2009-09-21 11:30:05 +00:00
if ( ! grep ( /^$q_attr$/ , @ no_dup_query_list ) ) {
2009-09-21 06:33:27 +00:00
push @ no_dup_query_list , $ q_attr ;
}
}
$ query_attrs = join ( ',' , @ no_dup_query_list ) ;
}
}
} else {
# If has not nodes, the -h or -v option must be input
if ( ! GetOptions ( 'h|help' = > \ $ ::HELP ,
'v|version' = > \ $ ::VERSION ) ) {
return ( & usage ( ) ) ;
}
if ( ! ( $ ::HELP || $ ::VERSION ) ) {
return ( & usage ( ) ) ;
}
if ( $ ::HELP ) {
return ( & usage ( ) ) ;
}
if ( $ ::VERSION ) {
my $ version_string = xCAT::Usage - > getVersion ( 'renergy' ) ;
return ( [ $ _ [ 0 ] , $ version_string ] ) ;
}
2010-01-30 14:35:01 +00:00
if ( scalar ( @ ARGV ) ) {
return ( & usage ( ) ) ;
}
2009-09-21 06:33:27 +00:00
}
} else {
return ( & usage ( ) ) ;
}
2011-01-26 13:27:25 +00:00
# Check whether the hardware type of nodes are fsp or cec
2009-09-21 06:33:27 +00:00
my $ nodetype_tb = xCAT::Table - > new ( 'nodetype' ) ;
unless ( $ nodetype_tb ) {
2010-01-30 14:35:01 +00:00
return ( [ undef , "Error: Cannot open the nodetype table" ] ) ;
2009-09-21 06:33:27 +00:00
}
my $ nodetype_v = $ nodetype_tb - > getNodesAttribs ( $ nodes , [ 'nodetype' ] ) ;
foreach my $ node ( @ { $ nodes } ) {
2011-01-26 13:27:25 +00:00
if ( $ nodetype_v - > { $ node } - > [ 0 ] - > { 'nodetype' } ne 'fsp' &&
$ nodetype_v - > { $ node } - > [ 0 ] - > { 'nodetype' } ne 'cec' ) {
2009-09-21 06:33:27 +00:00
push @ notfspnodes , $ node ;
}
}
2009-09-21 11:30:05 +00:00
$ nodetype_tb - > close ( ) ;
2009-09-21 06:33:27 +00:00
if ( @ notfspnodes ) {
2011-01-26 13:27:25 +00:00
return ( [ undef , "Error: The hardware type of following nodes are not fsp or cec: " . join ( ',' , @ notfspnodes ) ] ) ;
2009-09-21 06:33:27 +00:00
}
if ( $ query_attrs ) {
$ opt { 'query' } = $ query_attrs ;
} elsif ( $ set_pair ) {
$ opt { 'set' } = $ set_pair ;
}
$ request - > { method } = $ cmd ;
return ( \ % opt ) ;
}
# Handle the energy query and setting work
sub renergy {
my $ request = shift ;
my $ hcphost = shift ;
my $ nodehash = shift ;
my @ return_msg = ( ) ;
my $ opt = $ request - > { 'opt' } ;
my $ verbose = $ opt - > { 'verbose' } ;
# Get the CEC
my ( $ node , $ attrs ) = %$ nodehash ;
my $ cec_name = @$ attrs [ 2 ] ;
2011-01-26 13:27:25 +00:00
my $ hw_type = @$ attrs [ 4 ] ;
2009-09-21 06:33:27 +00:00
2011-01-26 13:27:25 +00:00
if ( ! $ cec_name ) {
return ( [ [ $ node , "ERROR: Cannot find the cec name, check the attributes: vpd.serial, vpd.mtm." , 1 ] ] ) ;
2009-09-21 06:33:27 +00:00
}
# Check the existence of cim client
if ( ( ! - f $ ::CIM_CLIENT_PATH )
|| ( ! - x $ ::CIM_CLIENT_PATH ) ) {
2010-06-18 12:40:14 +00:00
return ( [ [ $ node , "ERROR: Cannot find the Energy Management Plugin for xCAT [$::CIM_CLIENT_PATH] or it's NOT executable. Please install the xCAT-cimclient package correctly. Get more information from man page of renergy command." , 1 ] ] ) ;
2009-09-21 06:33:27 +00:00
}
my $ verb_arg = "" ;
if ( $ verbose ) {
$ verb_arg = "-V" ;
}
2011-01-26 13:27:25 +00:00
# get the user and passwd for hcp: hmc, fsp, cec
my $ hcp_type = xCAT::DBobjUtils - > getnodetype ( $ hcphost ) ;
my $ user ;
my $ password ;
2011-01-27 09:09:18 +00:00
if ( $ hcp_type eq "hmc" ) {
2011-01-26 13:27:25 +00:00
( $ user , $ password ) = xCAT::PPCdb:: credentials ( $ hcphost , $ hcp_type ) ;
} else {
( $ user , $ password ) = xCAT::PPCdb:: credentials ( $ hcphost , $ hcp_type , 'HMC' ) ;
}
my $ fsps ; #The node of fsp that belong to the cec
2011-02-18 02:10:25 +00:00
my @ hcps_ip ;
if ( $ hcp_type ne "hmc" && $ hw_type eq "cec" ) {
2011-01-26 13:27:25 +00:00
$ fsps = xCAT::DBobjUtils - > getchildren ( $ node ) ;
if ( ! defined ( $ fsps ) ) {
return ( [ [ $ node , "Failed to get the FSPs for the cec $hcphost." , - 1 ] ] ) ;
}
2011-02-18 02:10:25 +00:00
my $ hcp_ip = xCAT::Utils:: getNodeIPaddress ( $ hcphost ) ;
push @ hcps_ip , split ( ',' , $ hcp_ip ) ;
2011-01-26 13:27:25 +00:00
my $ fsp_node = $$ fsps [ 0 ] ;
( $ user , $ password ) = xCAT::PPCdb:: credentials ( $ fsp_node , "fsp" , 'HMC' ) ;
if ( ! $ password ) {
return ( [ [ $ node , "Cannot get password of userid 'HMC'. Please check table 'ppchcp' or 'ppcdirect'." , - 1 ] ] ) ;
}
2011-02-18 02:10:25 +00:00
} else {
# for the case that hcp is hmc or fsp
push @ hcps_ip , xCAT::Utils:: getNodeIPaddress ( $ hcphost ) ;
}
2011-01-26 13:27:25 +00:00
if ( ! $ user || ! $ password ) {
return ( [ [ $ node , "Cannot get user:password for the node. Please check table 'ppchcp' or 'ppcdirect'." , - 1 ] ] ) ;
}
2009-09-21 06:33:27 +00:00
if ( $ verbose ) {
2011-02-18 02:10:25 +00:00
push @ return_msg , [ $ node , "Attributes of $node:\n User=$user\n Password=$password\n CEC=$cec_name\n nodetype=$hw_type\n inithcp=$hcphost\n hcps=@hcps_ip\n hcptype=$hcp_type" , 0 ] ;
2009-09-21 06:33:27 +00:00
}
2011-02-18 02:10:25 +00:00
my $ master = xCAT::Utils - > get_site_Master ( ) ;
my $ masterip = xCAT::NetworkUtils - > getipaddr ( $ master ) ;
if ( $ masterip =~ /:/ ) { #IPv6, needs fping6 support
if ( ! - x '/usr/bin/fping6' )
{
push @ return_msg , [ $ node , "fping6 is not availabe for IPv6 ping." , - 1 ] ;
return \ @ return_msg ;
2011-01-26 13:27:25 +00:00
}
2011-02-18 02:10:25 +00:00
open ( FPING , "fping6 " . join ( ' ' , @ hcps_ip ) . " 2>&1 |" ) or die ( "Cannot open fping pipe: $!" ) ;
} else {
open ( FPING , "fping " . join ( ' ' , @ hcps_ip ) . " 2>&1 |" ) or die ( "Cannot open fping pipe: $!" ) ;
2011-01-26 13:27:25 +00:00
}
my @ pingable_hcp ;
2011-02-18 02:10:25 +00:00
while ( <FPING> ) {
if ( $ verbose ) {
push @ return_msg , [ $ node , $ _ , 0 ] ;
}
if ( $ _ =~ /is alive/ ) {
s/ is alive// ;
push @ pingable_hcp , $ _ ;
2011-01-26 13:27:25 +00:00
}
}
if ( ! @ pingable_hcp ) {
2011-02-18 02:10:25 +00:00
push @ return_msg , [ $ node , "No hcp can be pinged." , - 1 ] ;
return \ @ return_msg ;
2011-01-26 13:27:25 +00:00
}
2011-02-18 02:10:25 +00:00
2011-01-26 13:27:25 +00:00
# try the ip of hcp one by one
2011-02-18 02:10:25 +00:00
my @ lastnoerr_msg ;
my @ noerr_msg ;
my @ last_msg ;
2011-01-26 13:27:25 +00:00
foreach my $ hcp ( @ pingable_hcp ) {
2011-02-18 02:10:25 +00:00
push @ noerr_msg , @ lastnoerr_msg ;
@ lastnoerr_msg = ( ) ;
@ last_msg = ( ) ;
2011-01-26 13:27:25 +00:00
# Generate the url path for CIM communication
2011-02-18 02:10:25 +00:00
chomp ( $ hcp ) ;
2011-01-26 13:27:25 +00:00
my $ url_path = "https://" . "$user" . ":" . "$password" . "\@" . "$hcp" . ":5989" ;
# Execute the request
my $ cmd = "" ;
if ( $ opt - > { 'set' } ) {
$ cmd = "$::CIM_CLIENT_PATH $verb_arg -u $url_path -n $cec_name -o $opt->{'set'}" ;
} elsif ( $ opt - > { 'query' } ) {
$ cmd = "$::CIM_CLIENT_PATH $verb_arg -u $url_path -n $cec_name -o $opt->{'query'}" ;
}
if ( $ verbose ) {
2011-02-18 02:10:25 +00:00
push @ noerr_msg , [ $ node , "Run following command: $cmd" , 0 ] ;
2011-01-26 13:27:25 +00:00
}
# Disable the CHID signal before run the command. Otherwise the
# $? value of `$cmd` will come from handler of CHID signal
$ SIG { CHLD } = ( ) ;
# Call the xCAT_cim_client to query or set the energy capabilities
$ cmd . = " 2>&1" ;
2011-01-27 09:09:18 +00:00
my @ result = xCAT::Utils - > runcmd ( "$cmd" , - 1 ) ;
2011-01-26 13:27:25 +00:00
foreach my $ line ( @ result ) {
chomp ( $ line ) ;
if ( $ line =~ /^\s*$/ ) {
next ;
}
2011-02-18 02:10:25 +00:00
push @ lastnoerr_msg , [ $ node , $ line , 0 ] ;
push @ last_msg , [ $ node , $ line , $ ::RUNCMD_RC ] ;
2009-09-21 06:33:27 +00:00
}
2011-01-26 13:27:25 +00:00
if ( ! $ ::RUNCMD_RC ) {
last ;
}
}
2011-02-18 02:10:25 +00:00
# only display the correct msg when getting correct result from one fsp
if ( $ ::RUNCMD_RC || $ verbose ) {
push @ return_msg , @ noerr_msg ;
}
push @ return_msg , @ last_msg ;
2009-09-21 06:33:27 +00:00
return \ @ return_msg ;
}
2011-02-18 02:10:25 +00:00
2009-09-21 06:33:27 +00:00
1 ;