#!@PERL@
#
# An improved rILOII plugin
# Works for heartbeat v2
# v1.0 gmpc at sanger.ac.uk
#  27/01/2006
# Implements all mandatory directives.
# poweron/off not yet implemented.
#
# v1.1 Tijl Van den Broeck subspawn@gmail.com
#  09/01/2007
#  - Implemented on/off functions
#  - Code cleanup, generic ilo_login & ilo_logout functions
#  - Added ILOUSER parameter, not everybody uses the Administrator account
# 
# See HP Integrated Lights-Out Management Processor Scripting and Command Line Resource Guide
# at the HP website for more information on the RIBCL language implementation and other
# available commands.
#
# Put in /usr/lib/stonith/plugins/external to use
#
use IO::Socket::SSL;

#Environment variables
# REALHOST (list of hosts wot we are responsible for)
# ILOHOST (hostname of the ilo)
# ILOUSER (username for ilo login)
# ILOPASS (password for the ilo)


$ilohost= $ENV{ILOHOST}.":443";
$ilopasswd=$ENV{ILOPASS};
$ilouser=$ENV{ILOUSER} || "Administrator";
$realhost=$ENV{REALHOST} || "<unconfigured>";

# Connect to ILO
# Push initial XML statements to login
# Return SSL socket
sub ilo_login {
  $client = new IO::Socket::SSL->new(PeerAddr => $ilohost) || die ("Unable to contact ILO $ilohost\n");
  print $client '<?xml version="1.0"?>' . "\r\n";
  print $client '<LOCFG version="2.25"/>';
  print $client '<RIBCL version="2.0">';
  print $client "<LOGIN USER_LOGIN=\"$ilouser\" PASSWORD=\"$ilopasswd\" >";
  return $client
}

# Push logout XML statements
sub ilo_logout {
  my ($client) = @_;
  print $client '</LOGIN>';
  print $client '</RIBCL>';
  return $client;
}

# Status iLO, can we retrieve power state
sub status_ilo {
    $client=ilo_login();
    print $client '<SERVER_INFO MODE="read">';
    print $client '<GET_HOST_POWER_STATUS/>';
    print $client '</SERVER_INFO>';
    $client=ilo_logout($client);

    # Catch output from ILO, check for HOST_POWER
    while($ln=<$client>) {
  if ( $ln=~/HOST_POWER=/ )
  {
      # Status ok
      exit 0;
  }
    }
    # Status failed
    exit 1;
}


sub reset_ilo {
    
    $client=ilo_login();
    print $client '<SERVER_INFO MODE="write">';
    print $client '<RESET_SERVER/>';
    print $client '</SERVER_INFO>';
    $client=ilo_logout($client);
    
   # Two responses are acceptable; either the server has been reset,    
   # or the power is already off.
   
   while($ln=<$client>) {
   
if ( $ln=~/MESSAGE='Server being reset.'/ )
{
   exit 0;
}
if ( $ln=~/Host power is already OFF/ )
{
   exit 0;
}
   }
   # If we get here, then we did not stonith.
   exit 1;
}

# To power off the system, ILO offers 2 options:
# ACPI -> <SET_HOST_POWER HOST_POWER="No"/>
# Cold -> <HOLD_PWR_BTN/>
# ACPI will try to shutdown when the system supports it
# If the system we're trying to shoot is "crashed" it is higly
# likely it will not respond to ACPI shutdowns, so cold is used
sub off_ilo {
   $client=ilo_login();
   print $client '<SERVER_INFO MODE="write">';
   print $client '<HOLD_PWR_BTN/>';
   print $client '</SERVER_INFO>';
   $client=ilo_logout($client);

   # check if the power is off

   while($ln=<$client>) {

  if ( $ln=~/Host power is already OFF/ )
  {
      exit 0;
  }
    }
# The following statements ONLY apply when using <SET_HOST_POWER HOST_POWER="No"/> !!!!!
#     # power is not off... but did we succeed ?
#     # ilo is not very polite, it does not tell us what it just did (unless an error occured)
#     # so we reconnect once again, and query it's state
#     $client=ilo_login();
#     print $client '<SERVER_INFO MODE="read">';
#     print $client '<GET_HOST_POWER_STATUS/>';
#     print $client '</SERVER_INFO>';
#     $client=ilo_logout($client);
#   
#     while($ln=<$client>) {
#   if ( $ln=~/HOST_POWER="OFF"/ )
#   {
#       # Ok. power is off
#       exit 0;
#   }
#     }
 
    # If we get here, then we did not stonith.
    exit 1;

}

sub on_ilo {

    $client=ilo_login();
    print $client '<SERVER_INFO MODE="write">';
    print $client '<SET_HOST_POWER HOST_POWER="Yes"/>';
    print $client '</SERVER_INFO>';
    $client=ilo_logout($client);

    # check if the power is already on.

    while($ln=<$client>) {

  if ( $ln=~/Host power is already ON/ )
  {
      exit 0;
  }
    }
    
    # did we succeed ?
    # ilo is not very polite, it does not tell us what it just did (unless an error occured)
    # so we reconnect once again, and query it's state
    $client=ilo_login();
    print $client '<SERVER_INFO MODE="read">';
    print $client '<GET_HOST_POWER_STATUS/>';
    print $client '</SERVER_INFO>';
    $client=ilo_logout($client);
  
    while($ln=<$client>) {
  if ( $ln=~/HOST_POWER="ON"/ )
  {
      # Ok. power is off
      exit 0;
  }
    }
 
    # If we get here, then we did not stonith.
    exit 1;

}


sub gethosts {
    print "$realhost";
    exit 0;
}


sub getinfo_xml {

format  = 
<parameters>
 <parameter name="REALHOST" unique=1>
  <content type="string"/>
  <shortdesc lang="en">hostname</shortdesc>
  <longdesc lang=en>
   The hostname that the ilo controls
  </longdesc>
 </parameter>
<parameter name="ILOHOST" unique=1>
  <content type="string"/>
  <shortdesc lang="en">ilohostname</shortdesc>
  <longdesc lang=en>
   The hostname of the ilo device
  </longdesc>
 </parameter>
<parameter name="ILOUSER" unique=1>
  <content type="string"/>
  <shortdesc lang="en">ilousername</shortdesc>
  <longdesc lang=en>
   The user for connecting to the ilo device
  </longdesc>
 </parameter>
<parameter name="ILOPASS" unique=1>
  <content type="string"/>
  <shortdesc lang="en">password</shortdesc>
  <longdesc lang=en>
   The password for the ilo device user
  </longdesc>
 </parameter>
</parameters>
.
    write ;
}

sub getconfig {
    print "REALHOST ILOHOST ILOUSER ILOPASS\n";
}

sub getinfodev {
    print "Improved Sanger rilo2 stonith device\n";
}

sub getinfourl {
    print "http://www.sanger.ac.uk\n";
}


SWITCH:
{
($ARGV[0] =~ /getinfo-xml/) and getinfo_xml() and last SWITCH;
($ARGV[0] =~ /status/) and  status_ilo() and last SWITCH;
($ARGV[0] =~ /reset/) and reset_ilo() and last SWITCH;
($ARGV[0] =~ /gethosts/) and gethosts() and last SWITCH;
($ARGV[0] =~ /getconfignames/) and getconfig() and last SWITCH;
($ARGV[0] =~ /getinfo-devid/) and getinfodev() and last SWITCH;
($ARGV[0] =~ /getinfo-devname/) and getinfodev() and last SWITCH;
($ARGV[0] =~ /getinfo-devdescr/) and getinfodev() and last SWITCH;
($ARGV[0] =~ /getinfo-devurl/) and getinfourl() and last SWITCH;
($ARGV[0] =~ /off/) and off_ilo() and last SWITCH;
($ARGV[0] =~ /on/) and on_ilo() and last SWITCH;
}





exit 0;
