blob: 69510c427a7cd127b6f3f453d738e9a6fecc9ba3 [file] [log] [blame]
#!/usr/bin/expect --
#
# blade -- console and management control for IBM blade servers.
#
# Obtain consoles for and hard reset support for blades in
# IBM blade centres. Blades are identified by their blade centre ids.
#
# usage:
# blade reboot|console <blade id> <user> <password> <connect command> ...
#
# example:
# blade reboot blade[4] FOO BAR telnet 1.2.3.4
# blade console blade[4] FOO BAR telnet 1.2.3.4
#
# (C) Copyright IBM Corp. 2004, 2005, 2006
# Author: Andy Whitcroft <andyw@uk.ibm.com>
#
# The Console Multiplexor is released under the GNU Public License V2
#
set P "blade"
if { [llength $argv] < 5 } {
puts stderr "Usage: $P <command> <blade> <login> <password> <connect command ...>"
exit 1
}
log_user 0
set cmd [lindex $argv 0]
set system [lindex $argv 1]
set username [lindex $argv 2]
set password [lindex $argv 3]
set command [lrange $argv 4 end]
# Validate the command.
switch -- $cmd {
console {}
reboot {}
default {
puts stderr "$P: $cmd: unrecognised command";
exit 1
}
}
# Ensure the blade name is fully qualified. This ensures that
# the console prompt detection as reliable as possible. Add the system
# prefix if it was not specified.
switch -re -- "$system" {
system:.* { }
.* { set system "system:$system" }
}
#log_file -a "$logfile"
set elapsed_time 0
set timeout 30
proc note {m} {
global P
puts "$P: $m"
}
proc warn {m} {
global P
puts "$P: WARNING: $m"
}
proc winge {m} {
global P
puts "$P: ERROR: $m"
}
note "Logging into blade centre with command \"$command\" to restart it";
# CONNECT: connect to the remote console.
eval spawn $command
expect {
default {
winge "login prompt not issued"
exit 2
}
"Connection closed by foreign host." {
winge "Telnet connection closed."
exit 1
}
"Unable to connect to remote host:" {
winge "Connection to remote console failed"
exit 2
}
"username:" {
#note "saw login prompt"
}
}
# AUTHENTICATE: send username and password at the relevant prompts
note "sending login ..."
send -- "$username\r"
expect {
default {
winge "password prompt not issued"
exit 2
}
"password:" {
#note "password prompt found"
}
}
note "sending password ..."
send -- "$password\r"
expect {
default {
winge "command prompt not issued"
exit 2
}
"Invalid login!" {
winge "login/password incorrect ... aborting"
exit 1
}
-- "system>" {
#note "command prompt found"
}
}
# SYSTEM: first validate the system specifier, if it does not
# exist get a listing and print that out whilst we are connected.
note "selecting system '$system' ..."
send "env -T $system\r"
set found 0
set prompt "$system>"
expect {
default {
winge "command prompt not issued"
exit 2
}
OK {
set found 1
exp_continue
}
-- "system>" {
#note "command prompt found"
}
-ex $prompt {
#note "command prompt found"
}
}
# The system the user specified was not found, give them a hand by
# getting a list of systems.
if {$found == 0} {
note "Defined systems:"
send "list -l 2\r"
expect {
default {
winge "command prompt not issued"
exit 2
}
-- "system>" {
#note "command prompt found"
}
"\n$" {
puts -nonewline "$expect_out(buffer)"
exp_continue
}
}
note "complete ... exiting"
send "exit\r"
exit 1
}
# CONSOLE: open a console channel
if {[string compare $cmd "console"] == 0} {
set ts_start 1
set ts_cur 1
set retry 0;
note "connecting to console ..."
# Unless console session lasts for more than two seconds, retry every
# thirty seconds for up to a day. This prevents repeated login events
# which fill logs and cause loss of useful event log information.
while {($ts_cur - $ts_start < 2) && ($retry < 2880)} {
# 30 second delay between attempts, except for the first one
if {$ts_start != 1} {
note "connection failed, retrying after 30 second delay"
after 30000
}
set ts_start [timestamp];
send "console -o\r"
interact {
-o -ex $prompt {
return
}
}
set ts_cur [timestamp];
incr retry
}
winge "console lost"
exit 0
}
# Function to wait until the issued power command has taken effect.
proc powerWait {s} {
global prompt
set ok 0
for {set retry 1} {$ok == 0 && $retry < 30} {incr retry} {
note "checking for power state $s ..."
after 2000
send "power -state\r"
expect {
default {
winge "command prompt not issued"
exit 2
}
-ex $s {
set ok 1
exp_continue
}
-ex "$prompt" {
#note "command prompt found"
}
}
}
if {$ok == 0} {
winge "system did not enter power $s state ... aborting"
exit 2
}
}
# DOWN: shut the system down ... hard. Expect to OK before the
# prompt in the case of success.
note "powering cycling the system ..."
send "power -cycle\r"
set fail 1
expect {
default {
winge "command prompt not issued"
exit 2
}
"OK" {
set fail 0
exp_continue
}
-ex "$prompt" {
#note "command prompt found"
}
}
if {$fail == 1} {
winge "power cycle failed ... system not rebooted"
exit 2
}
powerWait On
note "complete ... exiting"
send "exit"
exit 0