# IBM(c) 2009 EPL license http://www.eclipse.org/legal/epl-v10.html package xCAT::PPCenergy; BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; } use lib "$::XCATROOT/lib/perl"; use strict; use Getopt::Long; use xCAT::Usage; use xCAT::NodeRange; use xCAT::DBobjUtils; use xCAT::FSPUtils; use xCAT::TableUtils; %::QUERY_ATTRS = ( 'savingstatus' => 1, 'dsavingstatus' => 1, 'cappingstatus' => 1, 'cappingmaxmin' => 1, 'cappingvalue' => 1, 'cappingsoftmin' => 1, 'averageAC' => 1, 'averageDC' => 1, 'ambienttemp' => 1, 'exhausttemp' => 1, 'CPUspeed' => 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, ); %::SET_ATTRS = ( 'savingstatus' => 1, 'dsavingstatus' => 1, 'cappingstatus' => 1, 'cappingwatt' => 1, 'cappingperc' => 1, # for FFO 'fsavingstatus' => 1, 'ffovalue' => 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); return( [ $_[0], $usage_string ] ); }; 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); if (defined($set_value)) { if ($argv_flag) { return (&usage()); } if ($::SET_ATTRS{$set_attr} != 1) { return (&usage()); } if (($set_attr eq "savingstatus" || $set_attr eq "fsavingstatus") && ($set_value ne "on" && $set_value ne "off")) { return (&usage()); } elsif ($set_attr eq "dsavingstatus" && ($set_value ne "off" && $set_value ne "on-norm" && $set_value ne "on-maxp")) { return (&usage()); } 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_attr eq "ffovalue") && $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; if ($query_list[0] eq "all" and $#query_list == 0) { $query_attrs = "all"; } else { my @no_dup_query_list = (); foreach my $q_attr (@query_list) { chomp($q_attr); if ($::QUERY_ATTRS{$q_attr} != 1) { return (&usage()); } if (!grep (/^$q_attr$/, @no_dup_query_list)) { 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] ); } if (scalar(@ARGV)) { return (&usage()); } } } else { return (&usage()); } # Check whether the hardware type of nodes are fsp or cec #my $nodetype_tb = xCAT::Table->new('nodetype'); #unless ($nodetype_tb) { # return ([undef, "Error: Cannot open the nodetype table"]); #} #my $nodetype_v = $nodetype_tb->getNodesAttribs($nodes, ['nodetype']); my $nodetyperef = xCAT::DBobjUtils->getnodetype($nodes, "ppc"); my $i = 0; foreach my $node (@{$nodes}) { if ($$nodetyperef{$node} ne 'fsp' && $$nodetyperef{$node} ne 'cec') { push @notfspnodes, $node; } $i++; } #$nodetype_tb->close(); if (@notfspnodes) { return ([undef, "Error: The hardware type of following nodes are not fsp or cec: ".join(',', @notfspnodes)]); } 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]; my $hw_type = @$attrs[4]; if (!$cec_name) { return ([[$node, "ERROR: Cannot find the cec name, check the attributes: vpd.serial, vpd.mtm.", 1]]); } # Check the existence of cim client if ( (! -f $::CIM_CLIENT_PATH) || (! -x $::CIM_CLIENT_PATH) ) { 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]]); } my $verb_arg = ""; if ($verbose) { $verb_arg = "-V"; } # get the user and passwd for hcp: hmc, fsp, cec my $hcp_type = xCAT::DBobjUtils->getnodetype($hcphost, "ppc"); my $user; my $password; if ($hcp_type eq "hmc") { ($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 my @hcps_ip; if ($hcp_type ne "hmc" && $hw_type eq "cec") { $fsps = xCAT::DBobjUtils->getchildren($node); if( !defined($fsps) ) { return ([[$node, "Failed to get the FSPs for the cec $hcphost.", -1]]); } #my $hcp_ip = xCAT::NetworkUtils::getNodeIPaddress($hcphost); my $hcp_ip = xCAT::FSPUtils::getIPaddress($request, $hw_type, $hcphost); if (!defined($hcp_ip) or ($hcp_ip == -3)) { return ([[$node, "Failed to get IP address for $hcphost.", -1]]); } push @hcps_ip, split(',', $hcp_ip); 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]]); } } else { # for the case that hcp is hmc or fsp push @hcps_ip, xCAT::NetworkUtils::getNodeIPaddress($hcphost); } if (!$user || !$password) { return ([[$node, "Cannot get user:password for the node. Please check table 'ppchcp' or 'ppcdirect'.", -1]]); } # secure passwd in verbose mode my $tmpv = $verbose; $verbose = 0; if ($verbose) { 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]; } $verbose = $tmpv; my @pingable_hcp; if (-x '/usr/bin/nmap' or -x '/usr/local/bin/nmap') { #use nmap #print "use nmap\n"; if ($verbose) { push @return_msg, [$node, "Checking ping status using nmap for @hcps_ip", 0]; } my %deadnodes; foreach (@hcps_ip) { $deadnodes{$_}=1; } # get additional options from site table my @nmap_options = xCAT::TableUtils->get_site_attribute("nmapoptions"); my $more_options = $nmap_options[0]; open (NMAP, "nmap -PE --system-dns --send-ip -sP $more_options ". join(' ',@hcps_ip) . " 2> /dev/null|") or die("Cannot open nmap pipe: $!"); my $node; while () { #print "$_\n"; if (/Host (.*) \((.*)\) appears to be up/) { $node=$2; unless ($deadnodes{$node}) { foreach (keys %deadnodes) { if ($node =~ /^$_\./) { $node = $_; last; } } } delete $deadnodes{$node}; if ($verbose) { push @return_msg, [$node, $_, 0]; } push(@pingable_hcp, $node); } elsif (/Nmap scan report for ([^ ]*)/) { $node=$1; } elsif (/Host is up./) { unless ($deadnodes{$node}) { foreach (keys %deadnodes) { if ($node =~ /^$_\./) { $node = $_; last; } } } delete $deadnodes{$node}; push(@pingable_hcp, $node); } } } else { #use fping #print "use fping\n"; my $master = xCAT::TableUtils->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; } 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: $!"); } while () { if ($verbose) { push @return_msg, [$node, $_, 0]; } if ($_ =~ /is alive/) { s/ is alive//; push @pingable_hcp, $_; } } } if (!@pingable_hcp) { push @return_msg, [$node, "No hcp can be pinged.", -1]; return \@return_msg; } # try the ip of hcp one by one my @lastnoerr_msg; my @noerr_msg; my @last_msg; foreach my $hcp (@pingable_hcp) { push @noerr_msg, @lastnoerr_msg; @lastnoerr_msg = (); @last_msg = (); # Generate the url path for CIM communication chomp($hcp); my $url_path = "https://"."$user".":"."$password"."\@"."$hcp".":5989"; # Not display password in command outupt. my $display_url_path = "https://"."$user".":"."xxxxxx"."\@"."$hcp".":5989"; # Execute the request my $cmd = ""; my $display_cmd = ""; if ($opt->{'set'}) { $cmd = "$::CIM_CLIENT_PATH $verb_arg -u $url_path -n $cec_name -o $opt->{'set'}"; $display_cmd = "$::CIM_CLIENT_PATH $verb_arg -u $display_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'}"; $display_cmd = "$::CIM_CLIENT_PATH $verb_arg -u $display_url_path -n $cec_name -o $opt->{'query'}"; } if ($verbose) { push @noerr_msg, [$node, "Run following command: $display_cmd", 0]; } # Disable the CHID signal before run the command. Otherwise the # $? value of `$cmd` will come from handler of CHID signal $SIG{CHLD} = 'DEFAULT'; # Call the xCAT_cim_client to query or set the energy capabilities $cmd .= " 2>&1"; # secure passwd in verbose mode my $tmpv = $::VERBOSE; $::VERBOSE = 0; my @result = xCAT::Utils->runcmd("$cmd", -1); $::VERBOSE = $tmpv; foreach my $line (@result) { chomp($line); if ($line =~ /^\s*$/) { next; } push @lastnoerr_msg, [$node, $line, 0]; push @last_msg, [$node, $line, $::RUNCMD_RC]; } if (!$::RUNCMD_RC) { last; } } # 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; return \@return_msg; } 1;