| 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 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 DEFINE_boolean ignore_version ${FLAGS_TRUE} \ | 15 DEFINE_boolean ignore_version ${FLAGS_TRUE} \ |
| 16 "Ignore existing version on running instance and always update" | 16 "Ignore existing version on running instance and always update" |
| 17 DEFINE_boolean ignore_hostname ${FLAGS_TRUE} \ | 17 DEFINE_boolean ignore_hostname ${FLAGS_TRUE} \ |
| 18 "Ignore existing AU hostname on running instance use this hostname" | 18 "Ignore existing AU hostname on running instance use this hostname" |
| 19 DEFINE_boolean update_known_hosts ${FLAGS_FALSE} \ | 19 DEFINE_boolean update_known_hosts ${FLAGS_FALSE} \ |
| 20 "Update your known_hosts with the new remote instance's key" | 20 "Update your known_hosts with the new remote instance's key" |
| 21 DEFINE_boolean verbose ${FLAGS_FALSE} \ | 21 DEFINE_boolean verbose ${FLAGS_FALSE} \ |
| 22 "Whether to output verbose information for debugging." | 22 "Whether to output verbose information for debugging." |
| 23 DEFINE_integer devserver_port 8080 \ | 23 DEFINE_integer devserver_port 8080 \ |
| 24 "Port to use for devserver" | 24 "Port to use for devserver" |
| 25 DEFINE_string update_url "" "Full url of an update image" | 25 DEFINE_string update_url "" "Full url of an update image" |
| 26 | 26 |
| 27 UPDATER_BIN='/usr/bin/update_engine_client' |
| 28 UPDATER_IDLE='UPDATE_STATUS_IDLE' |
| 29 UPDATER_NEED_REBOOT='UPDATE_STATUS_UPDATED_NEED_REBOOT' |
| 30 |
| 27 function kill_all_devservers { | 31 function kill_all_devservers { |
| 28 echo "Killing dev server." | |
| 29 # Using ! here to avoid exiting with set -e is insufficient, so use | 32 # Using ! here to avoid exiting with set -e is insufficient, so use |
| 30 # || true instead. | 33 # || true instead. |
| 31 sudo pkill -f devserver\.py || true | 34 sudo pkill -f devserver\.py || true |
| 32 } | 35 } |
| 33 | 36 |
| 34 function cleanup { | 37 function cleanup { |
| 35 if [ -z "${FLAGS_update_url}" ]; then | 38 if [ -z "${FLAGS_update_url}" ]; then |
| 36 kill_all_devservers | 39 kill_all_devservers |
| 37 fi | 40 fi |
| 38 cleanup_remote_access | 41 cleanup_remote_access |
| 39 rm -rf "${TMP}" | 42 rm -rf "${TMP}" |
| 40 } | 43 } |
| 41 | 44 |
| 42 function remote_reboot_sh { | 45 function remote_reboot_sh { |
| 43 rm -f "${TMP_KNOWN_HOSTS}" | 46 rm -f "${TMP_KNOWN_HOSTS}" |
| 44 remote_sh "$@" | 47 remote_sh "$@" |
| 45 } | 48 } |
| 46 | 49 |
| 47 function start_dev_server { | 50 function start_dev_server { |
| 48 kill_all_devservers | 51 kill_all_devservers |
| 49 if [ ${FLAGS_verbose} -eq ${FLAGS_FALSE} ]; then | 52 if [ ${FLAGS_verbose} -eq ${FLAGS_FALSE} ]; then |
| 50 ./enter_chroot.sh "sudo ./start_devserver ${FLAGS_devserver_port} \ | 53 ./enter_chroot.sh "sudo ./start_devserver ${FLAGS_devserver_port} \ |
| 51 > dev_server.log 2>&1" & | 54 --client_prefix=ChromeOSUpdateEngine > dev_server.log 2>&1" & |
| 52 else | 55 else |
| 53 ./enter_chroot.sh "sudo ./start_devserver ${FLAGS_devserver_port}" & | 56 ./enter_chroot.sh "sudo ./start_devserver ${FLAGS_devserver_port} \ |
| 57 --client_prefix=ChromeOSUpdateEngine &" |
| 54 fi | 58 fi |
| 55 echo -n "Waiting on devserver to start" | 59 echo -n "Waiting on devserver to start" |
| 56 until netstat -anp 2>&1 | grep 0.0.0.0:${FLAGS_devserver_port} > /dev/null | 60 until netstat -anp 2>&1 | grep 0.0.0.0:${FLAGS_devserver_port} > /dev/null |
| 57 do | 61 do |
| 58 sleep .5 | 62 sleep .5 |
| 59 echo -n "." | 63 echo -n "." |
| 60 done | 64 done |
| 61 echo "" | 65 echo "" |
| 62 } | 66 } |
| 63 | 67 |
| 64 # Copys stateful update script which fetches the newest stateful update | 68 # Copys stateful update script which fetches the newest stateful update |
| 65 # from the dev server and prepares the update. chromeos_startup finishes | 69 # from the dev server and prepares the update. chromeos_startup finishes |
| 66 # the update on next boot. | 70 # the update on next boot. |
| 67 function copy_stateful_update { | 71 function copy_stateful_update { |
| 68 echo "Starting stateful update." | 72 info "Starting stateful update." |
| 69 local dev_dir="$(dirname $0)/../platform/dev" | 73 local dev_dir="$(dirname $0)/../platform/dev" |
| 70 | 74 |
| 71 # Copy over update script and run update. | 75 # Copy over update script and run update. |
| 72 remote_cp_to "$dev_dir/stateful_update" "/tmp" | 76 remote_cp_to "$dev_dir/stateful_update" "/tmp" |
| 73 remote_sh "/tmp/stateful_update" | 77 remote_sh "/tmp/stateful_update" |
| 74 } | 78 } |
| 75 | 79 |
| 76 function prepare_update_metadata { | 80 function get_update_args { |
| 77 remote_sh "mount -norw,remount /" | 81 if [ -z ${1} ]; then |
| 78 | 82 die "No url provided for update." |
| 83 fi |
| 84 local update_args="--omaha_url ${1}" |
| 79 if [[ ${FLAGS_ignore_version} -eq ${FLAGS_TRUE} ]]; then | 85 if [[ ${FLAGS_ignore_version} -eq ${FLAGS_TRUE} ]]; then |
| 80 echo "Forcing update independent of the current version" | 86 info "Forcing update independent of the current version" |
| 81 remote_sh "cat /etc/lsb-release |\ | 87 update_args="--update ${update_args}" |
| 82 grep -v CHROMEOS_RELEASE_VERSION > /etc/lsb-release~;\ | |
| 83 mv /etc/lsb-release~ /etc/lsb-release; \ | |
| 84 echo 'CHROMEOS_RELEASE_VERSION=0.0.0.0' >> /etc/lsb-release" | |
| 85 fi | 88 fi |
| 86 | 89 |
| 90 echo "${update_args}" |
| 91 } |
| 92 |
| 93 function get_devserver_url { |
| 94 local devserver_url="" |
| 87 if [ ${FLAGS_ignore_hostname} -eq ${FLAGS_TRUE} ]; then | 95 if [ ${FLAGS_ignore_hostname} -eq ${FLAGS_TRUE} ]; then |
| 88 if [ -z ${FLAGS_update_url} ]; then | 96 if [ -z ${FLAGS_update_url} ]; then |
| 89 devserver_url="http://$HOSTNAME:${FLAGS_devserver_port}/update" | 97 devserver_url="http://$HOSTNAME:${FLAGS_devserver_port}/update" |
| 90 else | 98 else |
| 91 devserver_url="${FLAGS_update_url}" | 99 devserver_url="${FLAGS_update_url}" |
| 92 fi | 100 fi |
| 93 echo "Forcing update from ${devserver_url}" | 101 fi |
| 94 remote_sh "cat /etc/lsb-release |\ | 102 echo "${devserver_url}" |
| 95 grep -v '^CHROMEOS_AUSERVER=' |\ | 103 } |
| 96 grep -v '^CHROMEOS_DEVSERVER=' > /etc/lsb-release~;\ | 104 |
| 97 mv /etc/lsb-release~ /etc/lsb-release; \ | 105 function get_update_status { |
| 98 echo 'CHROMEOS_AUSERVER=${devserver_url}' >> \ | 106 remote_sh "${UPDATER_BIN} -status | |
| 99 /etc/lsb-release; \ | 107 grep CURRENT_OP | |
| 100 echo 'CHROMEOS_DEVSERVER=${devserver_url}' >> /etc/lsb-release" | 108 cut -f 2 -d =" |
| 109 echo "${REMOTE_OUT}" |
| 110 } |
| 111 |
| 112 function run_auto_update { |
| 113 local update_args="$(get_update_args "$(get_devserver_url)")" |
| 114 info "Starting update using args ${update_args}" |
| 115 remote_sh "${UPDATER_BIN} ${update_args}" |
| 116 |
| 117 local update_status="$(get_update_status)" |
| 118 if [ "${update_status}" = ${UPDATER_NEED_REBOOT} ]; then |
| 119 info "Autoupdate was successful." |
| 120 return 0 |
| 121 else |
| 122 warn "Autoupdate was unsuccessful. Status returned was ${update_status}." |
| 123 return 1 |
| 101 fi | 124 fi |
| 102 } | 125 } |
| 103 | 126 |
| 104 function run_auto_update { | |
| 105 echo "Starting update" | |
| 106 local update_file=/var/log/softwareupdate.log | |
| 107 # Clear it out so we don't see a prior run and make sure it | |
| 108 # exists so the first tail below can't fail if it races the | |
| 109 # memento updater first write and wins. | |
| 110 remote_sh "rm -f /tmp/memento_autoupdate_completed; rm -f ${update_file}; \ | |
| 111 touch ${update_file}; \ | |
| 112 /opt/google/memento_updater/memento_updater.sh --force_update < /dev/null\ | |
| 113 >&/dev/null&" | |
| 114 | |
| 115 local update_error | |
| 116 local output_file | |
| 117 local progress | |
| 118 | |
| 119 update_error=1 | |
| 120 output_file="${TMP}/output" | |
| 121 | |
| 122 while true; do | |
| 123 # The softwareupdate.log gets pretty bit with download progress | |
| 124 # lines so only look in the last 100 lines for status. | |
| 125 remote_sh "tail -100 ${update_file}" | |
| 126 echo "${REMOTE_OUT}" > "${output_file}" | |
| 127 progress=$(tail -4 "${output_file}" | grep 0K | head -1) | |
| 128 if [ -n "${progress}" ]; then | |
| 129 echo "Image fetching progress: ${progress}" | |
| 130 fi | |
| 131 if grep -q 'updatecheck status="noupdate"' "${output_file}"; then | |
| 132 echo "devserver is claiming there is no update available." | |
| 133 echo "Consider setting --ignore_version." | |
| 134 break | |
| 135 fi | |
| 136 if grep -q 'Autoupdate applied. You should now reboot' "${output_file}" | |
| 137 then | |
| 138 echo "Autoupdate was successful." | |
| 139 update_error=0 | |
| 140 fi | |
| 141 if grep -q 'Memento AutoUpdate terminating' "${output_file}"; then | |
| 142 break | |
| 143 fi | |
| 144 # Sleep for a while so that ssh handling doesn't slow down the install | |
| 145 sleep 2 | |
| 146 done | |
| 147 | |
| 148 return ${update_error} | |
| 149 } | |
| 150 | |
| 151 function remote_reboot { | 127 function remote_reboot { |
| 152 echo "Rebooting." | 128 info "Rebooting." |
| 153 remote_sh "touch /tmp/awaiting_reboot; reboot" | 129 remote_sh "touch /tmp/awaiting_reboot; reboot" |
| 154 local output_file | 130 local output_file |
| 155 output_file="${TMP}/output" | 131 output_file="${TMP}/output" |
| 156 | 132 |
| 157 while true; do | 133 while true; do |
| 158 REMOTE_OUT="" | 134 REMOTE_OUT="" |
| 159 # This may fail while the machine is down so generate output and a | 135 # This may fail while the machine is down so generate output and a |
| 160 # boolean result to distinguish between down/timeout and real failure | 136 # boolean result to distinguish between down/timeout and real failure |
| 161 ! remote_sh_allow_changed_host_key \ | 137 ! remote_sh_allow_changed_host_key \ |
| 162 "echo 0; [ -e /tmp/awaiting_reboot ] && echo '1'; true" | 138 "echo 0; [ -e /tmp/awaiting_reboot ] && echo '1'; true" |
| 163 echo "${REMOTE_OUT}" > "${output_file}" | 139 echo "${REMOTE_OUT}" > "${output_file}" |
| 164 if grep -q "0" "${output_file}"; then | 140 if grep -q "0" "${output_file}"; then |
| 165 if grep -q "1" "${output_file}"; then | 141 if grep -q "1" "${output_file}"; then |
| 166 echo "Not yet rebooted" | 142 info "Not yet rebooted" |
| 167 else | 143 else |
| 168 echo "Rebooted and responding" | 144 info "Rebooted and responding" |
| 169 break | 145 break |
| 170 fi | 146 fi |
| 171 fi | 147 fi |
| 172 sleep .5 | 148 sleep .5 |
| 173 done | 149 done |
| 174 } | 150 } |
| 175 | 151 |
| 176 function main() { | 152 function main() { |
| 177 assert_outside_chroot | 153 assert_outside_chroot |
| 178 | 154 |
| 179 cd $(dirname "$0") | 155 cd $(dirname "$0") |
| 180 | 156 |
| 181 FLAGS "$@" || exit 1 | 157 FLAGS "$@" || exit 1 |
| 182 eval set -- "${FLAGS_ARGV}" | 158 eval set -- "${FLAGS_ARGV}" |
| 183 | 159 |
| 184 set -e | 160 set -e |
| 185 | 161 |
| 186 trap cleanup EXIT | 162 trap cleanup EXIT |
| 187 | 163 |
| 188 TMP=$(mktemp -d /tmp/image_to_live.XXXX) | 164 TMP=$(mktemp -d /tmp/image_to_live.XXXX) |
| 189 | 165 |
| 190 remote_access_init | 166 remote_access_init |
| 191 | 167 |
| 192 if remote_sh [ -e /tmp/memento_autoupdate_completed ]; then | 168 if [ "$(get_update_status)" = "${UPDATER_NEED_REBOOT}" ]; then |
| 193 echo "Machine has been updated but not yet rebooted. Rebooting it now." | 169 warn "Machine has been updated but not yet rebooted. Rebooting it now." |
| 194 echo "Rerun this script if you still wish to update it." | 170 warn "Rerun this script if you still wish to update it." |
| 195 remote_reboot | 171 remote_reboot |
| 196 exit 1 | 172 exit 1 |
| 197 fi | 173 fi |
| 198 | 174 |
| 199 if [ -z "${FLAGS_update_url}" ]; then | 175 if [ -z "${FLAGS_update_url}" ]; then |
| 200 # only start local devserver if no update url specified. | 176 # only start local devserver if no update url specified. |
| 201 start_dev_server | 177 start_dev_server |
| 202 fi | 178 fi |
| 203 | 179 |
| 204 prepare_update_metadata | |
| 205 | |
| 206 if ! run_auto_update; then | 180 if ! run_auto_update; then |
| 207 echo "Update was not successful." | 181 die "Update was not successful." |
| 208 exit 1 | |
| 209 fi | 182 fi |
| 210 | 183 |
| 211 if ! copy_stateful_update; then | 184 if ! copy_stateful_update; then |
| 212 echo "Stateful update was not successful." | 185 warn "Stateful update was not successful." |
| 213 fi | 186 fi |
| 214 | 187 |
| 215 remote_reboot | 188 remote_reboot |
| 216 | 189 |
| 217 if [[ ${FLAGS_update_hostkey} -eq ${FLAGS_TRUE} ]]; then | 190 if [[ ${FLAGS_update_hostkey} -eq ${FLAGS_TRUE} ]]; then |
| 218 local known_hosts="${HOME}/.ssh/known_hosts" | 191 local known_hosts="${HOME}/.ssh/known_hosts" |
| 219 cp "${known_hosts}" "${known_hosts}~" | 192 cp "${known_hosts}" "${known_hosts}~" |
| 220 grep -v "^${FLAGS_remote} " "${known_hosts}" > "${TMP}/new_known_hosts" | 193 grep -v "^${FLAGS_remote} " "${known_hosts}" > "${TMP}/new_known_hosts" |
| 221 cat "${TMP}/new_known_hosts" "${TMP_KNOWN_HOSTS}" > "${known_hosts}" | 194 cat "${TMP}/new_known_hosts" "${TMP_KNOWN_HOSTS}" > "${known_hosts}" |
| 222 chmod 0640 "${known_hosts}" | 195 chmod 0640 "${known_hosts}" |
| 223 echo "New updated in ${known_hosts}, backup made." | 196 info "New updated in ${known_hosts}, backup made." |
| 224 fi | 197 fi |
| 225 | 198 |
| 226 remote_sh "grep ^CHROMEOS_RELEASE_DESCRIPTION= /etc/lsb-release" | 199 remote_sh "grep ^CHROMEOS_RELEASE_DESCRIPTION= /etc/lsb-release" |
| 227 local release_description=$(echo $REMOTE_OUT | cut -d '=' -f 2) | 200 local release_description=$(echo ${REMOTE_OUT} | cut -d '=' -f 2) |
| 228 echo "Update was successful and rebooted to $release_description" | 201 info "Update was successful and rebooted to $release_description" |
| 229 | 202 |
| 230 return 0 | 203 return 0 |
| 231 } | 204 } |
| 232 | 205 |
| 233 main $@ | 206 main $@ |
| OLD | NEW |