btpeerd: Add scripts/update_btpeers.sh Adds a script to remotely update btpeerd on one or more btpeer hosts for testing changes during development. See script doc for details on usage. BUG=b:331246657 TEST=used new script to update and test latest btpeerd change TEST=script fails as expected when trying to update an invalid host Change-Id: I8f9c1582bfae8bdee7990f62888af751e9d5154f Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/btpeerd/+/5508278 Tested-by: Jared Bennett <jaredbennett@google.com> Commit-Queue: Jared Bennett <jaredbennett@google.com> Reviewed-by: Jason Stanko <jstanko@google.com>
diff --git a/scripts/update_btpeers.sh b/scripts/update_btpeers.sh new file mode 100755 index 0000000..35e1d1b --- /dev/null +++ b/scripts/update_btpeers.sh
@@ -0,0 +1,130 @@ +#!/bin/bash + +# Copyright 2024 The ChromiumOS Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Replaces the existing btpeerd version on the btpeer(s) with the current +# local state of this repository to allow for quick testing of changes to +# btpeerd. +# +# The btpeers' ImageUUID in its build info is updated with a `-needs-reinstall` +# suffix so that auto-repair re-images it, undoing these changes. +# +# For development purposes only. Normal deployments should still be bundled +# within images. +# +# Specify a dut hostname to update all of its btpeers or btpeer hostname(s). +# Assumes anything ending in "-host\d+" to be a dut hostname, and its btpeers to +# be <dut_hostname>-btpeerN for N [1,4]. Attempts to ssh each host before +# any updates to validate access and hostname resolution, any hosts that failed +# are skipped. Fails if btpeerd does not exist already on the host. +# +# Usage: +# ./update_btpeers.sh <dut_or_btpeer_host1> [...<dut_or_btpeer_host1>] + +set -e + +SCRIPT_DIR="$(dirname "$(realpath -e "${BASH_SOURCE[0]}")")" +PROJECT_DIR="$(realpath -e "${SCRIPT_DIR}/..")" +BTPEER_PATH_TO_BTPEERD_DIR="/etc/chromiumos/src/platform/btpeerd/" +BTPEER_PATH_TO_BUILD_INFO_FILE="/etc/chromiumos/raspios_cros_btpeer_build_info.json" +DIRTY_IMAGE_UUID_SUFFIX="-needs-reinstall" +CHROMIUMOS_CONFIG_SRC_LOCAL_DIR="${PROJECT_DIR}/../../config/go" +CHROMIUMOS_CONFIG_SRC_BTPEER_DIR="/etc/chromiumos/src/config/go" + +# Collect hosts from script args. +HOSTS_TO_CHECK=() +for HOST in "$@"; do + # Remove crossk prefix. + HOST="${HOST#crossk-}" + if [[ "${HOST}" =~ host[0-9]+$ ]]; then + # Likely a DUT host, so add all btpeers. + echo "Assuming host '${HOST}' is a dut hostname, will try to update its 4 btpeers" + HOSTS_TO_CHECK+=( + "${HOST}-btpeer1" + "${HOST}-btpeer2" + "${HOST}-btpeer3" + "${HOST}-btpeer4" + ) + else + HOSTS_TO_CHECK+=("${HOST}") + fi +done +if [ "${#HOSTS_TO_CHECK[@]}" -eq 0 ]; then + echo "ERROR: At least one dut or btpeer hostname is required" + exit 1 +fi +echo "Got ${#HOSTS_TO_CHECK[@]} btpeer hostnames from CLI args" + +# Validate hosts as btpeers. +BTPEER_HOSTS_TO_UPDATE=() +for HOST in "${HOSTS_TO_CHECK[@]}"; do + echo "Checking if host '${HOST}' is a valid host to update" + set +e + ssh -q "${HOST}" "test -d ${BTPEER_PATH_TO_BTPEERD_DIR}" + SSH_RET_CODE=$? + set -e + if [ "${SSH_RET_CODE}" -eq 255 ]; then + echo "WARNING: Failed to connect to host '${HOST}', assuming host does not exist and will not update it" + elif [ "${SSH_RET_CODE}" -eq 1 ]; then + echo "ERROR: Invalid host '${HOST}': missing btpeerd install dir ${BTPEER_PATH_TO_BTPEERD_DIR}" + exit 1 + elif [ "${SSH_RET_CODE}" -ne 0 ]; then + echo "ERROR: Failed to verify host '${HOST}' has btpeerd install dir ${BTPEER_PATH_TO_BTPEERD_DIR}" + exit 2 + else + echo "Successfully verified host '${HOST}' as a valid btpeer, will update it" + BTPEER_HOSTS_TO_UPDATE+=("${HOST}") + fi +done +if [ "${#BTPEER_HOSTS_TO_UPDATE[@]}" -eq 0 ]; then + echo "ERROR: No valid btpeer hosts to update" + exit 1 +fi +echo "Successfully identified ${#BTPEER_HOSTS_TO_UPDATE[@]} btpeer hosts to update" + +# Update btpeerd on btpeers. +LOG_DIVIDER="==============================================================================" +for HOST in "${BTPEER_HOSTS_TO_UPDATE[@]}"; do + echo -e "\n${LOG_DIVIDER}" + echo "Updating btpeerd on host '${HOST}'" + + echo "Marking btpeer image as dirty" + BUILD_INFO_JSON=$(ssh -q "${HOST}" "cat '${BTPEER_PATH_TO_BUILD_INFO_FILE}'") + IMAGE_UUID=$(jq -r ."image_uuid" <<< "${BUILD_INFO_JSON}") + if [ "${#IMAGE_UUID}" -ne 36 ]; then + echo "Btpeer image already marked as dirty with image UUID '${IMAGE_UUID}', skipping step" + else + IMAGE_UUID="${IMAGE_UUID}${DIRTY_IMAGE_UUID_SUFFIX}" + BUILD_INFO_JSON=$(jq '."image_uuid" = $val' --arg val "${IMAGE_UUID}" <<< "${BUILD_INFO_JSON}") + echo "${BUILD_INFO_JSON}" | ssh -q "${HOST}" "cat - > '${BTPEER_PATH_TO_BUILD_INFO_FILE}'" + echo "Successfully marked btpeer image as dirty with image UUID '${IMAGE_UUID}'" + fi + + echo "Stopping btpeerd service" + ssh -q "${HOST}" "systemctl stop btpeerd.service" + + echo "Copying source files to btpeer" + ssh -q "${HOST}" "mkdir -p '${CHROMIUMOS_CONFIG_SRC_BTPEER_DIR}'" + rsync -a "${CHROMIUMOS_CONFIG_SRC_LOCAL_DIR}"/* \ + "${HOST}:${CHROMIUMOS_CONFIG_SRC_BTPEER_DIR}" + rsync -av "${PROJECT_DIR}/" "${HOST}:${BTPEER_PATH_TO_BTPEERD_DIR}/" \ + --exclude .git --exclude .idea --exclude .vscode \ + --exclude go/bin --exclude go/pkg + + echo "Building btpeerd on btpeer" + ssh "${HOST}" "${BTPEER_PATH_TO_BTPEERD_DIR}/scripts/build.sh" + + echo "Starting btpeerd service" + ssh -q "${HOST}" "systemctl start btpeerd.service" + + echo "Successfully updated btpeerd on host '${HOST}'" +done + +# Print summary. +echo -e "\n${LOG_DIVIDER}\n${LOG_DIVIDER}" +echo "Successfully updated btpeerd on ${#BTPEER_HOSTS_TO_UPDATE[@]} hosts:" +for HOST in "${BTPEER_HOSTS_TO_UPDATE[@]}"; do + echo "${HOST}" +done