OLD | NEW |
1 #!/bin/bash | 1 #!/bin/bash |
2 | 2 |
3 # Copyright (c) 2009 The Chromium OS Authors. All rights reserved. | 3 # Copyright (c) 2009-2010 The Chromium OS Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 # Script to update an image onto a live running ChromiumOS instance. | 7 # Script to update an image onto a live running ChromiumOS instance. |
8 | 8 |
9 # Load common constants. This should be the first executable line. | 9 # Load common constants. This should be the first executable line. |
10 # The path to common.sh should be relative to your script's location. | 10 # The path to common.sh should be relative to your script's location. |
11 | 11 |
12 . "$(dirname $0)/common.sh" | 12 . "$(dirname $0)/common.sh" |
13 . "$(dirname $0)/remote_access.sh" | 13 . "$(dirname $0)/remote_access.sh" |
14 | 14 |
| 15 # Flags to control image_to_live. |
| 16 DEFINE_boolean ignore_hostname ${FLAGS_TRUE} \ |
| 17 "Ignore existing AU hostname on running instance use this hostname." |
15 DEFINE_boolean ignore_version ${FLAGS_TRUE} \ | 18 DEFINE_boolean ignore_version ${FLAGS_TRUE} \ |
16 "Ignore existing version on running instance and always update" | 19 "Ignore existing version on running instance and always update." |
17 DEFINE_boolean ignore_hostname ${FLAGS_TRUE} \ | 20 DEFINE_string server_log "dev_server.log" \ |
18 "Ignore existing AU hostname on running instance use this hostname" | 21 "Path to log for the devserver." |
| 22 DEFINE_boolean update "${FLAGS_TRUE}" \ |
| 23 "Perform update of root partition." |
19 DEFINE_boolean update_known_hosts ${FLAGS_FALSE} \ | 24 DEFINE_boolean update_known_hosts ${FLAGS_FALSE} \ |
20 "Update your known_hosts with the new remote instance's key" | 25 "Update your known_hosts with the new remote instance's key." |
21 DEFINE_boolean verbose ${FLAGS_FALSE} \ | 26 DEFINE_string update_log "update_engine.log" \ |
22 "Whether to output verbose information for debugging." | 27 "Path to log for the update_engine." |
| 28 |
| 29 # Flags for devserver. |
| 30 DEFINE_string archive_dir "" \ |
| 31 "Update using the test image in the image.zip in this directory." a |
23 DEFINE_integer devserver_port 8080 \ | 32 DEFINE_integer devserver_port 8080 \ |
24 "Port to use for devserver" | 33 "Port to use for devserver." |
25 DEFINE_string update_url "" "Full url of an update image" | 34 DEFINE_string image "" \ |
| 35 "Update with this image path that is in this source checkout." i |
| 36 DEFINE_string update_url "" "Full url of an update image." |
| 37 |
| 38 # Flags for stateful update. |
| 39 DEFINE_string stateful_update_flag "" \ |
| 40 "Flag to pass to stateful update e.g. old, clean, etc." s |
26 | 41 |
27 UPDATER_BIN='/usr/bin/update_engine_client' | 42 UPDATER_BIN='/usr/bin/update_engine_client' |
28 UPDATER_IDLE='UPDATE_STATUS_IDLE' | 43 UPDATER_IDLE='UPDATE_STATUS_IDLE' |
29 UPDATER_NEED_REBOOT='UPDATE_STATUS_UPDATED_NEED_REBOOT' | 44 UPDATER_NEED_REBOOT='UPDATE_STATUS_UPDATED_NEED_REBOOT' |
| 45 UPDATER_UPDATE_CHECK='UPDATE_STATUS_CHECKING_FOR_UPDATE' |
| 46 UPDATER_DOWNLOADING='UPDATE_STATUS_DOWNLOADING' |
30 | 47 |
31 function kill_all_devservers { | 48 function kill_all_devservers { |
32 # Using ! here to avoid exiting with set -e is insufficient, so use | 49 # Using ! here to avoid exiting with set -e is insufficient, so use |
33 # || true instead. | 50 # || true instead. |
34 sudo pkill -f devserver\.py || true | 51 sudo pkill -f devserver\.py || true |
35 } | 52 } |
36 | 53 |
37 function cleanup { | 54 function cleanup { |
38 if [ -z "${FLAGS_update_url}" ]; then | 55 if [ -z "${FLAGS_update_url}" ]; then |
39 kill_all_devservers | 56 kill_all_devservers |
40 fi | 57 fi |
41 cleanup_remote_access | 58 cleanup_remote_access |
42 rm -rf "${TMP}" | 59 rm -rf "${TMP}" |
43 } | 60 } |
44 | 61 |
45 function remote_reboot_sh { | 62 function remote_reboot_sh { |
46 rm -f "${TMP_KNOWN_HOSTS}" | 63 rm -f "${TMP_KNOWN_HOSTS}" |
47 remote_sh "$@" | 64 remote_sh "$@" |
48 } | 65 } |
49 | 66 |
| 67 # Reinterprets path from outside the chroot for use inside. |
| 68 # $1 - The path to reinterpret. |
| 69 function reinterpret_path_for_chroot() { |
| 70 local path_abs_path=$(readlink -f "${1}") |
| 71 local gclient_root_abs_path=$(readlink -f "${GCLIENT_ROOT}") |
| 72 |
| 73 # Strip the repository root from the path. |
| 74 local relative_path=$(echo ${path_abs_path} \ |
| 75 | sed s:${gclient_root_abs_path}/::) |
| 76 |
| 77 if [ "${relative_path}" = "${path_abs_path}" ]; then |
| 78 die "Error reinterpreting path. Path ${1} is not within your source tree." |
| 79 fi |
| 80 |
| 81 # Prepend the chroot repository path. |
| 82 echo "/home/${USER}/trunk/${relative_path}" |
| 83 } |
| 84 |
50 function start_dev_server { | 85 function start_dev_server { |
51 kill_all_devservers | 86 kill_all_devservers |
52 if [ ${FLAGS_verbose} -eq ${FLAGS_FALSE} ]; then | 87 local devserver_flags=${FLAGS_devserver_port} |
53 ./enter_chroot.sh "sudo ./start_devserver ${FLAGS_devserver_port} \ | 88 # Parse devserver flags. |
54 --client_prefix=ChromeOSUpdateEngine > dev_server.log 2>&1" & | 89 if [ -n "${FLAGS_image}" ]; then |
55 else | 90 devserver_flags="${devserver_flags} \ |
56 ./enter_chroot.sh "sudo ./start_devserver ${FLAGS_devserver_port} \ | 91 --image $(reinterpret_path_for_chroot ${FLAGS_image})" |
57 --client_prefix=ChromeOSUpdateEngine &" | 92 elif [ -n "${FLAGS_archive_dir}" ]; then |
| 93 devserver_flags="${devserver_flags} \ |
| 94 --archive_dir $(reinterpret_path_for_chroot ${FLAGS_archive_dir}) -t" |
58 fi | 95 fi |
| 96 |
| 97 info "Starting devserver with flags ${devserver_flags}" |
| 98 ./enter_chroot.sh "sudo ./start_devserver ${devserver_flags} \ |
| 99 --client_prefix=ChromeOSUpdateEngine > ${FLAGS_server_log} 2>&1" & |
| 100 |
59 echo -n "Waiting on devserver to start" | 101 echo -n "Waiting on devserver to start" |
60 until netstat -anp 2>&1 | grep 0.0.0.0:${FLAGS_devserver_port} > /dev/null | 102 until netstat -anp 2>&1 | grep 0.0.0.0:${FLAGS_devserver_port} > /dev/null |
61 do | 103 do |
62 sleep .5 | 104 sleep .5 |
63 echo -n "." | 105 echo -n "." |
64 done | 106 done |
65 echo "" | 107 echo "" |
66 } | 108 } |
67 | 109 |
68 # Copys stateful update script which fetches the newest stateful update | 110 # Copies stateful update script which fetches the newest stateful update |
69 # from the dev server and prepares the update. chromeos_startup finishes | 111 # from the dev server and prepares the update. chromeos_startup finishes |
70 # the update on next boot. | 112 # the update on next boot. |
71 function copy_stateful_update { | 113 function run_stateful_update { |
72 local dev_url=$(get_devserver_url) | 114 local dev_url=$(get_devserver_url) |
73 local stateful_url="" | 115 local stateful_url="" |
| 116 local stateful_update_args="" |
| 117 |
| 118 # Parse stateful update flag. |
| 119 if [ -n "${FLAGS_stateful_update_flag}" ]; then |
| 120 stateful_update_args="${stateful_update_args} \ |
| 121 --stateful_change ${FLAGS_stateful_update_flag}" |
| 122 fi |
74 | 123 |
75 # Assume users providing an update url are using an archive_dir path. | 124 # Assume users providing an update url are using an archive_dir path. |
76 if [ -n "${FLAGS_update_url}" ]; then | 125 if [ -n "${FLAGS_update_url}" ]; then |
77 stateful_url=$(echo ${dev_url} | sed -e "s/update/static\/archive/") | 126 stateful_url=$(echo ${dev_url} | sed -e "s/update/static\/archive/") |
78 else | 127 else |
79 stateful_url=$(echo ${dev_url} | sed -e "s/update/static/") | 128 stateful_url=$(echo ${dev_url} | sed -e "s/update/static/") |
80 fi | 129 fi |
81 | 130 |
82 info "Starting stateful update using URL ${stateful_url}" | 131 info "Starting stateful update using URL ${stateful_url}" |
83 | 132 |
84 # Copy over update script and run update. | 133 # Copy over update script and run update. |
85 local dev_dir="$(dirname $0)/../platform/dev" | 134 local dev_dir="$(dirname $0)/../platform/dev" |
86 remote_cp_to "${dev_dir}/stateful_update" "/tmp" | 135 remote_cp_to "${dev_dir}/stateful_update" "/tmp" |
87 remote_sh "/tmp/stateful_update ${stateful_url}" | 136 remote_sh "/tmp/stateful_update ${stateful_update_args} ${stateful_url}" |
88 } | 137 } |
89 | 138 |
90 function get_update_args { | 139 function get_update_args { |
91 if [ -z ${1} ]; then | 140 if [ -z ${1} ]; then |
92 die "No url provided for update." | 141 die "No url provided for update." |
93 fi | 142 fi |
94 local update_args="--omaha_url ${1}" | 143 local update_args="--omaha_url ${1}" |
95 if [[ ${FLAGS_ignore_version} -eq ${FLAGS_TRUE} ]]; then | 144 if [[ ${FLAGS_ignore_version} -eq ${FLAGS_TRUE} ]]; then |
96 info "Forcing update independent of the current version" | 145 info "Forcing update independent of the current version" |
97 update_args="--update ${update_args}" | 146 update_args="--update ${update_args}" |
98 fi | 147 fi |
99 | 148 |
100 echo "${update_args}" | 149 echo "${update_args}" |
101 } | 150 } |
102 | 151 |
103 function get_devserver_url { | 152 function get_devserver_url { |
104 local devserver_url="" | 153 local devserver_url="" |
105 if [ ${FLAGS_ignore_hostname} -eq ${FLAGS_TRUE} ]; then | 154 if [ ${FLAGS_ignore_hostname} -eq ${FLAGS_TRUE} ]; then |
106 if [ -z ${FLAGS_update_url} ]; then | 155 if [ -z ${FLAGS_update_url} ]; then |
107 devserver_url="http://$HOSTNAME:${FLAGS_devserver_port}/update" | 156 devserver_url="http://$HOSTNAME:${FLAGS_devserver_port}/update" |
108 else | 157 else |
109 devserver_url="${FLAGS_update_url}" | 158 devserver_url="${FLAGS_update_url}" |
110 fi | 159 fi |
111 fi | 160 fi |
112 echo "${devserver_url}" | 161 echo "${devserver_url}" |
113 } | 162 } |
114 | 163 |
115 function get_update_status { | 164 function truncate_update_log { |
116 remote_sh "${UPDATER_BIN} -status | | 165 remote_sh "> /var/log/update_engine.log" |
117 grep CURRENT_OP | | 166 } |
| 167 |
| 168 function get_update_log { |
| 169 remote_sh "cat /var/log/update_engine.log" |
| 170 echo "${REMOTE_OUT}" > "${FLAGS_update_log}" |
| 171 } |
| 172 |
| 173 |
| 174 # Returns ${1} reported by the update client e.g. PROGRESS, CURRENT_OP. |
| 175 function get_update_var { |
| 176 remote_sh "${UPDATER_BIN} --status 2> /dev/null | |
| 177 grep ${1} | |
118 cut -f 2 -d =" | 178 cut -f 2 -d =" |
119 echo "${REMOTE_OUT}" | 179 echo "${REMOTE_OUT}" |
120 } | 180 } |
121 | 181 |
| 182 # Returns the current status / progress of the update engine. |
| 183 # This is expected to run in its own thread. |
| 184 function status_thread { |
| 185 local timeout=5 |
| 186 # Let update engine receive call to ping the dev server. |
| 187 info "Devserver handling ping. Check ${FLAGS_server_log} for more info." |
| 188 sleep ${timeout} |
| 189 |
| 190 # The devserver generates images when the update engine checks for updates. |
| 191 while [ $(get_update_var CURRENT_OP) = ${UPDATER_UPDATE_CHECK} ]; do |
| 192 echo -n "." && sleep ${timeout} |
| 193 done |
| 194 |
| 195 info "Update generated. Update engine downloading update." |
| 196 while [ $(get_update_var CURRENT_OP) = ${UPDATER_DOWNLOADING} ]; do |
| 197 echo "Download progress $(get_update_var PROGRESS)" && sleep ${timeout} |
| 198 done |
| 199 |
| 200 info "Download complete." |
| 201 } |
| 202 |
| 203 |
122 function run_auto_update { | 204 function run_auto_update { |
| 205 # Truncate the update log so our log file is clean. |
| 206 truncate_update_log |
| 207 |
123 local update_args="$(get_update_args "$(get_devserver_url)")" | 208 local update_args="$(get_update_args "$(get_devserver_url)")" |
124 info "Starting update using args ${update_args}" | 209 info "Starting update using args ${update_args}" |
| 210 |
| 211 # Sets up a secondary thread to track the update progress. |
| 212 status_thread & |
| 213 local status_thread_pid=$! |
| 214 trap "kill ${status_thread_pid} && cleanup" EXIT |
| 215 |
| 216 # Actually run the update. This is a blocking call. |
125 remote_sh "${UPDATER_BIN} ${update_args}" | 217 remote_sh "${UPDATER_BIN} ${update_args}" |
126 | 218 |
127 local update_status="$(get_update_status)" | 219 # Clean up secondary thread. |
| 220 ! kill ${status_thread_pid} 2> /dev/null |
| 221 trap cleanup EXIT |
| 222 |
| 223 # We get the log file now. |
| 224 get_update_log |
| 225 |
| 226 local update_status="$(get_update_var CURRENT_OP)" |
128 if [ "${update_status}" = ${UPDATER_NEED_REBOOT} ]; then | 227 if [ "${update_status}" = ${UPDATER_NEED_REBOOT} ]; then |
129 info "Autoupdate was successful." | 228 info "Autoupdate was successful." |
130 return 0 | 229 return 0 |
131 else | 230 else |
132 warn "Autoupdate was unsuccessful. Status returned was ${update_status}." | 231 warn "Autoupdate was unsuccessful. Status returned was ${update_status}." |
133 return 1 | 232 return 1 |
134 fi | 233 fi |
135 } | 234 } |
136 | 235 |
137 function remote_reboot { | 236 function remote_reboot { |
(...skipping 30 matching lines...) Expand all Loading... |
168 eval set -- "${FLAGS_ARGV}" | 267 eval set -- "${FLAGS_ARGV}" |
169 | 268 |
170 set -e | 269 set -e |
171 | 270 |
172 trap cleanup EXIT | 271 trap cleanup EXIT |
173 | 272 |
174 TMP=$(mktemp -d /tmp/image_to_live.XXXX) | 273 TMP=$(mktemp -d /tmp/image_to_live.XXXX) |
175 | 274 |
176 remote_access_init | 275 remote_access_init |
177 | 276 |
178 if [ "$(get_update_status)" = "${UPDATER_NEED_REBOOT}" ]; then | 277 if [ "$(get_update_var CURRENT_OP)" != "${UPDATER_IDLE}" ]; then |
179 warn "Machine has been updated but not yet rebooted. Rebooting it now." | 278 warn "Machine is in a bad state. Rebooting it now." |
180 warn "Rerun this script if you still wish to update it." | |
181 remote_reboot | 279 remote_reboot |
182 exit 1 | |
183 fi | 280 fi |
184 | 281 |
185 if [ -z "${FLAGS_update_url}" ]; then | 282 if [ -z "${FLAGS_update_url}" ]; then |
186 # only start local devserver if no update url specified. | 283 # Start local devserver if no update url specified. |
187 start_dev_server | 284 start_dev_server |
188 fi | 285 fi |
189 | 286 |
190 if ! run_auto_update; then | 287 if [ "${FLAGS_update}" -eq "${FLAGS_TRUE}" ] && ! run_auto_update; then |
191 die "Update was not successful." | 288 die "Update was not successful." |
192 fi | 289 fi |
193 | 290 |
194 if ! copy_stateful_update; then | 291 if ! run_stateful_update; then |
195 warn "Stateful update was not successful." | 292 warn "Stateful update was not successful." |
196 fi | 293 fi |
197 | 294 |
198 remote_reboot | 295 remote_reboot |
199 | 296 |
200 if [[ ${FLAGS_update_hostkey} -eq ${FLAGS_TRUE} ]]; then | 297 if [[ ${FLAGS_update_hostkey} -eq ${FLAGS_TRUE} ]]; then |
201 local known_hosts="${HOME}/.ssh/known_hosts" | 298 local known_hosts="${HOME}/.ssh/known_hosts" |
202 cp "${known_hosts}" "${known_hosts}~" | 299 cp "${known_hosts}" "${known_hosts}~" |
203 grep -v "^${FLAGS_remote} " "${known_hosts}" > "${TMP}/new_known_hosts" | 300 grep -v "^${FLAGS_remote} " "${known_hosts}" > "${TMP}/new_known_hosts" |
204 cat "${TMP}/new_known_hosts" "${TMP_KNOWN_HOSTS}" > "${known_hosts}" | 301 cat "${TMP}/new_known_hosts" "${TMP_KNOWN_HOSTS}" > "${known_hosts}" |
205 chmod 0640 "${known_hosts}" | 302 chmod 0640 "${known_hosts}" |
206 info "New updated in ${known_hosts}, backup made." | 303 info "New updated in ${known_hosts}, backup made." |
207 fi | 304 fi |
208 | 305 |
209 remote_sh "grep ^CHROMEOS_RELEASE_DESCRIPTION= /etc/lsb-release" | 306 remote_sh "grep ^CHROMEOS_RELEASE_DESCRIPTION= /etc/lsb-release" |
210 local release_description=$(echo ${REMOTE_OUT} | cut -d '=' -f 2) | 307 local release_description=$(echo ${REMOTE_OUT} | cut -d '=' -f 2) |
211 info "Update was successful and rebooted to $release_description" | 308 info "Update was successful and rebooted to $release_description" |
212 | 309 |
213 return 0 | 310 return 0 |
214 } | 311 } |
215 | 312 |
216 main $@ | 313 main $@ |
OLD | NEW |