Watch
0
0
Fork
You've already forked hyperhive
0

swarm-wire: take wanted's wire types

This commit is contained in:
atlas 2026-10-18 12:22:36 +02:00 • committed by mara
commit 266be0a5db
17 changed files with 298 additions and 282 deletions

View file

@ -68,7 +68,7 @@ pub(crate) struct SetAgentStateRequest {
/// a value this build does not know is a 400 rather than a field that
/// silently does nothing.
#[schema(value_type = String, example = "up")]
pub(crate) state: swarm_queue_client::wanted::AgentState,
pub(crate) state: swarm_wire::wanted::AgentState,
}
/// One agent's line in a hive's declaration.
@ -79,7 +79,7 @@ pub(crate) struct AgentDeclaration {
}
pub(crate) fn render(
declaration: &swarm_queue_client::wanted::HiveWanted,
declaration: &swarm_wire::wanted::HiveWanted,
) -> Vec<AgentDeclaration> {
declaration
.agents
@ -223,8 +223,8 @@ pub(crate) async fn set_agent_state(
///
/// Exhaustive for the reason [`revokes_queue_credential`] is. A `Destroyed`
/// agent is gone from that hive, and the hive deploys nothing for it.
fn places_agent(state: swarm_queue_client::wanted::AgentState) -> bool {
use swarm_queue_client::wanted::AgentState;
fn places_agent(state: swarm_wire::wanted::AgentState) -> bool {
use swarm_wire::wanted::AgentState;
match state {
AgentState::Up | AgentState::Offline | AgentState::Paused => true,
AgentState::Destroyed => false,
@ -243,7 +243,7 @@ fn places_agent(state: swarm_queue_client::wanted::AgentState) -> bool {
async fn refuse_placement<R, D>(
agent: &str,
hive: &str,
here: Option<&swarm_queue_client::wanted::HiveWanted>,
here: Option<&swarm_wire::wanted::HiveWanted>,
reserved: Option<&str>,
read_roster: impl FnOnce() -> R,
snapshot_queued: impl FnOnce() -> Vec<(String, String)>,
@ -253,7 +253,7 @@ where
R: std::future::Future<Output = Result<bool, String>>,
D: std::future::Future<
Output = Result<
Vec<(String, swarm_queue_client::wanted::HiveWanted)>,
Vec<(String, swarm_wire::wanted::HiveWanted)>,
problem_details::ProblemDetails,
>,
>,
@ -295,13 +295,13 @@ where
/// Whether declaring an agent into `state` ends its queue credential's life.
///
/// Exhaustive on purpose, like every other match on
/// [`AgentState`][swarm_queue_client::wanted::AgentState] in this
/// [`AgentState`][swarm_wire::wanted::AgentState] in this
/// tree: a state added later has to say whether it revokes rather than
/// inheriting "no" from a catch-all. `Offline` and `Paused` deliberately do
/// not — both are states an agent comes back from, and revoking on either
/// would mean an agent that could be stopped but never restarted.
fn revokes_queue_credential(state: swarm_queue_client::wanted::AgentState) -> bool {
use swarm_queue_client::wanted::AgentState;
fn revokes_queue_credential(state: swarm_wire::wanted::AgentState) -> bool {
use swarm_wire::wanted::AgentState;
match state {
AgentState::Destroyed => true,
AgentState::Up | AgentState::Offline | AgentState::Paused => false,
@ -425,7 +425,7 @@ pub(crate) async fn get_agents_status(
rows.iter().filter_map(|r| r.hive.clone()).collect();
let mut declarations: std::collections::HashMap<
String,
swarm_queue_client::wanted::HiveWanted,
swarm_wire::wanted::HiveWanted,
> = std::collections::HashMap::new();
for hive in hives {
match writer.view(&hive).await {
@ -711,7 +711,7 @@ pub(crate) async fn create_agent(
/// The settings a `POST /api/agents` body gives, as they are stored.
struct CreateSettings {
limits: Option<swarm_queue_client::agent_limits::AgentCaps>,
limits: Option<swarm_wire::agent_limits::AgentCaps>,
inference: Option<swarm_wire::agent_inference::AgentInference>,
permissions: Option<swarm_queue_client::agent_permissions::AgentPermissions>,
archetype: Option<swarm_queue_client::agent_archetype::ArchetypeRef>,
@ -794,7 +794,7 @@ impl StoredSettings {
async fn store(
client: &async_nats::Client,
agent: &str,
limits: Option<&swarm_queue_client::agent_limits::AgentCaps>,
limits: Option<&swarm_wire::agent_limits::AgentCaps>,
inference: Option<&swarm_wire::agent_inference::AgentInference>,
permissions: Option<&swarm_queue_client::agent_permissions::AgentPermissions>,
archetype: Option<&swarm_queue_client::agent_archetype::ArchetypeRef>,
@ -868,7 +868,7 @@ async fn placements_elsewhere<E, Fut>(
) -> Result<Vec<String>, E>
where
Fut: std::future::Future<
Output = Result<Vec<(String, swarm_queue_client::wanted::HiveWanted)>, E>,
Output = Result<Vec<(String, swarm_wire::wanted::HiveWanted)>, E>,
>,
{
let queued = snapshot_queued();
@ -886,7 +886,7 @@ async fn declarations_elsewhere(
state: &AppState,
agent: &str,
hive: &str,
) -> Result<Vec<(String, swarm_queue_client::wanted::HiveWanted)>, problem_details::ProblemDetails>
) -> Result<Vec<(String, swarm_wire::wanted::HiveWanted)>, problem_details::ProblemDetails>
{
read_declarations(state, state.hives.iter().filter(|h| h.name != hive))
.await
@ -905,7 +905,7 @@ async fn declarations_elsewhere(
pub(crate) async fn read_declarations<'a>(
state: &AppState,
hives: impl Iterator<Item = &'a HiveEntry>,
) -> Result<Vec<(String, swarm_queue_client::wanted::HiveWanted)>, (String, anyhow::Error)> {
) -> Result<Vec<(String, swarm_wire::wanted::HiveWanted)>, (String, anyhow::Error)> {
let Some(writer) = state.wanted.as_deref() else {
return Ok(Vec::new());
};
@ -923,7 +923,7 @@ pub(crate) async fn read_declarations<'a>(
/// Every hive whose declaration places `agent` there.
pub(crate) fn claiming_hives(
agent: &str,
declared: &[(String, swarm_queue_client::wanted::HiveWanted)],
declared: &[(String, swarm_wire::wanted::HiveWanted)],
) -> Vec<String> {
declared
.iter()
@ -971,7 +971,7 @@ fn queued_placements(
fn placed_elsewhere(
agent: &str,
hive: &str,
declared: &[(String, swarm_queue_client::wanted::HiveWanted)],
declared: &[(String, swarm_wire::wanted::HiveWanted)],
queued: &[(String, String)],
) -> Vec<String> {
let declared = declared.iter().filter(|(_, declaration)| {
@ -1706,12 +1706,12 @@ mod tests {
pub(crate) fn declaring(
hive: &str,
agent: &str,
state: swarm_queue_client::wanted::AgentState,
) -> (String, swarm_queue_client::wanted::HiveWanted) {
let mut declaration = swarm_queue_client::wanted::HiveWanted::default();
state: swarm_wire::wanted::AgentState,
) -> (String, swarm_wire::wanted::HiveWanted) {
let mut declaration = swarm_wire::wanted::HiveWanted::default();
declaration.agents.insert(
agent.to_owned(),
swarm_queue_client::wanted::AgentWanted { state },
swarm_wire::wanted::AgentWanted { state },
);
(hive.to_owned(), declaration)
}
@ -1721,7 +1721,7 @@ mod tests {
/// terminal and declared. Only the queue-first order catches it.
#[tokio::test]
async fn a_placement_finishing_between_the_two_reads_is_still_caught() {
use swarm_queue_client::wanted::AgentState;
use swarm_wire::wanted::AgentState;
let reads = std::cell::Cell::new(0);
let snapshot_queued = || {
reads.set(reads.get() + 1);
@ -1750,7 +1750,7 @@ mod tests {
#[test]
fn a_live_declaration_on_another_hive_is_a_placement() {
use swarm_queue_client::wanted::AgentState;
use swarm_wire::wanted::AgentState;
for state in [AgentState::Up, AgentState::Offline, AgentState::Paused] {
let declared = [declaring("sec0nd", "atlas", state)];
assert_eq!(
@ -1767,14 +1767,14 @@ mod tests {
let declared = [declaring(
"sec0nd",
"atlas",
swarm_queue_client::wanted::AgentState::Destroyed,
swarm_wire::wanted::AgentState::Destroyed,
)];
assert!(super::placed_elsewhere("atlas", "pr1ma", &declared, &[]).is_empty());
}
#[test]
fn placements_on_the_requested_hive_or_of_other_names_do_not_count() {
use swarm_queue_client::wanted::AgentState;
use swarm_wire::wanted::AgentState;
let declared = [
declaring("pr1ma", "atlas", AgentState::Up),
declaring("sec0nd", "argus", AgentState::Up),
@ -1788,7 +1788,7 @@ mod tests {
#[test]
fn the_hive_placing_an_agent_claims_it_and_no_other_does() {
use swarm_queue_client::wanted::AgentState;
use swarm_wire::wanted::AgentState;
let declared = [
declaring("pr1ma", "atlas", AgentState::Paused),
declaring("sec0nd", "argus", AgentState::Up),
@ -1800,7 +1800,7 @@ mod tests {
#[test]
fn two_hives_placing_one_agent_both_claim_it() {
use swarm_queue_client::wanted::AgentState;
use swarm_wire::wanted::AgentState;
let declared = [
declaring("pr1ma", "atlas", AgentState::Up),
declaring("sec0nd", "atlas", AgentState::Up),
@ -1816,7 +1816,7 @@ mod tests {
/// state, `pr1ma`'s included.
async fn refuse_on_pr1ma_with(
agent: &str,
declared: Vec<(String, swarm_queue_client::wanted::HiveWanted)>,
declared: Vec<(String, swarm_wire::wanted::HiveWanted)>,
roster: Result<bool, String>,
) -> Result<(), problem_details::ProblemDetails> {
let here = declared
@ -1838,15 +1838,15 @@ mod tests {
/// [`refuse_on_pr1ma_with`] for an `agent` the roster does not hold.
async fn refuse_on_pr1ma(
agent: &str,
declared: Vec<(String, swarm_queue_client::wanted::HiveWanted)>,
declared: Vec<(String, swarm_wire::wanted::HiveWanted)>,
) -> Result<(), problem_details::ProblemDetails> {
refuse_on_pr1ma_with(agent, declared, Ok(false)).await
}
const PLACING: [swarm_queue_client::wanted::AgentState; 3] = [
swarm_queue_client::wanted::AgentState::Up,
swarm_queue_client::wanted::AgentState::Offline,
swarm_queue_client::wanted::AgentState::Paused,
const PLACING: [swarm_wire::wanted::AgentState; 3] = [
swarm_wire::wanted::AgentState::Up,
swarm_wire::wanted::AgentState::Offline,
swarm_wire::wanted::AgentState::Paused,
];
/// The handler checks exactly the placing states; a destroy is never
@ -1857,7 +1857,7 @@ mod tests {
assert!(super::places_agent(state), "{state:?}");
}
assert!(!super::places_agent(
swarm_queue_client::wanted::AgentState::Destroyed
swarm_wire::wanted::AgentState::Destroyed
));
}
@ -1920,7 +1920,7 @@ mod tests {
/// first declaration and its name is checked.
#[tokio::test]
async fn a_destroyed_declaration_here_does_not_exempt_the_name() {
use swarm_queue_client::wanted::AgentState;
use swarm_wire::wanted::AgentState;
let err = refuse_on_pr1ma(
"admin",
vec![declaring("pr1ma", "admin", AgentState::Destroyed)],
@ -1953,7 +1953,7 @@ mod tests {
#[tokio::test]
async fn a_first_declaration_of_a_name_placed_on_another_hive_is_refused() {
use swarm_queue_client::wanted::AgentState;
use swarm_wire::wanted::AgentState;
let err = refuse_on_pr1ma("atlas", vec![declaring("sec0nd", "atlas", AgentState::Up)])
.await
.expect_err("a name placed on another hive must be refused");
@ -1976,7 +1976,7 @@ mod tests {
#[tokio::test]
async fn changing_the_state_of_an_agent_on_its_own_hive_is_accepted() {
use swarm_queue_client::wanted::AgentState;
use swarm_wire::wanted::AgentState;
refuse_on_pr1ma("atlas", vec![declaring("pr1ma", "atlas", AgentState::Up)])
.await
.expect("an agent's own hive must accept a new state for it");
@ -1986,7 +1986,7 @@ mod tests {
/// connected and with no identity bridge.
async fn set_on_disconnected_pr1ma(
agent: &str,
wanted_state: swarm_queue_client::wanted::AgentState,
wanted_state: swarm_wire::wanted::AgentState,
) -> problem_details::ProblemDetails {
let (state, _sched) = state_with_two_hives();
let state = crate::routes::AppState {
@ -2011,7 +2011,7 @@ mod tests {
#[tokio::test]
async fn set_agent_state_refuses_when_the_wanted_state_is_unreadable() {
let err =
set_on_disconnected_pr1ma("atlas", swarm_queue_client::wanted::AgentState::Up).await;
set_on_disconnected_pr1ma("atlas", swarm_wire::wanted::AgentState::Up).await;
assert_eq!(
err.status,
Some(axum::http::StatusCode::SERVICE_UNAVAILABLE),
@ -2029,7 +2029,7 @@ mod tests {
#[tokio::test]
async fn set_agent_state_does_not_check_a_destroy() {
let err =
set_on_disconnected_pr1ma("admin", swarm_queue_client::wanted::AgentState::Destroyed)
set_on_disconnected_pr1ma("admin", swarm_wire::wanted::AgentState::Destroyed)
.await;
assert_eq!(
err.status,
@ -2197,7 +2197,7 @@ mod tests {
#[test]
fn declaring_an_agent_destroyed_revokes_its_queue_credential() {
assert!(super::revokes_queue_credential(
swarm_queue_client::wanted::AgentState::Destroyed
swarm_wire::wanted::AgentState::Destroyed
));
}
@ -2207,7 +2207,7 @@ mod tests {
/// a state added later shows up here as well as in the match itself.
#[test]
fn no_state_an_agent_comes_back_from_revokes() {
use swarm_queue_client::wanted::AgentState;
use swarm_wire::wanted::AgentState;
for state in [AgentState::Up, AgentState::Offline, AgentState::Paused] {
assert!(
!super::revokes_queue_credential(state),
@ -2350,7 +2350,7 @@ mod tests {
axum::extract::State(state),
axum::extract::Path(("pr1ma".to_owned(), "atlas".to_owned())),
axum::Json(SetAgentStateRequest {
state: swarm_queue_client::wanted::AgentState::Paused,
state: swarm_wire::wanted::AgentState::Paused,
}),
)
.await;
@ -2395,7 +2395,7 @@ mod tests {
axum::extract::State(state),
axum::extract::Path(("not-a-hive".to_owned(), "atlas".to_owned())),
axum::Json(SetAgentStateRequest {
state: swarm_queue_client::wanted::AgentState::Paused,
state: swarm_wire::wanted::AgentState::Paused,
}),
)
.await;