87 lines
2.7 KiB
Bash
87 lines
2.7 KiB
Bash
|
|
#!/usr/bin/env bash
|
||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
usage() {
|
||
|
|
cat <<'EOF'
|
||
|
|
Usage: remote_flash_titan_image.sh <remote-host> <node> <device>
|
||
|
|
|
||
|
|
Copy a prepared Titan replacement image to a remote flashing station and write it
|
||
|
|
to the specified removable block device.
|
||
|
|
|
||
|
|
Example:
|
||
|
|
./scripts/remote_flash_titan_image.sh tethys titan-13 /dev/sdd
|
||
|
|
EOF
|
||
|
|
}
|
||
|
|
|
||
|
|
if [ "${3:-}" = "" ] || [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then
|
||
|
|
usage
|
||
|
|
exit 0
|
||
|
|
fi
|
||
|
|
|
||
|
|
remote_host="$1"
|
||
|
|
node="$2"
|
||
|
|
device="$3"
|
||
|
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||
|
|
remote_dir="${METIS_REMOTE_DIR:-/tmp/metis-images}"
|
||
|
|
image_path="${repo_root}/artifacts/${node}.img"
|
||
|
|
max_bytes="${METIS_SD_MAX_BYTES:-300000000000}"
|
||
|
|
|
||
|
|
if [ ! -f "${image_path}" ]; then
|
||
|
|
echo "Missing local image: ${image_path}" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
case "${device}" in
|
||
|
|
/dev/sd*|/dev/mmcblk*|/dev/nvme*n1)
|
||
|
|
;;
|
||
|
|
*)
|
||
|
|
echo "Refusing suspicious device path: ${device}" >&2
|
||
|
|
exit 1
|
||
|
|
;;
|
||
|
|
esac
|
||
|
|
|
||
|
|
device_info="$(ssh "${remote_host}" "lsblk -b -dn -o NAME,TRAN,RM,HOTPLUG,SIZE '${device}' 2>/dev/null" || true)"
|
||
|
|
if [ -z "${device_info}" ]; then
|
||
|
|
echo "Could not inspect remote device ${device} on ${remote_host}" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
read -r remote_name remote_tran remote_rm remote_hotplug remote_size <<<"${device_info}"
|
||
|
|
if [ "/dev/${remote_name}" != "${device}" ]; then
|
||
|
|
echo "Remote device mismatch: expected ${device}, got /dev/${remote_name}" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
if [ "${remote_size}" -gt "${max_bytes}" ]; then
|
||
|
|
echo "Refusing to flash ${device}: size ${remote_size} is larger than ${max_bytes} bytes" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
if [ "${remote_tran}" != "usb" ] && [ "${remote_rm}" != "1" ] && [ "${remote_hotplug}" != "1" ]; then
|
||
|
|
echo "Refusing to flash ${device}: not detected as removable/hotplug media (${device_info})" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
echo "Copying ${image_path} to ${remote_host}:${remote_dir}/${node}.img ..."
|
||
|
|
ssh "${remote_host}" "mkdir -p '${remote_dir}'"
|
||
|
|
scp "${image_path}" "${remote_host}:${remote_dir}/${node}.img"
|
||
|
|
|
||
|
|
local_sha="$(sha256sum "${image_path}" | awk '{print $1}')"
|
||
|
|
remote_sha="$(ssh "${remote_host}" "sha256sum '${remote_dir}/${node}.img' | awk '{print \\$1}'")"
|
||
|
|
if [ "${local_sha}" != "${remote_sha}" ]; then
|
||
|
|
echo "Checksum mismatch after copy: local=${local_sha} remote=${remote_sha}" >&2
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
echo "About to flash ${node}.img to ${device} on ${remote_host}."
|
||
|
|
echo "You will be prompted for the remote sudo password."
|
||
|
|
ssh -t "${remote_host}" "lsblk '${device}' && sudo dd if='${remote_dir}/${node}.img' of='${device}' bs=4M conv=fsync status=progress && sync && sudo blockdev --flushbufs '${device}'"
|
||
|
|
|
||
|
|
cat <<EOF
|
||
|
|
|
||
|
|
Flash complete for ${node} on ${remote_host}:${device}
|
||
|
|
|
||
|
|
Next steps:
|
||
|
|
1. Tell your helper to remove the flashed card and swap it into ${node}.
|
||
|
|
2. Tell them to restore power to the Pi.
|
||
|
|
3. Watch the node with: kubectl get nodes -w
|
||
|
|
EOF
|