blob: fcbc60127776e3be198b25d562ba8de8acfb8d9e [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"
Douglas Andersonaaab1a32016-11-11 13:48:55 -080019DEFINE_boolean ssh_allow_agent ${FLAGS_FALSE} "Don't block out SSH_AUTH_SOCK"
Ken Mixter689b9ee2010-01-07 18:23:52 -080020
Marc Herbert5d519fa2015-06-12 15:15:44 -070021# Returns true if $1 has at least two colons.
22has_two_colons_or_more() {
23 # IPv6 addresses have at least two colons while IPv4 addresses and
24 # hostnames have none.
25 [[ "$1" == *:*:* ]]
26}
27
28# Prints $1 enclosed with brackets if it looks like an IPv6 address
29# and unchanged otherwise.
30brackets_enclosed_if_ipv6() {
31 local rem="$1"
32 if has_two_colons_or_more "${rem}"; then
33 rem="[${rem}]"
34 fi
35 echo "${rem}"
36}
37
Gilad Arnold2ff2f112012-08-28 10:13:05 -070038ssh_connect_settings() {
39 if [[ -n "$SSH_CONNECT_SETTINGS" ]]; then
40 # If connection settings were fixed in an environment variable, just return
41 # those values.
42 echo -n "$SSH_CONNECT_SETTINGS"
43 else
44 # Otherwise, return the default (or user overridden) settings.
45 local settings=(
46 "Protocol=2"
47 "ConnectTimeout=${FLAGS_ssh_connect_timeout}"
48 "ConnectionAttempts=${FLAGS_ssh_connection_attempts}"
49 "ServerAliveInterval=10"
50 "ServerAliveCountMax=3"
51 "StrictHostKeyChecking=no"
Dmitry Torokhovec132152016-05-13 11:22:59 -070052 "IdentitiesOnly=yes"
53 "IdentityFile=${TMP_PRIVATE_KEY}"
54 "UserKnownHostsFile=${TMP_KNOWN_HOSTS}"
Gilad Arnold2ff2f112012-08-28 10:13:05 -070055 )
56 printf -- '-o %s ' "${settings[@]}"
57 fi
58}
David Jamesf5850902011-09-30 10:51:48 -070059
Chris Sosaef964302010-04-27 13:21:08 -070060# Copies $1 to $2 on remote host
Mike Frysinger6b1abb22012-05-11 13:44:06 -040061remote_cp_to() {
Gilad Arnold2ff2f112012-08-28 10:13:05 -070062 REMOTE_OUT=$(scp -P ${FLAGS_ssh_port} $(ssh_connect_settings) \
Dmitry Torokhovec132152016-05-13 11:22:59 -070063 $1 root@$FLAGS_remote:$2)
Chris Sosaef964302010-04-27 13:21:08 -070064 return ${PIPESTATUS[0]}
65}
66
Doug Anderson4e678382012-12-07 12:38:54 -080067# Raw rsync access to the remote
68# Use like: remote_rsync_raw -a /path/from/ root@${FLAGS_remote}:/path/to/
69remote_rsync_raw() {
Dmitry Torokhovec132152016-05-13 11:22:59 -070070 rsync -e "ssh -p ${FLAGS_ssh_port} $(ssh_connect_settings)" "$@"
Doug Anderson4e678382012-12-07 12:38:54 -080071}
72
Ken Mixtercc4f1dd2010-08-31 12:07:11 -070073# Copies a list of remote files specified in file $1 to local location
74# $2. Directory paths in $1 are collapsed into $2.
Mike Frysinger6b1abb22012-05-11 13:44:06 -040075remote_rsync_from() {
Marc Herbert5d519fa2015-06-12 15:15:44 -070076 local rsync_rem
77 rsync_rem="$(brackets_enclosed_if_ipv6 "${FLAGS_remote}")"
78 remote_rsync_raw --no-R --files-from="$1" \
79 root@"${rsync_rem}:/" "$2"
Doug Anderson4e678382012-12-07 12:38:54 -080080}
81
82# Send a directory from $1 to $2 on remote host
83#
84# Tries to use rsync -a but will fall back to tar if the remote doesn't
85# have rsync.
86#
87# Use like: remote_send_to /build/board/lib/modules/ /lib/modules/
88remote_send_to() {
Marc Herbert5d519fa2015-06-12 15:15:44 -070089 local rsync_rem
Doug Anderson4e678382012-12-07 12:38:54 -080090 if [ ! -d "$1" ]; then
91 die "$1 must be a directory"
92 fi
93
94 if remote_sh rsync --version >/dev/null 2>&1; then
Marc Herbert5d519fa2015-06-12 15:15:44 -070095 rsync_rem="$(brackets_enclosed_if_ipv6 "${FLAGS_remote}")"
96 remote_rsync_raw -a "$1/" root@"${rsync_rem}:$2/"
Doug Anderson4e678382012-12-07 12:38:54 -080097 else
98 tar -C "$1" -cz . | remote_sh tar -C "$2" -xz
99 fi
Ken Mixtercc4f1dd2010-08-31 12:07:11 -0700100}
101
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400102_remote_sh() {
Gilad Arnold2ff2f112012-08-28 10:13:05 -0700103 REMOTE_OUT=$(ssh -p ${FLAGS_ssh_port} $(ssh_connect_settings) \
David Jamesf5850902011-09-30 10:51:48 -0700104 root@$FLAGS_remote "$@")
Ken Mixter689b9ee2010-01-07 18:23:52 -0800105 return ${PIPESTATUS[0]}
106}
107
Chris Sosafaeee5f2011-09-26 16:08:14 -0700108# Wrapper for ssh that runs the commmand given by the args on the remote host
Chris Sosa539b3412012-02-27 14:46:10 -0800109# If an ssh error occurs, re-runs the ssh command.
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400110remote_sh() {
Chris Sosafaeee5f2011-09-26 16:08:14 -0700111 local ssh_status=0
Chris Sosa539b3412012-02-27 14:46:10 -0800112 _remote_sh "$@" || ssh_status=$?
Chris Sosafaeee5f2011-09-26 16:08:14 -0700113 # 255 indicates an ssh error.
114 if [ ${ssh_status} -eq 255 ]; then
Chris Sosa539b3412012-02-27 14:46:10 -0800115 _remote_sh "$@"
Chris Sosafaeee5f2011-09-26 16:08:14 -0700116 else
117 return ${ssh_status}
118 fi
119}
120
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400121remote_sh_raw() {
Gilad Arnold2ff2f112012-08-28 10:13:05 -0700122 ssh -p ${FLAGS_ssh_port} $(ssh_connect_settings) \
David Jamesf5850902011-09-30 10:51:48 -0700123 $EXTRA_REMOTE_SH_ARGS root@$FLAGS_remote "$@"
Andrew de los Reyese08639b2011-09-21 15:44:05 -0700124 return $?
125}
126
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400127remote_sh_allow_changed_host_key() {
Ken Mixter689b9ee2010-01-07 18:23:52 -0800128 rm -f $TMP_KNOWN_HOSTS
129 remote_sh "$@"
130}
131
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400132set_up_remote_access() {
Ken Mixter689b9ee2010-01-07 18:23:52 -0800133 cp $FLAGS_private_key $TMP_PRIVATE_KEY
134 chmod 0400 $TMP_PRIVATE_KEY
Ken Mixter689b9ee2010-01-07 18:23:52 -0800135
136 # Verify the client is reachable before continuing
Gaurav Shahaf7d5d12011-09-21 16:42:16 -0700137 local output
138 local status=0
Frank Henigmand6b6cf62012-11-02 13:47:16 -0400139 if output=$(remote_sh -n "true" 2>&1); then
Gaurav Shahaf7d5d12011-09-21 16:42:16 -0700140 :
141 else
142 status=$?
143 echo "Could not initiate first contact with remote host"
144 echo "$output"
145 fi
146 return $status
Ken Mixter689b9ee2010-01-07 18:23:52 -0800147}
148
Ken Mixtercc4f1dd2010-08-31 12:07:11 -0700149# Ask the target what board it is
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400150learn_board() {
Ken Mixtercc4f1dd2010-08-31 12:07:11 -0700151 [ -n "${FLAGS_board}" ] && return
Frank Henigmand6b6cf62012-11-02 13:47:16 -0400152 remote_sh -n grep CHROMEOS_RELEASE_BOARD /etc/lsb-release
Ken Mixtercc4f1dd2010-08-31 12:07:11 -0700153 FLAGS_board=$(echo "${REMOTE_OUT}" | cut -d '=' -f 2)
154 if [ -z "${FLAGS_board}" ]; then
155 error "Board required"
156 exit 1
157 fi
158 info "Target reports board is ${FLAGS_board}"
159}
160
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400161learn_arch() {
Olof Johanssonf53fa0d2011-01-26 13:06:46 -0800162 [ -n "${FLAGS_arch}" ] && return
163 remote_sh uname -m
Mandeep Singh Baines175422f2011-05-31 10:51:02 -0700164 FLAGS_arch=$(echo "${REMOTE_OUT}" | sed -e s/armv7l/arm/ -e s/i686/x86/ )
Olof Johanssonf53fa0d2011-01-26 13:06:46 -0800165 if [ -z "${FLAGS_arch}" ]; then
166 error "Arch required"
167 exit 1
168 fi
169 info "Target reports arch is ${FLAGS_arch}"
170}
171
Chris Wolfed91df7a2012-02-29 16:55:48 -0500172# Checks whether a remote device has rebooted successfully.
173#
174# This uses a rapidly-retried SSH connection, which will wait for at most
175# about ten seconds. If the network returns an error (e.g. host unreachable)
176# the actual delay may be shorter.
177#
178# Return values:
179# 0: The device has rebooted successfully
180# 1: The device has not yet rebooted
181# 255: Unable to communicate with the device
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400182_check_if_rebooted() {
Chris Wolfed91df7a2012-02-29 16:55:48 -0500183 (
184 # In my tests SSH seems to be waiting rather longer than would be expected
185 # from these parameters. These values produce a ~10 second wait.
186 # (in a subshell to avoid clobbering the global settings)
187 SSH_CONNECT_SETTINGS="$(sed \
188 -e 's/\(ConnectTimeout\)=[0-9]*/\1=2/' \
189 -e 's/\(ConnectionAttempts\)=[0-9]*/\1=2/' \
Gilad Arnold2ff2f112012-08-28 10:13:05 -0700190 <<<"$(ssh_connect_settings)")"
Chris Wolfed91df7a2012-02-29 16:55:48 -0500191 remote_sh_allow_changed_host_key -q -- '[ ! -e /tmp/awaiting_reboot ]'
192 )
Chris Sosa24da49e2011-02-01 17:06:12 -0800193}
Mandeep Singh Bainesa63cd2d2010-12-02 11:58:26 -0800194
Chris Wolfed91df7a2012-02-29 16:55:48 -0500195# Triggers a reboot on a remote device and waits for it to complete.
196#
197# This function will not return until the SSH server on the remote device
198# is available after the reboot.
199#
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400200remote_reboot() {
Chris Wolfed91df7a2012-02-29 16:55:48 -0500201 info "Rebooting ${FLAGS_remote}..."
Chris Sosa24da49e2011-02-01 17:06:12 -0800202 remote_sh "touch /tmp/awaiting_reboot; reboot"
Chris Wolfed91df7a2012-02-29 16:55:48 -0500203 local start_time=${SECONDS}
204
205 # Wait for five seconds before we start polling
206 sleep 5
207
208 # Add a hard timeout of 5 minutes before giving up.
209 local timeout=300
210 local timeout_expiry=$(( start_time + timeout ))
211 while [ ${SECONDS} -lt ${timeout_expiry} ]; do
212 # Used to throttle the loop -- see step_remaining_time at the bottom.
213 local step_start_time=${SECONDS}
214
215 local status=0
216 _check_if_rebooted || status=$?
217
218 local elapsed=$(( SECONDS - start_time ))
219 case ${status} in
220 0) printf ' %4ds: reboot complete\n' ${elapsed} >&2 ; return 0 ;;
221 1) printf ' %4ds: device has not yet shut down\n' ${elapsed} >&2 ;;
222 255) printf ' %4ds: can not connect to device\n' ${elapsed} >&2 ;;
223 *) die " internal error" ;;
224 esac
225
226 # To keep the loop from spinning too fast, delay until it has taken at
227 # least five seconds. When we are actively trying SSH connections this
228 # should never happen.
229 local step_remaining_time=$(( step_start_time + 5 - SECONDS ))
230 if [ ${step_remaining_time} -gt 0 ]; then
231 sleep ${step_remaining_time}
232 fi
Mandeep Singh Bainesa63cd2d2010-12-02 11:58:26 -0800233 done
Chris Wolfed91df7a2012-02-29 16:55:48 -0500234 die "Reboot has not completed after ${timeout} seconds; giving up."
Mandeep Singh Bainesa63cd2d2010-12-02 11:58:26 -0800235}
236
Mandeep Singh Bainesaef91ad2011-01-14 14:17:25 -0800237# Called by clients before exiting.
238# Part of the remote_access.sh interface but now empty.
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400239cleanup_remote_access() {
Mandeep Singh Bainesaef91ad2011-01-14 14:17:25 -0800240 true
Sean O'Connor9969ce92010-02-01 17:10:03 -0800241}
242
Mike Frysinger6b1abb22012-05-11 13:44:06 -0400243remote_access_init() {
Ken Mixter689b9ee2010-01-07 18:23:52 -0800244 TMP_PRIVATE_KEY=$TMP/private_key
245 TMP_KNOWN_HOSTS=$TMP/known_hosts
246 if [ -z "$FLAGS_remote" ]; then
247 echo "Please specify --remote=<IP-or-hostname> of the Chromium OS instance"
248 exit 1
249 fi
Douglas Andersonaaab1a32016-11-11 13:48:55 -0800250
251 # Having SSH_AUTH_SOCK set makes our ssh connections super slow so unset
252 # if it's not really needed.
253 if [[ ${FLAGS_ssh_allow_agent} -eq ${FLAGS_FALSE} ]]; then
254 unset SSH_AUTH_SOCK
255 fi
256
Ken Mixter689b9ee2010-01-07 18:23:52 -0800257 set_up_remote_access
258}