Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/hivectl/src/power.rs
atlas d4f3d1ef8e hive: stop controlling the swarm's forge and matrix containers
The forge and matrix are swarm services; per mara's ruling on #5475
(shape a) a hive no longer starts, stops or restarts them.

- hive-priv-sock: InfraContainer keeps only Gateway; InfraTarget goes,
  service_unit maps the gateway to nginx.service directly. A
  ControlInfraContainer naming Forge/Matrix fails to decode.
- hive-host-sock: LifecycleScope drops forge/matrix and refuses unknown
  fields, so an older hivectl's --forge is an error rather than an
  all-false scope meaning everything.
- hive-c0re: scoped_infra selects only the gateway.
- hivectl: --forge/--matrix removed from stop/start/restart.
- docs: services.md says how the forge and matrix are managed;
  security.md, coordinator.md and hivectl-cli.md follow.
- hive-host-sock, hivectl/power.rs: Stop and RestartScoped doc comments name the gateway (host nginx.service), not infra containers.
2026-10-17 23:27:44 +02:00

71 lines
2.8 KiB
Rust

//! `hivectl stop` / `start` / `restart` — hive-wide + scoped container
//! lifecycle. Each verb makes one daemon call and renders the queued DAGs.
use std::path::Path;
use anyhow::{Context as _, Result};
use crate::dag_progress::wait_for_nodes;
use crate::util::render_lifecycle;
pub(crate) async fn stop(
socket: &Path,
scope: hive_host_sock::LifecycleScope,
graceful: bool,
no_wait: bool,
) -> Result<()> {
let resp = crate::client::request(
socket,
hive_host_sock::HostRequest::Stop { scope, graceful },
)
.await
.with_context(|| format!("connect to daemon socket {}", socket.display()))?;
// Render first, but even when an infra failure makes it bail,
// watch the already-queued agent DAGs before surfacing the error —
// they run regardless.
let rendered = render_lifecycle(&resp, "stop queued");
wait_for_nodes(socket, resp.queued_dags.unwrap_or_default(), no_wait).await?;
rendered
}
pub(crate) async fn start(
socket: &Path,
scope: hive_host_sock::LifecycleScope,
no_wait: bool,
) -> Result<()> {
let resp = crate::client::request(socket, hive_host_sock::HostRequest::Start { scope })
.await
.with_context(|| format!("connect to daemon socket {}", socket.display()))?;
let rendered = render_lifecycle(&resp, "start queued");
wait_for_nodes(socket, resp.queued_dags.unwrap_or_default(), no_wait).await?;
rendered
}
/// Restart — one `RestartScoped` daemon call, server-side DAG-based (see
/// issue tracker "dagify hivectl commands"). Each targeted agent rides
/// exactly one atomic DAG queued up front — `Restart` (mechanical stop +
/// reconcile), or `GracefulRestart` with `--graceful` (signal → drain →
/// mechanical stop → reconcile); the gateway (host `nginx.service`) restarts synchronously.
/// No "submit one DAG, wait for it, submit another" composition on either
/// side of the wire: unlike the old client-side stop-then-start compose, a
/// dropped `hivectl` connection mid-restart no longer leaves an agent
/// stopped with no automatic follow-up — the daemon owns the whole
/// sequence once this call is made.
///
/// No `--no-wait` here on purpose, same as before: the operator wants to
/// see the restart actually land, not just get queued.
pub(crate) async fn restart(
socket: &Path,
scope: hive_host_sock::LifecycleScope,
graceful: bool,
) -> Result<()> {
let resp = crate::client::request(
socket,
hive_host_sock::HostRequest::RestartScoped { scope, graceful },
)
.await
.with_context(|| format!("connect to daemon socket {}", socket.display()))?;
let rendered = render_lifecycle(&resp, "restart queued");
wait_for_nodes(socket, resp.queued_dags.unwrap_or_default(), false).await?;
rendered
}