[Linux-cluster] Dell iDRAC 6 Support for fencing device

Nitin Choudhary Nitin.Choudhary at palm.com
Fri Oct 2 19:10:11 UTC 2009


Hi!

I have pasted the modified version of fence script for Dell iDRAC6.
Thanks,
Nitin

#!/usr/bin/perl

# The following agent has been tested on:
#
#  Model                DRAC Version    Firmware
#  -------------------  --------------  ----------------------
#  PowerEdge 750        DRAC III/XT     3.20 (Build 10.25)
#  Dell Remote Access Controller - ERA and DRAC III/XT, v.3.20, A00 #
#  PowerEdge 1855       DRAC/MC         1.1  (Build 03.03)
#  PowerEdge 1855       DRAC/MC         1.2  (Build 03.03)
#  PowerEdge 1855       DRAC/MC         1.3  (Build 06.12)
#  PowerEdge 1850       DRAC 4/I        1.35 (Build 09.27)
#  PowerEdge 1850       DRAC 4/I        1.40 (Build 08.24)
#  PowerEdge 1950       DRAC 5          1.0  (Build 06.05.12)
#

use Getopt::Std;
use Net::Telnet ();

# Get the program name from $0 and strip directory names $_=$0; s/.*\///; my $pname = $_;

my $telnet_timeout = 10;      # Seconds to wait for matching telent response
my $power_timeout = 20;      # time to wait in seconds for power state changes
$action = 'reboot';          # Default fence action.

my $logged_in = 0;
my $quiet = 0;

my $t = new Net::Telnet;

my $DRAC_VERSION_UNKNOWN        = '__unknown__';
my $DRAC_VERSION_III_XT         = 'DRAC III/XT';
my $DRAC_VERSION_MC                     = 'DRAC/MC';
my $DRAC_VERSION_4I                     = 'DRAC 4/I';
my $DRAC_VERSION_4P                     = 'DRAC 4/P';
my $DRAC_VERSION_5                      = 'DRAC 5';
my $DRAC_VERSION_6                      = 'DRAC 6';

my $PWR_CMD_SUCCESS                     = "/^OK/";
my $PWR_CMD_SUCCESS_DRAC5       = "/^Server power operation successful$/";

# WARNING!! Do not add code bewteen "#BEGIN_VERSION_GENERATION" and # "#END_VERSION_GENERATION"  It is generated by the Makefile

#BEGIN_VERSION_GENERATION
$FENCE_RELEASE_NAME="2.0.115";
$REDHAT_COPYRIGHT=("Copyright (C) Red Hat, Inc.  2004  All rights reserved."); $BUILD_DATE="(built Wed Sep  2 11:45:31 EDT 2009)"; #END_VERSION_GENERATION

sub usage
{
        print "Usage:\n";
        print "\n";
        print "$pname [options]\n";
        print "\n";
        print "Options:\n";
        print "  -a <ip>          IP address or hostname of DRAC\n";
        print "  -c <cmd_prompt>  force DRAC command prompt\n";
        print "  -d <dracversion> force DRAC version to use\n";
        print "  -D <debugfile>   debugging output file\n";
        print "  -h               usage\n";
        print "  -l <name>        Login name\n";
        print "  -m <modulename>  DRAC/MC module name\n";
        print "  -o <string>      Action: reboot (default), off or on\n";
        print "  -p <string>      Login password\n";
        print "  -S <path>        Script to run to retrieve password\n";
        print "  -q               quiet mode\n";
        print "  -V               version\n";
        print "\n";
        print "CCS Options:\n";
        print "  action = \"string\"      Action: reboot (default), off or on\n";
        print "  debug  = \"debugfile\"   debugging output file\n";
        print "  ipaddr = \"ip\"          IP address or hostname of DRAC\n";
        print "  login  = \"name\"        Login name\n";
        print "  passwd = \"string\"      Login password\n";
        print "  passwd_script = \"path\" Script to run to retrieve password\n";

        exit 0;
}

sub msg
{
        ($msg)=@_;
        print $msg."\n" unless $quiet;
}

sub fail
{
        ($msg)=@_;
        print $msg."\n" unless $quiet;

        if (defined $t)
        {
                # make sure we don't get stuck in a loop due to errors
                $t->errmode('return');

                logout() if $logged_in;
                $t->close
        }
        exit 1;
}

sub fail_usage
{
        ($msg)=@_;
        print STDERR $msg."\n" if $msg;
        print STDERR "Please use '-h' for usage.\n";
        exit 1;
}

sub version
{
        print "$pname $FENCE_RELEASE_NAME $BUILD_DATE\n";
        print "$REDHAT_COPYRIGHT\n" if ( $REDHAT_COPYRIGHT );
        exit 0;
}


sub login
{
        $t->open($address) or
                fail "failed: telnet open failed: ". $t->errmsg."\n";

        # Expect 'Login: '
        ($_) = $t->waitfor(Match => "/[Ll]ogin: /", Timeout=>15) or
                fail "failed: telnet failed: ". $t->errmsg."\n" ;

        # Determine DRAC version
  if (/Dell Embedded Remote Access Controller \(ERA\)\nFirmware Version/m)
  {
    $drac_version = $DRAC_VERSION_III_XT;
  } else {
        if (/.*\((DRAC[^)]*)\)/m)
        {
                print "detected drac version '$1'\n" if $verbose;
                $drac_version = $1 unless defined $drac_version;

                print "WARNING: detected drac version '$1' but using "
                        . "user defined version '$drac_version'\n"
                        if ($drac_version ne $1);
        }
        else
        {
                $drac_version = $DRAC_VERSION_UNKNOWN;
        }
  }

        # Setup prompt
        if ($drac_version =~ /$DRAC_VERSION_III_XT/)
        {
                $cmd_prompt = "/\\[$login\\]# /"
                        unless defined $cmd_prompt;
        }
        elsif ($drac_version =~ /$DRAC_VERSION_MC/)
        {
                $cmd_prompt = "/DRAC\\/MC:/"
                        unless defined $cmd_prompt;
        }
        elsif ($drac_version =~ /$DRAC_VERSION_4I/)
        {
                $cmd_prompt = "/\\[$login\\]# /"
                        unless defined $cmd_prompt;
        }
  elsif ($drac_version =~ /$DRAC_VERSION_4P/)
  {
        $cmd_prompt = "/\\[$login\\]# /"
          unless defined $cmd_prompt;
  }
        else
        {
                $drac_version = $DRAC_VERSION_UNKNOWN;
        }

        # Take a guess as to what the prompt might be if not already defined
        $cmd_prompt="/(\\[$login\\]# |DRAC\\/MC:|\\\$ )/" unless defined $cmd_prompt;


        # Send login
        $t->print($login);

        # Expect 'Password: '
        $t->waitfor("/Password: /") or
                fail "failed: timeout waiting for password";

        # Send password
        $t->print($passwd);

        # DRAC5 prints version controller version info
        # only after you've logged in.
        if ($drac_version eq $DRAC_VERSION_UNKNOWN) {
                if ($t->waitfor(Match => "/.*\($DRAC_VERSION_5\)/m")) {
                        $drac_version = $DRAC_VERSION_5;
                        $cmd_prompt = "/\\\$ /";
                        $PWR_CMD_SUCCESS = $PWR_CMD_SUCCESS_DRAC5;
               } elsif ($t->waitfor(Match => "/.*\(admin\)/m")) {
                        $drac_version = $DRAC_VERSION_5;
                        $cmd_prompt = '/> $/';
                        $PWR_CMD_SUCCESS = $PWR_CMD_SUCCESS_DRAC5;
                } else {
                        print "WARNING: unable to detect DRAC version '$_'\n";
                }
        }

        $t->waitfor($cmd_prompt) or
                fail "failed: invalid username or password";

        if ($drac_version eq $DRAC_VERSION_UNKNOWN) {
                print "WARNING: unsupported DRAC version '$drac_version'\n";
        }

        $logged_in = 1;
}

#
# Set the power status of the node
#
sub set_power_status
{
        my ($state,$dummy) = @_;
        my $cmd,$svr_action;

        if   ( $state =~ /^on$/)  { $svr_action = "powerup"   }
        elsif( $state =~ /^off$/) { $svr_action = "powerdown" }

        if ($drac_version eq $DRAC_VERSION_MC)
        {
                $cmd = "serveraction -m $modulename  -d 0 $svr_action";
        }
        elsif ($drac_version eq $DRAC_VERSION_5) {
                $cmd = "racadm serveraction $svr_action";
        } else
        {
                $cmd = "serveraction -d 0 $svr_action";
        }

        $t->print($cmd);

        # Expect /$cmd_prompt/
        ($_) = $t->waitfor($cmd_prompt) or
                fail "failed: unexpected serveraction response";

        my @cmd_out = split /\n/;

        # discard command sent to DRAC
        $_ = shift @cmd_out;
        s/\e\[(([0-9]+;)*[0-9]+)*[ABCDfHJKmsu]//g; #strip ansi chars
        s/^.*\x0D//;

        fail "failed: unkown dialog exception: '$_'" unless (/^$cmd$/);

        # Additional lines of output probably means an error.
        # Aborting to be safe.  Note: additional user debugging will be
        # necessary,  run with -D and -v flags
        my $err;
        while (@cmd_out)
        {
                $_ = shift @cmd_out;
                #firmware vers 1.2 on DRAC/MC sends ansi chars - evil
                s/\e\[(([0-9]+;)*[0-9]+)*[ABCDfHJKmsu]//g;
                s/^.*\x0D//;

                next if (/^\s*$/); # skip empty lines
                if (defined $err)
                {
                        $err = $err."\n$_";
                }
                else
                {
                        next if ($PWR_CMD_SUCCESS);
                        $err = $_;
                }
        }
        fail "failed: unexpected response: '$err'" if defined $err; }


#
# get the power status of the node and return it in $status and $_ # sub get_power_status {
        my $status;
        my $modname = $modulename;
        my $cmd;

        if ($drac_version eq $DRAC_VERSION_5) {
                $cmd = "racadm serveraction powerstatus";
        } else {
                $cmd = "getmodinfo";
        }

        $t->print($cmd);

        ($_) = $t->waitfor($cmd_prompt);

        my $found_header = 0;
        my $found_module = 0;

        my @cmd_out = split /\n/;

        # discard command sent to DRAC
        $_ = shift @cmd_out;
        #strip ansi control chars
        s/\e\[(([0-9]+;)*[0-9]+)*[ABCDfHJKmsu]//g;
        s/^.*\x0D//;

        fail "failed: unkown dialog exception: '$_'" unless (/^$cmd$/);

        if ($drac_version ne $DRAC_VERSION_5) {
                #Expect:
                #  #<group>     <module>    <presence>  <pwrState>  <health>  <svcTag>
                #   1  ---->     chassis    Present         ON      Normal    CQXYV61
                #
                #  Note: DRAC/MC has many entries in the table whereas DRAC III has only
                #  a single table entry.

                while (1)
                {
                        $_ = shift @cmd_out;
                        if (/^#<group>\s*<module>\s*<presence>\s*<pwrState>\s*<health>\s*<svcTag>/)
                        {
                                $found_header = 1;
                                last;
                        }
                }
                fail "failed: invalid 'getmodinfo' header: '$_'" unless $found_header;
        }

        foreach (@cmd_out)
        {
                s/^\s+//g; #strip leading space
                s/\s+$//g; #strip training space

                if ($drac_version eq $DRAC_VERSION_5) {
                        if(m/^Server power status: (\w+)/) {
                                $status = lc($1);
                        }
                } else {
                        my ($group,$arrow,$module,$presence,$pwrstate,$health,
                                $svctag,$junk) = split /\s+/;

                        if ($drac_version eq  $DRAC_VERSION_III_XT || $drac_version eq $DRAC_VERSION_4I || $drac_version eq $DRAC_VERSION_4P)
                        {
                                fail "failed: extraneous output detected from 'getmodinfo'" if $found_module;
                                $found_module = 1;
                                $modname = $module;
                        }

                        if ($modname eq $module)
                        {
                                fail "failed: duplicate module names detected" if $status;
                                $found_module = 1;

                                fail "failed: module not reported present" unless ($presence =~ /Present/);
                                $status = $pwrstate;
                        }

                }
        }

        if ($drac_version eq $DRAC_VERSION_MC)
        {
                fail "failed: module '$modulename' not detected" unless $found_module;
        }

        $_=$status;
        if(/^(on|off)$/i)
        {
                # valid power states
        }
        elsif ($status)
        {
                fail "failed: unknown power state '$status'";
        }
        else
        {
                fail "failed: unable to determine power state";
        }
}


# Wait upto $power_timeout seconds for node power state to change to # $state before erroring out.
#
# return 1 on success
# return 0 on failure
#
sub wait_power_status
{
        my ($state,$dummy) = @_;
        my $status;

        $state = lc $state;

        for (my $i=0; $i<$power_timeout ; $i++)
        {
                get_power_status;
                $status = $_;
                my $check = lc $status;

                if ($state eq $check ) { return 1 }
                sleep 1;
        }
        $_ = "timed out waiting to power $state";
        return 0;
}

#
# logout of the telnet session
#
sub logout
{
        $t->print("");
        $t->print("exit");
}

#
# error routine for Net::Telnet instance # sub telnet_error {
        fail "failed: telnet returned: ".$t->errmsg."\n"; }

#
# execute the action.  Valid actions are 'on' 'off' 'reboot' and 'status'.
# TODO: add 'configure' that uses racadm rpm to enable telnet on the drac # sub do_action {
        get_power_status;
        my $status = $_;

        if ($action =~ /^on$/i)
        {
                if ($status =~ /^on$/i)
                {
                        msg "success: already on";
                        return;
                }

                set_power_status on;
                fail "failed: $_" unless wait_power_status on;

                msg "success: powered on";
        }
        elsif ($action =~ /^off$/i)
        {
                if ($status =~ /^off$/i)
                {
                        msg "success: already off";
                        return;
                }

                set_power_status off;
                fail "failed: $_" unless wait_power_status off;

                msg "success: powered off";
        }
        elsif ($action =~ /^reboot$/i)
        {
                if ( !($status =~ /^off$/i) )
                {
                        set_power_status off;
                }
                fail "failed: $_" unless wait_power_status off;

                set_power_status on;
                fail "failed: $_" unless wait_power_status on;

                msg "success: rebooted";
        }
        elsif ($action =~ /^status$/i)
        {
                msg "status: $status";
                return;
        }
        else
        {
                fail "failed: unrecognised action: '$action'";
        }
}

#
# Decipher STDIN parameters
#
sub get_options_stdin
{
        my $opt;
        my $line = 0;
        while( defined($in = <>) )
        {
                $_ = $in;
                chomp;

                # strip leading and trailing whitespace
                s/^\s*//;
                s/\s*$//;

                # skip comments
                next if /^#/;

                $line+=1;
                $opt=$_;
                next unless $opt;

                ($name,$val)=split /\s*=\s*/, $opt;

                if ( $name eq "" )
                {
                        print STDERR "parse error: illegal name in option $line\n";
                        exit 2;
                }
                # DO NOTHING -- this field is used by fenced
                elsif ($name eq "agent" )
                {
                }
                elsif ($name eq "ipaddr" )
                {
                        $address = $val;
                }
                elsif ($name eq "login" )
                {
                        $login = $val;
                }
                elsif ($name eq "action" )
                {
                        $action = $val;
                }
                elsif ($name eq "passwd" )
                {
                        $passwd = $val;
                }
                elsif ($name eq "passwd_script" )
                {
                        $passwd_script = $val;
                }
                elsif ($name eq "debug" )
                {
                        $debug = $val;
                }
                elsif ($name eq "modulename" )
                {
                        $modulename = $val;
                }
                elsif ($name eq "drac_version" )
                {
                        $drac_version = $val;
                }
                elsif ($name eq "cmd_prompt" )
                {
                        $cmd_prompt = $val;
                }
                # Excess name/vals will fail
                else
                {
                        fail "parse error: unknown option \"$opt\"";
                }
        }
}


### MAIN #######################################################

#
# Check parameters
#
if (@ARGV > 0) {
        getopts("a:c:d:D:hl:m:o:p:S:qVv") || fail_usage ;

        usage if defined $opt_h;
        version if defined $opt_V;

        $quiet = 1 if defined $opt_q;
        $debug = $opt_D;

        fail_usage "Unknown parameter." if (@ARGV > 0);

        fail_usage "No '-a' flag specified." unless defined $opt_a;
        $address = $opt_a;

        fail_usage "No '-l' flag specified." unless defined $opt_l;
        $login = $opt_l;

        $modulename = $opt_m if defined $opt_m;

        if (defined $opt_S) {
                $pwd_script_out = `$opt_S`;
                chomp($pwd_script_out);
                if ($pwd_script_out) {
                        $opt_p = $pwd_script_out;
                }
        }

        fail_usage "No '-p' or '-S' flag specified." unless defined $opt_p;
        $passwd = $opt_p;

        $verbose = $opt_v if defined $opt_v;

        $cmd_prompt = $opt_c if defined $opt_c;
        $drac_version = $opt_d if defined $opt_d;

        if ($opt_o)
        {
                fail_usage "Unrecognised action '$opt_o' for '-o' flag"
                unless $opt_o =~ /^(Off|On|Reboot|status)$/i;
                $action = $opt_o;
        }

} else {
        get_options_stdin();

        fail "failed: no IP address" unless defined $address;
        fail "failed: no login name" unless defined $login;

        if (defined $passwd_script) {
                $pwd_script_out = `$passwd_script`;
                chomp($pwd_script_out);
                if ($pwd_script_out) {
                        $passwd = $pwd_script_out;
                }
        }

        fail "failed: no password" unless defined $passwd;
        fail "failed: unrecognised action: $action"
                unless $action =~ /^(Off|On|Reboot|status)$/i; }


$t->timeout($telnet_timeout);
$t->input_log($debug) if $debug;
$t->errmode('return');

login;

# Abort on failure beyond here
$t->errmode(\&telnet_error);

if ($drac_version eq $DRAC_VERSION_III_XT) {
        fail "failed: option 'modulename' not compatilble with DRAC version '$drac_version'"
                if defined $modulename;
}
elsif ($drac_version eq $DRAC_VERSION_MC) {
        fail "failed: option 'modulename' required for DRAC version '$drac_version'"
                unless  defined $modulename;
}

do_action;

logout;

exit 0;


-----Original Message-----
From: linux-cluster-bounces at redhat.com [mailto:linux-cluster-bounces at redhat.com] On Behalf Of Andrew A. Neuschwander
Sent: Wednesday, September 30, 2009 3:48 PM
To: linux clustering
Subject: Re: [Linux-cluster] Dell iDRAC 6 Support for fencing device

Could you post your modified fence_drac for iDRAC 6?

Thanks,
-A
--
Andrew A. Neuschwander, RHCE
Systems/Software Engineer
College of Forestry and Conservation
The University of Montana
http://www.ntsg.umt.edu
andrew at ntsg.umt.edu - 406.243.6310


Nitin Choudhary wrote:
> Hi!
>
> With small modification to fence_drac script it is working now.
>
> Thanks,
>
> Nitin
>
>
> -----Original Message-----
> From: linux-cluster-bounces at redhat.com [mailto:linux-cluster-bounces at redhat.com] On Behalf Of Louis
> Sent: Tuesday, September 29, 2009 6:16 PM
> To: linux clustering
> Subject: Re: [Linux-cluster] Dell iDRAC 6 Support for fencing device
>
> Hi,
>
> I used ipmilan to bypass the iDREC6 fencing.
>
> <fencedevice agent="fence_ipmilan" ipaddr="10.10.10.10" login="xxxxx"
> name="xxxxx" passwd="yyyy">
>
>
> Regards
> Louis
> ----- Original Message -----
> From: "Nitin Choudhary" <Nitin.Choudhary at palm.com>
> To: "linux clustering" <linux-cluster at redhat.com>
> Sent: Tuesday, September 29, 2009 1:18 PM
> Subject: [Linux-cluster] Dell iDRAC 6 Support for fencing device
>
>
>> Hi!
>>
>> It seems that iDREC6 is not supported as fencing devices.
>>
>> Has anyone setup this before. Is there any workaround for this.
>>
>> Thanks,
>>
>> Nitin
>>
>> --
>> Linux-cluster mailing list
>> Linux-cluster at redhat.com
>> https://www.redhat.com/mailman/listinfo/linux-cluster
>>
>>
>
>
> --
> Linux-cluster mailing list
> Linux-cluster at redhat.com
> https://www.redhat.com/mailman/listinfo/linux-cluster
>
> --
> Linux-cluster mailing list
> Linux-cluster at redhat.com
> https://www.redhat.com/mailman/listinfo/linux-cluster
>

--
Linux-cluster mailing list
Linux-cluster at redhat.com
https://www.redhat.com/mailman/listinfo/linux-cluster




More information about the Linux-cluster mailing list