blob: be5d9ddbd3391dad943aa875db4959da63d4cad9 [file] [log] [blame]
Ken Mixter689b9ee2010-01-07 18:23:52 -08001# Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5# Library for setting up remote access and running remote commands.
6
Sean O'Connora6db82e2010-01-27 12:11:08 -08007DEFAULT_PRIVATE_KEY="${GCLIENT_ROOT}/src/scripts/mod_for_test_scripts/\
8ssh_keys/testing_rsa"
Ken Mixter689b9ee2010-01-07 18:23:52 -08009
10DEFINE_string remote "" "remote hostname/IP of running Chromium OS instance"
11DEFINE_string private_key "$DEFAULT_PRIVATE_KEY" \
12 "Private key of root account on remote host"
Zelidrag Hornung61d97682010-06-15 11:55:21 -070013DEFINE_integer ssh_port 22 \
14 "SSH port of the remote machine running Chromium OS instance"
Gilad Arnold2ff2f112012-08-28 10:13:05 -070015DEFINE_integer ssh_connect_timeout 30 \
16 "SSH connect timeout in seconds"
17DEFINE_integer ssh_connection_attempts 4 \
18 "SSH connection attempts"
Ken Mixter689b9ee2010-01-07 18:23:52 -080019
Gilad Arnold2ff2f112012-08-28 10:13:05 -070020ssh_connect_settings() {
21 if [[ -n "$SSH_CONNECT_SETTINGS" ]]; then
22 # If connection settings were fixed in an environment variable, just return
23 # those values.
24 echo -n "$SSH_CONNECT_SETTINGS"
25 else
26 # Otherwise, return the default (or user overridden) settings.
27 local settings=(
28 "Protocol=2"
29 "ConnectTimeout=${FLAGS_ssh_connect_timeout}"
30 "ConnectionAttempts=${FLAGS_ssh_connection_attempts}"
31 "ServerAliveInterval=10"
32 "ServerAliveCountMax=3"
33 "StrictHostKeyChecking=no"
34 )
35 printf -- '-o %s ' "${settings[@]}"
36 fi
37}
David Jamesf5850902011-09-30 10:51:48 -070038
Chris Sosaef964302010-04-27 13:21:08 -070039# Copies $1 to $2 on remote host
Mike Frysinger6b1abb22012-05-11 13:44:06 -040040remote_cp_to() {
Gilad Arnold2ff2f112012-08-28 10:13:05 -070041 REMOTE_OUT=$(scp -P ${FLAGS_ssh_port} $(ssh_connect_settings) \
David Jamesf5850902011-09-30 10:51:48 -070042 -o UserKnownHostsFile=$TMP_KNOWN_HOSTS -i $TMP_PRIVATE_KEY $1 \
43 root@$FLAGS_remote:$2)
Chris Sosaef964302010-04-27 13:21:08 -070044 return ${PIPESTATUS[0]}
45}
46
Ken Mixtercc4f1dd2010-08-31 12:07:11 -070047# Copies a list of remote files specified in file $1 to local location
48# $2. Directory paths in $1 are collapsed into $2.
Mike Frysinger6b1abb22012-05-11 13:44:06 -040049remote_rsync_from() {
Gilad Arnold2ff2f112012-08-28 10:13:05 -070050 rsync -e "ssh -p ${FLAGS_ssh_port} $(ssh_connect_settings) \
David Jamesf5850902011-09-30 10:51:48 -070051 -o UserKnownHostsFile=$TMP_KNOWN_HOSTS -i $TMP_PRIVATE_KEY" \
Mandeep Singh Bainesaef91ad2011-01-14 14:17:25 -080052 --no-R --files-from=$1 root@${FLAGS_remote}:/ $2
Ken Mixtercc4f1dd2010-08-31 12:07:11 -070053}
54
Mike Frysinger6b1abb22012-05-11 13:44:06 -040055_remote_sh() {
Gilad Arnold2ff2f112012-08-28 10:13:05 -070056 REMOTE_OUT=$(ssh -p ${FLAGS_ssh_port} $(ssh_connect_settings) \
David Jamesf5850902011-09-30 10:51:48 -070057 -o UserKnownHostsFile=$TMP_KNOWN_HOSTS -i $TMP_PRIVATE_KEY \
58 root@$FLAGS_remote "$@")
Ken Mixter689b9ee2010-01-07 18:23:52 -080059 return ${PIPESTATUS[0]}
60}
61
Chris Sosafaeee5f2011-09-26 16:08:14 -070062# Wrapper for ssh that runs the commmand given by the args on the remote host
Chris Sosa539b3412012-02-27 14:46:10 -080063# If an ssh error occurs, re-runs the ssh command.
Mike Frysinger6b1abb22012-05-11 13:44:06 -040064remote_sh() {
Chris Sosafaeee5f2011-09-26 16:08:14 -070065 local ssh_status=0
Chris Sosa539b3412012-02-27 14:46:10 -080066 _remote_sh "$@" || ssh_status=$?
Chris Sosafaeee5f2011-09-26 16:08:14 -070067 # 255 indicates an ssh error.
68 if [ ${ssh_status} -eq 255 ]; then
Chris Sosa539b3412012-02-27 14:46:10 -080069 _remote_sh "$@"
Chris Sosafaeee5f2011-09-26 16:08:14 -070070 else
71 return ${ssh_status}
72 fi
73}
74
Mike Frysinger6b1abb22012-05-11 13:44:06 -040075remote_sh_raw() {
Gilad Arnold2ff2f112012-08-28 10:13:05 -070076 ssh -p ${FLAGS_ssh_port} $(ssh_connect_settings) \
David Jamesf5850902011-09-30 10:51:48 -070077 -o UserKnownHostsFile=$TMP_KNOWN_HOSTS -i $TMP_PRIVATE_KEY \
78 $EXTRA_REMOTE_SH_ARGS root@$FLAGS_remote "$@"
Andrew de los Reyese08639b2011-09-21 15:44:05 -070079 return $?
80}
81
Mike Frysinger6b1abb22012-05-11 13:44:06 -040082remote_sh_allow_changed_host_key() {
Ken Mixter689b9ee2010-01-07 18:23:52 -080083 rm -f $TMP_KNOWN_HOSTS
84 remote_sh "$@"
85}
86
Mike Frysinger6b1abb22012-05-11 13:44:06 -040087set_up_remote_access() {
Ken Mixter689b9ee2010-01-07 18:23:52 -080088 cp $FLAGS_private_key $TMP_PRIVATE_KEY
89 chmod 0400 $TMP_PRIVATE_KEY
Ken Mixter689b9ee2010-01-07 18:23:52 -080090
91 # Verify the client is reachable before continuing
Gaurav Shahaf7d5d12011-09-21 16:42:16 -070092 local output
93 local status=0
94 if output=$(remote_sh "true" 2>&1); then
95 :
96 else
97 status=$?
98 echo "Could not initiate first contact with remote host"
99 echo "$output"
100 fi
101 return $status
Ken Mixter689b9ee2010-01-07 18:23:52 -0800102}
103
Ken Mixtercc4f1dd2010-08-31 12:07:11 -0700104# Ask the target what board it is
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400105learn_board() {
Ken Mixtercc4f1dd2010-08-31 12:07:11 -0700106 [ -n "${FLAGS_board}" ] && return
107 remote_sh grep CHROMEOS_RELEASE_BOARD /etc/lsb-release
108 FLAGS_board=$(echo "${REMOTE_OUT}" | cut -d '=' -f 2)
109 if [ -z "${FLAGS_board}" ]; then
110 error "Board required"
111 exit 1
112 fi
113 info "Target reports board is ${FLAGS_board}"
114}
115
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400116learn_arch() {
Olof Johanssonf53fa0d2011-01-26 13:06:46 -0800117 [ -n "${FLAGS_arch}" ] && return
118 remote_sh uname -m
Mandeep Singh Baines175422f2011-05-31 10:51:02 -0700119 FLAGS_arch=$(echo "${REMOTE_OUT}" | sed -e s/armv7l/arm/ -e s/i686/x86/ )
Olof Johanssonf53fa0d2011-01-26 13:06:46 -0800120 if [ -z "${FLAGS_arch}" ]; then
121 error "Arch required"
122 exit 1
123 fi
124 info "Target reports arch is ${FLAGS_arch}"
125}
126
Chris Wolfed91df7a2012-02-29 16:55:48 -0500127# Checks whether a remote device has rebooted successfully.
128#
129# This uses a rapidly-retried SSH connection, which will wait for at most
130# about ten seconds. If the network returns an error (e.g. host unreachable)
131# the actual delay may be shorter.
132#
133# Return values:
134# 0: The device has rebooted successfully
135# 1: The device has not yet rebooted
136# 255: Unable to communicate with the device
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400137_check_if_rebooted() {
Chris Wolfed91df7a2012-02-29 16:55:48 -0500138 (
139 # In my tests SSH seems to be waiting rather longer than would be expected
140 # from these parameters. These values produce a ~10 second wait.
141 # (in a subshell to avoid clobbering the global settings)
142 SSH_CONNECT_SETTINGS="$(sed \
143 -e 's/\(ConnectTimeout\)=[0-9]*/\1=2/' \
144 -e 's/\(ConnectionAttempts\)=[0-9]*/\1=2/' \
Gilad Arnold2ff2f112012-08-28 10:13:05 -0700145 <<<"$(ssh_connect_settings)")"
Chris Wolfed91df7a2012-02-29 16:55:48 -0500146 remote_sh_allow_changed_host_key -q -- '[ ! -e /tmp/awaiting_reboot ]'
147 )
Chris Sosa24da49e2011-02-01 17:06:12 -0800148}
Mandeep Singh Bainesa63cd2d2010-12-02 11:58:26 -0800149
Chris Wolfed91df7a2012-02-29 16:55:48 -0500150# Triggers a reboot on a remote device and waits for it to complete.
151#
152# This function will not return until the SSH server on the remote device
153# is available after the reboot.
154#
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400155remote_reboot() {
Chris Wolfed91df7a2012-02-29 16:55:48 -0500156 info "Rebooting ${FLAGS_remote}..."
Chris Sosa24da49e2011-02-01 17:06:12 -0800157 remote_sh "touch /tmp/awaiting_reboot; reboot"
Chris Wolfed91df7a2012-02-29 16:55:48 -0500158 local start_time=${SECONDS}
159
160 # Wait for five seconds before we start polling
161 sleep 5
162
163 # Add a hard timeout of 5 minutes before giving up.
164 local timeout=300
165 local timeout_expiry=$(( start_time + timeout ))
166 while [ ${SECONDS} -lt ${timeout_expiry} ]; do
167 # Used to throttle the loop -- see step_remaining_time at the bottom.
168 local step_start_time=${SECONDS}
169
170 local status=0
171 _check_if_rebooted || status=$?
172
173 local elapsed=$(( SECONDS - start_time ))
174 case ${status} in
175 0) printf ' %4ds: reboot complete\n' ${elapsed} >&2 ; return 0 ;;
176 1) printf ' %4ds: device has not yet shut down\n' ${elapsed} >&2 ;;
177 255) printf ' %4ds: can not connect to device\n' ${elapsed} >&2 ;;
178 *) die " internal error" ;;
179 esac
180
181 # To keep the loop from spinning too fast, delay until it has taken at
182 # least five seconds. When we are actively trying SSH connections this
183 # should never happen.
184 local step_remaining_time=$(( step_start_time + 5 - SECONDS ))
185 if [ ${step_remaining_time} -gt 0 ]; then
186 sleep ${step_remaining_time}
187 fi
Mandeep Singh Bainesa63cd2d2010-12-02 11:58:26 -0800188 done
Chris Wolfed91df7a2012-02-29 16:55:48 -0500189 die "Reboot has not completed after ${timeout} seconds; giving up."
Mandeep Singh Bainesa63cd2d2010-12-02 11:58:26 -0800190}
191
Mandeep Singh Bainesaef91ad2011-01-14 14:17:25 -0800192# Called by clients before exiting.
193# Part of the remote_access.sh interface but now empty.
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400194cleanup_remote_access() {
Mandeep Singh Bainesaef91ad2011-01-14 14:17:25 -0800195 true
Sean O'Connor9969ce92010-02-01 17:10:03 -0800196}
197
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400198remote_access_init() {
Ken Mixter689b9ee2010-01-07 18:23:52 -0800199 TMP_PRIVATE_KEY=$TMP/private_key
200 TMP_KNOWN_HOSTS=$TMP/known_hosts
201 if [ -z "$FLAGS_remote" ]; then
202 echo "Please specify --remote=<IP-or-hostname> of the Chromium OS instance"
203 exit 1
204 fi
205 set_up_remote_access
206}