Watch
0
0
Fork
You've already forked hyperhive
0

Compare commits

..
42 changed files with 886 additions and 903 deletions

2
Cargo.lock generated
View file

@ -1802,7 +1802,6 @@ dependencies = [
"swarm-matrix-client",
"swarm-queue-client",
"swarm-secret-client",
"swarm-wire",
"tempfile",
"tokio",
"tokio-stream",
@ -5036,6 +5035,7 @@ dependencies = [
"reqwest",
"serde",
"serde_json",
"strum",
"swarm-secret-client",
"swarm-wire",
"thiserror 2.0.18",

View file

@ -18,7 +18,7 @@ export interface AgentStatusSnapshot {
}
// `"up"` / `"offline"` / `"destroyed"`, wire-spelled by
// `swarm_wire::wanted::AgentState::as_str` — kept as a bare
// `swarm_queue_client::wanted::AgentState::as_str` — kept as a bare
// `string | null` rather than a union, same reason `config_pr`'s shape
// isn't re-derived here: this renders whatever the wire sends, it
// doesn't validate the enum client-side.

View file

@ -31,8 +31,7 @@ use std::time::Duration;
use anyhow::{Context as _, Result};
use rusqlite::{Connection, OptionalExtension as _, params};
use swarm_queue_client::agent_schedules::{Read, read_own};
use swarm_wire::agent_schedules::{AgentSchedules, Schedule};
use swarm_queue_client::agent_schedules::{AgentSchedules, Read, Schedule, read_own};
use tokio::sync::Notify;
use crate::todos::Todos;

View file

@ -72,7 +72,7 @@ pub fn spawn() {
async fn run(agent: String) {
let client = crate::swarm_queue::client().await;
let subject = swarm_wire::agent_icon::subject(&agent);
let subject = swarm_queue_client::agent_icon::subject(&agent);
let icon = match read_icon(Path::new(ICON_PATH)) {
Ok(icon) => icon,
Err(e) => {

View file

@ -33,9 +33,9 @@ use serde::Serialize;
use tokio::sync::broadcast;
use tokio::time::{Interval, MissedTickBehavior};
use swarm_queue_client::wanted::AgentState;
use swarm_wire::agent_inference::Effective;
use swarm_wire::agent_login::Login;
use swarm_wire::wanted::AgentState;
use crate::events::{Bus, BusEvent, LiveEvent, TurnState};
use crate::login::LoginState;
@ -337,8 +337,8 @@ mod tests {
use crate::events::{BusEvent, LiveEvent, TurnState};
use crate::login::LoginState;
use std::sync::Mutex;
use swarm_queue_client::wanted::AgentState;
use swarm_wire::agent_inference::{Effective, Source};
use swarm_wire::wanted::AgentState;
use tokio::sync::broadcast;
use tokio::time::{Duration, Instant};

View file

@ -63,7 +63,6 @@ swarm-queue-client = { workspace = true, features = [
] }
swarm-matrix-client.workspace = true
swarm-secret-client.workspace = true
swarm-wire.workspace = true
tokio.workspace = true
tokio-stream.workspace = true
tracing.workspace = true

View file

@ -1,7 +1,7 @@
//! Offering each locally-hosted agent's status upward to the swarm.
//!
//! Sibling task to [`crate::swarm_status`], not a field folded into it — see
//! `swarm_wire::agent_status`'s module doc for why hive status and
//! `swarm_queue_client::agent_status`'s module doc for why hive status and
//! agent status live in separate buckets. Same direction, though: a hive
//! **offers** what it already knows about its own agents (via
//! [`crate::container_view::read_agent_status_bounded`], the bounded form of
@ -9,7 +9,7 @@
//! controller never reaches down to collect it.
//!
//! **One publish per agent, not one document for the hive.** Each agent
//! gets its own key (`swarm_wire::agent_status::key`), so one
//! gets its own key (`swarm_queue_client::agent_status::key`), so one
//! agent's status changing does not touch any other agent's key, and a
//! consumer watching one agent reads exactly its own revision history.
@ -127,7 +127,7 @@ async fn publish_all(client: &async_nats::Client, hive: &str) -> Result<usize> {
tracing::warn!(agent = %spec.name, "agent status: unit state unreadable, skipping");
continue;
};
let payload = swarm_wire::agent_status::AgentStatus {
let payload = swarm_queue_client::agent_status::AgentStatus {
status_text,
status_set_at,
running,
@ -139,7 +139,7 @@ async fn publish_all(client: &async_nats::Client, hive: &str) -> Result<usize> {
continue;
}
};
let key = swarm_wire::agent_status::key(hive, &spec.name);
let key = swarm_queue_client::agent_status::key(hive, &spec.name);
if let Err(e) = store.put(key, bytes.into()).await {
tracing::warn!(agent = %spec.name, error = %e, "agent status: publish failed, skipping");
continue;

View file

@ -8,7 +8,7 @@
//! a status snapshot has a current value a late reader can always ask
//! for; a lifecycle notice ("container crashed at 04:12") does not — miss
//! it and there is nothing left to read later that says it happened. See
//! [`swarm_queue_client::notices`] for opening the stream this publishes into.
//! [`swarm_queue_client::notices`] for the stream this publishes into.
//!
//! **Best-effort, never fatal to the caller.** A hive with no queue
//! coordinates is a silent no-op (the ordinary case). A hive that cannot
@ -129,7 +129,7 @@ async fn publish(
.context("serialising the notice")?;
let js = async_nats::jetstream::new(client.clone());
js.publish(swarm_wire::notices::subject(hive), payload.into())
js.publish(swarm_queue_client::notices::subject(hive), payload.into())
.await
.context("publishing the notice")?
.await

View file

@ -1,7 +1,7 @@
//! Reading the caps the swarm sets for this hive's agents.
//!
//! swarm-controller keeps one key per agent in the `agent-limits` bucket
//! ([`swarm_wire::agent_limits`]). Every [`READ_INTERVAL`] this reads
//! ([`swarm_queue_client::agent_limits`]). Every [`READ_INTERVAL`] this reads
//! the key of each agent this hive has and stores what it finds in
//! `swarm-resource-limits.json`, where the drop-in reads it.
//! A running agent gets a changed cap at its first spawn or rebuild after
@ -14,8 +14,7 @@ use std::collections::BTreeMap;
use std::time::Duration;
use anyhow::{Context, Result};
use swarm_queue_client::agent_limits::{self, Read};
use swarm_wire::agent_limits::AgentCaps;
use swarm_queue_client::agent_limits::{self, AgentCaps, Read};
use crate::resource_limits::AgentLimits;
use crate::stats::sweep_health::{self, SweepHealth};
@ -128,7 +127,7 @@ mod tests {
use std::collections::BTreeMap;
use super::validated;
use swarm_wire::agent_limits::AgentCaps;
use swarm_queue_client::agent_limits::AgentCaps;
/// `atlas`'s answer with `atlas_key` as the value read for it, over the
/// hive-wide defaults of 200% / 4G.

View file

@ -1,7 +1,7 @@
//! Converging this hive onto the agent set the swarm controller declares.
//!
//! The controller gives each hive its own `hive-wanted-<hive>` bucket (see
//! [`swarm_wire::wanted`]); this reads its own and acts on it. It is
//! [`swarm_queue_client::wanted`]); this reads its own and acts on it. It is
//! the **repair** path, not the fast one: a deploy event
//! ([`crate::swarm_status`]) is core NATS, so a hive that was down never hears
//! it, and until this existed that left the hive on its old shape with nothing
@ -33,7 +33,7 @@ use std::collections::{BTreeMap, BTreeSet};
use std::sync::Arc;
use anyhow::{Context, Result};
use swarm_wire::wanted::{AgentState, HiveWanted};
use swarm_queue_client::wanted::{AgentState, HiveWanted};
use crate::coordinator::Coordinator;
use crate::power::Wanted;
@ -469,7 +469,7 @@ mod tests {
use super::{Converge, PauseConverge, Plan, carries_a_declaration, decide, decide_pause, plan};
use crate::power::Wanted;
use swarm_wire::wanted::{AgentState, AgentWanted, HiveWanted};
use swarm_queue_client::wanted::{AgentState, AgentWanted, HiveWanted};
fn declaration(agents: &[(&str, AgentState)]) -> HiveWanted {
HiveWanted {

View file

@ -7,7 +7,7 @@
//! property of it, so there is nothing for a timestamp to mean here.
//!
//! **No hive is named on this path**, because the key does not carry one —
//! see `swarm_wire::agent_icon` for why, and for who writes it.
//! see `swarm_queue_client::agent_icon` for why, and for who writes it.
//!
//! This reader is also what creates the bucket: the agents that write it are
//! granted their own key and nothing that could create a stream.

View file

@ -2,7 +2,7 @@
//! one agent.
//!
//! Each agent's caps are one value under its own key of `agent-limits`
//! (`swarm_wire::agent_limits`), which this daemon alone writes. The
//! (`swarm_queue_client::agent_limits`), which this daemon alone writes. The
//! hive running the agent reads the key; on the hive, a cap replaces the
//! hive's own answer for that field, and a field left unset stays with the
//! hive.
@ -16,8 +16,7 @@ use axum::extract::{Path, State};
use axum::http::StatusCode;
use problem_details::ProblemDetails;
use serde::{Deserialize, Serialize};
use swarm_queue_client::agent_limits;
use swarm_wire::agent_limits::AgentCaps;
use swarm_queue_client::agent_limits::{self, AgentCaps};
use utoipa::ToSchema;
use crate::routes::{AppState, error_problem, wanted_error_status};
@ -359,7 +358,7 @@ pub(crate) mod tests {
use axum::extract::{Path, State};
use axum::http::StatusCode;
use std::sync::Arc;
use swarm_wire::wanted::AgentState;
use swarm_queue_client::wanted::AgentState;
/// Of the `bad` values, systemd parses `""` (no quota) and `+5%`, and the
/// last adds a directive on a second line. It ignores every other one

View file

@ -860,7 +860,7 @@ mod tests {
State(state.clone()),
Path(("pr1ma".to_owned(), "atlas".to_owned())),
axum::Json(crate::routes::agents::SetAgentStateRequest {
state: swarm_wire::wanted::AgentState::Destroyed,
state: swarm_queue_client::wanted::AgentState::Destroyed,
}),
)
.await

View file

@ -33,8 +33,8 @@ use std::collections::BTreeSet;
use std::sync::Arc;
use anyhow::{Context, Result, bail};
use swarm_queue_client::wanted::{AgentState, HiveWanted};
use swarm_secret_client::{SecretStore, mtls, queue};
use swarm_wire::wanted::{AgentState, HiveWanted};
use x509_cert::der::DecodePem as _;
use crate::wanted::WantedWriter;
@ -429,7 +429,7 @@ pub fn spawn(
#[cfg(test)]
mod tests {
use super::*;
use swarm_wire::wanted::AgentWanted;
use swarm_queue_client::wanted::AgentWanted;
const NOW: i64 = 1_790_000_000;
const DAY: i64 = 86_400;

View file

@ -1,7 +1,7 @@
//! Swarm-wide view of what each agent last said about itself.
//!
//! Sibling of [`crate::status`], not a mode of it — see
//! `swarm_wire::agent_status`'s module doc for why the two buckets
//! `swarm_queue_client::agent_status`'s module doc for why the two buckets
//! stay separate. Everything about *how* a snapshot is read (queue is the
//! store, no cache, freshness derived at read time, rows come from the
//! roster so an empty bucket cannot render as "every agent is fine") is
@ -11,7 +11,7 @@
//! **The roster here is agent *names* only** ([`crate::auth::AuthBridge::list_agent_identities`]) —
//! it does not say which hive an agent lives on. That is not a gap this
//! module needs to close: a *reporting* agent's hive comes straight out of
//! its bucket key (`swarm_wire::agent_status::split_key`), and a
//! its bucket key (`swarm_queue_client::agent_status::split_key`), and a
//! *never-reported* agent's hive is unknowable regardless of what any
//! roster might claim, so [`AgentStatusRow::hive`] is `None` in exactly
//! that one case rather than a second lookup this module would have to
@ -42,7 +42,7 @@ pub struct AgentStatusRow {
pub age_seconds: Option<u64>,
/// The agent's status text + running flag, unopened. `None` exactly
/// when `freshness` is `NeverReported`, or when the stored bytes
/// failed to decode as [`swarm_wire::agent_status::AgentStatus`]
/// failed to decode as [`swarm_queue_client::agent_status::AgentStatus`]
/// (logged as a warning naming the agent).
pub snapshot: Option<serde_json::Value>,
/// The agent's open config PR, if any. Always `None` coming out of
@ -130,7 +130,7 @@ impl AgentStatusReader {
.await
.context("reading the agent-status bucket's key list")?
{
let Some((hive, agent)) = swarm_wire::agent_status::split_key(&key) else {
let Some((hive, agent)) = swarm_queue_client::agent_status::split_key(&key) else {
tracing::warn!(%key, "agent-status bucket key doesn't split into hive/agent, skipping");
continue;
};
@ -141,9 +141,10 @@ impl AgentStatusReader {
else {
continue;
};
let payload = match serde_json::from_slice::<swarm_wire::agent_status::AgentStatus>(
&entry.value,
) {
let payload = match serde_json::from_slice::<
swarm_queue_client::agent_status::AgentStatus,
>(&entry.value)
{
Ok(status) => serde_json::to_value(status).ok(),
Err(e) => {
tracing::warn!(

View file

@ -242,7 +242,7 @@ mod tests {
State(state.clone()),
Path(("pr1ma".to_owned(), "atlas".to_owned())),
axum::Json(crate::routes::agents::SetAgentStateRequest {
state: swarm_wire::wanted::AgentState::Destroyed,
state: swarm_queue_client::wanted::AgentState::Destroyed,
}),
)
.await

View file

@ -191,7 +191,7 @@ pub(crate) struct ArchetypeView {
/// As `PUT /api/agents/{name}/limits` takes them.
#[serde(skip_serializing_if = "Option::is_none")]
#[schema(value_type = Option<Object>)]
limits: Option<swarm_wire::agent_limits::AgentCaps>,
limits: Option<swarm_queue_client::agent_limits::AgentCaps>,
/// As `PUT /api/agents/{name}/inference` takes them.
#[serde(skip_serializing_if = "Option::is_none")]
#[schema(value_type = Option<Object>)]

View file

@ -259,8 +259,8 @@ pub(crate) struct WorkerDeps {
/// decision the node exists to carry — writing a declaration at all is the
/// mechanism, `Paused` is the policy — and a test can pin a name where it
/// cannot pin a value written into a KV bucket no unit test has a server for.
const NEW_AGENT_WANTED_STATE: swarm_wire::wanted::AgentState =
swarm_wire::wanted::AgentState::Paused;
const NEW_AGENT_WANTED_STATE: swarm_queue_client::wanted::AgentState =
swarm_queue_client::wanted::AgentState::Paused;
/// Run a claimed node's actual work. Mirrors `hive-c0re/src/job_queue/
/// exec.rs::run_node`'s role exactly — the one place a `SwarmNodeKind`
@ -665,7 +665,7 @@ async fn declare_new_agent(
agent: &str,
) -> hive_jobq::scheduler::Outcome {
use hive_jobq::scheduler::Outcome;
use swarm_wire::wanted::AgentState;
use swarm_queue_client::wanted::AgentState;
let existing = match writer.view(hive).await {
Ok(declaration) => declaration.and_then(|d| d.agents.get(agent).map(|a| a.state)),
@ -1645,7 +1645,7 @@ mod tests {
fn a_new_agent_is_declared_paused() {
assert_eq!(
super::NEW_AGENT_WANTED_STATE,
swarm_wire::wanted::AgentState::Paused
swarm_queue_client::wanted::AgentState::Paused
);
}

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_wire::wanted::AgentState,
pub(crate) state: swarm_queue_client::wanted::AgentState,
}
/// One agent's line in a hive's declaration.
@ -78,7 +78,9 @@ pub(crate) struct AgentDeclaration {
state: String,
}
pub(crate) fn render(declaration: &swarm_wire::wanted::HiveWanted) -> Vec<AgentDeclaration> {
pub(crate) fn render(
declaration: &swarm_queue_client::wanted::HiveWanted,
) -> Vec<AgentDeclaration> {
declaration
.agents
.iter()
@ -221,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_wire::wanted::AgentState) -> bool {
use swarm_wire::wanted::AgentState;
fn places_agent(state: swarm_queue_client::wanted::AgentState) -> bool {
use swarm_queue_client::wanted::AgentState;
match state {
AgentState::Up | AgentState::Offline | AgentState::Paused => true,
AgentState::Destroyed => false,
@ -241,7 +243,7 @@ fn places_agent(state: swarm_wire::wanted::AgentState) -> bool {
async fn refuse_placement<R, D>(
agent: &str,
hive: &str,
here: Option<&swarm_wire::wanted::HiveWanted>,
here: Option<&swarm_queue_client::wanted::HiveWanted>,
reserved: Option<&str>,
read_roster: impl FnOnce() -> R,
snapshot_queued: impl FnOnce() -> Vec<(String, String)>,
@ -251,7 +253,7 @@ where
R: std::future::Future<Output = Result<bool, String>>,
D: std::future::Future<
Output = Result<
Vec<(String, swarm_wire::wanted::HiveWanted)>,
Vec<(String, swarm_queue_client::wanted::HiveWanted)>,
problem_details::ProblemDetails,
>,
>,
@ -293,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_wire::wanted::AgentState] in this
/// [`AgentState`][swarm_queue_client::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_wire::wanted::AgentState) -> bool {
use swarm_wire::wanted::AgentState;
fn revokes_queue_credential(state: swarm_queue_client::wanted::AgentState) -> bool {
use swarm_queue_client::wanted::AgentState;
match state {
AgentState::Destroyed => true,
AgentState::Up | AgentState::Offline | AgentState::Paused => false,
@ -423,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_wire::wanted::HiveWanted,
swarm_queue_client::wanted::HiveWanted,
> = std::collections::HashMap::new();
for hive in hives {
match writer.view(&hive).await {
@ -709,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_wire::agent_limits::AgentCaps>,
limits: Option<swarm_queue_client::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>,
@ -792,7 +794,7 @@ impl StoredSettings {
async fn store(
client: &async_nats::Client,
agent: &str,
limits: Option<&swarm_wire::agent_limits::AgentCaps>,
limits: Option<&swarm_queue_client::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>,
@ -865,7 +867,9 @@ async fn placements_elsewhere<E, Fut>(
read_declared: impl FnOnce() -> Fut,
) -> Result<Vec<String>, E>
where
Fut: std::future::Future<Output = Result<Vec<(String, swarm_wire::wanted::HiveWanted)>, E>>,
Fut: std::future::Future<
Output = Result<Vec<(String, swarm_queue_client::wanted::HiveWanted)>, E>,
>,
{
let queued = snapshot_queued();
let declared = read_declared().await?;
@ -882,7 +886,8 @@ async fn declarations_elsewhere(
state: &AppState,
agent: &str,
hive: &str,
) -> Result<Vec<(String, swarm_wire::wanted::HiveWanted)>, problem_details::ProblemDetails> {
) -> Result<Vec<(String, swarm_queue_client::wanted::HiveWanted)>, problem_details::ProblemDetails>
{
read_declarations(state, state.hives.iter().filter(|h| h.name != hive))
.await
.map_err(|(other, e)| {
@ -900,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_wire::wanted::HiveWanted)>, (String, anyhow::Error)> {
) -> Result<Vec<(String, swarm_queue_client::wanted::HiveWanted)>, (String, anyhow::Error)> {
let Some(writer) = state.wanted.as_deref() else {
return Ok(Vec::new());
};
@ -918,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_wire::wanted::HiveWanted)],
declared: &[(String, swarm_queue_client::wanted::HiveWanted)],
) -> Vec<String> {
declared
.iter()
@ -966,7 +971,7 @@ fn queued_placements(
fn placed_elsewhere(
agent: &str,
hive: &str,
declared: &[(String, swarm_wire::wanted::HiveWanted)],
declared: &[(String, swarm_queue_client::wanted::HiveWanted)],
queued: &[(String, String)],
) -> Vec<String> {
let declared = declared.iter().filter(|(_, declaration)| {
@ -1160,7 +1165,7 @@ pub(crate) async fn get_agent_icon(
[
(
header::CONTENT_TYPE,
swarm_wire::agent_icon::MEDIA_TYPE.to_owned(),
swarm_queue_client::agent_icon::MEDIA_TYPE.to_owned(),
),
(
header::CACHE_CONTROL,
@ -1701,12 +1706,13 @@ mod tests {
pub(crate) fn declaring(
hive: &str,
agent: &str,
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_wire::wanted::AgentWanted { state });
state: swarm_queue_client::wanted::AgentState,
) -> (String, swarm_queue_client::wanted::HiveWanted) {
let mut declaration = swarm_queue_client::wanted::HiveWanted::default();
declaration.agents.insert(
agent.to_owned(),
swarm_queue_client::wanted::AgentWanted { state },
);
(hive.to_owned(), declaration)
}
@ -1715,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_wire::wanted::AgentState;
use swarm_queue_client::wanted::AgentState;
let reads = std::cell::Cell::new(0);
let snapshot_queued = || {
reads.set(reads.get() + 1);
@ -1744,7 +1750,7 @@ mod tests {
#[test]
fn a_live_declaration_on_another_hive_is_a_placement() {
use swarm_wire::wanted::AgentState;
use swarm_queue_client::wanted::AgentState;
for state in [AgentState::Up, AgentState::Offline, AgentState::Paused] {
let declared = [declaring("sec0nd", "atlas", state)];
assert_eq!(
@ -1761,14 +1767,14 @@ mod tests {
let declared = [declaring(
"sec0nd",
"atlas",
swarm_wire::wanted::AgentState::Destroyed,
swarm_queue_client::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_wire::wanted::AgentState;
use swarm_queue_client::wanted::AgentState;
let declared = [
declaring("pr1ma", "atlas", AgentState::Up),
declaring("sec0nd", "argus", AgentState::Up),
@ -1782,7 +1788,7 @@ mod tests {
#[test]
fn the_hive_placing_an_agent_claims_it_and_no_other_does() {
use swarm_wire::wanted::AgentState;
use swarm_queue_client::wanted::AgentState;
let declared = [
declaring("pr1ma", "atlas", AgentState::Paused),
declaring("sec0nd", "argus", AgentState::Up),
@ -1794,7 +1800,7 @@ mod tests {
#[test]
fn two_hives_placing_one_agent_both_claim_it() {
use swarm_wire::wanted::AgentState;
use swarm_queue_client::wanted::AgentState;
let declared = [
declaring("pr1ma", "atlas", AgentState::Up),
declaring("sec0nd", "atlas", AgentState::Up),
@ -1810,7 +1816,7 @@ mod tests {
/// state, `pr1ma`'s included.
async fn refuse_on_pr1ma_with(
agent: &str,
declared: Vec<(String, swarm_wire::wanted::HiveWanted)>,
declared: Vec<(String, swarm_queue_client::wanted::HiveWanted)>,
roster: Result<bool, String>,
) -> Result<(), problem_details::ProblemDetails> {
let here = declared
@ -1832,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_wire::wanted::HiveWanted)>,
declared: Vec<(String, swarm_queue_client::wanted::HiveWanted)>,
) -> Result<(), problem_details::ProblemDetails> {
refuse_on_pr1ma_with(agent, declared, Ok(false)).await
}
const PLACING: [swarm_wire::wanted::AgentState; 3] = [
swarm_wire::wanted::AgentState::Up,
swarm_wire::wanted::AgentState::Offline,
swarm_wire::wanted::AgentState::Paused,
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,
];
/// The handler checks exactly the placing states; a destroy is never
@ -1851,7 +1857,7 @@ mod tests {
assert!(super::places_agent(state), "{state:?}");
}
assert!(!super::places_agent(
swarm_wire::wanted::AgentState::Destroyed
swarm_queue_client::wanted::AgentState::Destroyed
));
}
@ -1914,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_wire::wanted::AgentState;
use swarm_queue_client::wanted::AgentState;
let err = refuse_on_pr1ma(
"admin",
vec![declaring("pr1ma", "admin", AgentState::Destroyed)],
@ -1947,7 +1953,7 @@ mod tests {
#[tokio::test]
async fn a_first_declaration_of_a_name_placed_on_another_hive_is_refused() {
use swarm_wire::wanted::AgentState;
use swarm_queue_client::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");
@ -1970,7 +1976,7 @@ mod tests {
#[tokio::test]
async fn changing_the_state_of_an_agent_on_its_own_hive_is_accepted() {
use swarm_wire::wanted::AgentState;
use swarm_queue_client::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");
@ -1980,7 +1986,7 @@ mod tests {
/// connected and with no identity bridge.
async fn set_on_disconnected_pr1ma(
agent: &str,
wanted_state: swarm_wire::wanted::AgentState,
wanted_state: swarm_queue_client::wanted::AgentState,
) -> problem_details::ProblemDetails {
let (state, _sched) = state_with_two_hives();
let state = crate::routes::AppState {
@ -2004,7 +2010,8 @@ mod tests {
/// declaration before it is written, as it refuses creation.
#[tokio::test]
async fn set_agent_state_refuses_when_the_wanted_state_is_unreadable() {
let err = set_on_disconnected_pr1ma("atlas", swarm_wire::wanted::AgentState::Up).await;
let err =
set_on_disconnected_pr1ma("atlas", swarm_queue_client::wanted::AgentState::Up).await;
assert_eq!(
err.status,
Some(axum::http::StatusCode::SERVICE_UNAVAILABLE),
@ -2022,7 +2029,8 @@ mod tests {
#[tokio::test]
async fn set_agent_state_does_not_check_a_destroy() {
let err =
set_on_disconnected_pr1ma("admin", swarm_wire::wanted::AgentState::Destroyed).await;
set_on_disconnected_pr1ma("admin", swarm_queue_client::wanted::AgentState::Destroyed)
.await;
assert_eq!(
err.status,
Some(axum::http::StatusCode::SERVICE_UNAVAILABLE),
@ -2189,7 +2197,7 @@ mod tests {
#[test]
fn declaring_an_agent_destroyed_revokes_its_queue_credential() {
assert!(super::revokes_queue_credential(
swarm_wire::wanted::AgentState::Destroyed
swarm_queue_client::wanted::AgentState::Destroyed
));
}
@ -2199,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_wire::wanted::AgentState;
use swarm_queue_client::wanted::AgentState;
for state in [AgentState::Up, AgentState::Offline, AgentState::Paused] {
assert!(
!super::revokes_queue_credential(state),
@ -2342,7 +2350,7 @@ mod tests {
axum::extract::State(state),
axum::extract::Path(("pr1ma".to_owned(), "atlas".to_owned())),
axum::Json(SetAgentStateRequest {
state: swarm_wire::wanted::AgentState::Paused,
state: swarm_queue_client::wanted::AgentState::Paused,
}),
)
.await;
@ -2387,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_wire::wanted::AgentState::Paused,
state: swarm_queue_client::wanted::AgentState::Paused,
}),
)
.await;

View file

@ -7,7 +7,7 @@
//! schedule exists for all of its agents or for none of them.
//!
//! Each agent reads only its own key of `agent-schedules`
//! (`swarm_wire::agent_schedules`), which holds the schedules naming
//! (`swarm_queue_client::agent_schedules`), which holds the schedules naming
//! it, without their names or other agents. That key is a projection of the
//! definitions: after a change this daemon rewrites the key of each agent the
//! change touched, and [`spawn_reconcile`] rewrites every agent's key every
@ -30,8 +30,7 @@ use serde::{Deserialize, Serialize};
use swarm_controller_api::schedules::{
AddScheduleRequest, EditScheduleRequest, IntervalEdit, ScheduleView,
};
use swarm_queue_client::agent_schedules;
use swarm_wire::agent_schedules::{AgentSchedules, Schedule};
use swarm_queue_client::agent_schedules::{self, AgentSchedules, Schedule};
use crate::agent_renewal::unix_now;
use crate::routes::{AppState, error_problem};

Some files were not shown because too many files have changed in this diff Show more