Commit 760e60f7 authored by Mike Hibler's avatar Mike Hibler

Serious munging of the ipmi-ms code to support the "cyclewhenoff" attribute.

We set this attribute for the Moonshot cartridges so that "power cycle"
will force a "power on" if it detects the node is off when attempting
a cycle operation.

Also, implement "power status" for the Moonshot nodes.
parent a896be22
......@@ -396,7 +396,7 @@ foreach my $power_id (keys %outlets) {
# of object
#
my $errors = 0;
if ($type eq "IPMI" || $type eq "ipmi-ms") {
if ($type eq "IPMI") {
my $device = new power_ipmi($type,$power_id,$verbose);
if (!defined $device) {
warn "Unable to contact controller for $nodestr. Skipping...\n";
......@@ -517,6 +517,60 @@ foreach my $power_id (keys %outlets) {
++$errors;
}
}
} elsif ($type eq 'ipmi-ms') {
#
# XXX a "cycle" operation on IPMI will fail if the node is off.
# See comment above for ipmi15 case.
#
# XXX Through a historic quirk, these speak in terms of outlets
# rather than nodes, so we map between the two.
#
my $device = new power_ipmi($type, $power_id, $verbose);
if (!defined $device) {
warn "Unable to contact controller for $nodestr. Skipping...\n";
next;
}
my (@forcenodes, @unforcenodes);
my (@forceoutlets, @unforceoutlets);
if ($op eq "cycle") {
for (my $ix = 0; $ix < @nodes; $ix++) {
my $nodeid = $nodes[$ix];
my $outlet = $outlets[$ix];
my $node = $nodes{$nodeid};
if ($node->cyclewhenoff()) {
push @forceoutlets, $outlet;
push @forcenodes, $nodeid;
} else {
push @unforceoutlets, $outlet;
push @unforcenodes, $nodeid;
}
}
} else {
@unforceoutlets = @outlets;
@unforcenodes = @nodes;
}
if (@forceoutlets) {
$nodestr = join(',', @forcenodes);
print "Calling device->power(forcecycle, @forceoutlets)\n"
if $verbose > 1;
if ($device->power("forcecycle", @forceoutlets)) {
print "Control of $nodestr failed.\n";
$exitval++;
$errors++;
}
}
if (@unforceoutlets) {
$nodestr = join(',', @unforcenodes);
print "Calling device->power($op, @unforceoutlets)\n"
if $verbose > 1;
if ($device->power($op, @unforceoutlets)) {
print "Control of $nodestr failed.\n";
$exitval++;
$errors++;
}
}
} elsif ($type eq 'ilo3' || $type eq 'ilo2' || $type eq 'ilo' ||
$type eq 'drac') {
if (iloctrl($type,$op,@nodes)) {
......@@ -661,10 +715,28 @@ sub dostatus(@) {
next;
}
# XXX hack for Moonshots is slightly different
if ($ctrls{$ctrl} eq "ipmi-ms") {
if (!exists($pernode{$ctrl})) {
push(@nwanted, $ctrl);
push(@{$pernode{$ctrl}}, $outlet);
} elsif (@{$pernode{$ctrl}} > 0) {
push(@{$pernode{$ctrl}}, $outlet);
}
print "$node: $ctrl outlet $outlet\n";
next;
}
print "$node is $ctrl outlet $outlet...\n";
}
} else {
$ctrl = $node;
if ($ctrls{$ctrl} eq "ipmi-ms") {
if (!exists($pernode{$ctrl})) {
push(@nwanted, $ctrl);
}
@{$pernode{$ctrl}} = ();
next;
}
}
push(@nwanted, $ctrl);
}
......@@ -742,6 +814,44 @@ sub dostatus(@) {
if (defined($status{$ostr}));
}
print "\n";
} elsif ($ctrls{$ctrl} =~ /^ipmi-ms/) {
# if there is an empty list of nodes, we wall all of them.
my @outlets = sort {$a <=> $b} @{$pernode{$ctrl}};
if (@outlets == 0) {
@outlets = (1..45);
}
delete $pernode{$ctrl};
print STDERR "Getting IPMI status for $ctrl outlets ", join(' ', @outlets), "\n"
if ($verbose);
my $device = new power_ipmi("ipmi-ms", $ctrl, $verbose);
if (!defined $device) {
warn "Unable to contact controller $ctrl.\n";
$errors++;
next;
} else {
print "Calling device->status()\n"
if $verbose > 1;
if ($device->status(\%status, @outlets)) {
print "Could not get status for $ctrl.\n";
$errors++;
next;
}
}
for my $outlet (@outlets) {
my $oname = "outlet$outlet";
my $state;
if (!exists($status{$oname})) {
$state = "<unknown>";
} elsif ($status{$oname} == 1) {
$state = "on";
} elsif ($status{$oname} == 0) {
$state = "off";
} else {
$state = "<unknown>";
}
print "$ctrl Node $outlet: $state\n";
}
} elsif (!$doall) {
warn "Cannot get status for $ctrl (type " .
$ctrls{$ctrl} . ") yet\n";
......
......@@ -52,7 +52,7 @@ my $MS_NODEBRIDGEID = 0x7;
my $MS_CARTBASEADDR = 0x82;
my $MS_CARTBRIDGEID = 0x0;
sub new($$$;$) {
sub new($$$;$$) {
# The next two lines are some voodoo taken from perltoot(1)
my $proto = shift;
......@@ -61,10 +61,14 @@ sub new($$$;$) {
my $devicetype = shift;
my $devicename = shift;
my $debug = shift;
my $withsdr = shift;
if (!defined($debug)) {
$debug = 0;
}
if (!defined($withsdr)) {
$withsdr = 0;
}
if ($debug) {
print "power_ipmi module initializing... debug level $debug\n";
......@@ -73,6 +77,7 @@ sub new($$$;$) {
my $self = {};
$self->{DEBUG} = $debug;
$self->{WITHSDR} = $withsdr;
$self->{DEVICETYPE} = $devicetype;
$self->{DEVICENAME} = $devicename;
......@@ -130,13 +135,17 @@ sub power($$@) {
my $self = shift;
my $op = shift;
my @outlets = @_;
my %status = ();
my $errors = 0;
my ($retval, $output);
my $force = 0;
if ($op eq "on") { $op = "power on"; }
elsif ($op eq "off") { $op = "power off"; }
elsif ($op =~ /cyc/) {
if ($op eq "forcecycle") {
$force = 1;
}
if ($self->{DEVICETYPE} eq "ipmi-ms") {
$op = "power cycle";
} else {
......@@ -144,7 +153,7 @@ sub power($$@) {
}
}
($errors, $output) = $self->_execipmicmd($op, @outlets);
$errors = $self->_execipmicmd($op, \@outlets, \%status, $force);
if ($errors) {
print STDERR $self->{DEVICENAME}, ": command '$op' failed for some/all outlets: @outlets\n";
}
......@@ -152,50 +161,68 @@ sub power($$@) {
return $errors;
}
# XXX: This isn't actually hooked in, and won't work for the moonshot
# as it is.
sub status($$$) {
sub status($$@) {
my $self = shift;
my $type = shift;
my $statusp = shift; # pointer to an associative (hashed) array (i.o.w. passed by reference)
my %status; # local associative array which we'll pass back through $statusp
my $statusp = shift;
my @outlets = @_;
my %status;
my $errors = 0;
my ($retval, $output);
# XXX: No support for the moonshot right now.
if ($type eq "ipmi-ms") {
return 0;
}
# Get power status (i.e. whether system is on/off)
($retval,$output) = $self->_execipmicmd("power status");
$retval = $self->_execipmicmd("power status", \@outlets, \%status, 0);
if ( $retval != 0 ) {
$errors++;
print STDERR $self->{DEVICENAME}, ": could not get power status from device\n";
}
else { $status{'outlet1'} = $output; print("Power status is: $output\n") if $self->{DEBUG}; } # there's only 1 "outlet" on an IPMI card
# Get Sensor Data Repository (sdr) entries and readings
($retval,$output) = $self->_execipmicmd("sdr");
if ( $retval != 0 ) {
$errors++;
print STDERR $self->{DEVICENAME}, ": could not get sensor data from device\n";
# XXX needs work
if ($self->{WITHSDR}) {
my %lstatus = ();
$retval = $self->_execipmicmd("sdr", \@outlets, \%lstatus, 0);
if ( $retval != 0 ) {
$errors++;
print STDERR $self->{DEVICENAME}, ": could not get sensor data from device\n";
}
else {
foreach my $outlet (@outlets) {
my $oname = "outlet" . $outlet;
$output = "UNKNOWN";
if (exists($lstatus{$oname})) {
$output = $lstatus{$oname};
}
print("SDR data is:\n$output\n") if $self->{DEBUG};
$status{'sdr'} = $output;
}
}
}
else { $status{'sdr'} = $output; print("SDR data is:\n$output\n") if $self->{DEBUG}; }
if ($statusp) { %$statusp = %status; } # update passed-by-reference array
return $errors;
}
sub _execipmicmd($$@) { # _ indicates that this is a private method (Perl convention)
my ($self, $op, @outlets) = @_;
#
# The returned status is expected to be:
#
# $status{'outletN'} = <status string from command> (e.g., "on", "off")
#
# where N is the outlet number.
#
sub _execipmicmd($$$$$) {
my ($self, $op, $outletsp, $statusp, $force) = @_;
my $exitval = 0;
my $output = "";
my @results = ();
if (!defined($outletsp)) {
return 0;
}
my $isstatus = ($op eq "power status") ? 1 : 0;
my $coderef = sub {
my $outlet = shift;
my $output = "";
......@@ -214,35 +241,65 @@ sub _execipmicmd($$@) { # _ indicates that this is a private method (Perl conven
$cmd = "$self->{IPMICMD} $op";
}
again:
print STDERR "**** Executing $cmd\n"
if ($self->{DEBUG});
$output = `$cmd 2>&1`; # get output of the $cmd, e.g. many lines of sensor readings or "Chassis power is on"
chomp ( $output ); # remove the \n at the end, if any
$output = `$cmd 2>&1`;
chomp ( $output );
print STDERR "impitool output:\n$output\n"
if ($self->{DEBUG});
if ($?) {
# XXX special case handling of node powered off
if ($output =~ /not supported in present state/) {
if ($force) {
print "*** Cycle failed, trying power on instead.\n"
if ($self->{DEBUG} > 1);
$cmd =~ s/power (cycle|reset)/power on/;
$force = 0;
goto again;
}
}
print STDERR "*** power_ipmi: ipmitool returned non-zero: $?\n";
print STDERR "ipmitool output:\n$output\n";
return -1;
}
# for a status command we have to interpret the output
if ($isstatus) {
if ($output =~ /power is (off|on)/i) {
return ($1 eq "off") ? 0 : 1;
}
print STDERR "*** power_ipmi: unexpected power status:\n$output\n";
return -1;
}
return 0;
};
my @outlets = @$outletsp;
if (ParRun(undef, \@results, $coderef, @outlets)) {
print STDERR "*** power_ipmi: Internal error in ParRun()!\n";
return (-1,undef);
return -1;
}
#
# Check the exit codes.
#
foreach my $result (@results) {
++$exitval
if ($result != 0);
for (my $ix = 0; $ix < @outlets; $ix++) {
my $outlet = "outlet" . $outlets[$ix];
my $rv = ($results[$ix] >> 8);
$statusp->{$outlet} = $rv;
if ($isstatus) {
++$exitval
if ($rv < 0);
} else {
++$exitval
if ($rv != 0);
}
}
return ($exitval, $output);
return $exitval;
}
sub _mkmsmap() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment