#!/usr/bin/expect --
################################################################################
#
# File: runCli
#
# Description: Perform functional CLI tests of power control
#
# Notes:
#		The general test procedure is:
#			1.  Check the power state of the systems
#			2.	Run the command (checking for successful completion)
#			3.	Check the power states of the systems  (verify
#				that only the target system's power state changed).
#			4.  Check the HISv log for error messages.
#         
#       
#      -*- 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: Just returns -- used by Usage()
#*******************************************************************************
proc PrintUsage {} {
   global MyName
   global timeout_setting

   puts "\nUsage: $MyName -blade=<blade_id> -chassis=<chassis_id> \[-state=<on|off>| -reset=<hard|soft>]"
   puts "   OR: $MyName -blade=<blade_id> -chassis=<chassis_id> \[-on|-off]"
   puts "   OR: $MyName -blade=<blade_id> -chassis=<chassis_id> \[-hard|-soft]"
   puts "   OR: $MyName -cmd=<cli_cmd>"
   puts "    Required options:"
   puts "\t-reset=<hard|soft>"
   puts "\t    Perform the specified reset on the target system."
   puts "\t-state=<on|off>"
   puts "\t    power state to set using the command-line interface"
   puts "\t-off"
   puts "\t    graceful power off."
   puts "\t-on"
   puts "\t    turn the system on."
   puts "\t-lock"
   puts "\t    force the system off."
   puts "\t-hard"
   puts "\t    perform hard (power cycle) reset."
   puts "\t-soft"
   puts "\t    perform soft (warm) reset."
   puts "\t-cmd"
   puts "\t    Specify a cli command to run."
   puts "\t-blade"
   puts "\t    Specify the blade location."
   puts "\t-chassis"
   puts "\t    Specify the chassis id (consistent with the information in /etc/opensaf/chassis_id)."
   puts ""
   puts "    Optional:"
   puts "\t-timeout=<command_timeout_sec>"
   puts "\t    Set the timeout for the command and its output."
   puts "\t    Default: $timeout_setting"
   puts "\t-v"
   puts "\t    Verbose (debug) output -- creates an expect log file as well (exp_internal 1)"
   puts "\t-dryrun"
   puts "\t    Don't run the test, just print the commands out"
   puts ""
}
	
	
#*******************************************************************************
# Usage: Print usage message
# Input: none
# Output: exits with value 0
#*******************************************************************************
proc Usage {} {
	PrintUsage
	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

   if {$VERBOSE} {
       send_user "\n\[SM] ParseArgs:\n"
   }
   if [info exists argv] {
      if {$VERBOSE} {
		send_user "\targv has [llength $argv] arguments\n"
		send_user "\targv = $argv\n"
	  }
   } \
   else {
      return
   }
 
   while {[llength $argv] > 0} {
       set opt [shift argv]
	   if {$VERBOSE} { send_user "\topt = '$opt'\n"}
       switch -- $opt {
           -command -
           -cmd	{
					 uplevel #0 set cmd [join $argv " "]
					 set argv {}
					 continue
				}
           -h -
           -help -
           --help -
           -? {  Usage }
           -chassis { uplevel #0 set chassis [shift argv]; continue }
           -F -
           -force -
           -f { uplevel #0 set Force 1; continue }
		   -cold -
           -hard {	uplevel #0 set reset "hard"
					uplevel #0 set hisvFunction "reset"
					continue
				}
           -lock {	uplevel #0 set powerState "lock"
					uplevel #0 set hisvFunction "power"
					continue
				}
           -shut -
           -shutdown -
           -off {	uplevel #0 set powerState "shutdown"
					uplevel #0 set hisvFunction "power"
					continue
				}
           -unlock -
           -on  {	uplevel #0 set powerState "unlock"
					uplevel #0 set hisvFunction "power"
					continue
				}
           -path  { uplevel #0 set path [shift argv]; continue }
           -reset { uplevel #0 set reset [shift argv]
					uplevel #0 set hisvFunction "reset"
					continue
				  }
		   -warm -
           -soft {	uplevel #0 set reset "soft"
					uplevel #0 set hisvFunction "reset"
					continue
				}
           -state { uplevel #0 set powerState [shift argv]
					uplevel #0 set hisvFunction "power"
					continue
				  }
       }
    }  ;# End while
}   ;# End ParseArgs


#*******************************************************************************
#  CheckUserInput: Check that the necessary parameters were specified.
#  Input: none
#  Output: Exits if validity check fails
#*******************************************************************************
proc CheckUserInput {} {
    global powerState blade chassis cmd path hisvFunction reset
	global VERBOSE
	  # In verbose mode, print out all of the parameters we're
	  # checking.
	if {$VERBOSE} {
		send_user "\n\[SM] CheckUserInput:\n"
		if {[info exists powerState]} {
			send_user "\tpowerState = $powerState\n"
		} else {
			send_user "\tpowerState NOT set\n"
		}
		if {[info exists reset]} {
			send_user "\treset = $reset\n"
		} else {
			send_user "\treset NOT set\n"
		}
		if {[info exists blade]} {
			send_user "\tblade = $blade\n"
		} else {
			send_user "\tblade NOT set\n"
		}
		if {[info exists chassis]} {
			send_user "\tchassis = $chassis\n"
		} else {
			send_user "\tchassis NOT set\n"
		}
		if {[info exists cmd]} {
			send_user "\tcmd = $cmd\n"
		} else {
			send_user "\tcmd NOT set\n"
		}
		if {[info exists path]} {
			send_user "\tpath = $path\n"
		} else {
			send_user "\tpath NOT set\n"
		}
		if {[info exists hisvFunction]} {
			send_user "\thisvFunction = $hisvFunction\n"
		} else {
			send_user "\thisvFunction NOT set\n"
		}
	}
		# Check to figure out which kind of HISv function we'll try to run
	if {![info exists hisvFunction] && ![info exists cmd]} {
		ErrorMessage "Couldn't figure out what HISv function (reset or power set) is requested" 1
	}
	if {[info exists cmd] && $cmd != "" } { return }

	if {$hisvFunction == "power"} {
        # Check requested power state
	    if {![info exists powerState]} {
			lappend missing "power state"
		}
	} \
	else {
	    if {![info exists reset]} {
			lappend missing "reset"
		}
	}

        # Entity path information
    if {![info exists blade] && ![info exists path]} {
		lappend missing "blade ID"
    }
    if {![info exists chassis] && ![info exists path]} {
		lappend missing "chassis ID"
    }
    if {![info exists blade] && ![info exists chassis] && ![info exists path]} {
		lappend missing "or path"
	}

	if {![info exists cmd]} {
		if {[info exists missing]} {
			send_user "\nERROR: You must specify [join $missing ", "] for the target system\n"
			PrintUsage
			exit 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
set send_slow {1 .02}
set timeout_setting 30

# 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/libsm"
source "$basepath/liblinux"
source "$basepath/libcli"

set Force 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 sut]} {set blade $sut}
if {![info exists prompt]} { set prompt "$cli_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 && ! $DRYRUN } {
    exp_internal -f $logfilename 0
    send_user "\n\[SM] Logfile is $logfilename\n"
}

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

if {$VERBOSE} {
   send_user "\[SM] $MyName:\n"
   if {[info exists powerState]} {send_user "\tpowerState is $powerState\n"}
   if {[info exists blade]} {send_user "\tblade is $blade\n"}
   if {[info exists chassis]} {send_user "\tchassis is $chassis\n"}
   if {[info exists path]} {send_user "\tpath is $path\n"}
   if {[info exists Force]} {send_user "\tForce is $Force\n"}
}

# Check for valid information
if {!$Force} {CheckUserInput}

if {![info exists cmd]} {
	set cmd [GetCliCmd $hisvFunction blade chassis path]
}
if {![info exists cmd] || $cmd == ""} {
	send_user "\nERROR: Couldn't translate input information into a command:\n"
    if {[info exists blade]} {send_user "\tblade is $blade\n"}
    if {[info exists chassis]} {send_user "\tchassis is $chassis\n"}
    if {[info exists path]} {send_user "\tpath is $path\n"}
    if {[info exists powerState]} {send_user "\tpowerState is $powerState\n"}
    if {[info exists reset]} {send_user "\treset is $reset\n"}
	Done 1
}

# Start the cli
set component avsv
if {![StartCli component]} {
	ErrorMessage "Failed to start the CLI\n" 1
}

# Clean out any chassis codes
expect *

#****************************** Start the Test *********************************
set failed 0
if {![RunCliCmd "$cmd"]} {
	set failed 1
}
StopCli

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



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