#!/usr/bin/expect --
################################################################################
#
# File: setPower
#
# Description:  Set the power state of a system using FW commands.
#
# Notes:
#		If the user inputs an iLO console hostname (using -ilo <iloHostname>
#		or -sut <system-ilo>), this tool will connect directly with the
#		ilo console and issue power-control commands, power off, power on, etc.
#		In general, the command will be power <state>, where state is the
#		state passed in using -state <state>.  Recognized arguments
#		to the power command are: on, off, reset, warm.
#
#		If the user passes in the OA hostname and a system location (using
#		-oa <OAhostname> -bay <bladeID>), setPower will connect to the
#		OA and use OA commands to set the power state.  In this case, the
#		control commands for on, off and warm are, "poweroff server <bladeID>",
#		"poweron server <bladeID>", "reboot server <bladeID>".
#		Note that there is no equivalent to the iLO "power reset" command.
#		(The equivalent action is poweroff/poweron).
#         
#       
#      -*- OpenSAF  -*-
#
# (C) Copyright 2008 The OpenSAF Foundation
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed
# under the GNU Lesser General Public License Version 2.1, February 1999.
# The complete license can be accessed from the following location:
# http://opensource.org/licenses/lgpl-license.php
# See the Copying file included with the OpenSAF distribution for full
# licensing terms.
#
# Author(s):
#           Hewlett-Packard Company
#
#
#
################################################################################

# Get the name of this script.
set MyName [lindex [split $argv0 {/}] end]
set caller "$MyName"

################################################################################
#                                 Subroutines
################################################################################

#*******************************************************************************
# SetLibraryPath: Sets the library path for common libraries
# Input: none
# Output: exits with value 0
#*******************************************************************************
proc SetLibraryPath {argv0} {
   global basepath locpath
   global env
   global VERBOSE

   if {![info exists VERBOSE]} {
      set VERBOSE 0
   }
   set libDir "tests/hisv/lib"
    # Get the path to the our libraries
    if {$VERBOSE} {
       send_user "\n\[SM] SetLibraryPath:\n"
       send_user "\targv0 = $argv0\n"
    }
    set pathToMe $argv0
     # If the path to this tool is relative to this directory,
     #   substitute $PWD.
    regsub {^./[^/]+} $pathToMe $env(PWD) pathToMe
     # set locpath to this directory
    regsub {/[^/]+$} $pathToMe "" locpath

    if {$VERBOSE} {
       send_user "\tpathToMe = $pathToMe\n"
       send_user "\tlocpath  = $locpath\n"
    }
    if [info exists env(BASEPATH)] {
        # Use the environment variable BASEPATH if set:
       set basepath "$env(BASEPATH)"
    } \
    else {
           set pathDirs [split $locpath /]
           set pLen [expr [llength $pathDirs] - 1]

            # Work backwards through the path to try to
            #  find the path to the library directory
           for {set i $pLen} {$i > 0 } {incr i -1} {

               if {$i == $pLen} {
                  set dummyPath $pathToMe
               }
               regsub {/[^/]+$} $dummyPath "" dummyPath
               if {[file exists $dummyPath/libsm]} {
                  set basepath $dummyPath
                  break
               } \
               elseif {[file exists $dummyPath/lib/libsm]} {
                  set basepath $dummyPath/lib
                  break
               }
           }

           if {![info exists basepath]} {
               send_user "ERROR: Can't find common library directory $libDir\n"
               exit 2
           }
    }

    if {$VERBOSE} {send_user "\tFound library path $basepath\n"}
}

#*******************************************************************************
# Usage: Print usage message
# Input: none
# Output: exits with value 0
#*******************************************************************************
proc Usage {} {
   global MyName
   global domain
   global iloUser iloPasswd
   global oaUser oaPasswd
   global user passwd

   puts "\nUsage: $MyName -sut=<ilo_hostname> \[optional]"
   puts "    Required options:"
   puts "\t-sut=<ilo_hostname>"
   puts "\t    hostname is the hostname of the system under test."
   puts "\t-state=<on|off|reset|warm>"
   puts "\t    power state to set at the ilo prompt (reset = power-cycle)."
   puts "\t-off"
   puts "\t    turn the system off."
   puts "\t-on"
   puts "\t    turn the system on."
   puts "\t-reset"
   puts "\t    toggle the system power -- only available from iLO."
   puts "\t-warm"
   puts "\t    perform a warm reset."
   puts "\t-reboot"
   puts "\t    perform an os shutdown -- only available from the OA"
   puts "\t-check"
   puts "\t    Verify that the power state was set correctly."
   puts "\t    Default: No checking."
   puts "\t-wait=<wait_seconds>"
   puts "\t    Set wait time before verifying that the system is in the new power state."
   puts ""
   puts "    Other options:"
   puts "\t-ilo_passwd=<ilo_admin_passwd>"
   puts "\t    ilo_admin_passwd is the password for a user with admin privileges on the target system."
   puts "\t    (default: $iloPasswd)."
   puts "\t-ilo_user=<ilo_admin>"
   puts "\t    ilo_admin is a user for a user with admin privileges on the target system."
   puts "\t    (default: $iloUser)."
   puts ""
   puts "\t-oa_passwd=<oa_admin_passwd>"
   puts "\t    oa_admin_passwd is the password for a user with admin privileges on the target system."
   puts "\t    default: $oaPasswd."
   puts "\t-oa_user=<oa_admin>"
   puts "\t    oa_admin is a user for a user with admin privileges on the target system."
   puts ""
   exit 0
} ;# End Usage


#*******************************************************************************
#  ParseArgs: Customized command-line parsing for this test
#  Input: rargv - reference to the argv string
#  Output: sets variables in caller's scope
#  Note: This parses options that didn't match options in
#        libcmdline::ParseCanonicalCmdline, so if the option
#        is not set properly here, check libcmdline.
#*******************************************************************************
proc ParseArgs {rargv} {
   global VERBOSE
   upvar $rargv argv

    # Access the console variable in the caller's scope
    # so the user can specify a console without a flag
   upvar console console

   set unusedArgs ""

   if {$VERBOSE} {
       send_user "\n\[SM] ParseArgs:\n"
   }
   if [info exists argv] {
      if {$VERBOSE} { send_user "\targv = $argv\n"}
   } \
   else {
      return
   }
 
   set argv [split $argv { =}]

   while {[llength $argv] > 0} {
       set opt [shift argv]
       switch -- $opt {
           -h -
           -help -
           --help -
           -? {  Usage }
           -off { uplevel #0 set powerState "off"; continue }
           -on  { uplevel #0 set powerState "on"; continue }
           -cycle -
           -power_cycle -
           -pwr_cycle -
           -reset { uplevel #0 set powerState "reset"; continue }
           -s -
           -set -
           -pwr -
           -state { uplevel #0 set powerState [shift argv]; continue }
           -warm { uplevel #0 set powerState "warm"; continue }
           -reset { uplevel #0 set powerState "reset"; continue }
           -wait { uplevel #0 set WaitForPower [shift argv]; continue }
           default {
              if { $opt != "" } {
                 if {![info exists console] || [info exists console] && [regexp {^[0-9]+$} $console]} {
                    set console $opt
                    SmartParse
                 } \
                 else {
                    send_user "\nWARNING: Unknown option $opt\n"
                    push unusedArgs $opt
                 }
              }
           }
       }
    }  ;# End while
    set argv $unusedArgs
}   ;# End ParseArgs


#*******************************************************************************
#  CheckUserInput: Check that the necessary parameters were specified.
#  Input: none
#  Output: Exits if validity check fails
#*******************************************************************************
proc CheckUserInput {} {
    global console powerState type sut

        # Check console information
    if {![info exists console]} {
       ErrorMessage "You must specify an iLO console to connect to" 1
    }
    if {![info exists type]} {
       ErrorMessage "No console type set, perhaps there was an error parsing? (console = $console)" 1
    }

    if {![info exists sut]} {
       ErrorMessage "You must specify the system to set the power on\n" 1
    }  
    if {$type == "oa"} {
       if {![regexp {[0-9]+} $sut]} {
           ErrorMessage "You must specify the system to set the power on\n\t(From the OA, specify bay [1-16])" 1
       }
    }

    if {$type != "oa" && $type != "ilo"} {
       ErrorMessage "Console type $type not recognized, parse error? (console = $console)" 1
    }
        # Check requested power state
    if {![info exists powerState]} {
       ErrorMessage "You must specify the power state you want to set\n" 1
    }
}

################################################################################
#                              End Subroutines
################################################################################
# Set verbose early to get verbose output from search for library
# path and command-line parsing
if {[regexp -- {-v} $argv]} { set VERBOSE 1 }

# Set library path
SetLibraryPath $argv0

#***************************** Global Variables ********************************
source $basepath/defaults

# Reset VERBOSE, since defaults sets it to zero
if {[regexp -- {-v} $argv]} { set VERBOSE 1 }

# Source libraries.
source "$basepath/libcmdline"
source "$basepath/stdlib"
source "$basepath/libilo"
source "$basepath/libsm"
source "$basepath/liblinux"
source "$basepath/libstate"

set WaitForPower 30
set DoCheck 0

################################################################################
#                           Overloaded Subroutines
################################################################################
#  Add subroutines, e.g., Done, here to override the
#  default action as defined in the libraries above.

################################################################################
#                         End Overloaded Subroutines
################################################################################

# Set interrupt handlers
SetSigTraps


################################################################################
#                                     MAIN
################################################################################
#************************** Configuration Loading ******************************

# Override default settings with command-line options
ParseCanonicalCmdline argv
if {[info exists argv] && [llength $argv]} { ParseArgs argv }
if {![info exists prompt]} { set prompt $root_prompt }

# Show the user what's going on...
if {$VERBOSE} { log_user 1 }

# Set the Expect log file if we are in verbose mode.
set log "$MyName"
set log [split $log {.}]
set logfilename "[lindex $log 0].log.[pid]"

if {[info exists env(DRYRUN)] && $env(DRYRUN)} {
   set DRYRUN 1
   set VERBOSE 3
}

#**************************** Start Debug-Logfile ******************************
if { $VERBOSE || [info exists env(DEBUG)] && $env(DEBUG)} {
    exp_internal -f $logfilename 0
    send_user "\n\[SM] Logfile is $logfilename\n"
}

#*************************** Connect to the System *****************************
set timeout $timeout_setting

# Check for valid information
CheckUserInput

if {$VERBOSE} {
   send_user "\[SM] $MyName:\n"
   if {[info exists console]} {send_user "\tconsole is $console\n"}
   if {[info exists sut]} {send_user "\tsut is $sut\n"}
   if {[info exists type]} {send_user "\ttype is $type\n"}
   if {[info exists powerState]} {send_user "\tpowerState is $powerState\n"}
}

# Connect to the iLO console

if {$type == "ilo"} {
   set fw_passwd $iloPasswd
   set fw_user $iloUser
} \
elseif {$type == "oa"} {
   if {![info exists sut]} {
      ErrorMessage "You must provide the iLO hostname, user and password\n" 1
   }
   set fw_passwd $oaPasswd
   set fw_user $oaUser
}
if {![ConnectFW $console $fw_user $fw_passwd]} {
   ErrorMessage "Failed to connect to $type" 1
}

# Clean out any chassis codes
expect *

#****************************** Start the Test *********************************
set failed 0
if {![SetPowerState $powerState $DoCheck sut]} {
      ErrorMessage "Failed to set power state to $powerState" 1
}

#******************************* End the Test **********************************
Done $failed

##
# vim: tabstop=4
# -*- tab-width:4 -*-
##
