image_to_live.sh: move to crostestutils
Nothing outside of crostestutils uses this script anymore, so move it there.
BUG=None
TEST=precq passes
CQ-DEPEND=CL:1493235
Change-Id: Ib31c6dd189f0243b7518735b2aaf04dd03be54b6
Reviewed-on: https://chromium-review.googlesource.com/1493213
Commit-Ready: Mike Frysinger <vapier@chromium.org>
Tested-by: Mike Frysinger <vapier@chromium.org>
Reviewed-by: Amin Hassani <ahassani@chromium.org>
diff --git a/host/image_to_live.sh b/host/image_to_live.sh
deleted file mode 100755
index 5c6b4fe..0000000
--- a/host/image_to_live.sh
+++ /dev/null
@@ -1,568 +0,0 @@
-#!/bin/bash
-
-# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# Script to update an image onto a live running ChromiumOS instance.
-. $(dirname "$(readlink -f "$0")")/outside_chroot_common.sh ||
- SCRIPT_ROOT=/usr/lib/crosutils
-
-. "${SCRIPT_ROOT}/common.sh" ||
- (echo "Unable to load common.sh" && false) ||
- exit 1
-
-. "${SCRIPT_ROOT}/remote_access.sh" || die "Unable to load remote_access.sh"
-
-# Flags to control image_to_live.
-DEFINE_boolean ignore_hostname ${FLAGS_TRUE} \
- "Ignore existing AU hostname on running instance use this hostname."
-DEFINE_boolean ignore_version ${FLAGS_TRUE} \
- "Ignore existing version on running instance and always update."
-DEFINE_string netdev "eth0" \
- "The network device to use for figuring out hostname. \
- This is useful on hosts with multiple NICs."
-DEFINE_string server_log "dev_server.log" \
- "Path to log for the devserver."
-DEFINE_boolean update "${FLAGS_TRUE}" \
- "Perform update of root partition."
-DEFINE_boolean update_hostkey ${FLAGS_TRUE} \
- "Update your known_hosts with the new remote instance's key."
-DEFINE_string update_log "update_engine.log" \
- "Path to log for the update_engine."
-DEFINE_string update_url "" "Full url of an update image."
-DEFINE_boolean verify ${FLAGS_TRUE} "Verify image on device after update."
-DEFINE_integer repeat 1 "Number of times to run image_to_live."
-
-# Flags for devserver.
-DEFINE_string archive_dir "" \
- "Deprecated."
-DEFINE_string board "" "Override the board reported by the target"
-DEFINE_integer devserver_port 8080 \
- "Port to use for devserver."
-DEFINE_string image "" \
- "Path to the image file to update with, xbuddy paths accepted." i
-DEFINE_string payload "" \
- "Update with this update payload, ignoring specified images."
-DEFINE_string proxy_port "" \
- "Have the client request from this proxy instead of devserver."
-DEFINE_string src_image "" \
- "Create a delta update by passing in the image on the remote machine."
-DEFINE_boolean update_stateful ${FLAGS_TRUE} \
- "Perform update of stateful partition e.g. /var /usr/local."
-DEFINE_boolean reboot_after_update ${FLAGS_TRUE} \
- "Reboot after update applied for the update to take effect."
-
-# Flags for stateful update.
-DEFINE_string stateful_update_flag "" \
- "Flag to pass to stateful update e.g. old, clean, etc." s
-
-DEPRECATION_WARNING="
-!!! You are using a deprecated script !!!
-
-Please use 'cros flash' in the future. See 'cros flash -h' for the details.
-More information available in the link below.
-https://sites.google.com/a/chromium.org/dev/chromium-os/build/cros-flash
-"
-
-FLAGS_HELP="
-Usage: $0 --remote=[target_ip] [--image=[...]] ...
-The remote flag is required to specify a ChromeOS machine to reimage.
-The image flag can be a path to a local image or an XBuddy path.
-For example:
- $0 --remote=172.0.0.0 --image=./some/path/to/chromium_test_image.bin
- Would reimage device at 172.0.0.0 with that locally available image.
- $0 --remote=172.0.0.0 --image='xbuddy:remote/parrot/latest/dev'
- Uses the latest developer parrot image available on Google Storage.
- $0 --remote=172.0.0.0 --image='xbuddy:release'
- Uses the latest test image available on Google Storage.
- $0 --remote=172.0.0.0 --image='xbuddy:'
- Uses the latest locally built image for the device board.
-Please see http://goo.gl/6WdLrD for XBuddy documentation."
-
-UPDATER_BIN="/usr/bin/update_engine_client"
-UPDATER_IDLE="UPDATE_STATUS_IDLE"
-UPDATER_NEED_REBOOT="UPDATE_STATUS_UPDATED_NEED_REBOOT"
-UPDATER_UPDATE_CHECK="UPDATE_STATUS_CHECKING_FOR_UPDATE"
-UPDATER_DOWNLOADING="UPDATE_STATUS_DOWNLOADING"
-
-IMAGE_PATH=""
-UPDATE_PATH=""
-ROOTFS_MOUNTPT=""
-STATEFUL_MOUNTPT=""
-
-kill_all_devservers() {
- # Using ! here to avoid exiting with set -e is insufficient, so use
- # || true instead.
- sudo pkill -f devserver\.py || true
-}
-
-cleanup() {
- if [ -z "${FLAGS_update_url}" ]; then
- kill_all_devservers
- fi
- cleanup_remote_access
- sudo rm -rf "${TMP}" || true
- if [ ! -z "${ROOTFS_MOUNTPT}" ]; then
- rm -rf "${ROOTFS_MOUNTPT}"
- fi
- if [ ! -z "${STATEFUL_MOUNTPT}" ]; then
- rm -rf "${STATEFUL_MOUNTPT}"
- fi
-}
-
-remote_reboot_sh() {
- rm -f "${TMP_KNOWN_HOSTS}"
- remote_sh "$@"
-}
-
-# Returns the hostname of this machine.
-# It tries to find the ipaddress using ifconfig, however, it will
-# default to $HOSTNAME on failure. We try to use the ip address first as
-# some targets may have dns resolution issues trying to contact back
-# to us.
-get_hostname() {
- local hostname
- # Try to parse ifconfig for ip address. Use sudo, because not all distros
- # allow a common user to call ifconfig.
- # TODO(zbehan): What if target is not connected via eth0? Update over wifi?
- # Dedicated usb NIC? Perhaps this detection should be done in the target,
- # which will get the return address in one way or another. Or maybe we should
- # just open a ssh tunnel and use localhost.
- hostname=$(/sbin/ifconfig ${FLAGS_netdev} |
- grep 'inet addr' |
- cut -f2 -d':' |
- cut -f1 -d' ')
-
- # Fallback to $HOSTNAME if that failed
- [ -z "${hostname}" ] && hostname=${HOSTNAME}
-
- echo ${hostname}
-}
-
-is_xbuddy_path() {
- [[ "${FLAGS_image}" == xbuddy:* ]]
-}
-
-# Starts the devserver and returns the update url to use to get the update.
-start_dev_server() {
- kill_all_devservers
- local devserver_flags="--board=${FLAGS_board} --port=${FLAGS_devserver_port}"
- # Parse devserver flags.
- if [ -n "${FLAGS_image}" ]; then
- if is_xbuddy_path; then
- info "Image flag is an xBuddy path to an image."
- else
- info "Forcing the devserver to serve a local image."
- devserver_flags="${devserver_flags} --pregenerate_update \
- --image=$(reinterpret_path_for_chroot ${FLAGS_image})"
- IMAGE_PATH="${FLAGS_image}"
- fi
- elif [ -n "${FLAGS_archive_dir}" ]; then
- echo "archive_dir flag is deprecated. Use --image."
- exit 1
- else
- # IMAGE_PATH should be the newest image and learn the board from
- # the target.
- learn_board
- IMAGE_PATH="${IMAGES_DIR}/${FLAGS_board}/latest"
- if [[ ! -L ${IMAGE_PATH} ]]; then
- die "No image found; have you run build_image?"
- fi
- IMAGE_PATH="${IMAGE_PATH}/chromiumos_image.bin"
- devserver_flags="${devserver_flags} \
- --image=$(reinterpret_path_for_chroot ${IMAGE_PATH})"
- fi
-
- if [ -n "${FLAGS_payload}" ]; then
- devserver_flags="${devserver_flags} \
- --payload=$(reinterpret_path_for_chroot ${FLAGS_payload})"
- fi
-
- if [ -n "${FLAGS_proxy_port}" ]; then
- devserver_flags="${devserver_flags} \
- --proxy_port=${FLAGS_proxy_port}"
- fi
-
- if [ -n "${FLAGS_src_image}" ]; then
- devserver_flags="${devserver_flags} \
- --src_image=\"$(reinterpret_path_for_chroot ${FLAGS_src_image})\""
- fi
- # Remove any extra whitespace between words in flags.
- devserver_flags=$(echo ${devserver_flags} | sed 's/ \+/ /g')
- info "Starting devserver with flags ${devserver_flags}"
-
- # Clobber dev_server log in case image_to_live is run with sudo previously.
- if [ -f "${FLAGS_server_log}" ]; then
- sudo rm -f "${FLAGS_server_log}"
- fi
-
- # Need to inherit environment variables to discover gsutil credentials.
- if cros_sdk -- cros_workon --host list |
- grep chromeos-base/cros-devutils &> /dev/null; then
- info "cros_workon for devserver detected. Running devserver from source."
- cros_sdk -- sudo -E ../platform/dev/devserver.py ${devserver_flags} \
- > ${FLAGS_server_log} 2>&1 &
- else
- cros_sdk -- sudo -E start_devserver ${devserver_flags} \
- > ${FLAGS_server_log} 2>&1 &
- fi
-
- info "Waiting on devserver to start. " \
- "Be patient as the server generates the update before starting."
- until netstat -lnp 2>&1 | grep :${FLAGS_devserver_port} > /dev/null; do
- sleep 5
- if ! pgrep -f "devserver" > /dev/null; then
- tail -n 10 "${FLAGS_server_log}"
- die "Devserver failed, see dev_server.log -- snippet above"
- fi
- done
- if is_xbuddy_path; then
- local devserver_url=$(echo $(get_devserver_url) | sed "s#/update##")
- local xbuddy_path="xbuddy/${FLAGS_image##*xbuddy:}?for_update=true"
- info "Xbuddy image detected. Using xbuddy RPC: " ${xbuddy_path}
- UPDATE_PATH="$(curl -f "${devserver_url}/${xbuddy_path}")"
- if [ -z "${UPDATE_PATH}" ]; then
- tail -n 10 "${FLAGS_server_log}"
- die "XBuddy failed to stage the image specified by ${FLAGS_image}."
- fi
- info "XBuddy returned uri to use for update: ${UPDATE_PATH}."
- if [[ "${UPDATE_PATH}" != *"/update"* ]]; then
- die "XBuddy did not return a valid update uri."
- fi
- fi
-}
-
-# Copies stateful update script which fetches the newest stateful update
-# from the dev server and prepares the update. chromeos_startup finishes
-# the update on next boot.
-run_stateful_update() {
- local dev_url="${UPDATE_PATH}"
- local stateful_url=""
- local stateful_update_args=""
-
- # Parse stateful update flag.
- if [ -n "${FLAGS_stateful_update_flag}" ]; then
- stateful_update_args="${stateful_update_args} \
- --stateful_change ${FLAGS_stateful_update_flag}"
- fi
-
- # Assume users providing an update url are using an archive_dir path.
- stateful_url=$(echo ${dev_url} | sed -e "s/update/static/")
-
- info "Starting stateful update using URL ${stateful_url}"
-
- # Copy over update script and run update.
- local chroot_path="${SCRIPTS_DIR}/../../chroot"
- local stateful_update_script="/usr/bin/stateful_update"
-
- remote_cp_to "${chroot_path}/${stateful_update_script}" "/tmp"
- remote_sh "mount -o remount,exec /tmp"
- remote_sh "/tmp/stateful_update ${stateful_update_args} ${stateful_url}"
-}
-
-get_update_args() {
- if [ -z "${1}" ]; then
- die "No url provided for update."
- fi
-
- local update_args="--omaha_url=${1}"
-
- info "Omaha URL: " ${update_args}
-
- if [[ ${FLAGS_ignore_version} -eq ${FLAGS_TRUE} ]]; then
- info "Forcing update independent of the current version"
- update_args="--update ${update_args}"
- fi
-
- echo "${update_args}"
-}
-
-get_devserver_url() {
- local devserver_url=""
- local port=${FLAGS_devserver_port}
-
- if [[ -n ${FLAGS_proxy_port} ]]; then
- port=${FLAGS_proxy_port}
- fi
-
- if [ ${FLAGS_ignore_hostname} -eq ${FLAGS_TRUE} ]; then
- if [ -z "${FLAGS_update_url}" ]; then
- devserver_url="http://$(get_hostname):${port}/update"
- else
- devserver_url="${FLAGS_update_url}"
- fi
- fi
-
- echo "${devserver_url}"
-}
-
-truncate_update_log() {
- remote_sh "> /var/log/update_engine.log"
-}
-
-get_update_log() {
- remote_sh "cat /var/log/update_engine.log"
- echo "${REMOTE_OUT}" > "${FLAGS_update_log}"
-}
-
-# Used to store the current update status of the remote update engine.
-REMOTE_UPDATE_STATUS=
-
-# Returns ${1} reported by the update client e.g. PROGRESS, CURRENT_OP.
-get_var_from_remote_status() {
- echo "${REMOTE_UPDATE_STATUS}" |
- grep ${1} |
- cut -f 2 -d =
-}
-
-# Updates the remote status variable for the update engine.
-update_remote_status() {
- remote_sh "${UPDATER_BIN} --status 2> /dev/null"
- REMOTE_UPDATE_STATUS="${REMOTE_OUT}"
-}
-
-# Both updates the remote status and gets the given variables.
-get_update_var() {
- update_remote_status
- get_var_from_remote_status "${1}"
-}
-
-# Returns the current status / progress of the update engine.
-# This is expected to run in its own thread.
-status_thread() {
- local timeout=5
-
- info "Devserver handling ping. Check ${FLAGS_server_log} for more info."
- sleep ${timeout}
-
- update_remote_status
- local current_state=""
- local next_state="$(get_var_from_remote_status CURRENT_OP)"
-
- # For current status, only print out status changes.
- # For download, show progress.
- # Finally if no status change print out .'s to keep dev informed.
- while [ "${current_state}" != "${UPDATER_NEED_REBOOT}" ] && \
- [ "${current_state}" != "${UPDATER_IDLE}" ]; do
- if [ "${current_state}" != "${next_state}" ]; then
- info "State of updater has changed to: ${next_state}"
- elif [ "${next_state}" = "${UPDATER_DOWNLOADING}" ]; then
- echo "Download progress $(get_var_from_remote_status PROGRESS)"
- else
- echo -n "."
- fi
-
- sleep ${timeout}
- current_state="${next_state}"
- update_remote_status
- next_state="$(get_var_from_remote_status CURRENT_OP)"
- done
-}
-
-# Pings the update_engine to see if it responds or a max timeout is reached.
-# Returns 1 if max timeout is reached.
-wait_until_update_engine_is_ready() {
- local wait_timeout=1
- local max_timeout=60
- local time_elapsed=0
- while ! get_update_var CURRENT_OP > /dev/null; do
- sleep ${wait_timeout}
- time_elapsed=$(( time_elapsed + wait_timeout ))
- echo -n "."
- if [ ${time_elapsed} -gt ${max_timeout} ]; then
- return 1
- fi
- done
-}
-
-# Runs the autoupdate.
-run_auto_update() {
- # Truncate the update log so our log file is clean.
- truncate_update_log
-
- local update_args="$(get_update_args "${UPDATE_PATH}")"
- info "Waiting to initiate contact with the update_engine."
- wait_until_update_engine_is_ready || die "Could not contact update engine."
-
- info "Starting update using args ${update_args}"
-
- # Sets up secondary threads to track the update progress and logs
- status_thread &
- local status_thread_pid=$!
- trap "kill ${status_thread_pid}; cleanup" EXIT INT TERM
-
- # Actually run the update. This is a blocking call.
- remote_sh "${UPDATER_BIN} ${update_args}"
-
- # Clean up secondary threads.
- kill ${status_thread_pid} 2> /dev/null || warn "Failed to kill status thread"
- trap cleanup EXIT INT TERM
-
- local update_status="$(get_update_var CURRENT_OP)"
- if [ "${update_status}" = ${UPDATER_NEED_REBOOT} ]; then
- info "Autoupdate was successful."
- return 0
- else
- warn "Autoupdate was unsuccessful. Status returned was ${update_status}."
- return 1
- fi
-}
-
-verify_image() {
- info "Verifying image."
- if [ -n "${FLAGS_update_url}" ]; then
- warn "Verify is not compatible with setting an update url."
- return
- fi
-
- if is_xbuddy_path; then
- warn "Verify is not currently compatible with xbuddy."
- return
- fi
-
- ROOTFS_MOUNTPT=$(mktemp -d)
- STATEFUL_MOUNTPT=$(mktemp -d)
- "${SCRIPTS_DIR}/mount_gpt_image.sh" --from "$(dirname "${IMAGE_PATH}")" \
- --image "$(basename ${IMAGE_PATH})" \
- --rootfs_mountpt="${ROOTFS_MOUNTPT}" \
- --stateful_mountpt="${STATEFUL_MOUNTPT}" \
- --read_only
-
- local lsb_release=$(cat ${ROOTFS_MOUNTPT}/etc/lsb-release)
- info "Verifying image with release:"
- echo ${lsb_release}
-
- "${SCRIPTS_DIR}/mount_gpt_image.sh" --unmount \
- --rootfs_mountpt="${ROOTFS_MOUNTPT}" \
- --stateful_mountpt="${STATEFUL_MOUNTPT}"
-
- remote_sh "cat /etc/lsb-release"
- info "Remote image reports:"
- echo ${REMOTE_OUT}
-
- if [ "${lsb_release}" = "${REMOTE_OUT}" ]; then
- info "Update was successful and image verified as ${lsb_release}."
- return 0
- else
- warn "Image verification failed."
- return 1
- fi
-}
-
-find_root_dev() {
- remote_sh "rootdev -s"
- echo ${REMOTE_OUT}
-}
-
-run_once() {
- if [ "$(get_update_var CURRENT_OP)" != "${UPDATER_IDLE}" ]; then
- warn "Machine is in a bad state. Resetting the update_engine."
- remote_sh "${UPDATER_BIN} --reset_status 2> /dev/null"
- fi
-
- local initial_root_dev=$(find_root_dev)
- UPDATE_PATH="$(get_devserver_url)"
- if [ -z "${FLAGS_update_url}" ]; then
- # Start local devserver if no update url specified.
- start_dev_server
- fi
-
- local update_pid
- if [ ${FLAGS_update} -eq ${FLAGS_TRUE} ]; then
- run_auto_update &
- update_pid=$!
- fi
-
- local stateful_pid
- local stateful_tmp_file
- if [ ${FLAGS_update_stateful} -eq ${FLAGS_TRUE} ]; then
- stateful_tmp_file=$(mktemp)
- run_stateful_update &> "${stateful_tmp_file}" &
- stateful_pid=$!
- fi
-
- if [ -n "${update_pid}" ] && ! wait ${update_pid}; then
- warn "Update failed. " \
- "Dumping update_engine.log for debugging and/or bug reporting."
- get_update_log
- tail -n 200 "${FLAGS_update_log}" >&2
- die "Update was not successful."
- fi
-
- if [ -n "${stateful_pid}" ]; then
- local stateful_success=0
- if ! wait ${stateful_pid}; then
- stateful_success=1
- fi
- cat "${stateful_tmp_file}"
- rm "${stateful_tmp_file}"
- if [ ${stateful_success} -ne 0 ]; then
- die "Stateful update was not successful."
- fi
- fi
-
- if [ ${FLAGS_reboot_after_update} -eq ${FLAGS_FALSE} ]; then
- echo "Not rebooting because of --noreboot_after_update"
- print_time_elapsed
- return 0
- fi
-
- remote_reboot
-
- if [[ ${FLAGS_update_hostkey} -eq ${FLAGS_TRUE} ]]; then
- local known_hosts="${HOME}/.ssh/known_hosts"
- cp "${known_hosts}" "${known_hosts}~"
- grep -v "^${FLAGS_remote} " "${known_hosts}" > "${TMP}/new_known_hosts"
- cat "${TMP}/new_known_hosts" "${TMP_KNOWN_HOSTS}" > "${known_hosts}"
- chmod 0640 "${known_hosts}"
- info "New updated in ${known_hosts}, backup made."
- fi
-
- remote_sh "grep ^CHROMEOS_RELEASE_DESCRIPTION= /etc/lsb-release"
- if [ ${FLAGS_verify} -eq ${FLAGS_TRUE} ]; then
- verify_image
-
- if [ "${initial_root_dev}" == "$(find_root_dev)" ]; then
- # At this point, the software version didn't change, but we didn't
- # switch partitions either. Means it was an update to the same version
- # that failed.
- die "The root partition did NOT change. The update failed."
- fi
- else
- local release_description=$(echo ${REMOTE_OUT} | cut -d '=' -f 2)
- info "Update was successful and rebooted to $release_description"
- fi
-
- print_time_elapsed
-}
-
-main() {
- echo "$DEPRECATION_WARNING"
-
- cd "${SCRIPTS_DIR}"
-
- FLAGS "$@" || exit 1
- eval set -- "${FLAGS_ARGV}"
-
- set -e
-
- trap cleanup EXIT INT TERM
-
- TMP=$(mktemp -d /tmp/image_to_live.XXXX)
-
- remote_access_init
-
- for i in $(seq 1 ${FLAGS_repeat}); do
- echo "Iteration: " $i of ${FLAGS_repeat}
- run_once
- if [ ${FLAGS_repeat} -gt 1 ]; then
- remote_sh "${UPDATER_BIN} --reset_status 2> /dev/null"
- fi
- done
-
- command_completed
- exit 0
-}
-
-main $@