swarm-controller: split main.rs into jobq, routes and startup modules
no behaviour change: a pure move of items and tests into new modules, plus visibility edits (pub(crate)) and path updates in sibling modules that named crate-root items. same routes, same OpenAPI, 561 tests before and after. why: #5470, new features stop landing in one 6.4k-line file by default. files outside swarm-controller/src: docs/agent-lifecycle/agent-roster.md, swarm-ui JobsPage.tsx and AgentsPage.tsx, nix/host-modules/swarm-controller.nix and swarm-grafana.nix hold comments that named main.rs for items that moved.
This commit is contained in:
parent
f0a6d6c042
commit
738dd1c95b
42 changed files with 6854 additions and 6680 deletions
|
|
@ -18,7 +18,7 @@ holds the hive directory, the agent roster and the job graph") is the
|
||||||
**swarm-wide** one: `GET /api/agents` on swarm-controller reads
|
**swarm-wide** one: `GET /api/agents` on swarm-controller reads
|
||||||
straight from the swarm's authelia identity store over
|
straight from the swarm's authelia identity store over
|
||||||
`swarm-authelia-bridge` (`swarm-controller/src/auth.rs::list_agent_identities`)
|
`swarm-authelia-bridge` (`swarm-controller/src/auth.rs::list_agent_identities`)
|
||||||
— "every agent the swarm holds an identity for" (`swarm-controller/src/main.rs`'s
|
— "every agent the swarm holds an identity for" (`swarm-controller/src/routes/agents.rs`'s
|
||||||
`get_agents` doc comment). It's authoritative: an agent exists in the
|
`get_agents` doc comment). It's authoritative: an agent exists in the
|
||||||
swarm if and only if it has an identity there, and `swarmctl agent
|
swarm if and only if it has an identity there, and `swarmctl agent
|
||||||
create` (or the swarm UI, via `POST /api/agents`) writes that identity
|
create` (or the swarm UI, via `POST /api/agents`) writes that identity
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
// queue) pointed at swarm-controller's own GET /api/jobq/graph instead
|
// queue) pointed at swarm-controller's own GET /api/jobq/graph instead
|
||||||
// of hive-c0re's — same wire shape (Vec<hive_jobq_wire::GraphNode>),
|
// of hive-c0re's — same wire shape (Vec<hive_jobq_wire::GraphNode>),
|
||||||
// different endpoint, no component fork. swarm-controller's graph has
|
// different endpoint, no component fork. swarm-controller's graph has
|
||||||
// no real node kinds wired in yet (see swarm-controller/src/main.rs's
|
// no real node kinds wired in yet (see swarm-controller/src/jobq.rs's
|
||||||
// SwarmNodeKind/SwarmResourceKind), so this renders an empty tree today
|
// SwarmNodeKind/SwarmResourceKind), so this renders an empty tree today
|
||||||
// — the page exists so the wiring is in place before the first real
|
// — the page exists so the wiring is in place before the first real
|
||||||
// swarm-level job (e.g. CreateAgent) lands.
|
// swarm-level job (e.g. CreateAgent) lands.
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
// three separate fetches joined client-side by name; per operator
|
// three separate fetches joined client-side by name; per operator
|
||||||
// review feedback ("the view should be filled by a single backend
|
// review feedback ("the view should be filled by a single backend
|
||||||
// call") the join moved server-side instead — see
|
// call") the join moved server-side instead — see
|
||||||
// `swarm-controller/src/main.rs`'s `get_agents_status` handler. No more
|
// `swarm-controller/src/routes/agents.rs`'s `get_agents_status` handler. No more
|
||||||
// per-page joining left to do here: the wire row *is* the row this page renders.
|
// per-page joining left to do here: the wire row *is* the row this page renders.
|
||||||
//
|
//
|
||||||
// Owns the "+ agent" trigger too — the roster this populates is the
|
// Owns the "+ agent" trigger too — the roster this populates is the
|
||||||
|
|
|
||||||
|
|
@ -754,7 +754,7 @@ in
|
||||||
# `AF_UNIX` for the socket this daemon serves on, plus what its
|
# `AF_UNIX` for the socket this daemon serves on, plus what its
|
||||||
# outbound clients need: it mints authelia tokens and calls the forge
|
# outbound clients need: it mints authelia tokens and calls the forge
|
||||||
# over HTTPS (`auth.rs`, `forge.rs`) and reaches the queue over NATS
|
# over HTTPS (`auth.rs`, `forge.rs`) and reaches the queue over NATS
|
||||||
# (`main.rs`, `status.rs`). `AF_NETLINK` because glibc's
|
# (`startup.rs`, `status.rs`). `AF_NETLINK` because glibc's
|
||||||
# `getaddrinfo` opens a netlink socket to enumerate local addresses
|
# `getaddrinfo` opens a netlink socket to enumerate local addresses
|
||||||
# before it will return one.
|
# before it will return one.
|
||||||
#
|
#
|
||||||
|
|
@ -789,7 +789,7 @@ in
|
||||||
# The swarm's hive directory, JSON-encoded — the full directory
|
# The swarm's hive directory, JSON-encoded — the full directory
|
||||||
# (this daemon has no "self" hive to exclude) rather than
|
# (this daemon has no "self" hive to exclude) rather than
|
||||||
# peers-minus-self. Consumed by `GET /api/hives`
|
# peers-minus-self. Consumed by `GET /api/hives`
|
||||||
# (swarm-controller/src/main.rs::load_hives).
|
# (swarm-controller/src/startup.rs::load_hives).
|
||||||
# The one blacklist of names an agent may not take, shared verbatim
|
# The one blacklist of names an agent may not take, shared verbatim
|
||||||
# with hive-c0re and with the collector's owner assertion — see
|
# with hive-c0re and with the collector's owner assertion — see
|
||||||
# `nix/reserved-names.nix`. Whitespace-separated rather than JSON
|
# `nix/reserved-names.nix`. Whitespace-separated rather than JSON
|
||||||
|
|
@ -806,7 +806,7 @@ in
|
||||||
);
|
);
|
||||||
# The merged links list — see `links`' description above for who
|
# The merged links list — see `links`' description above for who
|
||||||
# contributes to it. Consumed by `GET /api/links`
|
# contributes to it. Consumed by `GET /api/links`
|
||||||
# (swarm-controller/src/main.rs::load_links).
|
# (swarm-controller/src/startup.rs::load_links).
|
||||||
SWARM_CONTROLLER_LINKS = builtins.toJSON cfg.links;
|
SWARM_CONTROLLER_LINKS = builtins.toJSON cfg.links;
|
||||||
# Staleness threshold for `GET /api/hives/status` — see
|
# Staleness threshold for `GET /api/hives/status` — see
|
||||||
# `staleAfterSeconds`' description. Set unconditionally rather
|
# `staleAfterSeconds`' description. Set unconditionally rather
|
||||||
|
|
|
||||||
|
|
@ -1555,7 +1555,7 @@ in
|
||||||
for = "15m";
|
for = "15m";
|
||||||
summary = "swarm-controller has failed the agent credential renewal pass on consecutive ticks";
|
summary = "swarm-controller has failed the agent credential renewal pass on consecutive ticks";
|
||||||
})
|
})
|
||||||
# `MINT_IDENTITY_FAILED` in swarm-controller's main.rs,
|
# `MINT_IDENTITY_FAILED` in swarm-controller's jobq.rs,
|
||||||
# logged once per failed `MintAgentIdentity` job node, at
|
# logged once per failed `MintAgentIdentity` job node, at
|
||||||
# agent creation or on a certificate renewal; the window
|
# agent creation or on a certificate renewal; the window
|
||||||
# is how long the rule stays firing after it. Host
|
# is how long the rule stays firing after it. Host
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ use problem_details::ProblemDetails;
|
||||||
use swarm_queue_client::agent_archetype::{self, ArchetypeRef};
|
use swarm_queue_client::agent_archetype::{self, ArchetypeRef};
|
||||||
use swarm_queue_client::archetypes::SourceRecord;
|
use swarm_queue_client::archetypes::SourceRecord;
|
||||||
|
|
||||||
|
use crate::routes::{AppState, error_problem};
|
||||||
use crate::schedules::{queue, read_or_default, write_revision};
|
use crate::schedules::{queue, read_or_default, write_revision};
|
||||||
use crate::{AppState, error_problem};
|
|
||||||
|
|
||||||
/// How many times a losing writer re-reads and re-applies, as in
|
/// How many times a losing writer re-reads and re-applies, as in
|
||||||
/// `wanted::MAX_ATTEMPTS`.
|
/// `wanted::MAX_ATTEMPTS`.
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ use serde::Serialize;
|
||||||
use swarm_queue_client::{AgentControl, AgentControlReply};
|
use swarm_queue_client::{AgentControl, AgentControlReply};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
use crate::{AppState, error_problem};
|
use crate::routes::{AppState, error_problem};
|
||||||
|
|
||||||
/// What became of one command.
|
/// What became of one command.
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use swarm_queue_client::AgentInput;
|
use swarm_queue_client::AgentInput;
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
use crate::{AppState, error_problem};
|
use crate::routes::{AppState, error_problem};
|
||||||
|
|
||||||
/// The header the gateway names the session's user in.
|
/// The header the gateway names the session's user in.
|
||||||
const SENDER_HEADER: &str = "remote-user";
|
const SENDER_HEADER: &str = "remote-user";
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ use serde::{Deserialize, Serialize};
|
||||||
use swarm_queue_client::agent_limits::{self, AgentCaps};
|
use swarm_queue_client::agent_limits::{self, AgentCaps};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
|
use crate::routes::{AppState, error_problem, wanted_error_status};
|
||||||
use crate::schedules::{live, queue, read_or_default, refused, write_revision};
|
use crate::schedules::{live, queue, read_or_default, refused, write_revision};
|
||||||
use crate::{AppState, error_problem, wanted_error_status};
|
|
||||||
|
|
||||||
/// How many times a losing writer re-reads and re-applies, as in
|
/// How many times a losing writer re-reads and re-applies, as in
|
||||||
/// `wanted::MAX_ATTEMPTS`.
|
/// `wanted::MAX_ATTEMPTS`.
|
||||||
|
|
@ -478,9 +478,9 @@ pub(crate) mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// One hive, `pr1ma`, on `client`.
|
/// One hive, `pr1ma`, on `client`.
|
||||||
pub(crate) fn state(client: &async_nats::Client) -> crate::AppState {
|
pub(crate) fn state(client: &async_nats::Client) -> crate::routes::AppState {
|
||||||
crate::AppState {
|
crate::routes::AppState {
|
||||||
hives: Arc::new(vec![crate::HiveEntry {
|
hives: Arc::new(vec![crate::routes::hives::HiveEntry {
|
||||||
name: "pr1ma".to_owned(),
|
name: "pr1ma".to_owned(),
|
||||||
domain: "pr1ma.example".to_owned(),
|
domain: "pr1ma.example".to_owned(),
|
||||||
dashboard: "pr1ma.hives.example".to_owned(),
|
dashboard: "pr1ma.hives.example".to_owned(),
|
||||||
|
|
@ -516,7 +516,7 @@ pub(crate) mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A state on a real server whose `pr1ma` declares `atlas`.
|
/// A state on a real server whose `pr1ma` declares `atlas`.
|
||||||
pub(crate) async fn declared(client: &async_nats::Client) -> crate::AppState {
|
pub(crate) async fn declared(client: &async_nats::Client) -> crate::routes::AppState {
|
||||||
WantedWriter::new(client.clone())
|
WantedWriter::new(client.clone())
|
||||||
.set("pr1ma", "atlas", AgentState::Up)
|
.set("pr1ma", "atlas", AgentState::Up)
|
||||||
.await
|
.await
|
||||||
|
|
@ -532,7 +532,7 @@ pub(crate) mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn put(
|
async fn put(
|
||||||
state: &crate::AppState,
|
state: &crate::routes::AppState,
|
||||||
agent: &str,
|
agent: &str,
|
||||||
value: Caps,
|
value: Caps,
|
||||||
) -> Result<axum::Json<Caps>, problem_details::ProblemDetails> {
|
) -> Result<axum::Json<Caps>, problem_details::ProblemDetails> {
|
||||||
|
|
@ -544,7 +544,7 @@ pub(crate) mod tests {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get(state: &crate::AppState, agent: &str) -> Caps {
|
async fn get(state: &crate::routes::AppState, agent: &str) -> Caps {
|
||||||
get_agent_limits(State(state.clone()), Path(agent.to_owned()))
|
get_agent_limits(State(state.clone()), Path(agent.to_owned()))
|
||||||
.await
|
.await
|
||||||
.expect("caps are read")
|
.expect("caps are read")
|
||||||
|
|
@ -662,7 +662,7 @@ pub(crate) mod tests {
|
||||||
let _ = put(&state, "atlas", caps(Some("400%"), Some("8G")))
|
let _ = put(&state, "atlas", caps(Some("400%"), Some("8G")))
|
||||||
.await
|
.await
|
||||||
.expect("cap atlas");
|
.expect("cap atlas");
|
||||||
crate::build_app(state)
|
crate::startup::build_app(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn put_raw(app: &axum::Router, body: &'static str) -> StatusCode {
|
async fn put_raw(app: &axum::Router, body: &'static str) -> StatusCode {
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@ use serde::{Deserialize, Serialize};
|
||||||
use swarm_queue_client::agent_permissions::{self, AgentPermissions, Import, ImportReply};
|
use swarm_queue_client::agent_permissions::{self, AgentPermissions, Import, ImportReply};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
|
use crate::routes::{AppState, error_problem, wanted_error_status};
|
||||||
use crate::schedules::{live, queue, read_or_default, refused, write, write_revision};
|
use crate::schedules::{live, queue, read_or_default, refused, write, write_revision};
|
||||||
use crate::wanted::WantedWriter;
|
use crate::wanted::WantedWriter;
|
||||||
use crate::{AppState, error_problem, wanted_error_status};
|
|
||||||
|
|
||||||
/// How many times a losing writer re-reads and re-applies, as in
|
/// How many times a losing writer re-reads and re-applies, as in
|
||||||
/// `wanted::MAX_ATTEMPTS`.
|
/// `wanted::MAX_ATTEMPTS`.
|
||||||
|
|
@ -549,7 +549,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn put(
|
async fn put(
|
||||||
state: &crate::AppState,
|
state: &crate::routes::AppState,
|
||||||
agent: &str,
|
agent: &str,
|
||||||
value: Permissions,
|
value: Permissions,
|
||||||
) -> Result<axum::Json<Permissions>, problem_details::ProblemDetails> {
|
) -> Result<axum::Json<Permissions>, problem_details::ProblemDetails> {
|
||||||
|
|
@ -561,7 +561,7 @@ mod tests {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get(state: &crate::AppState, agent: &str) -> Permissions {
|
async fn get(state: &crate::routes::AppState, agent: &str) -> Permissions {
|
||||||
get_agent_permissions(State(state.clone()), Path(agent.to_owned()))
|
get_agent_permissions(State(state.clone()), Path(agent.to_owned()))
|
||||||
.await
|
.await
|
||||||
.expect("read")
|
.expect("read")
|
||||||
|
|
@ -641,7 +641,7 @@ mod tests {
|
||||||
let client = nats.client().await;
|
let client = nats.client().await;
|
||||||
let state = crate::agent_limits::tests::declared(&client).await;
|
let state = crate::agent_limits::tests::declared(&client).await;
|
||||||
let _ = put(&state, "atlas", granted()).await.expect("set");
|
let _ = put(&state, "atlas", granted()).await.expect("set");
|
||||||
let app = crate::build_app(state);
|
let app = crate::startup::build_app(state);
|
||||||
|
|
||||||
for (body, status) in [
|
for (body, status) in [
|
||||||
(
|
(
|
||||||
|
|
@ -803,9 +803,9 @@ mod tests {
|
||||||
let client = nats.client().await;
|
let client = nats.client().await;
|
||||||
let state = crate::agent_limits::tests::declared(&client).await;
|
let state = crate::agent_limits::tests::declared(&client).await;
|
||||||
let create = |name: &str, permissions| {
|
let create = |name: &str, permissions| {
|
||||||
crate::create_agent(
|
crate::routes::agents::create_agent(
|
||||||
State(state.clone()),
|
State(state.clone()),
|
||||||
axum::Json(crate::CreateAgentRequest {
|
axum::Json(crate::routes::agents::CreateAgentRequest {
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
hive: "pr1ma".to_owned(),
|
hive: "pr1ma".to_owned(),
|
||||||
limits: None,
|
limits: None,
|
||||||
|
|
@ -855,18 +855,18 @@ mod tests {
|
||||||
let state = crate::agent_limits::tests::declared(&client).await;
|
let state = crate::agent_limits::tests::declared(&client).await;
|
||||||
let _ = put(&state, "atlas", granted()).await.expect("set");
|
let _ = put(&state, "atlas", granted()).await.expect("set");
|
||||||
|
|
||||||
let _ = crate::set_agent_state(
|
let _ = crate::routes::agents::set_agent_state(
|
||||||
State(state.clone()),
|
State(state.clone()),
|
||||||
Path(("pr1ma".to_owned(), "atlas".to_owned())),
|
Path(("pr1ma".to_owned(), "atlas".to_owned())),
|
||||||
axum::Json(crate::SetAgentStateRequest {
|
axum::Json(crate::routes::agents::SetAgentStateRequest {
|
||||||
state: swarm_queue_client::wanted::AgentState::Destroyed,
|
state: swarm_queue_client::wanted::AgentState::Destroyed,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.expect("destroyed");
|
.expect("destroyed");
|
||||||
let _ = crate::create_agent(
|
let _ = crate::routes::agents::create_agent(
|
||||||
State(state.clone()),
|
State(state.clone()),
|
||||||
axum::Json(crate::CreateAgentRequest {
|
axum::Json(crate::routes::agents::CreateAgentRequest {
|
||||||
name: "atlas".to_owned(),
|
name: "atlas".to_owned(),
|
||||||
hive: "pr1ma".to_owned(),
|
hive: "pr1ma".to_owned(),
|
||||||
limits: None,
|
limits: None,
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ use axum::extract::{Path, State};
|
||||||
use axum::response::sse::{Event, KeepAlive, Sse};
|
use axum::response::sse::{Event, KeepAlive, Sse};
|
||||||
use futures_util::{Stream, StreamExt as _};
|
use futures_util::{Stream, StreamExt as _};
|
||||||
|
|
||||||
use crate::AppState;
|
use crate::routes::AppState;
|
||||||
|
|
||||||
#[utoipa::path(
|
#[utoipa::path(
|
||||||
get,
|
get,
|
||||||
|
|
@ -60,19 +60,21 @@ pub(crate) async fn stream_agent_state(
|
||||||
Path(agent): Path<String>,
|
Path(agent): Path<String>,
|
||||||
) -> Result<Sse<impl Stream<Item = Result<Event, Infallible>>>, problem_details::ProblemDetails> {
|
) -> Result<Sse<impl Stream<Item = Result<Event, Infallible>>>, problem_details::ProblemDetails> {
|
||||||
let Some(status) = state.status.as_ref() else {
|
let Some(status) = state.status.as_ref() else {
|
||||||
return Err(crate::error_problem(
|
return Err(crate::routes::error_problem(
|
||||||
axum::http::StatusCode::SERVICE_UNAVAILABLE,
|
axum::http::StatusCode::SERVICE_UNAVAILABLE,
|
||||||
"no swarm queue is configured on this host",
|
"no swarm queue is configured on this host",
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let Some(agent_status) = state.agent_status.as_ref() else {
|
let Some(agent_status) = state.agent_status.as_ref() else {
|
||||||
return Err(crate::error_problem(
|
return Err(crate::routes::error_problem(
|
||||||
axum::http::StatusCode::SERVICE_UNAVAILABLE,
|
axum::http::StatusCode::SERVICE_UNAVAILABLE,
|
||||||
"no agent-status reader is configured on this host",
|
"no agent-status reader is configured on this host",
|
||||||
));
|
));
|
||||||
};
|
};
|
||||||
let agent = hive_types::Ident::parse(&agent)
|
let agent = hive_types::Ident::parse(&agent)
|
||||||
.map_err(|reason| crate::error_problem(axum::http::StatusCode::BAD_REQUEST, reason))?
|
.map_err(|reason| {
|
||||||
|
crate::routes::error_problem(axum::http::StatusCode::BAD_REQUEST, reason)
|
||||||
|
})?
|
||||||
.into_string();
|
.into_string();
|
||||||
|
|
||||||
// One-agent "roster": reuses `AgentStatusReader::view`'s already-tested
|
// One-agent "roster": reuses `AgentStatusReader::view`'s already-tested
|
||||||
|
|
@ -84,12 +86,12 @@ pub(crate) async fn stream_agent_state(
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
let detail = format!("{e:#}");
|
let detail = format!("{e:#}");
|
||||||
tracing::warn!(%agent, error = %detail, "state stream: reading agent status failed");
|
tracing::warn!(%agent, error = %detail, "state stream: reading agent status failed");
|
||||||
crate::error_problem(axum::http::StatusCode::INTERNAL_SERVER_ERROR, &detail)
|
crate::routes::error_problem(axum::http::StatusCode::INTERNAL_SERVER_ERROR, &detail)
|
||||||
})?
|
})?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.find_map(|row| row.hive)
|
.find_map(|row| row.hive)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
crate::error_problem(
|
crate::routes::error_problem(
|
||||||
axum::http::StatusCode::NOT_FOUND,
|
axum::http::StatusCode::NOT_FOUND,
|
||||||
&format!("{agent:?} has never reported to the swarm"),
|
&format!("{agent:?} has never reported to the swarm"),
|
||||||
)
|
)
|
||||||
|
|
@ -101,7 +103,7 @@ pub(crate) async fn stream_agent_state(
|
||||||
// against a queue that is not there — the honest answer is 503, the
|
// against a queue that is not there — the honest answer is 503, the
|
||||||
// same shape every other queue-backed route here already uses.
|
// same shape every other queue-backed route here already uses.
|
||||||
swarm_queue_client::ensure_connected(&client).map_err(|e| {
|
swarm_queue_client::ensure_connected(&client).map_err(|e| {
|
||||||
crate::error_problem(
|
crate::routes::error_problem(
|
||||||
axum::http::StatusCode::SERVICE_UNAVAILABLE,
|
axum::http::StatusCode::SERVICE_UNAVAILABLE,
|
||||||
&swarm_queue_client::chain(&e),
|
&swarm_queue_client::chain(&e),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ use swarm_queue_client::AgentControl;
|
||||||
use swarm_queue_client::agents_md::{Apply, ApplyReply, Mirror};
|
use swarm_queue_client::agents_md::{Apply, ApplyReply, Mirror};
|
||||||
|
|
||||||
use crate::agent_control::{ControlSink, Outcome};
|
use crate::agent_control::{ControlSink, Outcome};
|
||||||
use crate::{AppState, error_problem, wanted_error_status};
|
use crate::routes::{AppState, error_problem, wanted_error_status};
|
||||||
|
|
||||||
/// Reads the `agents-md` bucket, the way [`crate::agent_icon::AgentIconReader`]
|
/// Reads the `agents-md` bucket, the way [`crate::agent_icon::AgentIconReader`]
|
||||||
/// reads the icon bucket, and creates it: the agents writing it cannot.
|
/// reads the icon bucket, and creates it: the agents writing it cannot.
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ use problem_details::ProblemDetails;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
use crate::{AppState, error_problem};
|
use crate::routes::{AppState, error_problem};
|
||||||
|
|
||||||
/// The env var `swarm-controller.nix` sets.
|
/// The env var `swarm-controller.nix` sets.
|
||||||
const URL_ENV: &str = "SWARM_CONTROLLER_GRAFANA_URL";
|
const URL_ENV: &str = "SWARM_CONTROLLER_GRAFANA_URL";
|
||||||
|
|
@ -282,12 +282,12 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_alerts_with(grafana: Option<Grafana>) -> (StatusCode, serde_json::Value) {
|
async fn get_alerts_with(grafana: Option<Grafana>) -> (StatusCode, serde_json::Value) {
|
||||||
let (mut state, _) = crate::tests::state_with_roster();
|
let (mut state, _) = crate::routes::tests::state_with_roster();
|
||||||
state.alerts = grafana.map(Arc::new);
|
state.alerts = grafana.map(Arc::new);
|
||||||
let req = Request::get("/api/alerts")
|
let req = Request::get("/api/alerts")
|
||||||
.body(Body::empty())
|
.body(Body::empty())
|
||||||
.expect("a request");
|
.expect("a request");
|
||||||
let res = crate::build_app(state)
|
let res = crate::startup::build_app(state)
|
||||||
.oneshot(req)
|
.oneshot(req)
|
||||||
.await
|
.await
|
||||||
.expect("infallible");
|
.expect("infallible");
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,9 @@ use swarm_wire::builder::{
|
||||||
};
|
};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
|
use crate::routes::{AppState, error_problem};
|
||||||
use crate::schedules::{queue, read_or_default, refused, write};
|
use crate::schedules::{queue, read_or_default, refused, write};
|
||||||
use crate::{AppState, agent_limits, agent_permissions, error_problem, inference};
|
use crate::{agent_limits, agent_permissions, inference};
|
||||||
|
|
||||||
/// How often the builder is asked. Its source only changes when its host is
|
/// How often the builder is asked. Its source only changes when its host is
|
||||||
/// redeployed, so this bounds how long a redeploy takes to reach the create
|
/// redeployed, so this bounds how long a redeploy takes to reach the create
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ use problem_details::ProblemDetails;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
|
use crate::routes::{AppState, error_problem};
|
||||||
use crate::schedules::{read_with, write};
|
use crate::schedules::{read_with, write};
|
||||||
use crate::{AppState, error_problem};
|
|
||||||
|
|
||||||
/// The bucket holding the builds. Agents hold no grant on it.
|
/// The bucket holding the builds. Agents hold no grant on it.
|
||||||
pub const BUCKET: &str = "builder-runs";
|
pub const BUCKET: &str = "builder-runs";
|
||||||
|
|
@ -449,9 +449,9 @@ pub(crate) mod tests {
|
||||||
push(&*doc, &record("b")).await.expect("stored");
|
push(&*doc, &record("b")).await.expect("stored");
|
||||||
|
|
||||||
let get_at = |builds: Builds, path: &'static str| async move {
|
let get_at = |builds: Builds, path: &'static str| async move {
|
||||||
let (mut state, _) = crate::tests::state_with_roster();
|
let (mut state, _) = crate::routes::tests::state_with_roster();
|
||||||
state.builds = builds;
|
state.builds = builds;
|
||||||
let res = crate::build_app(state)
|
let res = crate::startup::build_app(state)
|
||||||
.oneshot(Request::get(path).body(Body::empty()).expect("a request"))
|
.oneshot(Request::get(path).body(Body::empty()).expect("a request"))
|
||||||
.await
|
.await
|
||||||
.expect("infallible");
|
.expect("infallible");
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ use serde::{Deserialize, Serialize};
|
||||||
use swarm_wire::claude_login::{REPLY_DEADLINE, Reply, Request, SUBJECT};
|
use swarm_wire::claude_login::{REPLY_DEADLINE, Reply, Request, SUBJECT};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
use crate::{AppState, error_problem};
|
use crate::routes::{AppState, error_problem};
|
||||||
|
|
||||||
/// The header the gateway names the session's user in.
|
/// The header the gateway names the session's user in.
|
||||||
const OPERATOR_HEADER: &str = "remote-user";
|
const OPERATOR_HEADER: &str = "remote-user";
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ use swarm_secret_client::forge;
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
use super::linked_accounts::link;
|
use super::linked_accounts::link;
|
||||||
use super::{AppState, error_problem, swarm_hive};
|
use crate::routes::agents::swarm_hive;
|
||||||
|
use crate::routes::{AppState, error_problem};
|
||||||
|
|
||||||
/// The account to store for one agent's external forge.
|
/// The account to store for one agent's external forge.
|
||||||
///
|
///
|
||||||
|
|
@ -141,9 +142,9 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bare-minimum `AppState`, as `matrix_account`'s tests build it.
|
/// Bare-minimum `AppState`, as `matrix_account`'s tests build it.
|
||||||
fn state(store: &Arc<FakeStore>) -> super::super::AppState {
|
fn state(store: &Arc<FakeStore>) -> crate::routes::AppState {
|
||||||
super::super::AppState {
|
crate::routes::AppState {
|
||||||
hives: std::sync::Arc::new(vec![super::super::HiveEntry {
|
hives: std::sync::Arc::new(vec![crate::routes::hives::HiveEntry {
|
||||||
name: "pr1ma".to_owned(),
|
name: "pr1ma".to_owned(),
|
||||||
domain: "pr1ma.example".to_owned(),
|
domain: "pr1ma.example".to_owned(),
|
||||||
dashboard: "pr1ma.hives.example".to_owned(),
|
dashboard: "pr1ma.hives.example".to_owned(),
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,8 @@ use swarm_secret_client::github;
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
use super::linked_accounts::link;
|
use super::linked_accounts::link;
|
||||||
use super::{AppState, error_problem, swarm_hive};
|
use crate::routes::agents::swarm_hive;
|
||||||
|
use crate::routes::{AppState, error_problem};
|
||||||
|
|
||||||
/// The token to store for one agent.
|
/// The token to store for one agent.
|
||||||
///
|
///
|
||||||
|
|
@ -111,9 +112,9 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bare-minimum `AppState`, as `forge_account`'s tests build it.
|
/// Bare-minimum `AppState`, as `forge_account`'s tests build it.
|
||||||
fn state(store: &Arc<FakeStore>) -> super::super::AppState {
|
fn state(store: &Arc<FakeStore>) -> crate::routes::AppState {
|
||||||
super::super::AppState {
|
crate::routes::AppState {
|
||||||
hives: std::sync::Arc::new(vec![super::super::HiveEntry {
|
hives: std::sync::Arc::new(vec![crate::routes::hives::HiveEntry {
|
||||||
name: "pr1ma".to_owned(),
|
name: "pr1ma".to_owned(),
|
||||||
domain: "pr1ma.example".to_owned(),
|
domain: "pr1ma.example".to_owned(),
|
||||||
dashboard: "pr1ma.hives.example".to_owned(),
|
dashboard: "pr1ma.hives.example".to_owned(),
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@ use serde::{Deserialize, Serialize};
|
||||||
use swarm_queue_client::agent_inference::{self, AgentInference, Effective, Effort, Source};
|
use swarm_queue_client::agent_inference::{self, AgentInference, Effective, Effort, Source};
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
|
||||||
|
use crate::routes::{AppState, error_problem, wanted_error_status};
|
||||||
use crate::schedules::{live, queue, read_or_default, refused, write_revision};
|
use crate::schedules::{live, queue, read_or_default, refused, write_revision};
|
||||||
use crate::{AppState, error_problem, wanted_error_status};
|
|
||||||
|
|
||||||
/// How many times a losing writer re-reads and re-applies, as in
|
/// How many times a losing writer re-reads and re-applies, as in
|
||||||
/// `wanted::MAX_ATTEMPTS`.
|
/// `wanted::MAX_ATTEMPTS`.
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ use axum::{
|
||||||
extract::{Path, State},
|
extract::{Path, State},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AppState, StatusUnavailable, error_problem};
|
|
||||||
use crate::forge;
|
use crate::forge;
|
||||||
|
use crate::routes::{AppState, StatusUnavailable, error_problem};
|
||||||
|
|
||||||
/// The 503 detail when the forge did not answer within
|
/// The 503 detail when the forge did not answer within
|
||||||
/// [`forge::FORGE_DEADLINE`].
|
/// [`forge::FORGE_DEADLINE`].
|
||||||
|
|
@ -21,7 +21,7 @@ const DEADLINE_DETAIL: &str = "the forge did not answer within the deadline";
|
||||||
|
|
||||||
/// Repos with at least one open issue, as `owner/name` full names — the
|
/// Repos with at least one open issue, as `owner/name` full names — the
|
||||||
/// data source for swarm-ui's repo-filter dropdown. Not scoped to
|
/// data source for swarm-ui's repo-filter dropdown. Not scoped to
|
||||||
/// `forge::CONFIG_ORG` the way `main.rs`'s `get_config_prs` is: this
|
/// `forge::CONFIG_ORG` the way `routes/config_prs.rs`'s `get_config_prs` is: this
|
||||||
/// report deliberately covers the whole forge instance, not one org, since
|
/// report deliberately covers the whole forge instance, not one org, since
|
||||||
/// the report itself is a general-purpose browsing tool rather than
|
/// the report itself is a general-purpose browsing tool rather than
|
||||||
/// something agent-config-specific.
|
/// something agent-config-specific.
|
||||||
|
|
@ -156,7 +156,7 @@ pub async fn get_issue_report(
|
||||||
///
|
///
|
||||||
/// `Client::issue_report` propagates through `anyhow`, so the concrete
|
/// `Client::issue_report` propagates through `anyhow`, so the concrete
|
||||||
/// [`forgejo_api::ForgejoError`] survives underneath but is not the type in
|
/// [`forgejo_api::ForgejoError`] survives underneath but is not the type in
|
||||||
/// hand — downcasting back to it, same pattern `main.rs`'s
|
/// hand — downcasting back to it, same pattern `routes`'s
|
||||||
/// `wanted_error_status` uses for `swarm_queue_client::Error`. A 404 there
|
/// `wanted_error_status` uses for `swarm_queue_client::Error`. A 404 there
|
||||||
/// (`forge::is_repo_not_found`) means the repo itself doesn't exist;
|
/// (`forge::is_repo_not_found`) means the repo itself doesn't exist;
|
||||||
/// anything else — including a 404 on some *other* call this function
|
/// anything else — including a 404 on some *other* call this function
|
||||||
|
|
@ -257,7 +257,7 @@ mod tests {
|
||||||
"/api/issue-report",
|
"/api/issue-report",
|
||||||
"/api/repos/o/r/issue-report",
|
"/api/repos/o/r/issue-report",
|
||||||
] {
|
] {
|
||||||
let (state, _) = crate::tests::state_with_roster();
|
let (state, _) = crate::routes::tests::state_with_roster();
|
||||||
assert!(
|
assert!(
|
||||||
state
|
state
|
||||||
.forge
|
.forge
|
||||||
|
|
@ -268,7 +268,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
let start = tokio::time::Instant::now();
|
let start = tokio::time::Instant::now();
|
||||||
let req = Request::get(uri).body(Body::empty()).expect("a request");
|
let req = Request::get(uri).body(Body::empty()).expect("a request");
|
||||||
let res = crate::build_app(state)
|
let res = crate::startup::build_app(state)
|
||||||
.oneshot(req)
|
.oneshot(req)
|
||||||
.await
|
.await
|
||||||
.expect("infallible");
|
.expect("infallible");
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue