fix(missions): a microvm mission could not be created at all
`runtime_kind='microvm'` passes the DB CHECK, is honoured by placement, and now has an executor — but `POST /api/missions` rejected the value with 400, so the only interface that creates missions could not produce one. And `backend`, which selects the per-CLI rootfs, was not in the create payload at all: it existed as a column and as a parameter to `vm_create`, with nothing able to set it. microvm needs no target_node_id at create time, unlike local_herdr: placement resolves a KVM-capable node at launch and fails the launch when there is none, so an explicit target is a request rather than a requirement. 461 tests pass, clippy clean. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
0206be68e5
commit
c9b7d8b6ca
@@ -38,6 +38,9 @@ pub struct CreateMissionRequest {
|
|||||||
/// Defaults to "zeroclaw". "local_herdr" requires target_node_id.
|
/// Defaults to "zeroclaw". "local_herdr" requires target_node_id.
|
||||||
pub runtime_kind: Option<String>,
|
pub runtime_kind: Option<String>,
|
||||||
pub target_node_id: Option<Uuid>,
|
pub target_node_id: Option<Uuid>,
|
||||||
|
/// Which per-CLI rootfs a `microvm` mission boots (`missions.backend`), e.g.
|
||||||
|
/// "claude". NULL boots the node's default image.
|
||||||
|
pub backend: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn default_schedule() -> Value {
|
fn default_schedule() -> Value {
|
||||||
@@ -260,6 +263,12 @@ pub async fn create(
|
|||||||
return Err(ApiError::BadRequest);
|
return Err(ApiError::BadRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// microvm needs no target here: placement resolves a KVM-capable node at
|
||||||
|
// launch and fails the launch when there is none, so an explicit target is
|
||||||
|
// a request rather than a requirement. Rejecting the value outright — as
|
||||||
|
// this did until B4.5 — made `runtime_kind='microvm'` unreachable through
|
||||||
|
// the only interface that creates missions.
|
||||||
|
"microvm" => {}
|
||||||
_ => return Err(ApiError::BadRequest),
|
_ => return Err(ApiError::BadRequest),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,6 +284,7 @@ pub async fn create(
|
|||||||
config: body.config,
|
config: body.config,
|
||||||
runtime_kind: Some(runtime_kind),
|
runtime_kind: Some(runtime_kind),
|
||||||
target_node_id: body.target_node_id,
|
target_node_id: body.target_node_id,
|
||||||
|
backend: body.backend.as_deref(),
|
||||||
phases: phases_for_create(
|
phases: phases_for_create(
|
||||||
crate::workflow_registry::get(body.template_kind.trim()),
|
crate::workflow_registry::get(body.template_kind.trim()),
|
||||||
body.phases,
|
body.phases,
|
||||||
|
|||||||
@@ -129,6 +129,10 @@ pub struct NewMission<'a> {
|
|||||||
/// Defaults to 'zeroclaw' when None.
|
/// Defaults to 'zeroclaw' when None.
|
||||||
pub runtime_kind: Option<&'a str>,
|
pub runtime_kind: Option<&'a str>,
|
||||||
pub target_node_id: Option<Uuid>,
|
pub target_node_id: Option<Uuid>,
|
||||||
|
/// Which per-CLI image a `microvm` mission boots. NULL = the node's default
|
||||||
|
/// rootfs. Deliberately unconstrained in the schema: which images exist is a
|
||||||
|
/// property of the NODES, not of the database.
|
||||||
|
pub backend: Option<&'a str>,
|
||||||
pub phases: Vec<NewMissionPhase>,
|
pub phases: Vec<NewMissionPhase>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,9 +161,9 @@ pub async fn insert(pool: &PgPool, m: NewMission<'_>) -> Result<Uuid, DbError> {
|
|||||||
"INSERT INTO missions
|
"INSERT INTO missions
|
||||||
(id, workspace_id, title, template_kind, team_id,
|
(id, workspace_id, title, template_kind, team_id,
|
||||||
team_template_id, repo_id, schedule, status, description, config,
|
team_template_id, repo_id, schedule, status, description, config,
|
||||||
runtime_kind, target_node_id)
|
runtime_kind, target_node_id, backend)
|
||||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,'draft',$9,$10,
|
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,'draft',$9,$10,
|
||||||
COALESCE($11,'zeroclaw'),$12)",
|
COALESCE($11,'zeroclaw'),$12,$13)",
|
||||||
)
|
)
|
||||||
.bind(mission_id)
|
.bind(mission_id)
|
||||||
.bind(m.workspace_id)
|
.bind(m.workspace_id)
|
||||||
@@ -173,6 +177,7 @@ pub async fn insert(pool: &PgPool, m: NewMission<'_>) -> Result<Uuid, DbError> {
|
|||||||
.bind(&m.config)
|
.bind(&m.config)
|
||||||
.bind(m.runtime_kind)
|
.bind(m.runtime_kind)
|
||||||
.bind(m.target_node_id)
|
.bind(m.target_node_id)
|
||||||
|
.bind(m.backend)
|
||||||
.execute(&mut *tx)
|
.execute(&mut *tx)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user