# BEGIN_ICS_COPYRIGHT8 ****************************************
#
# Copyright (c) 2015-2020, Intel Corporation
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of Intel Corporation nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# END_ICS_COPYRIGHT8 ****************************************
# [ICS VERSION STRING: unknown]
# This is an expect (tcl) library of procedures to aid testing
# These functions provide support for remote login and command execution
# against a test target host
## tcl procedures to support testing:
## =============================================
# pattern to match for unix prompts (both local and on target)
global target_unix_prompt
set target_unix_prompt {[$#>][\033 ]}
# pattern to match for chassis prompts
# since it starts with a -, -gl must be passed to expect
global target_chassis_prompt
set target_chassis_prompt {-> }
# prompt which comes after login when connect to support shell
global target_chassis_shell_prompt
set target_chassis_shell_prompt {shell-> }
# limit on login retries
global target_chassis_retry_limit
set target_chassis_retry_limit 3
# is the present chassis session a support shell session?
global target_chassis_shell
set target_chassis_shell 0
# save area for main card when in a rlogin shell
global target_chassis_shell_save
set target_chassis_shell_save 0
global os_type
set os_type [ exec uname -s ]
proc chassis_strip_slots { chassis } {
##
## chassis_strip_slots
## -------------------
## strip slot specifications from chassis
##
## Usage:
## chassis_strip_slots chassis
## Arguments:
## chassis - chassis name of the form: name[:slot,slot...]
## Returns:
## resulting chassis name
## -code error on failure
if { [ regexp {.*\[(.*)\].*:.*} "$chassis" full ret] } {
# [chassis]:slot format
return "$ret"
} elseif { [ regexp {.*\[(.*)\].*} "$chassis" full ret] } {
# [chassis] format
return "$ret"
} elseif { [ regexp {.*:.*:.*} "$chassis" full ] } {
# ipv6 without [] nor slot
return "$chassis"
} elseif { [regexp {([^:]+):.*} "$chassis" full ret] } {
# chassis:slot format
return "$ret"
} else {
# chassis without [] nor slot
return "$chassis"
}
}
proc chassis_get_slots { chassis } {
##
## chassis_get_slots
## -------------------
## get slot specifications from chassis
##
## Usage:
## chassis_get_slots chassis
## Arguments:
## chassis - chassis name of the form: name[:slot,slot...]
## Returns:
## resulting list of slots as a TCL list : slot nos after colon
## if no slots, returns "all"
## -code error on failure
if { [ regexp {.*\[.*\].*:(.*)} "$chassis" full slots] } {
# [chassis]:slot format
return [string map {, " "} "$slots"]
} elseif { [ regexp {.*\[.*\].*} "$chassis" full] } {
# [chassis] format
return "all"
} elseif { [ regexp {.*:.*:.*} "$chassis" full ] } {
# ipv6 without [] nor slot
return "all"
} elseif { [regexp {[^:]+:(.*)} "$chassis" full slots] } {
# chassis:slot format
return [string map {, " "} "$slots"]
} else {
# chassis without [] nor slot
return "all"
}
}
proc local_sh { } {
##
## local_sh
## -------------------
## start a local shell
##
## Usage:
## local_sh
## Arguments:
## Returns:
## 0 - success
## -code error on failure
global spawn_id expect_out spawn_out timeout
global expecting
test_spawn "bash" bash
expect_unix_prompt 60
local_set_env
return 0
}
proc local_sh_exit { } {
##
## local_sh_exit
## ----------------
## exit from shell connection created by local_sh
##
## Usage:
## local_sh_exit
##
## Returns:
## 0 - success
## -code error on failure
send_unix_cmd "exit 0"
ignore_rest
return 0
}
proc local_set_env { } {
##
## local_set_env
## -------------------
## setup environment for shell session to allow testing
##
## Usage:
## local_set_env
## Arguments:
## None
## Returns:
## 0 - success
## -code error on failure
# set COLUMNS real large so the Posix shell doesn't enter
# command edit mode and confuse us
#unix_cmd 60 "" "export COLUMNS=500"
#unix_cmd 60 "" "unset EDITOR"
#unix_cmd 60 "" "unset VISUAL"
#unix_cmd 60 "" "umask 0"
#target_set_intr
# get rid of cr and control characters in logs for easier reading
#unix_cmd 60 0 {unset PROMPT_COMMAND; export PS1='[\u@\h]\$ '; stty -onlcr columns 500}
unix_cmd 60 0 {unset PROMPT_COMMAND HISTFILE; set +o history; export PS1='[\u@\h]\$ '}
}
proc target_rlogin { target usercode password } {
##
## target_rlogin
## -------------------
## rlogin to the given target host
##
## Usage:
## target_rlogin target usercode password
## Arguments:
## target - hostname to rlogin to
## usercode - usercode
## password - password
## Returns:
## 0 - success
## -code error on failure
global spawn_id expect_out spawn_out timeout
global expecting
global stty_init
global target_unix_prompt
test_spawn "rlogin" rlogin $target -l $usercode
set_timeout 120
set expecting "rlogin session ($target $usercode)"
expect {
"assword:" { exp_send "$password\r"
exp_continue
}
"incorrect" { set info "Failed to rlogin to $target as $usercode, incorrect usercode"
return -code error -errorinfo $info $info
}
"failure" { set info "Failed to rlogin to $target as $usercode"
return -code error -errorinfo $info $info
}
"refused" { set info "Failed to rlogin to $target as $usercode"
return -code error -errorinfo $info $info
}
"nknown" { set info "Failed to rlogin to $target as $usercode"
return -code error -errorinfo $info $info
}
"$target_unix_prompt" noop
}
return 0
}
proc target_telnet { target usercode password } {
##
## target_telnet
## -------------------
## telnet to the given target host
##
## Usage:
## target_telnet target usercode password
## Arguments:
## target - hostname to rlogin to
## usercode - usercode
## password - password
## Returns:
## 0 - success
## -code error on failure
global spawn_id expect_out spawn_out timeout
global expecting
global stty_init
global target_unix_prompt
test_spawn "telnet" telnet $target -l $usercode
set_timeout 120
set expecting "telnet session ($target $usercode)"
expect {
"assword:" { exp_send "$password\r"
exp_continue
}
"incorrect" { set info "Failed to telnet to $target as $usercode, incorrect usercode"
return -code error -errorinfo $info $info
}
"failure" { set info "Failed to telnet to $target as $usercode"
return -code error -errorinfo $info $info
}
"refused" { set info "Failed to telnet to $target as $usercode"
return -code error -errorinfo $info $info
}
"nknown" { set info "Failed to telnet to $target as $usercode"
return -code error -errorinfo $info $info
}
"$target_unix_prompt" noop
}
return 0
}
proc target_chassis_telnet {target usercode password} {
##
## target_chassis_telnet
## -------------------
## telnet to the given target chassis
##
## Usage:
## target_chassis_telnet target usercode password
## Arguments:
## target - chassis name to telnet to
## usercode - usercode
## password - password
## Returns:
## 0 - success
## -code error on failure
global spawn_id expect_out spawn_out timeout
global expecting
global stty_init
global target_chassis_prompt
global target_chassis_shell target_chassis_shell_prompt
global target_chassis_retry_limit
set target_chassis_shell 0
test_spawn "telnet" telnet $target
set_timeout 120
set expecting "telnet session ($target $usercode)"
set retries 0
expect {
"ogin:" { exp_send "$usercode\r"
set retries [ expr $retries + 1 ]
if { $retries > $target_chassis_retry_limit } {
set info "Failed to telnet to $target as $usercode"
return -code error -errorinfo $info $info
}
exp_continue
}
"sername:" { exp_send "$usercode\r"
set retries [ expr $retries + 1 ]
if { $retries > $target_chassis_retry_limit } {
set info "Failed to telnet to $target as $usercode"
return -code error -errorinfo $info $info
}
exp_continue
}
"sername->" { exp_send "$usercode\r"
set retries [ expr $retries + 1 ]
if { $retries > $target_chassis_retry_limit } {
set info "Failed to telnet to $target as $usercode"
return -code error -errorinfo $info $info
}
exp_continue
}
"assword:" { exp_send "$password\r"
exp_continue
}
"assword->" { exp_send "$password\r"
exp_continue
}
"incorrect" { set info "Failed to telnet to $target as $usercode, incorrect usercode"
return -code error -errorinfo $info $info
}
"failure" { set info "Failed to telnet to $target as $usercode"
return -code error -errorinfo $info $info
}
"refused" { set info "Failed to telnet to $target as $usercode"
return -code error -errorinfo $info $info
}
"nknown" { set info "Failed to telnet to $target as $usercode"
return -code error -errorinfo $info $info
}
-gl "$target_chassis_shell_prompt" { set target_chassis_shell 1 }
-gl "$target_chassis_prompt" noop
}
return 0
}
proc target_ssh { target usercode password } {
##
## target_ssh
## -------------------
## ssh to the given target host
##
## Usage:
## target_ssh target usercode password
## Arguments:
## target - hostname to ssh to
## usercode - usercode
## password - password
## Returns:
## 0 - success
## -code error on failure
global spawn_id expect_out spawn_out timeout
global expecting
global stty_init
global target_unix_prompt
test_spawn "ssh" ssh -q $usercode@$target
set_timeout 30
set expecting "ssh session ($target $usercode)"
expect {
"assword:" { exp_send "$password\r"
exp_continue
}
"denied" { set info "Failed to ssh to $target as $usercode, incorrect password"
return -code error -errorinfo $info $info
}
"failure" { set info "Failed to ssh to $target as $usercode"
return -code error -errorinfo $info $info
}
"refused" { set info "Failed to ssh to $target as $usercode"
return -code error -errorinfo $info $info
}
"nknown" { set info "Failed to ssh to $target as $usercode"
return -code error -errorinfo $info $info
}
"ast login" {
noop
}
"$target_unix_prompt" noop
}
return 0
}
proc target_chassis_ssh { target usercode password } {
##
## target_chassis_ssh
## -------------------
## ssh to the given target chassis
##
## Usage:
## target_chassis_ssh target usercode password
## Arguments:
## target - chassis to ssh to
## usercode - usercode
## password - password
## Returns:
## 0 - success
## -code error on failure
global spawn_id expect_out spawn_out timeout
global expecting
global stty_init
global target_chassis_prompt
global target_chassis_shell target_chassis_shell_prompt
global target_chassis_retry_limit
set target_chassis_shell 0
test_spawn "ssh" ssh -q $usercode@$target
set_timeout 60
set expecting "ssh session ($target $usercode)"
set retries 0
expect {
"ogin:" { exp_send "$usercode\r"
set retries [ expr $retries + 1 ]
if { $retries > $target_chassis_retry_limit } {
set info "Failed to telnet to $target as $usercode"
return -code error -errorinfo $info $info
}
exp_continue
}
"sername:" { exp_send "$usercode\r"
set retries [ expr $retries + 1 ]
if { $retries > $target_chassis_retry_limit } {
set info "Failed to telnet to $target as $usercode"
return -code error -errorinfo $info $info
}
exp_continue
}
"sername->" { exp_send "$usercode\r"
set retries [ expr $retries + 1 ]
if { $retries > $target_chassis_retry_limit } {
set info "Failed to telnet to $target as $usercode"
return -code error -errorinfo $info $info
}
exp_continue
}
"assword:" { exp_send "$password\r"
exp_continue
}
"assword->" { exp_send "$password\r"
exp_continue
}
"denied" { set info "Failed to ssh to $target as $usercode, incorrect password"
return -code error -errorinfo $info $info
}
"failure" { set info "Failed to ssh to $target as $usercode"
return -code error -errorinfo $info $info
}
"refused" { set info "Failed to ssh to $target as $usercode"
return -code error -errorinfo $info $info
}
"nknown" { set info "Failed to ssh to $target as $usercode"
return -code error -errorinfo $info $info
}
"continue connecting" { exp_send "yes\n"
exp_continue
}
"ast login" {
noop
}
-gl "$target_chassis_shell_prompt" { set target_chassis_shell 1 }
-gl "$target_chassis_prompt" noop
}
return 0
}
proc target_chassis_rlogin_slot {slot usercode password} {
##
## target_chassis_rlogin_slot
## -------------------
## rlogin to the given slot within the present chassis
## This should only be called by target_chassis_admin_sh
## otherwise tracking of shell vs cli prompt will be incorrect
##
## Usage:
## target_chassis_rlogin_slot slot usercode password
## Arguments:
## slot - slot to login to
## usercode - usercode
## password - password
## Returns:
## 0 - success
## -code error on failure
global spawn_id expect_out spawn_out timeout
global expecting
global stty_init
global target_chassis_prompt
global target_chassis_shell target_chassis_shell_prompt
global target_chassis_retry_limit
global target_chassis_shell_save
set target_chassis_shell_save $target_chassis_shell
send_chassis_cmd "rlogin $slot"
set_timeout 60
set expecting "rlogin session to slot $slot ($usercode)"
set retries 0
expect {
"sername:" { exp_send "$usercode\r"
set retries [ expr $retries + 1 ]
if { $retries > $target_chassis_retry_limit } {
set info "Failed to rlogin to slot $slot as $usercode"
return -code error -errorinfo $info $info
}
exp_continue
}
"sername->" { exp_send "$usercode\r"
set retries [ expr $retries + 1 ]
if { $retries > $target_chassis_retry_limit } {
set info "Failed to rlogin to slot $slot as $usercode"
return -code error -errorinfo $info $info
}
exp_continue
}
"assword:" { exp_send "$password\r"
exp_continue
}
"assword->" { exp_send "$password\r"
exp_continue
}
"incorrect" { set info "Failed to rlogin to slot $slot as $usercode, incorrect usercode"
return -code error -errorinfo $info $info
}
"failure" { set info "Failed to rlogin to slot $slot as $usercode"
return -code error -errorinfo $info $info
}
"refused" { set info "Failed to rlogin to slot $slot as $usercode"
return -code error -errorinfo $info $info
}
"nknown" { set info "Failed to rlogin to slot $slot as $usercode"
return -code error -errorinfo $info $info
}
"orry" { set info "Failed to rlogin to slot $slot as $usercode"
return -code error -errorinfo $info $info
}
"not responding" { set info "Failed to rlogin to slot $slot as $usercode"
return -code error -errorinfo $info $info
}
-gl "$target_chassis_shell_prompt" { set target_chassis_shell 1 }
-gl "$target_chassis_prompt" { set target_chassis_shell 0 }
}
return 0
}
proc send_unix { text } {
##
## send_unix
## -------------------
## send a interactive response to a unix command during a login session
##
## Usage:
## send_unix text
## Arguments:
## text - text to send
## Returns:
## nothing
## Additional Information:
## Do NOT use this to send commands.
## send_unix_cmd or unix_cmd should be used for that purpose
global spawn_id expect_out spawn_out
exp_send "$text"
}
proc send_chassis { text } {
##
## send_chassis
## -------------------
## send a interactive response to a chassis command during a login session
##
## Usage:
## send_chassis text
## Arguments:
## text - text to send
## Returns:
## nothing
## Additional Information:
## Do NOT use this to send commands.
## send_chassis_cmd or chassis_cmd should be used for that purpose
global spawn_id expect_out spawn_out
exp_send "$text"
}
proc target_set_intr {} {
##
## target_set_intr
## ----------------
## set the interrupt character to control-C
##
## Usage:
## target_set_intr
## Returns:
## 0 - success
## -code error on failure
unix_cmd 60 0 "stty intr ^C"
}
proc target_send_intr {} {
##
## target_send_intr
## ----------------
## set the interrupt character (eg. control-C) to a host
##
## Usage:
## target_send_intr
## Returns:
## 0 - success
## -code error on failure
global spawn_id expect_out spawn_out timeout
exp_send "\003"
}
proc chassis_send_intr {} {
##
## chassis_send_intr
## ----------------
## set the interrupt character (eg. control-C) to a chassis
##
## Usage:
## chassis_send_intr
## Returns:
## 0 - success
## -code error on failure
global spawn_id expect_out spawn_out timeout
exp_send "\003"
}
proc target_set_noecho {} {
##
## target_set_noecho
## ----------------
## disable echo during a unix login session or sh
##
## Usage:
## target_set_noecho
## Returns:
## 0 - success
## -code error on failure
unix_cmd 60 0 "stty -echo"
}
proc target_set_echo {} {
##
## target_set_echo
## ----------------
## enable echo during a unix login session or sh
##
## Usage:
## target_set_echo
## Returns:
## 0 - success
## -code error on failure
unix_cmd 60 0 "stty echo"
}
proc target_su { usercode {password "" }} {
##
## target_su
## -------------------
## change usercode during a unix login session
##
## Usage:
## target_su usercode [password]
## Arguments:
## usercode - usercode
## password - password, if omitted assumes no password needed
## Returns:
## 0 - success
## -code error on failure
global spawn_id expect_out spawn_out timeout
global expecting env
global target_unix_prompt
send_unix_cmd "su - $usercode"
set_timeout 120
set expecting "su session ($usercode)"
expect {
"assword:" { if { "$password" == "" } {
set info "Failed to su $usercode, password required"
return -code error -errorinfo $info $info
} else {
exp_send "$password\n"
exp_continue
}
}
"Sorry" { set info "Failed to su $usercode, incorrect password"
return -code error -errorinfo $info $info
}
"$target_unix_prompt" noop
}
#unix_cmd 60 0 "ksh"
target_set_env
return 0
}
proc target_su_exit { } {
##
## target_su_exit
## -------------------
## exit super user shell created by target_su
##
## Usage:
## target_su_exit
## Returns:
## 0 - success
## -code error on failure
global env
# exit ksh
#unix_cmd 60 "" "exit 0"
# exit su
unix_cmd 60 "" "exit 0"
}
proc target_set_env { } {
##
## target_set_env
## -------------------
## setup environment for unix shell session to allow testing
##
## Usage:
## target_set_env
## Arguments:
## None
## Returns:
## 0 - success
## -code error on failure
# set COLUMNS real large so the Posix shell doesn't enter
# command edit mode and confuse us
#unix_cmd 60 "" "export COLUMNS=500"
#unix_cmd 60 "" "unset EDITOR"
#unix_cmd 60 "" "unset VISUAL"
#unix_cmd 60 "" "umask 0"
#target_set_intr
# get rid of cr and control characters in logs for easier reading
unix_cmd 60 0 {unset PROMPT_COMMAND HISTFILE; set +o history; export PS1='[\u@\h]\$ '; stty -onlcr columns 500}
}
proc target_root_sh { target } {
##
## target_root_sh
## ----------------
## prepare for a test by login'ing to target host as user root
##
## Usage:
## target_root_sh target
##
## Arguments:
## target - hostname to login to
## Returns:
## 0 - success
## -code error on failure
## Additional Information:
## uses:
## env(CFG_LOGIN_METHOD) to select between rlogin or ssh
## env(CFG_USERNAME) as a non-root user name for rlogin (followed by su)
## env(CFG_PASSWORD) as password for CFG_USERNAME for rlogin
## env(CFG_ROOTPASS) as root password for ssh or su
global env
if { "$env(CFG_LOGIN_METHOD)" == "rlogin" } {
target_rlogin $target $env(CFG_USERNAME) $env(CFG_PASSWORD)
target_su root $env(CFG_ROOTPASS)
} elseif { "$env(CFG_LOGIN_METHOD)" == "telnet" } {
target_telnet $target $env(CFG_USERNAME) $env(CFG_PASSWORD)
target_su root $env(CFG_ROOTPASS)
} elseif { "$env(CFG_LOGIN_METHOD)" == "ssh" } {
target_ssh $target root $env(CFG_ROOTPASS)
target_set_env
} else {
set info "CFG_LOGIN_METHOD must be rlogin, telnet or ssh"
return -code error -errorinfo $info $info
}
return 0
}
proc target_root_sh_exit { } {
##
## target_root_sh_exit
## ----------------
## exit from shell connection created by target_root_sh
##
## Usage:
## target_root_sh_exit
##
## Returns:
## 0 - success
## -code error on failure
## uses:
## env(CFG_LOGIN_METHOD) to select between rlogin or ssh
global env
if { "$env(CFG_LOGIN_METHOD)" == "rlogin" } {
target_su_exit
} elseif { "$env(CFG_LOGIN_METHOD)" == "telnet" } {
target_su_exit
} elseif { "$env(CFG_LOGIN_METHOD)" == "ssh" } {
#unix_cmd 60 "" "exit 0"
send_unix_cmd "exit 0"
} else {
set info "CFG_LOGIN_METHOD must be rlogin, telnet or ssh"
return -code error -errorinfo $info $info
}
ignore_rest
return 0
}
proc target_chassis_admin_sh { target {slot ""} {user "admin"}} {
##
## target_chassis_admin_sh
## ----------------
## prepare for a test by login'ing to chassis as user admin
##
## Usage:
## target_chassis_admin_sh target [slot] [user]
##
## Arguments:
## target - chassis to login to
## slot - slot to login to, default is ""
## user - user code to login as, default is admin
## Returns:
## 0 - success
## -code error on failure
## Additional Information:
## uses:
## env(CFG_CHASSIS_LOGIN_METHOD) to select between telnet or ssh
## env(CFG_CHASSIS_ADMIN_PASSWORD) as password for admin (if no password-less ssh)
global env
if { "$env(CFG_CHASSIS_LOGIN_METHOD)" == "ssh" } {
target_chassis_ssh $target $user $env(CFG_CHASSIS_ADMIN_PASSWORD)
} elseif { "$env(CFG_CHASSIS_LOGIN_METHOD)" == "telnet" } {
target_chassis_telnet $target $user $env(CFG_CHASSIS_ADMIN_PASSWORD)
} else {
set info "CFG_CHASSIS_LOGIN_METHOD must be ssh or telnet"
return -code error -errorinfo $info $info
}
if { "$slot" != "" } {
target_chassis_rlogin_slot $slot $user $env(CFG_CHASSIS_ADMIN_PASSWORD)
}
return 0
}
proc target_chassis_admin_sh_exit { {rlogin 0} } {
##
## target_chassis_admin_sh_exit
## ----------------
## exit from shell connection created by target_chassis_admin_sh
##
## Usage:
## target_chassis_admin_sh_exit [rlogin]
## Arguments:
## rlogin - are we in an rlogin subshell
##
## Returns:
## 0 - success
## -code error on failure
## uses:
global target_chassis_shell
global target_chassis_shell_save
if { $rlogin } {
send_chassis "logout\n"
expect_list 60 "connection closed"
set target_chassis_shell $target_chassis_shell_save
}
send_chassis "logout\n"
set target_chassis_shell 0
ignore_rest
return 0
}
proc expect_prompt { timelimit prompt {out_var ""}} {
##
## expect_prompt
## -------------------------
## wait for prompt during a session
##
## Usage:
## expect_prompt timelimit prompt [out_var]
## Arguments:
## timelimit - maximum wait for shell prompt
## prompt - regular expression for prompt
## out_var - variable in callers context to receive all text which was
## received during during this expect
## Returns:
## 0 - success
## -code error on failure
## Additional Information:
global spawn_id expect_out spawn_out timeout
if { "$out_var" != "" } {
upvar $out_var $out_var
}
expect_list $timelimit "{$prompt}" {} $out_var
return 0
}
proc expect_unix_prompt { timelimit {out_var ""}} {
##
## expect_unix_prompt
## -------------------------
## wait for a unix/darwin prompt during a session
##
## Usage:
## expect_unix_prompt timelimit [out_var]
## Arguments:
## timelimit - maximum wait for shell prompt
## out_var - variable in callers context to receive all text which was
## received during during this expect
## Returns:
## 0 - success
## -code error on failure
## Additional Information:
global target_unix_prompt
if { "$out_var" != "" } {
upvar $out_var $out_var
}
return [ expect_prompt $timelimit "$target_unix_prompt" $out_var ]
}
proc expect_chassis_prompt { timelimit {out_var ""}} {
##
## expect_chassis_prompt
## -------------------------
## wait for a chassis prompt during a session
##
## Usage:
## expect_chassis_prompt timelimit [out_var]
## Arguments:
## timelimit - maximum wait for shell prompt
## out_var - variable in callers context to receive all text which was
## received during during this expect
## Returns:
## 0 - success
## -code error on failure
## Additional Information:
global target_chassis_prompt
global target_chassis_shell target_chassis_shell_prompt
if { "$out_var" != "" } {
upvar $out_var $out_var
}
if { $target_chassis_shell } {
set prompt "$target_chassis_shell_prompt"
} else {
set prompt "$target_chassis_prompt"
}
return [ expect_prompt $timelimit "$prompt" $out_var ]
}
proc target_get_config_stack_type { { host "" } } {
##
## target_get_config_stack_type
## -------------------------
## get the configured stack type of the specified system.
##
## Usage:
## target_get_config_stack_type host
## Arguments:
## host - host to look for in CFG_OFED_HOSTS
## Returns:
## "OPENIB" or "IBACCESS"
## -code error on failure (eg. unable to identify stack type)
## Additional Information:
## checks for host CFG_OFED_HOSTS and stack type is reported based solely
## on CFG_OFED_HOSTS. If not specified or CFG_OFED_HOSTS is not exported
## then returns an error
global env
if { "$host" == "" || ! [ info exists env(CFG_OFED_HOSTS) ] } {
set info "Unable to Determine IB Stack Type"
return -code error -errorinfo $info $info
}
set index [ lsearch -exact $env(CFG_OFED_HOSTS) $host ]
if { $index != -1 } {
return "OPENIB"
} else {
return "IBACCESS"
}
}
proc target_get_stack_type { { checkrun "y"} { host "" } } {
##
## target_get_stack_type
## -------------------------
## get the stack type of the current target Linux/Unix system.
##
## Usage:
## target_get_stack_type [checkrun [host]]
## Arguments:
## checkrun - if y, the running stack is checked first, otherwise
## just installed stack is checked. Note that during reinstall
## an old stack could be left running until the next reboot
## default is y. Beware, due to newer distros including openib, if it
## appears both are installed and 'n' is used, this reports IBACCESS.
## It is safest to invoke this with 'y'.
## host - if specified and CFG_OFED_HOSTS is exported, then host is looked
## for in CFG_OFED_HOSTS and stack type is reported based solely on
## CFG_OFED_HOSTS. If not specified or CFG_OFED_HOSTS is not exported
## then actual running or installed stack is checked
## Returns:
## "OPENIB" or "IBACCESS"
## -code error on failure (eg. unable to identify stack type)
## Additional Information:
## The global timeout is changed by this routine
## If no IB stack is found running, then checks which stack is installed
global spawn_id expect_out spawn_out
global env
# try static lookup first
if { [ catch { target_get_config_stack_type "$host" } res ] == 0 } {
return "$res";
}
set target_os_type [target_get_os_type]
if { "$checkrun" == "y" } {
# ib_umad is a required module for OPEN IB stack
send_unix_cmd {lsmod|egrep '^ib_umad[[:space:]]'}
if { 0 == [ get_exit_status 60 ] } {
return "OPENIB"
}
# ibt is a required module for IbAccess stack
send_unix_cmd {lsmod|egrep '^ibt[[:space:]]'}
if { 0 == [ get_exit_status 60 ] } {
return "IBACCESS"
}
}
# see if IbAccess installed, 0 -> yes
send_unix_cmd {test -e /etc/init.d/iba -o -e /lib/modules/`uname -r`/iba/ibt.ko}
set iba_not_installed [ get_exit_status 60 ]
# see if Open IB installed, 0 -> yes
send_unix_cmd {test -e /etc/init.d/openibd -o -e /lib/modules/`uname -r`/kernel/drivers/infiniband/core/ib_umad.ko -o -e /lib/modules/`uname -r`/kernel/drivers/infiniband/core/ib_umad.ko.xz}
set openib_not_installed [ get_exit_status 60 ]
# newer distros include openib, so if both appear installed also assume iba
# presently this is only called with checkrun=n for automated tests configio
if { ! $iba_not_installed } {
return "IBACCESS"
}
if { $iba_not_installed && ! $openib_not_installed } {
return "OPENIB"
}
set info "Unable to Determine IB Stack Type"
return -code error -errorinfo $info $info
}
proc target_get_os_type { } {
##
## target_get_os_type
## -------------------------
## get the os_type of the current target Linux/Darwin/Unix system.
##
## Usage:
## target_get_os_type
## Arguments:
## Returns:
## "Linux" or "Darwin" (eg. uname -s output of target system)
## -code error on failure
## Additional Information:
## The global timeout is changed by this routine
global spawn_id expect_out spawn_out timeout
global expecting
set_timeout 60
# we use SSS around output so we don't mistake other text in output
# (such as in hostname in prompt) for the os_type
send_unix_cmd "echo SSS`uname -s`SSS"
set expecting "target os_type"
expect {
-re {SSS[A-Za-z0-9]+SSS} noop
}
regexp {SSS([A-Za-z0-9]+)SSS} $expect_out(0,string) line ret
expect_unix_prompt 60
return $ret
}
# TBD - could be moved to TestTools/mpi.exp
# Note: not used by FF, only by Int Tests
proc target_get_registered_mpi_version {mpi_type} {
global spawn_id expect_out spawn_out timeout
global expecting
# Below cmd to flushing out the out buffet that might contains
# too many lines of screen output, causing the output of a cmd
# not being capture in the output. May be there is other better
# way to clean the out buffet
set out ""
send_unix_cmd "echo SSS`mpi-selector --list`EEE"
expect_list 60 { "mpi-selector" "EEE" "EEE" } {} out
set out ""
send_unix_cmd "echo SSS`mpi-selector --list`EEE"
expect_list 60 { "mpi-selector" "EEE" "EEE" } {} out
regexp "EEE.*SSS+(.*)EEE$" $out full_out mpi_list
check_exit_status 60 0
if {![regexp "($mpi_type)-(\[^ ]+)" $mpi_list line mpi_type_match mpi_version]} {
set info "Did not find mpi_type($mpi_type) in mpi_list($mpi_list)"
return -code error -errorinfo $info $info
}
return $mpi_version
}
proc get_exit_status { timelimit { wait_prompt 1 } } {
##
## get_exit_status
## -------------------------
## wait for shell prompt and return the exit status of the last command executed
## during a login session, then wait for shell prompt
##
## Usage:
## get_exit_status timelimit [wait_prompt]
## Arguments:
## timelimit - maximum wait for shell prompt
## wait_prompt - should we wait for prompt before issuing echo of status
## Returns:
## exit code - success
## -code error on failure
## Additional Information:
## The global timeout is changed by this routine
global spawn_id expect_out spawn_out timeout
global expecting
if { $wait_prompt } {
expect_unix_prompt $timelimit
}
set_timeout 60
# we use SSS around number so we don't mistake other numbers in output
# (such as in hostname in prompt) for the exit code
send_unix_cmd "echo SSS$?SSS"
set expecting "exit code"
expect {
-re {SSS[0-9]+SSS} noop
}
regexp {[0-9]+} $expect_out(0,string) ret
expect_unix_prompt 60
return $ret
}
proc check_exit_status { timelimit exit_code { wait_prompt 1 } } {
##
## check_exit_status
## -------------------------
## wait for shell prompt and check the exit status of the last command executed
## during a login session, then wait for shell prompt
##
## Usage:
## check_exit_status timelimit exit_code [wait_prompt]
## Arguments:
## timelimit - maximum wait for shell prompt
## exit_code - expected exit code ([0-9] if don't care)
## wait_prompt - should we wait for prompt before issuing echo of status
## Returns:
## 0 - success
## -code error on failure
## Additional Information:
## The global timeout is changed by this routine
global spawn_id expect_out spawn_out timeout
global expecting
if { $wait_prompt } {
expect_unix_prompt $timelimit
}
set_timeout 60
# we use SSS around number so we don't mistake other numbers in output
# (such as in hostname in prompt) for the exit code
send_unix_cmd "echo SSS$?SSS"
set expecting "exit code: $exit_code"
expect {
"SSS${exit_code}SSS" noop
-re {SSS[0-9]+SSS} { set info "Incorrect exit code: Expected $exit_code, Got: $expect_out(0,string)"
return -code error -errorinfo $info $info
}
}
expect_unix_prompt 60
return 0
}
proc get_chassis_exit_status { timelimit { wait_prompt 1 } } {
##
## get_chassis_exit_status
## -------------------------
## wait for shell prompt and return the exit status of the last command executed
## during an chassis session, then wait for shell prompt
##
## Usage:
## get_exit_status timelimit [wait_prompt]
## Arguments:
## timelimit - maximum wait for shell prompt
## wait_prompt - should we wait for prompt before issuing echo of status
## Returns:
## 0 - success
## -code error on failure
## Additional Information:
## The global timeout is changed by this routine
global spawn_id expect_out spawn_out timeout
global expecting
if { $wait_prompt } {
expect_chassis_prompt $timelimit
}
set_timeout 60
send_chassis_cmd "showLastRetCode"
set expecting "exit code"
expect {
-re {Code: [0-9]+:} noop
}
regexp {[0-9]+} $expect_out(0,string) ret
expect_chassis_prompt 60
return $ret
}
proc check_chassis_exit_status { timelimit exit_code { wait_prompt 1 } } {
##
## check_chassis_exit_status
## -------------------------
## wait for shell prompt and check the exit status of the last command executed
## during an chassis session, then wait for shell prompt
##
## Usage:
## check_exit_status timelimit exit_code [wait_prompt]
## Arguments:
## timelimit - maximum wait for shell prompt
## exit_code - expected exit code ([0-9] if don't care)
## wait_prompt - should we wait for prompt before issuing echo of status
## Returns:
## 0 - success
## -code error on failure
## Additional Information:
## The global timeout is changed by this routine
global spawn_id expect_out spawn_out timeout
global expecting
if { $wait_prompt } {
expect_chassis_prompt $timelimit
}
set_timeout 60
send_chassis_cmd "showLastRetCode"
set expecting "exit code: $exit_code"
expect {
"Code: ${exit_code}:" noop
-re {Code: [0-9]+:} { set info "Incorrect exit code: Expected $exit_code, Got: $expect_out(0,string)"
return -code error -errorinfo $info $info
}
}
expect_chassis_prompt 60
return 0
}
proc longcmd { cmd } {
##
## longcmd
## --------
## Add newlines and backslashes to a command to avoid command line editor
##
## Usage:
## longcmd cmd
## Arguments:
## cmd - a shell command to break up into multiple lines
## Returns:
## A command to execute
##
## Additional Information:
## On some platforms the command line editor cannot be turned off. On other
## platforms setting COLUMNS=500, unset EDITOR and unset VISUAL would
## cause the command line editor to not affect entry of long command lines
## Unfortunately, the entry of such long
## lines causes the command line editor to re-display the line
## including the # or $ prompt. This makes the expect scripts think the
## command has completed before it has even started.
##
if { [ string length $cmd ] < 70 } {
return $cmd
}
# break up every 70th character
set result {}
while { [ string length $cmd ] > 0 } {
append result [string range $cmd 0 69 ]
append result "\\\n"
set cmd [ string range $cmd 70 end ]
}
return $result
}
proc send_unix_cmd { cmd { separator "\n"} } {
##
## send_unix_cmd
## -------------------
## issue a unix command to the target system during a login session
##
## Usage:
## send_unix_cmd cmd [separator]
## Arguments:
## cmd - unix command to issue
## separator - separator at end of command, default is newline
## Returns:
## nothing
## Additional Information:
## This must be used to send any command which could be larger than
## 70 characters and for which the first expect is for a shell prompt
## If there are other expect's before the wait for the shell prompt,
## a simple send can also be used
##
## Do NOT use this to send responses to interactive commands.
## exp_send should be used for that purpose
global spawn_id expect_out spawn_out timeout
global env
exp_send "$cmd$separator"
# possible workaround if command line editor gets involved
#exp_send [ longcmd "$cmd$separator" ]
}
proc send_chassis_cmd { cmd } {
##
## send_chassis_cmd
## -------------------
## issue a command to the target chassis during a login session
##
## Usage:
## send_chassis_cmd cmd
## Arguments:
## cmd - chassis command to issue
## Returns:
## nothing
## Additional Information:
## This should be used to send all chassis commands. It handles
## the support shell vs cli interface as needed. The decision as to
## type of shell inteface is made per chassis during login.
##
## Do NOT use this to send responses to interactive commands.
## exp_send should be used for that purpose
##
## unlike send_unix_cmd, there is no "separator" argument. This is for a
## few reasons:
## - implementation with target_chassis_shell could be tricky
## - older versions of chassis FW only allowed newline as the separator
global spawn_id expect_out spawn_out timeout
global env
global target_chassis_shell
if { $target_chassis_shell } {
exp_send "cli \"$cmd\"\n"
} else {
exp_send "$cmd\n"
}
}
proc unix_cmd { timelimit exit_code cmd } {
##
## unix_cmd
## -------------------
## issue a unix command to the target system during a login session
##
## Usage:
## unix_cmd timelimit exit_code cmd
## Arguments:
## timelimit - maximum wait for command to complete (shell prompt)
## exit_code - expected exit code ("" if don't care)
## cmd - unix command to issue
## Returns:
## 0 - success
## -code error on failure
## Additional Information:
## The global timeout is changed by this routine
global spawn_id expect_out spawn_out timeout
global env
if { "$exit_code" != "" } {
send_unix_cmd $cmd ";"
check_exit_status $timelimit $exit_code 0
} else {
send_unix_cmd $cmd
expect_unix_prompt $timelimit
}
return 0
}
proc chassis_cmd { timelimit exit_code cmd } {
##
## chassis_cmd
## -------------------
## issue a chassis command to the target system during a login session
##
## Usage:
## chassis_cmd timelimit exit_code cmd
## Arguments:
## timelimit - maximum wait for command to complete (shell prompt)
## exit_code - expected exit code ("" if don't care)
## cmd - chassis command to issue
## Returns:
## 0 - success
## -code error on failure
## Additional Information:
## The global timeout is changed by this routine
global spawn_id expect_out spawn_out timeout
global env
if { "$exit_code" != "" } {
send_chassis_cmd $cmd
check_chassis_exit_status $timelimit $exit_code
} else {
send_chassis_cmd $cmd
expect_chassis_prompt $timelimit
}
return 0
}
proc host_send_unix_cmd { host cmd { separator "\n"} } {
##
## host_send_unix_cmd
## -------------------
## issue a unix command to host via the target system during a login session
##
## Usage:
## host_send_unix_cmd host cmd [separator]
## Arguments:
## host - host to issue command to
## cmd - unix command to issue
## separator - separator at end of command, default is newline
## Returns:
## nothing
## Additional Information:
## This must be used to send any command which could be larger than
## 70 characters and for which the first expect is for a shell prompt
## If there are other expect's before the wait for the shell prompt,
## a simple send can be used
global spawn_id expect_out spawn_out timeout
global env
exp_send "ssh -q -o ForwardX11=no -P root@$host $cmd$separator"
# possible workaround if command line editor gets involved
#exp_send [ longcmd "ssh -q -o ForwardX11=no -P root@$host $cmd$separator" ]
}
proc opacmdall_stop_child { spawn_id } {
##
## opacmdall_stop_child
## ----------
## stop the given child process
## provided for use by opacmdall only
## This avoids use of the test infrastructure
##
## Usage:
## opacmdall_stop_child spawn_id
## Arguments:
## spawn_id - spawn id's from spawn
## Returns:
## exit status of process
## or -code error if unable to wait for process
global errorCode
# see if child still running
if { [catch {set pid [exp_pid -i $spawn_id]}] == 1 } {
# child must already be dead
#puts "Child exited"
} else {
#puts "Stopping $pid"
# terminate child
catch {exp_close -i $spawn_id }
catch {exec kill -s INT $pid }
#catch {exec kill -s TERM $pid }
}
set status {}
catch {set status [exp_wait -i $spawn_id] }
# return the exit status of the process
# exp_wait returns a list:
# { pid spawn_id OS_ret exit_status }
# if OS_ret is 0, status is process exit status
# if OS_ret is -1, status is OS errno and errorCode also set
# if child was killed, there can be 3 more elements in list:
# { pid spawn_id 0 0 CHILDKILLED signal desc}
if { [ llength $status ] < 4 } {
set info "wait for child failed"
return -code error -errorinfo $info $info
} elseif { [ lindex $status 4] == "CHILDKILLED" } {
set info "child killed: [lrange $status 5 end]"
return -code error -errorinfo $info $info
} elseif { [ lindex $status 2 ] == 0 } {
# process exited
set exit_status [ lindex $status 3]
return $exit_status
} else {
# OS error running wait
set info "wait for child failed: $errorCode"
return -code error -errorinfo $info $info
}
}
proc host_run_cmd { host user cmd {quiet 0} {timelimit -1} {prefix ""} } {
##
## host_run_cmd
## -------------------
## issue a unix command to host directly via ssh
## provided for use by opacmdall only
## This avoids use of the test infrastructure
##
## Usage:
## host_run_cmd host user cmd [[[quiet] timelimit] prefix]
## Arguments:
## host - host to issue command to
## user - user code to connect to host as
## cmd - unix command to issue
## quiet - if 1 command is not shown
## timelimit - maximum time to allow for command to complete, -1-> unlimited
## prefix - prefix to output at start of every line output by host
## Returns:
## nothing
## Additional Information:
## errors are caught and output to stderr
global spawn_id expect_out spawn_out timeout errorCode
global env
if { ! $quiet } {
puts "$prefix\[$user@$host\]# $cmd"
}
if { $timelimit <= 0 } {
set timelimit -1
}
if { $timelimit == -1 && [string equal "$prefix" "" ] } {
if { [ catch { exec ssh -q -o ForwardX11=no -P "$user@$host" "$cmd" >@ stdout 2>@ stderr } res ] != 0 } {
set exit_status [concat $errorCode]
if { [ lindex $exit_status 0 ] == "CHILDSTATUS" } {
set res "child exit code: [lindex $exit_status 2]"
} elseif { [ lindex $exit_status 0 ] == "CHILDKILLED" } {
set res "child killed: [lrange $exit_status 2 end]"
} else {
set res "$res: $errorCode"
}
puts stderr "$prefix$user@$host: $cmd: Command execution FAILED: $res"
}
} else {
global spawn_id user_spawn_id expect_out spawn_out timeout
# disable normal output so we can insert prefix
set save_log_user [log_user -info]
if { [ catch {
log_user 0
spawn -noecho ssh -q -o ForwardX11=no -P "$user@$host" "$cmd"
# do not use TEST_TIMEOUT_MULT
set timeout $timelimit
expect {
\n {puts -nonewline "$prefix$expect_out(buffer)"; exp_continue -continue_timer}
\r {puts -nonewline "$prefix$expect_out(buffer)"; exp_continue -continue_timer}
eof {
# handle output without newline at end
if { ! [ string equal "$expect_out(buffer)" "" ] } {
puts "$prefix$expect_out(buffer)"
}
}
timeout {return -code error -errorinfo "Timeout" "Timeout" }
}
#interact {
# -input $user_spawn_id
# timeout [ calc_timeout $timelimit ] {
# #puts "Timeout"
# return -code error -errorinfo "Timeout" "Timeout"
# }
# \003 {
# #puts "Interrupted"
# return -code error -errorinfo "Interrupted" "Interrupted"
# }
# -output $spawn_id
# eof return
#}
set ret [opacmdall_stop_child $spawn_id]
if { $ret != 0 } {
set info "child exit code: $ret"
return -code error -errorinfo $info $info
}
} res ] != 0 } {
catch { opacmdall_stop_child $spawn_id }
puts stderr "$prefix$user@$host: $cmd: Command execution FAILED: $res"
}
log_user $save_log_user
}
}
proc chassis_run_cmd { chassis user cmd {quiet 0} {slot ""} {marker ""} {prefix ""}} {
##
## chassis_run_cmd
## -------------------
## issue a chassis command to chassis
## provided for use by opacmdall only
##
## Usage:
## chassis_run_cmd host user cmd [quiet [slot [marker]]]
## Arguments:
## chassis - chassis to issue command to
## user - user code to connect to chassis as
## cmd - chassis CLI command to issue
## quiet - if 1 command is not shown
## slot - slot to login to, default is ""
## marker - marker for end of command output, otherwise first instance of
## prompt marks end of data. When marker is supplied, prompts which
## preceed marker are ignored, but a final prompt is still waited for
## after the marker
## prefix - prefix to output at start of every line output by host
## Returns:
## nothing
## Additional Information:
## errors are caught and output to stderr
global spawn_id expect_out spawn_out timeout
global env
global target_chassis_prompt
global target_chassis_shell target_chassis_shell_prompt
global log_disable
# disable detailed logging to stdout
log_user 0
set log_disable 1
setup_expect_after
if { ! $quiet } {
if { "$slot" != "" } {
puts "$prefix\[$user@$chassis:$slot\]# $cmd"
} else {
puts "$prefix\[$user@$chassis\]# $cmd"
}
}
if { [ catch { target_chassis_admin_sh "$chassis" "$slot" "$user" } res ] != 0 } {
puts stderr "$prefix$user@$chassis: $cmd: Command execution FAILED (Login): $res"
return
}
if { $target_chassis_shell } {
set prompt "$target_chassis_shell_prompt"
} else {
set prompt "$target_chassis_prompt"
}
if { [ catch {
send_chassis_cmd "$cmd"
set out ""
if { "$marker" == "" } {
expect_progress 120 {[\r\n\b]} "{$prompt}" {} out
} else {
expect_progress 120 {[\r\n\b]} "{$marker} {$prompt}" {} out
}
} res ] != 0 } {
puts stderr "$prefix$user@$chassis: $cmd: Command execution FAILED: $res"
} elseif { [ catch {
# filter out $cmd at start
set match [string first "$cmd" "$out"]
set length [string length "$cmd" ]
if { $match != -1 } {
set out [string range "$out" [expr $match + $length] end]
}
# filter out prompt
if { "$marker" == "" } {
regexp "\[\\\r\\\n\]+(.*)${prompt}" "$out" full_out output
} else {
regexp "\[\\\r\\\n\]+(.*$marker.*)${prompt}" "$out" full_out output
}
if { ! [string equal "$prefix" "" ] } {
# insert prefix
regsub -all -line {^.*$} "$output" "$prefix\\0" new_output
# if last character is not newline add one
set lastchar [string index $new_output end ]
if { "$lastchar" != {\n} && "$lastchar" != {\r} } {
puts stdout $new_output
} else {
puts -nonewline stdout $new_output
}
} else {
puts -nonewline stdout $output
}
check_chassis_exit_status 60 0 0
} res ] != 0 } {
puts stderr "$prefix$user@$chassis: $cmd: Command execution FAILED: $res"
}
catch { target_chassis_admin_sh_exit [expr {"$slot" != ""} ] }
}
proc hosts_run_cmd { hosts user cmd {quiet 0} {timelimit -1} {output_prefix 0} } {
##
## hosts_run_cmd
## -------------------
## issue a unix command to hosts directly via ssh
## provided for use by opacmdall only
## This avoids use of the test infrastructure
##
## Usage:
## hosts_run_cmd hosts user cmd [[[quiet] timelimit] output_prefix]
## Arguments:
## hosts - hosts to issue command to, if "" uses $env(CFG_HOSTS)
## user - user code to connect to host as
## cmd - unix command to issue
## quiet - if 1 command is not shown
## timelimit - maximum time to allow for command to complete, -1-> unlimited
## output_prefix - should host: be output as a prefix to each line
## Returns:
## nothing
## Additional Information:
## errors are caught and output to stderr
global env
if { "$hosts" == "" } {
set hosts $env(CFG_HOSTS)
}
foreach host $hosts {
if { $output_prefix } {
set prefix "$host: "
} else {
set prefix ""
}
host_run_cmd $host $user "$cmd" $quiet $timelimit "$prefix"
}
}
# pardon my spelling but I need a plural version of chassis
# which has a different spelling so function names are unique
proc chassises_run_cmd { chassises user cmd {quiet 0} {marker ""} {output_prefix 0}} {
##
## chassises_run_cmd
## -------------------
## issue a chassis command to chassises directly via ssh
## provided for use by opacmdall only
##
## Usage:
## chassises_run_cmd hosts user cmd [[quiet [marker]] output_prefix]
## Arguments:
## chassises - chassises to issue command to, if "" uses $env(CFG_CHASSIS)
## can have slot specifier per chassis entry
## user - user code to connect to host as
## cmd - unix command to issue
## quiet - if 1 command is not shown
## marker - marker for end of command output, otherwise first instance of
## prompt marks end of data. When marker is supplied, prompts which
## preceed marker are ignored, but a final prompt is still waited for
## after the marker
## output_prefix - should host: be output as a prefix to each line
## Returns:
## nothing
## Additional Information:
## errors are caught and output to stderr
global env
if { "$chassises" == "" } {
set chassises $env(CFG_CHASSIS)
}
foreach chassis $chassises {
set slots [chassis_get_slots "$chassis"]
set chassis [chassis_strip_slots "$chassis"]
foreach slot $slots {
if { "$slot" == "all" } {
set slot ""
}
if { $output_prefix } {
if { "$slot" != "" } {
set prefix "$chassis:$slot: "
} else {
set prefix "$chassis: "
}
} else {
set prefix ""
}
chassis_run_cmd $chassis $user "$cmd" $quiet $slot "$marker" "$prefix"
}
}
}
proc hosts_parallel_run_cmd { hosts user cmd {quiet 0} {timelimit -1} {output_prefix 0}} {
##
## hosts_parallel_run_cmd
## -------------------
## issue a unix command to hosts directly via ssh, in parallel on all hosts
## provided for use by opacmdall only
## This avoids use of the test infrastructure
##
## Usage:
## hosts_parallel_run_cmd hosts user cmd [[[quiet] timelimit] output_prefix]
## Arguments:
## hosts - hosts to issue command to, if "" uses $env(CFG_HOSTS)
## user - user code to connect to host as
## cmd - unix command to issue
## quiet - if 1 command is not shown
## timelimit - maximum time to allow for command to complete, -1-> unlimited
## output_prefix - should host: be output as a prefix to each line
## Returns:
## nothing
## Additional Information:
## errors are caught and output to stderr
global env
global os_type
if { "$hosts" == "" } {
set hosts $env(CFG_HOSTS)
}
parallel host $hosts {
if { $output_prefix } {
set prefix "$host: "
} else {
set prefix ""
}
host_run_cmd "$host" $user "$cmd" $quiet $timelimit "$prefix"
}
}
# pardon my spelling but I need a plural version of chassis
# which has a different spelling so function names are unique
proc chassises_parallel_run_cmd { chassises user cmd {quiet 0} {marker ""} {output_prefix 0}} {
##
## chassises_parallel_run_cmd
## -------------------
## issue a chassis command to chassises, in parallel on all chassises
## provided for use by opacmdall only
##
## Usage:
## chassises_parallel_run_cmd chassises user cmd [[quiet [marker]] output_prefix]
## Arguments:
## chassises - chassises to issue command to, if "" uses $env(CFG_HOSTS)
## can have slot specifier per chassis entry
## user - user code to connect to chassis as
## cmd - chassis command to issue
## quiet - if 1 command is not shown
## marker - marker for end of command output, otherwise first instance of
## prompt marks end of data. When marker is supplied, prompts which
## preceed marker are ignored, but a final prompt is still waited for
## after the marker
## output_prefix - should host: be output as a prefix to each line
## Returns:
## nothing
## Additional Information:
## errors are caught and output to stderr
global env
if { "$chassises" == "" } {
set chassises $env(CFG_CHASSIS)
}
parallel chassis $chassises {
set slots [chassis_get_slots "$chassis"]
set chassis [chassis_strip_slots "$chassis"]
foreach slot $slots {
if { "$slot" == "all" } {
set slot ""
}
if { $output_prefix } {
if { "$slot" != "" } {
set prefix "$chassis:$slot: "
} else {
set prefix "$chassis: "
}
} else {
set prefix ""
}
chassis_run_cmd "$chassis" $user "$cmd" $quiet $slot "$marker" "$prefix"
}
}
}
proc chassis_scp_cmd { scp_cmd } {
##
## chassis_scp_cmd
## -------------------
## perform an scp to a chassis
## provided for use by opascpall, opauploadall, opadownloadall only
##
## Usage:
## chassis_scp_cmd scp_cmd
## Arguments:
## scp_cmd - scp unix command to issue
## Returns:
## nothing
## Additional Information:
## errors are caught and output to stderr
global spawn_id expect_out spawn_out timeout
global env
global log_disable
global expecting
# disable detailed logging to stdout
log_user 0
set log_disable 1
local_sh
send_unix_cmd "$scp_cmd; echo 'SCP IS DONE'"
# handle password prompts, once we start to see progress indicators
# we can do a normal wait progress
set_timeout 120
set expecting "scp session ($scp_cmd)"
expect {
"assword:" { exp_send "$env(CFG_CHASSIS_ADMIN_PASSWORD)\r"
exp_continue
}
"assword->" { exp_send "$env(CFG_CHASSIS_ADMIN_PASSWORD)\r"
exp_continue
}
"refused" { set info "Failed to $scp_cmd"
return -code error -errorinfo $info $info
}
"denied" { set info "Failed to $scp_cmd"
return -code error -errorinfo $info $info
}
"Error" { set info "Failed to $scp_cmd"
return -code error -errorinfo $info $info
}
"continue connecting" { exp_send "yes\r"
exp_continue
}
{\*} noop
"%" noop
"No such" { set info "Failed to $scp_cmd"
return -code error -errorinfo $info $info
}
}
expect_progress 200 { "\\\*" "\\\." "=" "-" "%" } { "SCP IS DONE" } {"No such" "Error" "Invalid" "lost" }
check_exit_status 60 0
local_sh_exit
return 0
}
proc chassis_sftp_cmd { sftp_cmd sftp_action { not_found 1 } } {
##
## chassis_sftp_cmd
## -------------------
## perform an sftp to a chassis
## provided for use by opachassisadmin
##
## Usage:
## chassis_sftp_cmd sftp_cmd sftp_action
## Arguments:
## sftp_cmd - sftp unix command to issue
## sftp_action - sftp command to issue once sftp connection has
## been established
## Returns:
## nothing
## Additional Information:
## errors are caught and output to stderr
global spawn_id expect_out spawn_out timeout
global env
global log_disable
global expecting
# disable detailed logging to stdout
log_user 0
set log_disable 1
local_sh
send_unix_cmd "$sftp_cmd; echo 'SFTP IS DONE'"
# handle password prompts, once we start to see progress indicators
# we can do a normal wait progress
set_timeout 120
set expecting "sftp session ($sftp_cmd)"
expect {
"assword:" { exp_send "$env(CFG_CHASSIS_ADMIN_PASSWORD)\r"
exp_continue
}
"assword->" { exp_send "$env(CFG_CHASSIS_ADMIN_PASSWORD)\r"
exp_continue
}
"refused" { set info "Failed to $sftp_cmd"
return -code error -errorinfo $info $info
}
"denied" { set info "Failed to $sftp_cmd"
return -code error -errorinfo $info $info
}
"Error" { set info "Failed to $sftp_cmd"
return -code error -errorinfo $info $info
}
"continue connecting" { exp_send "yes\r"
exp_continue
}
"sftp>" { exp_send "$sftp_action\r"
exp_send "bye\r"
}
{\*} noop
"%" noop
"No such" { set info "Failed to $sftp_cmd"
return -code error -errorinfo $info $info
}
}
if { $not_found } {
expect_progress 200 { "\\\*" "\\\." "=" "-" "%" } { "SFTP IS DONE" } {"No such" "Error" "Invalid" "lost" "not found"}
} else {
expect_progress 200 { "\\\*" "\\\." "=" "-" "%" } { "SFTP IS DONE" } {"No such" "Error" "Invalid" "lost"}
}
check_exit_status 60 0
local_sh_exit
return 0
}
proc host_unix_cmd { timelimit exit_code host cmd } {
##
## host_unix_cmd
## -------------------
## issue a unix command to host via the target system during a login session
##
## Usage:
## host_unix_cmd timelimit exit_code host cmd
## Arguments:
## timelimit - maximum wait for command to complete (shell prompt)
## exit_code - expected exit code ("" if don't care)
## host - host to issue command to
## cmd - unix command to issue
## Returns:
## 0 - success
## -code error on failure
## Additional Information:
## The global timeout is changed by this routine
global spawn_id expect_out spawn_out timeout
global env
if { "$exit_code" != "" } {
host_send_unix_cmd $host $cmd ";"
check_exit_status $timelimit $exit_code 0
} else {
host_send_unix_cmd $host $cmd
expect_unix_prompt $timelimit
}
return 0
}
proc host_save_log { hostname } {
##
## host_save_log
## -------------------
## Save OS log file for hostname for later use by check_log
##
## Usage:
## host_save_log hostname
## Arguments:
## hostname - host to save log on, saved to /tmp/log
## Returns:
## 0 - success
## -code error on failure
## Additional Information:
global tests_dir
exec "ssh -q root@$hostname '$tests_dir/bin/save_log /tmp/log'"
}
proc host_check_log { hostname testname } {
##
## host_check_log
## -------------------
## Check OS log file for hostname relative to last host_save_log
##
## Usage:
## host_check_log hostname testname
## Arguments:
## hostname - host to check log on
## testname - name of test to be used in log filenames
## Returns:
## 0 - success
## -code error on failure
## Additional Information:
## The global timeout is changed by this routine
## assumes already logged into hostname
global tests_dir
send_unix_cmd "cd /root/$tests_dir; ./bin/check_log /tmp/log ./logs/$test/$test. ./logs/$test"
expect_list 120 "DONE" { "ERROR" "WARN" "kernel" }
}
proc host_basename { hostname } {
##
## host_basename
## -------------------
## return hostname with any $env(CFG_IPOIB_SUFFIX) or $env(CFG_INIC_SUFFIX)
## suffix removed
##
## Usage:
## host_basename hostname
## Arguments:
## hostname - host name used by test driver (could be an $env(CFG_IPOIB_SUFFIX)
## or $env(CFG_INIC_SUFFIX) name)
## Returns:
## base of hostname, suitable for an $env(CFG_IPOIB_SUFFIX),
## or $env(CFG_INIC_SUFFIX) suffix to be added
## Additional Information:
## When called by FastFabric, CFG_IPOIB_SUFFIX is "", so this is a noop
global env
set result $hostname
if { "$env(CFG_IPOIB_SUFFIX)" != "" } {
regsub -- "$env(CFG_IPOIB_SUFFIX)\$" $hostname "" result
}
if { "$env(CFG_INIC_SUFFIX)" != "" } {
regsub -- "$env(CFG_INIC_SUFFIX)\$" $hostname "" result
}
return "$result"
}
proc get_hostname { number } {
##
## get_hostname
## -------------------
## return hostname for number'th host in CFG_HOSTS
##
## Usage:
## get_hostname number
## Arguments:
## number - host number, 1 is 1st host
## Returns:
## hostname from CFG_HOSTS, might not be the host_basename
global env
return [ lindex $env(CFG_HOSTS) [ expr $number - 1] ]
}
proc same_host { hostname1 hostname2 } {
##
## same_host
## -------------------
## determine if hostnames are equivalent basenames
##
## Usage:
## same_host hostname1 hostname2
## Arguments:
## hostname1 - host name used by test driver (could be an
## $env(CFG_IPOIB_SUFFIX) or $env(CFG_IPOIB_SUFFIX) name)
## hostname2 - host name used by test driver (could be an
## $env(CFG_IPOIB_SUFFIX) or $env(CFG_IPOIB_SUFFIX) name)
## Returns:
## 1 - names are same
## 0 - names are different
return [ expr {"[ host_basename $hostname1 ]" == "[ host_basename $hostname2 ]"} ]
}
proc get_hostnumber { name } {
##
## get_hostnumber
## -------------------
## return host number for host in CFG_HOSTS
##
## Usage:
## get_hostnumber name
## Arguments:
## name - host name
## Returns:
## host number in CFG_HOSTS, 1 is 1st host
## 0 - if name not in CFG_HOSTS
global env
set number 1
foreach host $env(CFG_HOSTS) {
if { [same_host $name $host ] } {
return $number
}
incr number
}
return 0
}
proc have_other_hosts { hostname desthosts } {
##
## have_other_hosts
## -------------------
## determine if desthosts includes any others other than hostname
##
## Usage:
## have_other_hosts hostname desthosts
## Arguments:
## hostname - host name used by test driver (could be an $env(CFG_IPOIB_SUFFIX) or $env(CFG_IPOIB_SUFFIX) name)
## desthosts - list of hosts to check
## Returns:
## 1 - there is at least 1 host other than hostname in desthosts
## 0 - desthosts has no hosts other than hostname
foreach host $desthosts {
if { ! [ same_host $hostname $host ] } {
return 1
}
}
return 0
}
proc get_local_stack_type { {checkrun "y"}} {
##
## get_local_stack_type
## --------------------
## get IB stack type on this host
##
## Arguments:
## checkrun - if y, the running stack is checked first, otherwise
## just installed stack is checked. Note that during reinstall
## an old stack could be left running until the next reboot
## default is y. Beware, due to newer distros including openib, if it
## appears both are installed and 'n' is used, this reports IBACCESS.
## It is safest to invoke this with 'y'.
##
global spawn_id expect_out spawn_out timeout
global env
global log_disable
global expecting
# disable detailed logging to stdout
log_user 0
set log_disable 1
set hostname [ host_basename [exec hostname | cut -f1 -d.]]
local_sh
set target_stack [target_get_stack_type "$checkrun" "$hostname"]
local_sh_exit
return "$target_stack"
}
proc add_module_parameter { module_name module_parameter value {conffile ""} } {
##
## add_module_parameter
## --------------------
## edit modules.conf to add the specified parameter
##
## Arguments:
## module_name - (i.e ics_sdp)
## module_parameter - parameter (i.e. NoTcpFilter)
## value - literal value
## conffile - existing file within /etc/modprobe.d on RHEL6 and newer distros
##
# determine correct file name
if { ! [string equal "$conffile" "" ] && [ catch { unix_cmd 60 0 "[ -e /etc/modprobe.d/$conffile ]" } res ] == 0 } {
set mconf "/etc/modprobe.d/$conffile"
} else {
set mconf "/etc/modprobe.conf"
}
send_unix_cmd "cat > /tmp/add.txt <<!
/^#.*options $module_name/ \{
s/#.*options $module_name/options $module_name $module_parameter=$value/;
ba;
\}
/^options $module_name/s/ $module_parameter=\[^ \]//;s/options $module_name/options $module_name $module_parameter=$value/
:a
!
"
check_exit_status 60 0
unix_cmd 60 0 "sed -f /tmp/add.txt $mconf > $mconf-new && mv -f $mconf-new $mconf && rm -f /tmp/add.txt"
}
proc remove_module_parameter { module_name module_parameter {conffile ""}} {
##
## remove_module_parameter
## --------------------
## edit modules.conf to remove the specified parameter
## Arguments:
## module_name - (i.e ics_sdp)
## module_parameter - parameter (i.e. NoTcpFilter)
## parameter - literal value
## conffile - existing file within /etc/modprobe.d on RHEL6 and newer distros
##
# determine correct file name
if { ! [string equal "$conffile" "" ] && [ catch { unix_cmd 60 0 "[ -e /etc/modprobe.d/$conffile ]" } res ] == 0 } {
set mconf "/etc/modprobe.d/$conffile"
} elseif { [ catch { unix_cmd 60 0 {[ -e /etc/modprobe.conf ]} } res ] == 0 } {
set mconf "/etc/modprobe.conf"
} else {
# parameter is not in a place we added it, do nothing
return
}
send_unix_cmd "cat > /tmp/remove.txt <<!
/^options $module_name/s/ $module_parameter=\[^ \]//;s/^options $module_name$/# options $module_name/
!
"
check_exit_status 60 0
unix_cmd 60 0 "sed -f /tmp/remove.txt $mconf > $mconf-new && mv -f $mconf-new $mconf && rm -f /tmp/add.txt"
}
proc scp_local_file { file_name host {directory "."} } {
##
## scp_local_file
## -------------------
## scp a file from local_sh to remote host/directory
## Arguments:
## file_name - local file name to scp to remote host
## host - remote host to scp file to
## optional: directory - the remote directory to scp to (should end in '/.')
global spawn_id
set save_spawn_id $spawn_id
local_sh
send_unix_cmd "scp $file_name root@$host:$directory"
# catch {expect_list 10 {"password:"} {"command not found"} out}
# send_unix_cmd "thepassword"
expect_unix_prompt 20
local_sh_exit
set spawn_id $save_spawn_id
}