Remove all alternate update paths — fleet redeploy is release + upgrade all

Killed:
- rebuild_and_restart (in-container cargo self-compile): the MCP tool,
  the `rebuild` chat command in all four transports, the web-ui bot
  command, and the underlying function. This was the path that caused
  the exec() deadlocks.
- upgrade_sled gateway MCP tool: second entry point to sled upgrades,
  defaulted to serving the gateway's own macOS binary to Linux sleds.
- GET /api/huskies-binary (both sled and gateway route trees): served
  current_exe(), wrong platform when the gateway is macOS. Superseded
  by /api/artifacts/ which now also serves on the gateway route tree.
- `huskies upgrade` CLI subcommand and --source flag: third way of
  doing the same download-and-replace. Escape hatch for a bricked sled
  is `docker cp` + restart.

Kept, distinct jobs: `project-rebuild` (container/image updates),
`rebuild gateway` + script/local-release (gateway self-update).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019fHdm92yjvguPi2LiXfLB9
This commit is contained in:
Timmy
2026-07-15 16:46:11 +01:00
co-authored by Claude Fable 5
parent 83f941b77e
commit f39c4b7c4b
24 changed files with 36 additions and 824 deletions
-58
View File
@@ -80,19 +80,6 @@ mod cli;
use cli::{parse_cli_args, resolve_path_arg};
/// Convert a WebSocket gateway URL into the binary download HTTP URL.
///
/// `ws://gateway:3000/api/sled-uplink?token=x` → `http://gateway:3000/api/huskies-binary`
fn derive_binary_url_from_ws(ws_url: &str) -> Option<String> {
let http = ws_url
.strip_prefix("wss://")
.map(|s| format!("https://{s}"))
.or_else(|| ws_url.strip_prefix("ws://").map(|s| format!("http://{s}")))?;
// Strip any path and query string, then append the binary endpoint.
let base = http.split('/').take(3).collect::<Vec<_>>().join("/");
Some(format!("{base}/api/huskies-binary"))
}
#[tokio::main]
async fn main() -> Result<(), std::io::Error> {
// Reap zombie grandchildren on Unix (for native deployments without tini/init).
@@ -171,27 +158,6 @@ async fn main() -> Result<(), std::io::Error> {
trampoline::run_trampoline(std::path::Path::new(job_path)).await;
}
// ── Upgrade mode: fetch new binary, replace, exit ───────────────────────
if cli.upgrade {
let source = cli
.upgrade_source
.clone()
.or_else(|| std::env::var("HUSKIES_BINARY_SOURCE").ok())
.unwrap_or_else(|| {
// Derive from HUSKIES_UPSTREAM_GATEWAY: ws://host:port/... → http://host:port/api/huskies-binary
std::env::var("HUSKIES_UPSTREAM_GATEWAY")
.ok()
.and_then(|ws| derive_binary_url_from_ws(&ws))
.unwrap_or_else(|| "http://gateway:3000/api/huskies-binary".to_string())
});
let target = upgrade::resolve_target_path();
if let Err(e) = upgrade::run_cli_upgrade(&source, &target).await {
eprintln!("error: {e}");
std::process::exit(1);
}
return Ok(());
}
// ── Gateway mode: multi-project proxy ────────────────────────────────────
if is_gateway {
let config_dir = explicit_path.unwrap_or_else(|| cwd.clone());
@@ -526,28 +492,4 @@ name = "coder"
config::ProjectConfig::load(tmp.path())
.unwrap_or_else(|e| panic!("Invalid project.toml: {e}"));
}
#[test]
fn derive_binary_url_strips_ws_scheme_and_path() {
let url = derive_binary_url_from_ws("ws://gateway:3000/api/sled-uplink?token=abc");
assert_eq!(
url.as_deref(),
Some("http://gateway:3000/api/huskies-binary")
);
}
#[test]
fn derive_binary_url_handles_wss_scheme() {
let url = derive_binary_url_from_ws("wss://myhost:443/path");
assert_eq!(
url.as_deref(),
Some("https://myhost:443/api/huskies-binary")
);
}
#[test]
fn derive_binary_url_invalid_scheme_returns_none() {
let url = derive_binary_url_from_ws("http://not-a-ws-url");
assert!(url.is_none());
}
}