use serde_json::{Value, json};
use crate::client::Client;
use crate::sandbox::Sandbox;
pub(super) const OWNER: &str = "user.isb.build.owner";
pub(super) fn owned(mut config: Value) -> Value {
if let Some(t) = crate::foreground::owner_tag() {
config[OWNER] = json!(t);
}
config
}
pub fn reap_stale(client: &Client, untagged: bool, log: &mut dyn FnMut(&str)) -> usize {
let Ok(list) = client.get("/1.0/instances?recursion=1") else {
return 0;
};
let mut n = 0;
for i in list.as_array().into_iter().flatten() {
let Some(name) = i["name"].as_str() else {
continue;
};
let config = &i["config"];
let build = config.get("user.isb.build").is_some()
|| config.get("user.isb.workspace-image-build").is_some()
|| name.starts_with("builder-prep-");
let stale = match config[OWNER].as_str() {
Some(t) => crate::foreground::owner_alive(t) == Some(false),
None => untagged,
};
if !(build && stale) {
continue;
}
match Sandbox::remove(client, name, true) {
Ok(()) => {
log(&format!(
"deleted {name}: its build ended with the process that ran it"
));
n += 1;
}
Err(e) if e.is_not_found() => {}
Err(e) => log(&format!("{name}: a stale build sandbox, not deleted: {e}")),
}
}
n
}
pub fn reap_stale_everywhere(base: &Client, log: &mut dyn FnMut(&str)) -> usize {
let Ok(projects) = base.get("/1.0/projects") else {
return 0;
};
projects
.as_array()
.into_iter()
.flatten()
.filter_map(|p| p.as_str()?.rsplit('/').next())
.filter(|p| p.starts_with("isb-"))
.map(|p| reap_stale(&base.clone().project(p), true, log))
.sum()
}