3 # hmc -- handle consoles and rebooting of HMC based systems
5 # Allow connecting to the console of and rebooting of HMC connected
6 # machines. Machines are identified by the HMC IP address, connected
7 # system name, and partition name.
10 # hmc open-term|reboot -h <hmc IP> -m <system> -p <partition> \
11 # -U <user> -P <password> -V <hmc version>
14 # hmc open-term -m elm3b70 -p FullSystemPartition -U hscroot -P passwd \
16 # hmc reboot -m elm3b70 -p FullSystemPartition -U hscroot -P passwd \
19 # (C) Copyright IBM Corp. 2004, 2005, 2006
20 # Author: Andy Whitcroft <andyw@uk.ibm.com>
22 # The Console Multiplexor is released under the GNU Public License V2
36 puts "$P: WARNING: $m"
40 puts "$P: MACHINE ERROR: $m"
44 # OPTIONS: options parser.
49 set res [lindex $list 0]
50 set list [lreplace $list 0 0]
54 proc arg {_list arg} {
57 if {[llength $list] < 1} {
58 winge "$arg: required argument missing"
74 set cmd [lindex $argv 0]
76 while {[llength $argv] > 0} {
77 switch -- [shift argv] {
78 -h { set host [arg argv h]}
79 hmc { set host [arg argv h]}
80 -m { set system [arg argv m]}
81 -l { set lpar [arg argv l]}
82 -p { set lpar [arg argv p]}
83 -f { set profile [arg argv f]}
84 -b { set mode [arg argv b]}
85 -U { set user [arg argv P]}
86 -P { set passwd [arg argv P]}
87 -V { set version [arg argv P]}
91 if {[llength $argv] > 0} {
92 puts stderr "Usage: $P <cmd> -h <hmc> -m <system> -p <lpar> -f <profile> -b <mode>"
95 if {[string compare $host ""] == 0 ||
96 [string compare $system ""] == 0 ||
97 [string compare $lpar ""] == 0} \
99 winge "hmc (-h), machine (-m) and lpar (-p) required"
103 set prompt {___EOF___HMC___EOF___}
104 set hscpath {/opt/hsc/bin}
106 #log_file -a "$logfile"
111 # Ensure we have a terminal so we don't get prompted for one.
112 if {![info exists env(TERM)]} {
113 set env(TERM) {vt100}
116 # If we have a password don't use any ssh-keys we may have been offered.
117 if {[string compare $passwd ""] == 0} {
118 set command "ssh $env(SSH_OPTIONS) $user@$host"
120 set command "ssh $user@$host"
123 # CONNECT: connect to the remote console. Set the prompt up so we
124 # know when a command we execute has completed.
125 note "Logging into HMC console with command \"$command\" ..."
130 if {[string compare $passwd ""] == 0} {
131 winge "$host: requesting password - not hacked"
139 "Connection timed out" {
140 winge "$host: cannot connect to console"
143 "Name or service not known" {
144 winge "$host: HMC name invalid"
147 "Permission denied" {
148 winge "$host: authentication failure, permission denied"
152 winge "$host: HMC did not prompt us, timed out"
156 winge "$host: HMC disconnected without prompting"
167 # Ignore us typing the change to the prompt.
171 # Prompt see, we are in and working, drop out.
172 ## note "prompt seen"
176 # We need to absorb any login information, motd etc.
177 ## puts "NOISE<$expect_out(buffer)>"
182 proc runit {cmd _out} {
196 ##note "LINE: $expect_out(buffer)"
198 append text $expect_out(buffer)
209 set out "hmc: command timeout"
213 set out [string trimright $text]
221 ##note "LINE: $expect_out(buffer)"
223 append text $expect_out(buffer)
234 set out "hmc: command status timeout"
240 return [string trimright $text]
243 proc extract_names {out} {
245 foreach sys [split $out] {
246 if {[string compare $sys ""] != 0} {
254 # Find out the current version of the HMC software.
255 if {[string compare $version ""] == 0} {
256 runit "rpm -q IBMhsc.coreserver --qf '%{VERSION}'; echo ''\r" version
258 if {[string compare $version ""] == 0} {
259 winge "unable to obtain HMC code version"
262 note "HMC revision v$version"
264 # Based on the version of the HMC software select payload.
265 if {$version < 4.0} {
267 # VERSION 2.6/3.0 specific support.
269 proc system_list {} {
272 # Ask for a list of systems.
273 if {[runit "lssyscfg -r sys --all -F name\r" out] != 0} {
274 winge "unable to obtain list of systems"
278 return [extract_names $out]
280 proc system_state {system} {
283 # Ask for the system status.
284 if {[runit "lssyscfg -r sys -n $system -F state\r" out] != 0} {
285 winge "$system: failed to get status"
291 proc lpar_list {system} {
294 # Ask for a list of lpars for this system.
295 if {[runit "lssyscfg -r lpar -m $system --all -F name\r" out] != 0} {
296 winge "unable to obtain list of lpars"
300 return [extract_names $out]
302 proc state {system lpar} {
305 # Ask for the lpar status.
306 if {[runit "lssyscfg -r lpar -m $system -n $lpar -F state\r" out] != 0} {
307 winge "$system/$lpar: failed to get lpar status"
313 proc reboot_metal {system lpar profile mode} {
316 # If we have no connection wait for the machine to appear.
319 set when [clock seconds]
320 if {[string compare [system_state $system] "Ready"] != 0} {
321 while {([clock seconds] - $when) < 60} {
323 set state [system_state $system]
325 note "waiting for stable connected state ($state)"
326 if {$state != $was || [string compare $state "No Connection"] == 0} {
328 set when [clock seconds]
333 # See if the system is is in Error, if so attempt to
335 if {[string compare [system_state $system] "Error"] == 0} {
336 note "starting full system (from Error)"
337 if {[runit "chsysstate -r sys -m $system -n $system -b $mode -o on -c full\r" out] == 0} {
341 note "start failed - attempting shutdown"
344 # See if the system is up, if so shut it down.
345 if {[string compare [system_state $system] "No Power"] != 0} {
346 note "shutting down full system"
347 if {[runit "chsysstate -r sys -m $system -n $system -o off -c full\r" out] != 0} {
348 winge "$system: power off failed\n$out"
353 while {[string compare [system_state $system] "No Power"] != 0} {
354 note "waiting for shutdown"
358 note "starting full system"
359 if {[runit "chsysstate -r sys -m $system -n $system -b $mode -o on -c full\r" out] != 0} {
360 winge "$system: power on failed"
365 proc reboot {system lpar profile mode} {
368 # Handle the bare metal separatly.
369 if {[string compare $lpar "FullSystemPartition"] == 0} {
370 return [reboot_metal $system $lpar $profile $mode]
373 # Partitions in Error state are tricky, you _may_ either
374 # have to shut them down and then start them, or you may
375 # just have to start them. So, if we are in Error start
376 # the partition, if it fails we can just drop through
377 # to the regular stop/start cycle.
378 if {[string compare [state $system $lpar] "Error"] == 0} {
379 note "starting lpar (from Error)"
380 if {[runit "chsysstate -r lpar -m $system -n $lpar -b $mode -o on\r" out] == 0} {
384 note "start failed - attempting shutdown"
387 # See if the lpar is up, if so shut it down.
388 if {[string compare [state $system $lpar] "Ready"] != 0} {
389 note "shutting down lpar"
390 if {[runit "chsysstate -r lpar -m $system -n $lpar -o off\r" out] != 0} {
391 winge "$system/$lpar: power off failed\n$out"
396 while {[string compare [state $system $lpar] "Ready"] != 0} {
397 note "waiting for shutdown"
402 if {[runit "chsysstate -r lpar -m $system -n $lpar -b $mode -o on\r" out] != 0} {
403 winge "$system/$lpar: power on failed\n$out"
411 if {$version >= 4.0} {
413 # VERSION 4.x specific support.
415 proc system_list {} {
418 # Ask for a list of systems.
419 if {[runit "lssyscfg -r sys -F name\r" out] != 0} {
420 winge "unable to obtain list of systems"
424 return [extract_names $out]
426 proc system_state {system} {
429 # Ask for the system status.
430 if {[runit "lssyscfg -r sys -m $system -F state\r" out] != 0} {
431 winge "$system: failed to get system status"
437 proc lpar_list {system} {
440 # Ask for a list of lpars for this system.
441 if {[runit "lssyscfg -r lpar -m $system -F name\r" out] != 0} {
442 winge "unable to obtain list of lpars"
446 return [extract_names $out]
448 proc state {system lpar} {
451 # Ask for the lpar status.
452 if {[runit "lssyscfg -r lpar -m $system --filter lpar_names=$lpar -F state\r" out] != 0} {
453 winge "$system/$lpar: failed to get lpar status"
460 proc reboot {system lpar profile mode} {
463 # Partitions in Error state are tricky, you _may_ either
464 # have to shut them down and then start them, or you may
465 # just have to start them. So, if we are in Error start
466 # the partition, if it fails we can just drop through
467 # to the regular stop/start cycle.
468 if {[string compare [state $system $lpar] "Error"] == 0} {
469 note "starting lpar (from Error)"
470 if {[runit "chsysstate -r lpar -m $system -n $lpar -f $profile -b $mode -o on\r" out] == 0} {
474 note "start failed - attempting shutdown"
477 # See if the lpar is up, if so shut it down.
478 if {[string compare [state $system $lpar] "Not Activated"] != 0} {
479 note "shutting down lpar"
480 if {[runit "chsysstate -r lpar -m $system -n $lpar -o shutdown --immed\r" out] != 0} {
481 winge "$system/$lpar: power off failed\n$out"
486 while {[string compare [state $system $lpar] "Not Activated"] != 0} {
487 note "waiting for shutdown"
492 if {[runit "chsysstate -r lpar -m $system -n $lpar -f $profile -b $mode -o on\r" out] != 0} {
493 winge "$system/$lpar: power on failed\n$out"
503 proc open-term {system lpar} {
508 note "opening console ..."
509 send "ulimit -t 3600; \[ -f cleandown ] && sudo /home/hscroot/cleandown $system $lpar; mkvterm -m $system -p $lpar\r"
512 "Open in progress.." { }
514 winge "$system/$lpar: open console failed"
522 " Connection has closed" {
523 winge "$system/$lpar: console connection closed"
526 {Error in communication path to the partition} {
527 winge "$system/$lpar: lost contact with lpar"
531 winge "$system/$lpar: open console failed"
535 winge "$system/$lpar: payload lost"
542 note "console closed"
545 proc close-term {system lpar} {
548 note "closing console ..."
549 if {[runit "rmvterm -m $system -p $lpar\r" out] != 0} {
550 winge "$system/$lpar: close console failed"
555 # Look and see if this system exists.
556 set systems [system_list]
557 if {[lsearch -exact $systems $system] < 0} {
558 winge "$system: system not known; console knows: $systems"
561 set lpars [lpar_list $system]
562 if {[lsearch -exact $lpars $lpar] < 0} {
563 winge "$system/$lpar: lpar not known; console knows: $lpars"
567 # Check for system in Operating/Ready.
568 set state [system_state $system]
569 if {[string compare $lpar "FullSystemPartition"] != 0 &&
570 [string compare $state "Operating"] != 0 &&
571 [string compare $state "Ready"] != 0} \
573 winge "$system: unusable - $state"
577 # Ask for the lpar status, to see if it exists.
578 set lstate [state $system $lpar]
579 note "$system/$lpar: found ($state/$lstate)"
586 close-term $system $lpar
587 open-term $system $lpar
590 close-term $system $lpar
593 reboot $system $lpar $profile $mode
596 winge "$cmd: unknown command"