lifecycle::spawn through meta
after setup_proposed + setup_applied, spawn now syncs the meta flake (one input + one nixosConfiguration per agent) so `--flake /var/lib/hyperhive/meta#<name>` resolves before nixos-container create runs. flake ref switches from applied/<n>#default to meta#<name>; the wrapper modules (identity, HIVE_PORT, HIVE_LABEL, HIVE_DASHBOARD_PORT) now live in the meta flake's mkAgent. new helper agents_for_meta builds the AgentSpec list by enumerating containers + optionally appending a not-yet-present name for the spawn case. spawn keeps its caller signature; rebuild + auto_update get wired up in follow-up commits.
This commit is contained in:
parent
c42ad1330c
commit
8f94e4379a
1 changed files with 49 additions and 6 deletions
|
|
@ -139,16 +139,13 @@ async fn port_collision(self_name: &str) -> Option<String> {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub async fn spawn(
|
pub async fn spawn(
|
||||||
name: &str,
|
name: &str,
|
||||||
// hyperhive_flake + dashboard_port are unused now that the meta
|
hyperhive_flake: &str,
|
||||||
// flake owns the wrapper; left here as the caller surface settles
|
|
||||||
// — meta-module landing will remove them in a follow-up.
|
|
||||||
_hyperhive_flake: &str,
|
|
||||||
agent_dir: &Path,
|
agent_dir: &Path,
|
||||||
proposed_dir: &Path,
|
proposed_dir: &Path,
|
||||||
applied_dir: &Path,
|
applied_dir: &Path,
|
||||||
claude_dir: &Path,
|
claude_dir: &Path,
|
||||||
notes_dir: &Path,
|
notes_dir: &Path,
|
||||||
_dashboard_port: u16,
|
dashboard_port: u16,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
validate(name)?;
|
validate(name)?;
|
||||||
if let Some(other) = port_collision(name).await {
|
if let Some(other) = port_collision(name).await {
|
||||||
|
|
@ -161,8 +158,13 @@ pub async fn spawn(
|
||||||
setup_applied(applied_dir, Some(proposed_dir), name).await?;
|
setup_applied(applied_dir, Some(proposed_dir), name).await?;
|
||||||
ensure_claude_dir(claude_dir)?;
|
ensure_claude_dir(claude_dir)?;
|
||||||
ensure_state_dir(notes_dir)?;
|
ensure_state_dir(notes_dir)?;
|
||||||
|
// Meta flake gets the new agent's input + nixosConfiguration
|
||||||
|
// before `nixos-container create` so the `--flake meta#<name>`
|
||||||
|
// ref resolves.
|
||||||
|
let agents = agents_after_spawn(name).await?;
|
||||||
|
crate::meta::sync_agents(hyperhive_flake, dashboard_port, &agents).await?;
|
||||||
let container = container_name(name);
|
let container = container_name(name);
|
||||||
let flake_ref = format!("{}#default", applied_dir.display());
|
let flake_ref = format!("{}#{name}", crate::meta::meta_dir().display());
|
||||||
run(&["create", &container, "--flake", &flake_ref]).await?;
|
run(&["create", &container, "--flake", &flake_ref]).await?;
|
||||||
set_nspawn_flags(&container, agent_dir, claude_dir, notes_dir)?;
|
set_nspawn_flags(&container, agent_dir, claude_dir, notes_dir)?;
|
||||||
set_resource_limits(&container)?;
|
set_resource_limits(&container)?;
|
||||||
|
|
@ -170,6 +172,47 @@ pub async fn spawn(
|
||||||
run(&["start", &container]).await
|
run(&["start", &container]).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build the `AgentSpec` list for the meta flake from `nixos-container
|
||||||
|
/// list` + a hypothetical extra name not yet in the list (for spawn
|
||||||
|
/// where the new agent's container doesn't exist yet). Pass empty
|
||||||
|
/// `name_to_add` from rebuild paths where the agent is already in the
|
||||||
|
/// container list.
|
||||||
|
async fn agents_for_meta(name_to_add: Option<&str>) -> Result<Vec<crate::meta::AgentSpec>> {
|
||||||
|
let containers = list().await.unwrap_or_default();
|
||||||
|
let mut out: Vec<crate::meta::AgentSpec> = containers
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|c| {
|
||||||
|
let (name, is_manager) = if c == MANAGER_NAME {
|
||||||
|
(MANAGER_NAME.to_owned(), true)
|
||||||
|
} else if let Some(n) = c.strip_prefix(AGENT_PREFIX) {
|
||||||
|
(n.to_owned(), false)
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
Some(crate::meta::AgentSpec {
|
||||||
|
port: agent_web_port(&name),
|
||||||
|
name,
|
||||||
|
is_manager,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
if let Some(extra) = name_to_add
|
||||||
|
&& !out.iter().any(|a| a.name == extra)
|
||||||
|
{
|
||||||
|
out.push(crate::meta::AgentSpec {
|
||||||
|
name: extra.to_owned(),
|
||||||
|
is_manager: is_manager(extra),
|
||||||
|
port: agent_web_port(extra),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
out.sort_by(|a, b| a.name.cmp(&b.name));
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn agents_after_spawn(name: &str) -> Result<Vec<crate::meta::AgentSpec>> {
|
||||||
|
agents_for_meta(Some(name)).await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn kill(name: &str) -> Result<()> {
|
pub async fn kill(name: &str) -> Result<()> {
|
||||||
validate(name)?;
|
validate(name)?;
|
||||||
let container = container_name(name);
|
let container = container_name(name);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue