KVM test: Virtio console - Adding migration test
[autotest-zwu.git] / conmux / drivers / hmc
blob72647c024cc48d22fa5473448d97466273431d99
1 #!/usr/bin/expect --
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.
9 # usage:
10 #  hmc open-term|reboot -h <hmc IP> -m <system> -p <partition> \
11 #       -U <user> -P <password> -V <hmc version>
13 # example:
14 #  hmc open-term -m elm3b70 -p FullSystemPartition -U hscroot -P passwd \
15 #       -V 2.6 -h 1.2.3.4 
16 #  hmc reboot -m elm3b70 -p FullSystemPartition -U hscroot -P passwd \
17 #       -V 2.6 -h 1.2.3.4
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
24 set P "hmc"
26 # See interactions.
27 log_user 0
28 #exp_internal 1
30 proc note {m} {
31         global P
32         puts "$P: $m"
34 proc warn {m} {
35         global P
36         puts "$P: WARNING: $m"
38 proc winge {m} {
39         global P
40         puts "$P: MACHINE ERROR: $m"
44 # OPTIONS: options parser.
46 proc shift {_list} {
47         upvar $_list list
49         set res [lindex $list 0]
50         set list [lreplace $list 0 0]
52         return $res
54 proc arg {_list arg} {
55         upvar $_list list
57         if {[llength $list] < 1} {
58                 winge "$arg: required argument missing"
59                 exit 1
60         }
61         
62         return [shift list]
65 set user                {hscroot}
66 set host                {}
67 set system              {}
68 set lpar                {}
69 set profile             {default}
70 set mode                {norm}
71 set passwd              {}
72 set version             {}
74 set cmd [lindex $argv 0]
75 shift argv
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]}
88         }
91 if {[llength $argv] > 0} {
92         puts stderr "Usage: $P <cmd> -h <hmc> -m <system> -p <lpar> -f <profile> -b <mode>"
93         exit 1
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"
100         exit 1
103 set prompt              {___EOF___HMC___EOF___}
104 set hscpath             {/opt/hsc/bin}
106 #log_file -a "$logfile"
108 set elapsed_time 0
109 set timeout 30
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"
119 } else {
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\" ..."
126 eval spawn $command
127 send "PS1=$prompt\r"
128 expect {
129         -re {[pP]assword:} {
130                 if {[string compare $passwd ""] == 0} {
131                         winge "$host: requesting password - not hacked"
132                         exit 2
133                 }
134                 send "$passwd\r"
135                 after 500
136                 send "PS1=$prompt\r"
137                 exp_continue
138         }
139         "Connection timed out" {
140                 winge "$host: cannot connect to console"
141                 exit 2
142         }
143         "Name or service not known" {
144                 winge "$host: HMC name invalid"
145                 exit 1
146         }
147         "Permission denied" {
148                 winge "$host: authentication failure, permission denied"
149                 exit 2
150         }
151         timeout {
152                 winge "$host: HMC did not prompt us, timed out"
153                 exit 2
154         }
155         eof {
156                 winge "$host: HMC disconnected without prompting"
157                 exit 2
158         }
160         "Terminal type?" {
161                 send "vt100\r"
162                 send "PS1=$prompt\r"
163                 exp_continue
164         }
166         "PS1=$prompt" {
167                 # Ignore us typing the change to the prompt.
168                 exp_continue
169         }
170         "$prompt" {
171                 # Prompt see, we are in and working, drop out.
172                 ## note "prompt seen"
173         }
175         -re "^\[^\n]*\n" {
176                 # We need to absorb any login information, motd etc.
177                 ## puts "NOISE<$expect_out(buffer)>"
178                 exp_continue
179         }
182 proc runit {cmd _out} {
183         upvar $_out out
185         global prompt
187         send "$cmd"
189         set text ""
190         set line 0
192         set timeout 120
193         expect {
194                 
195                 -re "^\[^\n]*\n" {
196                         ##note "LINE: $expect_out(buffer)"
197                         if { $line > 0 } {
198                                 append text $expect_out(buffer)
199                         }
200                         incr line
201                         exp_continue
202                 }
204                 -re "$prompt" {
205                         ##note "prompt seen"
206                 }
208                 timeout {
209                         set out "hmc: command timeout"
210                         return 255
211                 }
212         }
213         set out [string trimright $text]
215         send "echo \$?\r"
216         set text ""
217         set line 0
218         set timeout 30
219         expect {
220                 -re "^\[^\n]*\n" {
221                         ##note "LINE: $expect_out(buffer)"
222                         if { $line > 0 } {
223                                 append text $expect_out(buffer)
224                         }
225                         incr line
226                         exp_continue
227                 }
229                 -re "$prompt" {
230                         ##note "prompt seen"
231                 }
233                 timeout {
234                         set out "hmc: command status timeout"
235                         return 255
236                 }
237         }
238         ##note "EXIT: $text"
240         return [string trimright $text]
243 proc extract_names {out} {
244         set res {}
245         foreach sys [split $out] {
246                 if {[string compare $sys ""] != 0} {
247                         lappend res $sys
248                 }
249         }
251         return $res
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"
260         exit 1
262 note "HMC revision v$version"
264 # Based on the version of the HMC software select payload.
265 if {$version < 4.0} {
266         #
267         # VERSION 2.6/3.0 specific support.
268         #
269         proc system_list {} {
270                 global hscpath
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"
275                         exit 1
276                 }
278                 return [extract_names $out]
279         }
280         proc system_state {system} {
281                 global hscpath
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"
286                         exit 1
287                 }
289                 return $out
290         }
291         proc lpar_list {system} {
292                 global hscpath
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"
297                         exit 1
298                 }
300                 return [extract_names $out]
301         }
302         proc state {system lpar} {
303                 global hscpath
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"
308                         exit 1
309                 }
311                 return $out
312         }
313         proc reboot_metal {system lpar profile mode} {
314                 global hscpath
316                 # If we have no connection wait for the machine to appear.
317                 # XXX: timeout?
318                 set was {}
319                 set when [clock seconds]
320                 if {[string compare [system_state $system] "Ready"] != 0} {
321                         while {([clock seconds] - $when) < 60} {
322                                 sleep 15
323                                 set state [system_state $system]
324                                 
325                                 note "waiting for stable connected state ($state)"
326                                 if {$state != $was || [string compare $state "No Connection"] == 0} {
327                                         set was $state
328                                         set when [clock seconds]
329                                 }
330                         }
331                 }
333                 # See if the system is is in Error, if so attempt to
334                 # power it on.
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} {
338                                 note "started"
339                                 return
340                         }
341                         note "start failed - attempting shutdown"
342                 }
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"
349                                 exit 2
350                         }
351                 }
353                 while {[string compare [system_state $system] "No Power"] != 0} {
354                         note "waiting for shutdown"
355                         sleep 15
356                 }
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"
361                         exit 2
362                 }
363                 note "started"
364         }
365         proc reboot {system lpar profile mode} {
366                 global hscpath
368                 # Handle the bare metal separatly.
369                 if {[string compare $lpar "FullSystemPartition"] == 0} {
370                         return [reboot_metal $system $lpar $profile $mode]
371                 }
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} {
381                                 note "started"
382                                 return
383                         }
384                         note "start failed - attempting shutdown"
385                 }
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"
392                                 exit 2
393                         }
394                 }
396                 while {[string compare [state $system $lpar] "Ready"] != 0} {
397                         note "waiting for shutdown"
398                         sleep 15
399                 }
401                 note "starting lpar"
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"
404                         exit 2
405                 }
406                 note "started"
407         }
411 if {$version >= 4.0} {
412         #
413         # VERSION 4.x specific support.
414         #
415         proc system_list {} {
416                 global hscpath
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"
421                         exit 1
422                 }
424                 return [extract_names $out]
425         }
426         proc system_state {system} {
427                 global hscpath
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"
432                         exit 1
433                 }
435                 return $out
436         }
437         proc lpar_list {system} {
438                 global hscpath
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"
443                         exit 1
444                 }
446                 return [extract_names $out]
447         }
448         proc state {system lpar} {
449                 global hscpath
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"
454                         exit 1
455                 }
457                 return $out
458         }
460         proc reboot {system lpar profile mode} {
461                 global hscpath
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} {
471                                 note "started"
472                                 return
473                         }
474                         note "start failed - attempting shutdown"
475                 }
476                                 
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"
482                                 exit 2
483                         }
484                 }
486                 while {[string compare [state $system $lpar] "Not Activated"] != 0} {
487                         note "waiting for shutdown"
488                         sleep 15
489                 }
491                 note "starting lpar"
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"
494                         exit 2
495                 }
496                 note "started"
497         }
501 # VERSION: common
503 proc open-term {system lpar} {
504         global prompt
505         global hscpath
506         global spawn_id
508         note "opening console ..."
509         send "ulimit -t 3600; \[ -f cleandown ] && sudo /home/hscroot/cleandown $system $lpar; mkvterm -m $system -p $lpar\r"
510         expect {
511                 "NVTS" { }
512                 "Open in progress.." { }
513                 "$prompt" {
514                         winge "$system/$lpar: open console failed"
515                         exit 2
516                 }
517         }
519         note "console open"
520         interact {
521                 -i $spawn_id
522                 " Connection has closed" {
523                         winge "$system/$lpar: console connection closed"
524                         exit 2
525                 }
526                 {Error in communication path to the partition} {
527                         winge "$system/$lpar: lost contact with lpar"
528                         exit 2
529                 }
530                 "$prompt" {
531                         winge "$system/$lpar: open console failed"
532                         exit 2
533                 }
534                 eof {
535                         winge "$system/$lpar: payload lost"
536                         exit 2
537                 }
538                 \000 {
539                 }
540                         
541         }
542         note "console closed"
545 proc close-term {system lpar} {
546         global hscpath
548         note "closing console ..."
549         if {[runit "rmvterm -m $system -p $lpar\r" out] != 0} {
550                 winge "$system/$lpar: close console failed"
551                 exit 2
552         }
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"
559         exit 1
561 set lpars [lpar_list $system]
562 if {[lsearch -exact $lpars $lpar] < 0} {
563         winge "$system/$lpar: lpar not known; console knows: $lpars"
564         exit 1
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"
574         exit 1
577 # Ask for the lpar status, to see if it exists.
578 set lstate [state $system $lpar]
579 note "$system/$lpar: found ($state/$lstate)"
582 # COMMANDS: command.
584 switch -- $cmd {
585         {open-term}     {
586                 close-term $system $lpar
587                 open-term $system $lpar
588         }
589         {close-term}    {
590                 close-term $system $lpar
591         }
592         {reboot}        {
593                 reboot $system $lpar $profile $mode
594         }
595         default         {
596                 winge "$cmd: unknown command"
597         }
600 exit 0