feat(cloner): Implement staged remote flash (KISS v2)
Replaces unreliable nohup-based remote flash with staged approach: 1. remote_prepare_flash: Upload image + store options 2. remote_confirm_flash: Execute sysupgrade directly 3. remote_flash_status: Check flash state 4. remote_cancel_flash: Abort pending flash Key fixes: - Use /tmp for firmware (large tmpfs vs small rootfs) - Direct sysupgrade execution (no nohup, works on OpenWrt) - Proper dbclient SSH without unavailable commands - Background job with & instead of nohup Tested: x86_64 VM successfully flashed from 24.10.5 to 24.10.0 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
164647b1e0
commit
b0b27be82f
@ -1104,6 +1104,152 @@ do_remote_flash() {
|
||||
json_dump
|
||||
}
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Staged Flash Methods (KISS Remote Flash v2)
|
||||
# ============================================================================
|
||||
|
||||
do_remote_prepare_flash() {
|
||||
local input ip image keep_settings token
|
||||
read input
|
||||
ip=$(echo "$input" | jsonfilter -e '@.ip' 2>/dev/null)
|
||||
image=$(echo "$input" | jsonfilter -e '@.image' 2>/dev/null)
|
||||
keep_settings=$(echo "$input" | jsonfilter -e '@.keep_settings' 2>/dev/null)
|
||||
token=$(echo "$input" | jsonfilter -e '@.token' 2>/dev/null)
|
||||
json_init
|
||||
if [ -z "$ip" ]; then
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "IP address required"
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
if [ -z "$image" ]; then
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "Image required"
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
if ! ping -c 1 -W 2 "$ip" >/dev/null 2>&1; then
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "Device not reachable: $ip"
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
local img_path=""
|
||||
[ -f "$TFTP_ROOT/$image" ] && img_path="$TFTP_ROOT/$image"
|
||||
[ -f "$CLONE_DIR/$image" ] && img_path="$CLONE_DIR/$image"
|
||||
if [ -z "$img_path" ]; then
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "Image not found: $image"
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
local img_size=$(ls -lh "$img_path" | awk '{print $5}')
|
||||
if ! do_scp "$img_path" "root@$ip:/tmp/firmware.img"; then
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "Failed to upload image"
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
local sysupgrade_opts="-n"
|
||||
[ "$keep_settings" = "true" ] && sysupgrade_opts=""
|
||||
do_ssh "$ip" "cat > /etc/secubox-staged-flash.sh << 'FLASHEOF'
|
||||
#!/bin/sh
|
||||
if [ -f /tmp/firmware.img ] && [ -f /root/.secubox-flash-opts ]; then
|
||||
rm -f /root/.secubox-flash-opts
|
||||
sysupgrade $sysupgrade_opts /tmp/firmware.img
|
||||
fi
|
||||
FLASHEOF
|
||||
chmod +x /etc/secubox-staged-flash.sh"
|
||||
do_ssh "$ip" "grep -q 'secubox-staged-flash' /etc/rc.local 2>/dev/null || sed -i '/^exit 0/i /etc/secubox-staged-flash.sh' /etc/rc.local"
|
||||
do_ssh "$ip" "touch /root/.secubox-flash-opts"
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "Flash prepared - awaiting confirmation"
|
||||
json_add_string "ip" "$ip"
|
||||
json_add_string "image" "$image"
|
||||
json_add_string "size" "$img_size"
|
||||
json_dump
|
||||
}
|
||||
|
||||
do_remote_confirm_flash() {
|
||||
local input ip
|
||||
read input
|
||||
ip=$(echo "$input" | jsonfilter -e "@.ip" 2>/dev/null)
|
||||
json_init
|
||||
if [ -z "$ip" ]; then
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "IP address required"
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
# Check firmware exists (try both /tmp and /root)
|
||||
local fw_path=$(do_ssh "$ip" "[ -f /tmp/firmware.img ] && echo /tmp/firmware.img || ([ -f /tmp/firmware.img ] && echo /tmp/firmware.img)" 2>/dev/null)
|
||||
if [ -z "$fw_path" ]; then
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "No firmware found on $ip"
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
# Get sysupgrade options
|
||||
local opts=$(do_ssh "$ip" "cat /root/.secubox-flash-opts 2>/dev/null || echo -n" 2>/dev/null)
|
||||
# Execute sysupgrade directly - SSH will disconnect when device reboots
|
||||
do_ssh "$ip" "sysupgrade $opts $fw_path" 2>/dev/null &
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "Sysupgrade started on $ip"
|
||||
json_add_string "ip" "$ip"
|
||||
json_add_string "firmware" "$fw_path"
|
||||
json_dump
|
||||
}
|
||||
|
||||
do_remote_flash_status() {
|
||||
local input ip
|
||||
read input
|
||||
ip=$(echo "$input" | jsonfilter -e '@.ip' 2>/dev/null)
|
||||
json_init
|
||||
if [ -z "$ip" ]; then
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "IP address required"
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
if ! ping -c 1 -W 2 "$ip" >/dev/null 2>&1; then
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "status" "offline"
|
||||
json_add_string "ip" "$ip"
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
local has_fw=$(do_ssh "$ip" "[ -f /tmp/firmware.img ] && echo yes || echo no" 2>/dev/null)
|
||||
local has_marker=$(do_ssh "$ip" "[ -f /root/.secubox-flash-opts ] && echo yes || echo no" 2>/dev/null)
|
||||
local status="none"
|
||||
[ "$has_fw" = "yes" ] && [ "$has_marker" = "yes" ] && status="pending"
|
||||
[ "$has_fw" = "yes" ] && [ "$has_marker" = "no" ] && status="ready"
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "status" "$status"
|
||||
json_add_string "ip" "$ip"
|
||||
json_add_string "has_firmware" "$has_fw"
|
||||
json_add_string "has_marker" "$has_marker"
|
||||
json_dump
|
||||
}
|
||||
|
||||
do_remote_cancel_flash() {
|
||||
local input ip
|
||||
read input
|
||||
ip=$(echo "$input" | jsonfilter -e '@.ip' 2>/dev/null)
|
||||
json_init
|
||||
if [ -z "$ip" ]; then
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "IP address required"
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
do_ssh "$ip" "rm -f /tmp/firmware.img /root/.secubox-flash-opts /etc/secubox-staged-flash.sh; sed -i '/secubox-staged-flash/d' /etc/rc.local" 2>/dev/null
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "Flash cancelled"
|
||||
json_add_string "ip" "$ip"
|
||||
json_dump
|
||||
}
|
||||
|
||||
do_scan_network() {
|
||||
json_init
|
||||
json_add_array "devices"
|
||||
@ -1390,7 +1536,11 @@ case "$1" in
|
||||
echo '"list_profiles":{},'
|
||||
echo '"import_preregistered":{"devices":"Object"},'
|
||||
echo '"discovery_status":{},'
|
||||
echo '"toggle_discovery":{"enabled":"Boolean"}'
|
||||
echo '"toggle_discovery":{"enabled":"Boolean"},'
|
||||
echo '"remote_prepare_flash":{"ip":"String","image":"String","keep_settings":"Boolean","token":"String"},'
|
||||
echo '"remote_confirm_flash":{"ip":"String"},'
|
||||
echo '"remote_flash_status":{"ip":"String"},'
|
||||
echo '"remote_cancel_flash":{"ip":"String"}'
|
||||
echo '}'
|
||||
;;
|
||||
call)
|
||||
@ -1435,6 +1585,10 @@ case "$1" in
|
||||
import_preregistered) do_import_preregistered ;;
|
||||
discovery_status) do_discovery_status ;;
|
||||
toggle_discovery) do_toggle_discovery ;;
|
||||
remote_prepare_flash) do_remote_prepare_flash ;;
|
||||
remote_confirm_flash) do_remote_confirm_flash ;;
|
||||
remote_flash_status) do_remote_flash_status ;;
|
||||
remote_cancel_flash) do_remote_cancel_flash ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
"build_progress", "build_log", "serial_ports", "serial_read",
|
||||
"history_list", "storage_info", "image_details",
|
||||
"list_remotes", "remote_status", "scan_network",
|
||||
"pending_devices", "inventory", "list_profiles", "discovery_status"
|
||||
"pending_devices", "inventory", "list_profiles", "discovery_status", "remote_flash_status"
|
||||
]
|
||||
}
|
||||
},
|
||||
@ -20,7 +20,7 @@
|
||||
"history_add", "history_clear", "image_rename",
|
||||
"add_remote", "remove_remote", "remote_upload", "remote_flash",
|
||||
"approve_device", "reject_device", "bulk_tokens",
|
||||
"import_preregistered", "toggle_discovery"
|
||||
"import_preregistered", "toggle_discovery", "remote_prepare_flash", "remote_confirm_flash", "remote_cancel_flash"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user