Categories

ID #1227

How do I use Raritan PDUs with the Bright Cluster Manager?

How do I use Raritan PDUs with the Bright Cluster Manager?

 

The Bright Cluster Manager, which is mainly tested on APC units, can also provide status information on non-APC power units using custom power scripts. Custom power scripts are covered in general in the section on power management in the Adminstrator manual.

 

For Raritan units, a custom power script based on Perl and the Expect module can be used. The Raritan custom power script is provided at the end of this article. To get the script to work, you need a recent revision of the cmdaemon (revision 15963 or later). You can then set the custom power script for the nodes connected to your PDU.

 

For the nodes, you can use cmgui or cmsh to set: 

 

  • the powercontrol attribute to custom 
  • the custompowerscript to the full path of the executable custom power management script on the head node(s) of a cluster.

 


The Raritan custom power script can then be enabled as follows:

 

  • the "powerdistributionunits" variables for the nodes that use the Raritan PDUs need to be cleared
  • the "custompowerscriptargument" should be set to the ports, eg: "savbu-qa-rar-490:1 savbu-qa-rar-490:2" (assuming that these are your Raritan PDU ports.)

 

For example:

 

cmsh
device use <node> 
clear powerdistributionunits
commit
set powercontrol custom
set custompowerscript <path to your script>
set custompowerscriptargument  "savbu-qa-rar-490:1 savbu-qa-rar-490:2"
commit 

 

The custom script for Raritan PDUs:

 

#!/usr/bin/env perl
# Courtesy of Jeff Squyres from Cisco
# Custom cmdaemon power management should adhere to the following rules
#
# Command line passed by cmdaemon: <action> <hostname>
#
# Script should exit with code when successful and contain
# the result in the first line of the output
#
# Action:  ON
#  result: ON / FAILED
#
# Action:  OFF
#  result: OFF / FAILED
#
# Action:  RESET
#  result: RESET* / OFF / FAILED
#
# Action:  STATUS
#  result: ON / OFF / RESET / FAILED
#
# * power is in twilight state between on and off, used in ipmi
#
# UNKNOWN should be returned for unknown devices or actions
#
use strict;

use Expect;

my $echo_to_stdout = 0;
my $timeout = 15;

my $op = uc($ARGV[0]);
my $device = $ARGV[1];
my $pairs = $ARGV[2];

#---------------------------------------------------------------------------

# Check arguments
# if script invocation isn't accompanied with the operation required, the device on which to do the operation, a string of PDUs through the operation will be performed, or the operation in not one the predefined operations
# print UNKNOWN and exit
if ((!defined($op) || !defined($device) || !defined($pairs)) ||
    ($op ne "ON" && $op ne "OFF" && $op ne "RESET" && $op ne "STATUS")) {
    print "UNKNOWN\n";
    exit(1);
}

#---------------------------------------------------------------------------

sub doit {
    my ($ip, $outlet) = @_; # copy parameters passed to the function into $ip and $outlet

    my @params;
    push(@params, $ip);
    my $exp = Expect->spawn("telnet", @params) # telnet to PDU
        || return "FAILED"; # return FAILED if telnet to PDU failed
    $exp->log_stdout($echo_to_stdout);
    
    # Login
    return "FAILED"
    if ($exp->expect($timeout, "Username: ") != 1); # return failed if the prompt was idle for the predefined timeout
    $exp->send("admin\r"); # send user name
    return "FAILED" 
    if ($exp->expect($timeout, "Password: ") != 1); # return failed if the prompt was idle for the predefined timeout
    $exp->send("raritan\r"); # send password
    
    # Do the op
    my $result = "FAILED";
    $exp->expect($timeout, "# ");

    # send the appropriate operation to the PDU port and save the the performed operation
    if ($op eq "ON") {
        $exp->send("power outlets $outlet on /y\r");
        $result = "ON";
    } elsif ($op eq "OFF") {
        $exp->send("power outlets $outlet off /y\r");
        $result = "OFF";
    } elsif ($op eq "RESET") {
        $exp->send("power outlets $outlet cycle /y\r");
        $result = "RESET";
    } elsif ($op eq "STATUS") {
        $exp->send("show outlets $outlet\r");
        my $ret = $exp->expect($timeout,
                     ["Power state: On"      => sub { $result = "ON" }],
                     ["Power state: Off"     => sub { $result = "OFF" }],
                     ["Power state: Cycling" => sub { $result = "RESET" }]);
    $result = "FAILED"
        if ($ret < 1 || $ret > 3);
    }
    
    # Make sure it finished
    $result = "FAILED"
    if ($exp->expect($timeout, "# ") != 1);


    $exp->send("exit\r"); # terminate the telnet tunnel opened earlier
    $exp->soft_close(); # nicely shut down the command

    # Return the result
    return $result;
}

#---------------------------------------------------------------------------

# Loop over all the PDUs
# split the PDUs string on spaces


# call doit subroutine
my @results;
foreach my $pair (split(/\s+/, $pairs)) {
    my ($ip, $outlet) = split(':', $pair); # split each PDU on ":" to extract the port of communication; place the first item in $ip and the last in $outlet
    push(@results, { # call doit subroutine to get the power status or perform power action, and save the results in a list
    pair => $pair,
    result => doit($ip, $outlet)
     });
}

# Examine all the results
my %sums;
foreach my $r (@results) {
    ++$sums{$r->{result}}; # add a hash key with power result and increment its value
}

# Print a single line for ON, OFF, RESET, FAILED
if ($sums{"ON"} > 0) {
    print "ON";
} elsif ($sums{"RESET"} > 0) {
    print "RESET";
} elsif ($sums{"FAILED"} > 0) {
    print "FAILED";
} else {
    print "OFF";
}
print "\n";

# Print another line showing the status of each PDU
my $first = 1;
foreach my $r (@results) {
    print ", "
      if (!$first);
    print "$r->{pair} $r->{result}";
    $first = 0;
}
print "\n";

# Done
exit(0);

 

 

Tags: -

Related entries:

You cannot comment on this entry