home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / pub / public_html / cudocs / ilosetup < prev    next >
Text File  |  2020-01-01  |  36KB  |  919 lines

  1. #!/p/kd/fdc/RHEL4/wermit +
  2. #!/p/kd/fdc/solaris9/wermit +
  3. #!/p/sy/subsys/scripts/wermit +
  4. #
  5. # IMPORTANT: The first line must indicate the path to C-Kermit 8.0.212 or 9.0
  6. #  and there must be a + sign after the path, separated by a space.
  7. #
  8. # ilosetup: C-Kermit Script to configure an HP server through its
  9. #            iLO management interface.
  10. #
  11. # Author: Frank da Cruz, Columbia University, 2009-2011
  12. #
  13. .scriptversion = 1.15
  14. .scriptdate = 20110207
  15. #
  16. #   Created:  
  17. #    1.01 20090428
  18. #
  19. #   Modified:
  20. #    1.15 20110207: Get to RBSU directly with ESC+9 in iLO3, which
  21. #                   avoids infinite DHCP query loop when machine is
  22. #                   not registered.
  23. #    1.14 20101217: Add notelnet option meaning don't even try to
  24. #                   connect to iLO with telnet.
  25. #    1.13 20101216: Allow for different response messages when attempting
  26. #                   to create an account that already exists and also
  27. #                   to power commands; fix usage message to say ilo_userid
  28. #                   instead of ilo_username.
  29. #    1.12 20101215: Get iLO version number.  If 3 or higher do not attempt
  30. #                   certain oemhp configurations that have been discontinued.
  31. #                   Renamed MESSAGE macro to PMSG to avoid conflict.
  32. #    1.11 20100621: Added BIOS and POWERMODE:n options.
  33. #    1.10 20100322: Allow hyphens in host names;
  34. #    1.09 20091221: Added raid / noraid option to configure RAID (or not);
  35. #                   added telnet and ssh options to specify which to try first;
  36. #                   added iloonly option to only do iLO commands.
  37. #    1.08 20091123: Undo 1.07 because the command doesn't work on all models.
  38. #                   Fix echoing of username when typed in manually.
  39. #                   Capture iLO firmware version and record in log.
  40. #                   Don't produce a debug.log unless asked.
  41. #    1.07 20091113: Enable remote console acquire (spelled "aquire")
  42. #    1.06 20091104: Handle login failure on Telnet connections.
  43. #    1.05 20091104: Add 'usepassword' and 'nopassword' options;
  44. #                   Try both in specified order.
  45. #    1.04 20091103: Handle console login failure more gracefully;
  46. #                   Allow empty password in serials file.
  47. #    1.03 20091028: Remove IF WRITEABLE check for log directory
  48. #    1.02 20090916: Prompt for username if not in environment.
  49. # Usage: [ ilo_userid=x ] [ ilo_userpass=y ] ilosetup hostname [ keywords ]
  50. #
  51. # After the hostname you can put zero or more of these keywords:
  52. #
  53. #   connect - make an interactive connection after logging in
  54. #   debug - create a debug log (very big, only for Frank)
  55. #   usepassword - try to log in first with a serials file password
  56. #   nopassword - try to log in first with a blank password
  57. #   nopoweroff - don't power the host machine off at the end
  58. #   noreset - no reset at end
  59. #   poweroff - power the host machine off at the end (default)
  60. #   pwrmode:n - set power regulator mode to n (1-4)
  61. #   raid - set Logical Drive 1 to RAID 1
  62. #   bios - go straight to the BIOS prompt without doing anything else
  63. #   noraid - Don't mess with RAID configuration (default)
  64. #   iloonly - Only do iLO commands and don't reset or power off the server
  65. #   quiet - only show error, warning, or status messages on the screen
  66. #   reset - reset at end (default)
  67. #   verbose - watch the script play on the screen (default)
  68. #
  69. # The keywords can be abbreviated to any unique left substring.
  70. #
  71. # Examples for host fillmore:
  72. #   ilosetup fillmore
  73. #   ilosetup fillmore poweroff
  74. #   ilosetup fillmore pow (same as poweroff)
  75. #   ilosetup fillmore pow q (poweroff and run quietly)
  76. #
  77. # The hostname should match (case independently) a hostname in the HP
  78. # serials file, which is just the first part of the first field of the
  79. # IP hostname, e.g. fillmore instead of fillmore-console.cc.columbia.edu.
  80. # But if you do include the extra fields, the script allows for it.
  81. #
  82. # Exit status:
  83. #   0 on success; 1 on failure.
  84. #
  85. # Creates in the log directory (logdirectory defined below):
  86. #   A session log file xxx-session.log (xxx is the hostname)
  87. #  (the log directory itself is created if it doesn't exist)
  88. #
  89. # Requires: C-Kermit 8.0.212 or later because it uses some recent features.
  90. # Version 8.0.211 or earlier lack at least the following, which are used in
  91. # this script:
  92. #  . FSEEK /FIND:string
  93. #  . The \fkwval() function
  94. # (The script could be recoded at some effort to use older ways of doing
  95. #  the same things.)
  96. #
  97. # If this script is run directly as if it were a shell command, the C-Kermit
  98. # binary that executes it is the one in the "kerbang line" (the first line in
  99. # the file).  Of course you can move the binary anywhere you want, or rename
  100. # it, but then you have to change the kerbang line to match.
  101. #
  102. # Other dependencies:
  103. #  . The HP serial numbers file (path defined a few lines down)
  104. #  . That the first field in a serials file record is the simple hostname
  105. #    (e.g. FILLMORE, not FILLMORE-CONSOLE or FILLMORE-CONSOLE.CC.COLUMBIA.EDU)
  106. #  . That the corresponding iLO console password is the 6th field.
  107. #
  108. # Documentation: http://kermit.columbia.edu/cudocs/ilosetup.html
  109. #
  110. ###############################################################################
  111.  
  112. .myname := \fbasename(\v(cmdfile))      # Name of this script without path
  113. if < \v(version) 800212 {               # Check Kermit version
  114.     exit 1 "\m(myname): C-Kermit 8.0.212 or later required"
  115. }
  116. # Debugging
  117.  
  118. .dodebug = 0
  119. if > 0 \flen(\$(DEBUG)) if numeric \$(DEBUG) if \$(DEBUG) .dodebug = 1
  120. if \m(dodebug) {
  121.     echo DEBUGGING ON
  122.     echo ILO_USERID=[\$(ilo_userid)]
  123.     echo ILO_USERPASS=[\$(ilo_userpass)]
  124. }
  125. if not background set quiet off         # Allow messages (for foreground use)
  126. set session-log text            # filter out escape sequences
  127. set session-log timestamp               # Put timestamps in session log
  128.  
  129. # "Constant" definitions (that can be changed)...
  130.  
  131. .iloprompt = ">hpiLO-> "                # HP iLO console prompt
  132. .logdirectory = /var/log/ilosetup       # Directory for session log
  133. .outputpacing = 100                     # Intercharter pacing for OUTPUT (msec)
  134. .poweroff = 0                           # Whether to power off at end
  135. .connect = 0                            # Make an interactive connection
  136. .telnet = 1                             # Default connection method is Telnet
  137. .notelnet = 0                # Nonzero means there is no Telnet
  138. .iloonly = 0                            # Only do iLO commands
  139. .ssh = 0                                # and is not SSH
  140. .reset = 1                              # Reset at end
  141. .dopassword = 1                         # Use password from serials file
  142. .doingraid = 0                          # Don't configure RAID unless asked
  143. .serialsfile = /p/sy/subsys/HP/serials  # Path of blade serial numbers file
  144. .hostsuffix = -console.cc.columbia.edu  # Hostname suffix
  145. .loginname = Administrator              # iLO login name
  146. .bios = 0                # Go straight to BIOS
  147. .pwrmode = 0                # Change power mode value
  148. .saidpwrmode = 0            # For checking power mode value
  149.  
  150. if equ "\v(user)" "fdc" {               # Development / testing
  151.     .logdirectory = ~/net/shrimp # (dev/test)
  152.     # if \m(dodebug) .serialsfile = ./serials
  153. }
  154.  
  155. if \m(dodebug) show args                # development/test  
  156.  
  157. # COMMAND TABLE: Define command-line option keywords
  158.  
  159. dcl \&k[] = bios poweroff nopoweroff verbose quiet telnet ssh help iloonly -
  160.  connect debug reset noreset usepassword nopassword raid noraid pwrmode -
  161.  notelnet
  162.  
  163. array sort &k                           # Alphabetize them for table lookup
  164.  
  165. # If command line is invalid give usage message and exit
  166.  
  167. def usage {                             # Give usage message and exit
  168.     .verbose = "verbose"
  169.     .turnoff = "nopoweroff"
  170.     .doreset = "noreset"
  171.     .usepass = "nopassword"
  172.     .doraid = "raid"
  173.     if \m(notelnet) .telnet = 0
  174.     .dotelnet = "telnet"
  175.     if not \m(telnet) .dotelnet = "ssh"
  176.     echo -
  177. "Usage: [ ilo_userid=x ] [ ilo_userpass=y ] \m(myname) hostname [ options ]"
  178.     echo "Options:"
  179.     show array k
  180.     if quiet .verbose = "quiet"
  181.     if \m(poweroff) .turnoff = "poweroff"
  182.     if \m(reset) .doreset = "reset"
  183.     if \m(dopassword) .usepass = "usepassword"
  184.     xecho "Default options: \m(verbose) \m(turnoff)"
  185.     echo " \m(dotelnet) \m(doreset) \m(usepass) \m(doraid)"
  186.     echo "Optional environment variables:"
  187.     echo " ilo_userid:   user ID to create"
  188.     echo " ilo_userpass: password for user ID"
  189.     echo " DEBUG=1: turn on debugging"
  190.     echo "If created user ID and password are not found in the environment,"
  191.     echo "you are prompted for them."
  192.     echo
  193.     exit 1
  194. }
  195. # Parse and validate command line
  196.  
  197. if not def \%1 {
  198.     echo "FATAL - A hostname is required"
  199.     usage                               # A hostname is required
  200. }
  201. .hostname := \flower(\fword(\%1,1,.))   # First field of hostname argument
  202. .\%t := \findex(-console,\m(hostname))  # If "-console" found in hostname...
  203. if \%t .hostname := \s(hostname[1:\%t-1]) # remove it.
  204. .fullhost := \m(hostname)\m(hostsuffix) # Make full IP hostname
  205.  
  206. # Parse optional command-line keywords...
  207.  
  208. while defined \%2 {                     # While we still have trailing commands
  209.     .tmp := \%2                # Get the next one
  210.     void \fkwval(\%2,=:)        # Split it in case it has an arg
  211.     .\%2 := \v(lastkwval)        # This is the command without the arg
  212.     if not def \%2 .\%2 := \v(tmp)      # Just in case...
  213.     .\%2 := \ftablelook(\%2,&k)         # Look up this keyword and get index
  214.     if < \%2 1 {                        # Not found or ambiguous
  215.         echo "Invalid command-line option: '\m(tmp)'"
  216.         usage                   
  217.     }
  218.     .\%2 := \&k[\%2]                    # Resolve index to keyword itself
  219.     switch \%2 {                        # Handle the keyword
  220.       :bios                # Go straight to BIOS
  221.         .bios = 1
  222.         break
  223.       :iloonly                          # Do iLO commands only
  224.         .iloonly = 1
  225.         break
  226.       :help                             # Help
  227.         usage                # (exits)
  228.       :debug                            # Debug
  229.         .dodebug = 1
  230.         break 
  231.       :connect                          # Connect (interactive session)
  232.         .connect = 1
  233.         break
  234.       :poweroff                         # Leave power off at end
  235.         .poweroff = 1
  236.         break
  237.       :nopoweroff                       # Leave power on at end
  238.         .poweroff = 0
  239.         break
  240.       :quiet                            # Silent running (don't watch session)
  241.         set quiet on
  242.         set input echo off
  243.         break
  244.       :verbose                          # Show session on screen
  245.         set quiet off
  246.         set input echo on
  247.         break
  248.       :reset                            # Reset at end (default)
  249.         .reset = 1
  250.         break
  251.       :noreset                          # No reset at end
  252.         .reset = 0
  253.         break
  254.       :usepassword                      # Use password from serials file
  255.         .dopassword = 1
  256.         break
  257.       :nopassword                       # Use empty password
  258.         .dopassword = 0
  259.         break
  260.       :raid                             # Configure RAID 1 if RAID 0
  261.         .doingraid = 1
  262.         break
  263.       :noraid                           # Don't do anything with RAID
  264.         .doingraid = 0
  265.         break
  266.       :telnet                           # Try Telnet first
  267.         .telnet = 1
  268.         break
  269.       :ssh                              # Try ssh first
  270.         .telnet = 0
  271.         break
  272.       :notelnet                # Telnet is not allowed
  273.         .notelnet = 1
  274.         .telnet = 0
  275.         break
  276.       :pwrmode                # Change power mode
  277.         .saidpwrmode = 1        # Remember they said to do this
  278.         .bios = 1            # Go straight to BIOS for this
  279.     }
  280.     shift                               # Shift argument list to the left
  281. }
  282. if \m(saidpwrmode) {            # If they said "pwrmode"
  283.     .\%9 = 0                # validate powermode argument
  284.     if not defined pwrmode exit 1 "FATAL - pwrmode requires numeric argument"
  285.     if not numeric \m(pwrmode) exit 1 "FATAL - pwrmode nonnumeric argument"
  286.     if < \m(pwrmode) 1 exit 1 "FATAL - pwrmode argument must be 1..4"
  287.     if > \m(pwrmode) 4 exit 1 "FATAL - pwrmode argument must be 1..4"
  288. }
  289. if \m(bios) .doingraid = 0        # Avoid conflicts - BIOS wins
  290.  
  291. # Macro definitions...
  292.  
  293. define logit {                          # Write a message to session log
  294.     if not open session-log end 0
  295.     .\%1 := \frpad(\%1,7,.)             # Make fields line up
  296.     writeln session                     # Make sure we're on a new line
  297.     writeln session "%% \%1 - \m(myname): \v(timestamp) [\m(hostname)] - \%2"
  298. }
  299. define pmsg {                # Print and log a progress message
  300.     if not quiet echo                   # To avoid mixing up screen text
  301.     echo "[\v(timestamp)] MESSAGE - \%1" # Write message to screen (stdout)
  302.     logit MESSAGE "\%1"                 # and to session log
  303. }
  304. define warn {                           # Print and log warning message
  305.     if not quiet echo                   # To avoid mixing up screen text
  306.     echo "WARNING - \%1"                # Write it to to stdout
  307.     logit WARNING "\%1"                 # and to session log
  308. }
  309. define fatal {                          # Fatal error
  310.     .rc = 1                             # Failure exit code
  311.     echo "FATAL - \%1"                  # Write error message to screen
  312.     if \m(haveconnection) {             # If we have a connection
  313.         if not equ "\m(state)" "iLO" {  # but w're not in iLO...
  314.             output \{27}\{40}           # ESC+( - Escape back to iLO 
  315.             input 8 \m(iloprompt)       # and wait 8 sec for the prompt
  316.         }
  317.     }
  318.     logit FATAL "\%1"                   # write message to session log
  319.     logit INFO  "Most recent error: \v(errstring)"
  320.     goto DONE
  321. }
  322. define dotelnet {
  323.     set login user                      # Force a login prompt
  324.     set host \m(fullhost)               # Try Telnet (port 23)
  325.     if fail end 1                       # Return failure code if no go
  326.     input 10 "Login Name: "             # Wait for login prompt
  327.     if fail end 1 "Telnet Login Name timeout"
  328.     lineout \m(loginname)               # Send user ID
  329.     input 10 "password: "               # Wait for password prompt
  330.     if fail end 1 "Telnet password timeout"
  331.     end 0
  332. }
  333. define dossh {
  334.     set host /pty ssh -e none -l \m(loginname) \m(fullhost)
  335.     if fail end 1
  336.     # Watch out for RSA key fingerprint complaint and "are you sure?" prompt...
  337.     minput 20 "password: " "continue connecting (yes/no)? "
  338.     if fail end 1 "No response on SSH connection to \m(fullhost)"
  339.     if == \v(minput) 2 {
  340.         lineout "yes"
  341.         input 20 "password: "
  342.         if fail end 1 "SSH password timeout"
  343.     }
  344.     end 0
  345. }
  346. define getiloprompt {                   # Get iLO prompt
  347.     if not def \%1 .\%1 = 40            # Default timeout (secs)
  348.     if not numeric \%1 fatal "Non-numeric INPUT timeout"
  349.     input \%1 \m(iloprompt)             # Wait for the prompt
  350.     if fail fatal "Timed out waiting for iLO CLI prompt."
  351. }
  352. define getiloversion {            # Sets global iloversion
  353.     local s &a                # from login herald
  354.     .\%9 := \findex({\{10}iLO },\v(input)) # Call this right after
  355.     .s := \fsubstring(\v(input),\%9+1,32)  # sending the login password
  356.     void \fsplit(\m(s),&a)                 # and getting the first iLO prompt.
  357.     .iloversion = 0
  358.     if ( equ "\&a[1]" "iLO" && match "\&a[3]" "{Standard,Advanced}" ) {
  359.        if float \&a[2] .iloversion := \&a[2]
  360.     }
  361.     pmsg "iLO VERSION = \m(iloversion)"
  362. }
  363. define ilocommand {                     # Send an iLO command and get response
  364.     local cmd                           # Local (stack) variable
  365.     .cmd := \fword(\%1,1)               # First word of command
  366.     msleep 10                           # Pause 10 msec just in case
  367.     lineout \%1                         # Send the full command
  368.     if fail fatal "Output failed"       # Check for i/o error
  369.     clear input                         # Empty the INPUT result buffer
  370.     if equ "\m(cmd)" "vsp" {
  371.         clear input
  372.         end 0
  373.     }
  374.     getiloprompt \%2                    # Get response and next iLO prompt
  375.  
  376.     # The "power on/off" commands give no response...
  377.     if not equ "\%1" "power" {        # But "power" by itself does...
  378.         if equ "\m(cmd)" "power" end 0
  379.     }
  380.     .status = 9                         # Dummy inital status value
  381.     .tmp := \freplace(\v(input),\13,)   # Strip carriage returns (but not LFs)
  382.     .lines := \fsplit(\m(tmp),&a,\10)   # Split captured text into lines
  383.     undef ilofirmware                   # iLO firmware version
  384.     for i 1 lines 1 {                   # Loop through lines
  385.         void \fkwval(\&a[i])            # to get status and message values...
  386.     }     
  387.     if equ "\m(cmd)" "show" {
  388.         if def version .ilofirmware := \m(version) [\m(date)]
  389.         if def ilofirmware pmsg "iLO Firmware \m(ilofirmware)"
  390.     }
  391.     if not numeric \m(status) .status = 9 # Just in case
  392.     if == \m(status) 0 end 0            # If status was 0 then OK
  393.     if ( equ "\m(cmd)" "create" ) {
  394.         # In iLO 3 there is an extra blank line in the response.
  395.         if match "\&a[5]\&a[6]" "*Duplicate {login,user} name.*" {
  396.             end 0            # This is not an error
  397.         }
  398.     }
  399.     if ( equ "\m(cmd)" "set" && \findex(shared_console,\%1) ) {
  400.         if match "\&a[5]\&a[6]" "*Advanced License required*" {
  401.             pmsg "WARNING: HOST LACKS LICENSE for Shared Console"
  402.             # Change PMSG to FATAL if Advanced License should be there
  403.             # or if anything that follows depends on shared console.
  404.             end 0
  405.         }
  406.     }
  407.     if >= \m(iloversion) 3 {
  408.     if ( equ "\m(cmd)" "set" ) {
  409.         if \findex(oemhp_server_name,\%1) end 0
  410.         }
  411.     }
  412.     fatal "ILO COMMAND \%1: \m(error_tag)" # Fail with nonzero status
  413. }
  414. define rbsucommand {  # Send a command to RBSU and get next rbsu> prompt.
  415.     local i sleep pacing max
  416.     msleep 10                           # Pause 10 msec just in case
  417.     lineout \%1                         # Send the command
  418.     # Check for error response or next rbsu> prompt.
  419.     # Note: RBSU commands have no consistent error indication;
  420.     # There may be some error responses that are not caught here...
  421.     minput 30 {rbsu>} {Invalid Command} {Incomplete Command} {Invalid Option}
  422.     if fail fatal "RBSU: Timeout after [\%1]"
  423.     if == \v(minput) 1 end 0            # No error message - done.
  424.     warn "RBSU COMMAND FAILURE [\%1]"
  425.     .max = 10
  426.     for i 1 \m(max) 1 {                 # Try again this many times.
  427.         increment pacing 40             # Slower pacing each time.
  428.         warn "RETRYING WITH PACING = \m(pacing) msec..."
  429.         msleep 10*i                     # Pause a little longer each time
  430.         lineout \%1                     # Send the command
  431.         minput 30 {rbsu>} -
  432. {Invalid Command} {Incomplete Command} {Invalid Option}
  433.         if fail fatal "RBSU: Timeout [\%1]"
  434.         if == \v(minput) 1 break        # No error message - done.
  435.     }
  436.     if > \m(i) \m(max) fatal "RBSU command error"
  437.     warn "RBSU COMMAND RECOVERY OK"
  438. }
  439. def xsleep {                            # (for debugging display)
  440.     if not def \%1 .\%1 = 1
  441.     if quiet {
  442.         sleep \%1 
  443.     } else {
  444.         local i
  445.         for i 1 \%1 1 { sleep 1, xecho . }
  446.         echo
  447.     }
  448. }
  449.  
  450. # Execution begins here: Get host password from HP serial numbers file...
  451.  
  452. .haveconnection = 0                     # No connection yet
  453. set input cancellation off              # Essential because of Esc sequences
  454. set exit warning off                    # Allow exit without warning
  455.  
  456. if \m(dodebug) directory \m(serialsfile) # Check and open serials file
  457. if not exist \m(serialsfile) exit 1 "\m(serialsfile) not found"
  458. if not readable \m(serialsfile) exit 1 "\m(serialsfile) not readable"
  459.  
  460. fopen /read \%c \m(serialsfile)         # Open serials file
  461. if fail fatal                           # Check for failure
  462. # Seek to line with this hostname
  463. fseek /find:"^\fupper(\m(hostname))[\9\32]" \%c 0
  464. if fail fatal "Hostname [\m(hostname)] not found in HP serials file"
  465. fread /line \%c line                    # Read the line
  466. fclose \%c                              # Close the file
  467.  
  468. .\%n := \fsplit(\m(line),&a,,-)         # Split the line into words
  469. .pass := \&a[6]                         # The sixth word is the host password
  470.  
  471. if \m(dopassword) {                     # 2-element password array
  472.     dcl \&p[2] = \m(pass) ""            # Try serials file password first
  473. } else {
  474.     dcl \&p[2] =  "" \m(pass)           # Try blank password first
  475. }
  476. if \m(dodebug) show array p
  477.  
  478. # If this is a configuration run open the log file
  479.  
  480. if not \m(connect) {
  481.     if not directory \m(logdirectory) { # Check if log directory exists
  482.         fatal "Log directory \m(logdirectory) not found or not a directory"
  483.     }
  484.     cd \m(logdirectory)                 # cd to the log directory
  485.     if fail fatal "cd \m(logdirectory)" # failure is fatal
  486.  
  487.     .sessionlog := \m(logdirectory)/\m(hostname)-session.log # Session log name
  488.     log session \m(sessionlog)          # Open and start the session log
  489. } else {
  490.     # Make session log in current directory
  491.     log session \m(hostname)-connect.log
  492. }
  493. if fail warn "FAILURE TO OPEN \m(sessionlog)"
  494. pmsg "BEGIN ilosetup \m(scriptversion) \m(scriptdate)"
  495.  
  496. # Open the connection and log in
  497.  
  498. .protocol = "none"                      # No protocol yet
  499.  
  500. if \m(telnet) {                         # Try telnet first
  501.     pmsg "TRYING TELNET..."
  502.     dotelnet
  503.     if fail {                           # If it fails try ssh
  504.         hangup                          # First close Telnet connection
  505.         pmsg "TELNET FAILED - TRYING SSH..."
  506.         dossh
  507.         if fail fatal "SSH \m(fullhost) failed."
  508.         .protocol = "ssh"
  509.     }
  510.     .protocol = telnet
  511. } else {                                # Try ssh first
  512.     pmsg "TRYING SSH..."
  513.     dossh
  514.     if fail {                           # If it fails try Telnet
  515.         hangup                          # First close ssh connection
  516.         if \m(notelnet) "SSH \m(fullhost) failed."
  517.         pmsg "SSH FAILED - TRYING TELNET..."
  518.         dotelnet
  519.         if fail fatal "TELNET \m(fullhost) failed."
  520.         .protocol = telnet
  521.     }
  522.     .protocol = "ssh"
  523. }
  524.  
  525. # If we arrive here we should have the password prompt.
  526. # NOTE: This logic will need to be changed if it is possible to log in
  527. # via SSH (or some secure form of Telnet) without a password.
  528.  
  529. .haveiloprompt = 0
  530. for i 1 2 1 {
  531.     lineout \&p[i]                      # Send console password
  532.     if fail fatal "Output password to \m(fullhost) failed."
  533.     minput 30 \m(iloprompt) "Permission denied" "Invalid login."
  534.     if fail fatal "Timed out waiting for iLO CLI prompt."
  535.     if == \v(minput) 1 {
  536.         .haveiloprompt = 1
  537.         break 
  538.     }
  539.     if \m(dopassword) {
  540.         pmsg "Password from serials file failed - trying empty password..."
  541.     } else {
  542.         pmsg "Empty password failed - trying password from serials file..."
  543.     }
  544.     # After bad password Telnet prompts again for the username - ssh does not.
  545.     if eq "\m(protocol)" "telnet" {
  546.         input 10 "Login Name: "
  547.         if fail fatal "Telnet Login Name timeout"
  548.         lineout \m(loginname)
  549.     }
  550.     input 2 "password: "
  551.     if not quiet echo
  552.     if == \m(i) 2 fatal "Password not accepted"
  553.     if quiet continue
  554. }
  555. if not \m(haveiloprompt) fatal "iLO console login failure"
  556. getiloversion                # Get iLO version number
  557.  
  558. # CONNECT - Go interactive and do not execute the rest of the script.
  559.  
  560. .haveconnection = 1                     # Have connection
  561.  
  562. if \m(connect) {                        # Interactive session requested
  563.     lineout                             # Send a carriage return
  564.     connect                             # Connect to remote
  565.     if not open connection exit         # Exit from Kermit if connection closed
  566.     stop                                # Otherwise don't exit
  567. }
  568. if \m(bios) forward skipilocommands    # If "go to Bios" jump ahead
  569.  
  570. # Automated configuration run...
  571.  
  572. # Prompt for created-user ID if it wasn't in the environment
  573. .userid := \$(ilo_userid)
  574. .userpass := \$(ilo_userpass)
  575. while not defined userid {              # Prompt for created user ID
  576.     ask userid "User ID for created account: "
  577. }
  578. # Prompt for created-user password if it wasn't in the environment
  579. while not defined userpass {    
  580.     askq /echo:* userpass "Password for created account: "
  581. }
  582. if \m(dodebug) {
  583.     set debug timestamps on
  584.     log debug \m(hostname)-debug.log
  585. }
  586.  
  587. # Send iLO commands...
  588.  
  589. .state = iLO
  590. ilocommand "show /system1/firmware1"    # Get iLO firmware version
  591. ilocommand "create /map1/accounts1 username=\m(userid) -
  592.  password=\m(userpass) group=admin,config,oemhp_vm,oemhp_rc,oemhp_power"
  593. if < \m(iloversion) 3 {
  594.     if not notelnet ilocommand "set /map1/config1 oemhp_telnetenable=yes"
  595.     ilocommand "set /map1/config1 oemhp_shared_console_enable=yes"
  596. }
  597. ilocommand "set /system1 oemhp_server_name=\m(hostname)"
  598. # ilocommand "set /map1/config1 oemhp_rc_aquire=yes"
  599.  
  600. if \m(iloonly) {                        # Skip the rest if iloonly
  601.     .rc = 0                             # Set a good return code
  602.     forward done                        # and finish up
  603. }
  604. :skipilocommands
  605.  
  606. lineout "power"                         # Check power state
  607. minput 60 {server power is currently: On} {server power is currently: Off} 
  608. if fail fatal "No response to power command MINPUT=\v(minput)"
  609. switch \v(minput) {
  610.   :1, getiloprompt, lineout "reset /system1 hard", break
  611.   :2, getiloprompt, lineout "power on", break
  612. }
  613. .max = 10
  614. for i 1 \m(max) 1 {                     # Wait for power to come on
  615.     lineout "power"
  616.     minput 20+3*i -
  617.      {server power is currently: On} {server power is currently: Off} 
  618.     if == \v(minput) 1 break
  619.     if == \v(minput) 0 {
  620.         if == \v(instatus) 1 {
  621.             continue
  622.         } else {
  623.             fatal "\v(inmessage)"
  624.         }
  625.     }
  626.     xsleep \m(i)
  627.     getiloprompt
  628.     lineout "power on"
  629.     getiloprompt
  630. }
  631. if >= \m(i) \m(max) fatal "POWER ON DIDN'T TURN POWER ON"
  632.  
  633. # Enter VSP [virtual serial port]...
  634.  
  635. :dovsp
  636.  
  637. pmsg "Attempting to enter VSP..."
  638.  
  639. ilocommand "vsp"
  640. input 30 "Virtual Serial Port Active"
  641. if fail fatal "FAILURE TO ENTER VSP"
  642.  
  643. # Here we have to allow for many prompts and responses
  644. # including a Device Status Request escape sequence from the host
  645. # (ESC [ 5 n) which must be replied to.  (NOTE: doublequotes in
  646. # the MINPUT text arguments have to be escaped as \{34}).
  647.  
  648. .sendesc9 = 0 
  649. while true {
  650.     minput 300 -
  651.      {Press \{34}ESC+9\{34} for ROM-Based Setup Utility} -
  652.      {Press \{34}ESC+0\{34} for System Maintenance Menu} -
  653.      {\27[5n} -
  654.      {Press <F8> to run the Option ROM Configuration for Arrays Utility} -
  655.      {Requested service is unavailable\, it is already in use} -
  656.      {The server is not powered on} -
  657.      {The Virtual Serial Port is not available}
  658.     if fail {                           # If INPUT fails
  659.         output \{27}\{40}               # Escape back to iLO prompt
  660.         pmsg "INPUT: \v(inmessage)"    # and back out from there.
  661.         if open connection {            # Is the connection still open?
  662.             fatal "INPUT FAILED WITH CONNECTION STILL OPEN"
  663.         } else {
  664.             fatal "CONNECTION CLOSED BY SERVER"
  665.         }
  666.     }
  667.     if == 1 \v(minput) {        # What we want in iLO 3
  668.         .sendesc9 = 1            # Remember that we did this
  669.         break
  670.     }
  671.     if == 2 \v(minput) break            # What we want in iLO 2...
  672.     if == 3 \v(minput) {                # Device Status Report Request
  673.         output \27[0n                   # Send Device Status Report (I'm OK)
  674.         if \m(dodebug) echo SENT ESC [0n
  675.         continue
  676.     } 
  677.     if == 4 \v(minput) {                # If we are configuring RAID
  678.         if not \m(doingraid) continue
  679.         output \{27}8                   # Send Esc 8
  680.         break                           # and quit this loop
  681.     }
  682.     getiloprompt                        # Soak up rest of message
  683.     lineout "exit"                      # Exit from iLO
  684.     fatal "VSP service unavailable" 
  685.     .rc = 1
  686.     forward DONE
  687. }
  688. if not \m(doingraid) goto dorbsu        # If not doing RAID skip to next part
  689.  
  690. .havecli = 0                            # Flag for have CLI prompt
  691. input 20 "CLI> "                        # Wait for CLI prompt
  692. if fail {
  693.     pmsg "Arrays CLI> prompt did not appear - skipping..."
  694.     forward dorbsu
  695. }
  696. .havecli = 1
  697. set output pacing 200                   # Can't blast characters at CLI prompt
  698. clear input                             # Clear INPUT buffer
  699. lineout "physicaldrive * show"          # Show physical arrays
  700. input 30 "CLI> "                        # Wait for next CLI prompt
  701.  
  702. # Count the drives - \v(input) contains the results of the SHOW command"
  703.  
  704. .drives = 0              
  705. if \findex({Unknown Command},\v(input)) {
  706.     pmsg "Command 'physicaldrive * show' garbled - increase OUTPUT PACING"
  707.     forward dorbsu
  708. }
  709. if \findex({Invalid physical drive number specified},\v(input)) {
  710.     pmsg "Arrays CLI Invalid drive number specified - skipping"
  711.     forward dorbsu
  712. }
  713. .xx := \freplace(\v(input),\32,_)       # This solves a slight syntax problem
  714. if \findex(Physical_Drive_#_1,\m(xx)) incr drives
  715. if \findex(Physical_Drive_#_2,\m(xx)) incr drives
  716. if \findex(Physical_Drive_#_3,\m(xx)) incr drives
  717. if \findex(Physical_Drive_#_4,\m(xx)) incr drives
  718. if \findex(Physical_Drive_#_5,\m(xx)) incr drives
  719. if \findex(Physical_Drive_#_6,\m(xx)) incr drives
  720. if \findex(Physical_Drive_#_7,\m(xx)) incr drives
  721. if \findex(Physical_Drive_#_8,\m(xx)) incr drives
  722. if < \m(drives) 2 {
  723.     pmsg "Physical Drives: \m(drives) - skipping..."
  724.     forward dorbsu
  725. }
  726. pmsg "Physical Drives: \m(drives) - OK"
  727. set output pacing 250                   # Can't blast characters at CLI prompt
  728. clear input                             # Erase \v(input) again
  729. lineout "logicaldrive * show"           # Show logical drives
  730. input 30 "CLI> "                        # Wait for next CLI prompt
  731. if fail {
  732.     pmsg "No CLI prompt after 'logicaldrive * show' after \v(inwait) secs"
  733.     .havecli = 0
  734.     forward dorbsu
  735. }
  736. .raid = -1
  737. if \findex({Unknown Command},\v(input)) {
  738.     pmsg "Command 'logicaldrive * show' garbled - increase OUTPUT PACING"
  739.     forward dorbsu
  740. }
  741. .xx := \fsubstitute(\v(input),\32\44,_:) # Another syntax trick
  742. if \findex({Logical_Drive_#_1:RAID_0},\m(xx)) .raid = 0
  743. if \findex({Logical_Drive_#_1:RAID_1},\m(xx)) .raid = 1
  744. if < \m(raid) 0 {
  745.     pmsg "Unexpected response to 'logicaldrives * show'"
  746.     forward dorbsu
  747. }
  748. if == \m(raid) 1 {
  749.     pmsg "Logical Drive \# 1 RAID 1 - skipping..."
  750.     forward dorbsu
  751. }
  752. pmsg "Logical Drive \# 1 RAID 0 - Changing to RAID 1..."
  753.  
  754. lineout "logicaldrive 1 delete"
  755. minput 20 "Are you sure? (y/n):" "Unknown Command"
  756. if fail {
  757.     pmsg "Timeout after 'logical drive 1 delete' dialog - skipping...'"
  758.     forward dorbsu
  759. }
  760. if == \v(minput) 2 {
  761.     pmsg "Command 'logicaldrive 1 delete' garbled - increase OUTPUT PACING"
  762.     forward dorbsu
  763. }
  764. output y                                # Just the letter 'y', no CR.
  765. pmsg "Creating logicaldrive 1 RAID 1 mirrored..."
  766. input 10 "CLI> "                        # Wait for next CLI prompt
  767. if fail {
  768.     pmsg "No CLI prompt after 'logicaldrive 1 delete' after \v(inwait) secs"
  769.     .havecli = 0
  770.     forward dorbsu
  771. }
  772. clear input                             # In case we want to collect text
  773. lineout "controller create type=logicaldrive raid=1 drives=1,2"
  774.  
  775. # Note: when this succeeds there is no message at all.
  776. # It takes about 20 seconds.  I don't know what any error messages would be.
  777.  
  778. input 30 "CLI> "                        # Wait for next CLI prompt
  779.  
  780. :dorbsu
  781.  
  782. if \m(havecli) {                        # Exit from CLI if we were in it
  783.     lineout exit                        # and wait for another menu
  784.     input 30 {Press "ESC+0" for System Maintenance Menu}
  785. }
  786. if \m(sendesc9) {            # In iLO 3 we can go straight to RBSU
  787.     input 30 {for Network Boot}        # (wait for this...)
  788.     pause 1                # (wait a bit more...)
  789.     output \{27}9            # by "pressing" Esc (27) and 9
  790.     forward getrbsuprompt
  791. }
  792. output \{27}0                           # Send ESC and 0
  793.  
  794. # Here it is waiting for a DHCP response which might never come.
  795.  
  796. input 120 "MMenu> "            # Get MMenu> prompt
  797. if fail {
  798.     fatal "Timed out waiting for MMenu> prompt"
  799. }
  800. .state = MMenu                # Have MMenu> prompt
  801.  
  802. # Send the RBSU command one char at a time because this prompt is VERY LOSSY
  803.  
  804. .sentrbsu = 0
  805. clear input                # Clear the input buffer
  806. for \%9 1 4 1 {                # Echoplex loop - try this four times
  807.   output R                # R
  808.   input 2*\%9 R                # Wait for the echo
  809.   if fail { lineout, continue }        # On failure send CR and start over
  810.   output B                # B...
  811.   input 2*\%9 B
  812.   if fail { lineout, continue }
  813.   output S                # S...
  814.   input 2*\%9 S
  815.   if fail { lineout, continue }
  816.   output U                # U...
  817.   input 2*\%9 U
  818.   if fail { lineout, continue }
  819.   lineout                # Send carriage return
  820.   clear input
  821.   .sentrbsu = 1
  822.   break
  823. }
  824. if not \m(sentrbsu) fatal "Failure to send RBSU Command"
  825.  
  826. :getrbsuprompt
  827. input 30 "rbsu> "            # Wait for rbsu> prompt
  828.  
  829. if fail fatal "Timed out waiting for first rbsu> prompt"
  830.  
  831. :inrbsu
  832.  
  833. .state = rbsu
  834.  
  835. if ( \m(bios) && NOT \m(pwrmode) ) {    # Go interactive to RBSU prompt
  836.     pmsg "Attempting to access BIOS..."
  837.     connect                # Go interactive
  838.     forward DONE            # Upon return skip the rest
  839. }
  840.  
  841. set output pacing \m(outputpacing)      # Throttle output speed
  842.  
  843. if \m(pwrmode) {            # Change power mode
  844.  
  845.     rbsucommand "SHOW CONFIG HP POWER REGULATOR"
  846.     rbsucommand "SET CONFIG HP POWER REGULATOR \m(pwrmode)"
  847.  
  848. } else {
  849.  
  850.     # Send the RBSU commands.
  851.     # Here we could give a SHOW CONFIG VIRTUAL SERIAL PORT command and parse 
  852.     # the BIOS Serial Console Port menu choices in case the menu ever changes.
  853.  
  854.     rbsucommand "SET CONFIG VIRTUAL SERIAL PORT 2"
  855.     rbsucommand "SET CONFIG BIOS SERIAL CONSOLE PORT 4"
  856.     rbsucommand "SET CONFIG BIOS SERIAL CONSOLE BAUD RATE 4"
  857.     rbsucommand "SET CONFIG EMS CONSOLE 3"
  858. }
  859. lineout EXIT                            # Exit from RBSU
  860. pause 1                                 # Wait a sec and...
  861. output \27(                             # Escape back to iLO
  862. getiloprompt                            # Get iLO prompt
  863. .state = iLO
  864.  
  865. .rc = 0                                 # Our return code - assume success.
  866. if not \m(poweroff) {                   # Turn power off now?
  867.     
  868.     if not \m(reset) pmsg "LEAVING POWER ON" # No...
  869.     forward DONE
  870. }
  871. pmsg "TURNING POWER OFF"        # Yes...
  872. .max = 10                               # How many times to try.
  873. for i 1 \m(max) 1 {                     # Loop for each try.
  874.     lineout "power off"                 # Send power off command.
  875.     sleep 15                            # Give it a little time
  876.     getiloprompt                        # Get iLO prompt    
  877.     lineout "power"                     # Send "power" command to check
  878.     minput 30 {server power is currently: Off} {server power is currently: On} 
  879.     if == \v(minput) 1 {                # Power is off
  880.         getiloprompt                    # Read next iLO prompt
  881.         forward DONE                    # Exit loop and skip ahead
  882.     }
  883.     sleep 2*i                           # Sleep more each time
  884.     warn "RETRYING POWER OFF [\m(i)]..."
  885.     getiloprompt
  886. }
  887. warn "WARNING: POWER OFF FAILED AFTER \m(max) TRIES"
  888. .rc = 1
  889.  
  890. :DONE
  891. define fatal end 0                      # No fatal errors from now on
  892. if \m(haveconnection) {                 # If we have a connection...
  893.     if \m(reset) {                      # Reset the machine
  894.         .reset = 0                      # Prevent recursion in case of error
  895.         pmsg "HARD RESET AND CLOSE"
  896.         ilocommand "cd /Map1"
  897.         lineout "reset"
  898.         sleep 5
  899.         close connection                # Close our end of the connection
  900.     } else {
  901.         if not \m(rc) {
  902.             pmsg "EXIT WITHOUT RESET"
  903.             lineout "exit"              # Exit from iLO
  904.             input 30 "CLI session stopped" # Wait for final gasp
  905.         }
  906.         if open connection hangup       # Close our end too just in case
  907.     }
  908. }
  909. .haveconnection = 0
  910. pmsg "END: STATUS: \m(rc)"
  911. if open session-log close session-log   # Close log
  912. exit \m(rc)                             # Exit from script and Kermit
  913.  
  914. ; Local Variables:
  915. ; comment-column:40
  916. ; comment-start:"# "
  917. ; End:
  918.