huskies: merge 1231 story project-rebuild must not silently downgrade a live sled to the stale image binary

This commit is contained in:
Huskies Agent
2026-07-19 20:47:19 +00:00
parent 3f05648d25
commit 7bbd34bc3a
6 changed files with 344 additions and 10 deletions
@@ -181,7 +181,9 @@ pub async fn handle_upgrade_list_projects(
///
/// Returns `Err` with a user-facing message when no artifact has been
/// published yet.
fn resolve_artifact_source(gateway_port: Option<u16>) -> Result<(String, Option<String>), String> {
pub(crate) fn resolve_artifact_source(
gateway_port: Option<u16>,
) -> Result<(String, Option<String>), String> {
if let Ok(url) = std::env::var("HUSKIES_GATEWAY_BINARY_URL") {
return Ok((url, None));
}
@@ -311,7 +313,7 @@ where
/// resolved. Split from [`handle_sled_upgrade`] so tests can drive the wire
/// behaviour without a published artifact on the host.
#[allow(clippy::too_many_arguments)]
async fn run_sled_upgrade<F, Fut>(
pub(crate) async fn run_sled_upgrade<F, Fut>(
project: &str,
sled_url: &str,
source_url: &str,
@@ -427,7 +429,11 @@ where
/// Poll `GET {health_url}` every 3 seconds until it returns 200 or `timeout_secs` elapses.
///
/// Returns `true` when the probe succeeds, `false` on timeout.
async fn wait_for_health(client: &reqwest::Client, health_url: &str, timeout_secs: u64) -> bool {
pub(crate) async fn wait_for_health(
client: &reqwest::Client,
health_url: &str,
timeout_secs: u64,
) -> bool {
let deadline = std::time::Instant::now() + Duration::from_secs(timeout_secs);
let poll = Duration::from_secs(3);
loop {
@@ -446,7 +452,10 @@ async fn wait_for_health(client: &reqwest::Client, health_url: &str, timeout_sec
///
/// Returns `None` when the endpoint is unreachable or malformed — e.g. a sled
/// still running a binary that predates the endpoint.
async fn fetch_sled_version(client: &reqwest::Client, sled_url: &str) -> Option<(String, String)> {
pub(crate) async fn fetch_sled_version(
client: &reqwest::Client,
sled_url: &str,
) -> Option<(String, String)> {
let url = format!("{}/api/version", sled_url.trim_end_matches('/'));
let val: serde_json::Value = client.get(&url).send().await.ok()?.json().await.ok()?;
let version = val.get("version").and_then(|v| v.as_str())?.to_string();