Phase 7c: ApprovalResolved helper events into manager's inbox
This commit is contained in:
parent
7c1ed07cf2
commit
1ceabae892
3 changed files with 76 additions and 12 deletions
|
|
@ -9,7 +9,7 @@ use std::time::Duration;
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{Result, bail};
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use hive_ag3nt::{DEFAULT_SOCKET, DEFAULT_WEB_PORT, client, web_ui};
|
use hive_ag3nt::{DEFAULT_SOCKET, DEFAULT_WEB_PORT, client, web_ui};
|
||||||
use hive_sh4re::{ManagerRequest, ManagerResponse};
|
use hive_sh4re::{HelperEvent, ManagerRequest, ManagerResponse, SYSTEM_SENDER};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(name = "hive-m1nd", about = "hyperhive manager harness")]
|
#[command(name = "hive-m1nd", about = "hyperhive manager harness")]
|
||||||
|
|
@ -94,7 +94,14 @@ async fn serve(socket: &Path, interval: Duration) -> Result<()> {
|
||||||
let recv: Result<ManagerResponse> = client::request(socket, &ManagerRequest::Recv).await;
|
let recv: Result<ManagerResponse> = client::request(socket, &ManagerRequest::Recv).await;
|
||||||
match recv {
|
match recv {
|
||||||
Ok(ManagerResponse::Message { from, body }) => {
|
Ok(ManagerResponse::Message { from, body }) => {
|
||||||
tracing::info!(%from, %body, "manager inbox");
|
if from == SYSTEM_SENDER {
|
||||||
|
match serde_json::from_str::<HelperEvent>(&body) {
|
||||||
|
Ok(event) => tracing::info!(?event, "helper event"),
|
||||||
|
Err(_) => tracing::info!(%from, %body, "system message"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tracing::info!(%from, %body, "manager inbox");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(ManagerResponse::Empty) => {}
|
Ok(ManagerResponse::Empty) => {}
|
||||||
Ok(ManagerResponse::Ok) => {
|
Ok(ManagerResponse::Ok) => {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@
|
||||||
//! shape they want (HTTP redirect vs JSON).
|
//! shape they want (HTTP redirect vs JSON).
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use hive_sh4re::{
|
||||||
|
ApprovalStatus, HelperEvent, MANAGER_AGENT, Message, SYSTEM_SENDER,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::coordinator::Coordinator;
|
use crate::coordinator::Coordinator;
|
||||||
use crate::lifecycle;
|
use crate::lifecycle;
|
||||||
|
|
@ -11,7 +14,8 @@ use crate::lifecycle;
|
||||||
/// Approve a pending request: read the agent.nix at the approval's commit from
|
/// Approve a pending request: read the agent.nix at the approval's commit from
|
||||||
/// the proposed repo, copy into the applied repo, commit there, and rebuild
|
/// the proposed repo, copy into the applied repo, commit there, and rebuild
|
||||||
/// the agent container. On failure marks the approval failed (with the error
|
/// the agent container. On failure marks the approval failed (with the error
|
||||||
/// note) and returns the error.
|
/// note) and returns the error. Either way, an `ApprovalResolved` helper event
|
||||||
|
/// is pushed into the manager's inbox.
|
||||||
pub async fn approve(coord: &Coordinator, id: i64) -> Result<()> {
|
pub async fn approve(coord: &Coordinator, id: i64) -> Result<()> {
|
||||||
let approval = coord.approvals.mark_approved(id)?;
|
let approval = coord.approvals.mark_approved(id)?;
|
||||||
tracing::info!(%approval.id, %approval.agent, %approval.commit_ref, "approval: applying + rebuilding");
|
tracing::info!(%approval.id, %approval.agent, %approval.commit_ref, "approval: applying + rebuilding");
|
||||||
|
|
@ -30,16 +34,70 @@ pub async fn approve(coord: &Coordinator, id: i64) -> Result<()> {
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
.await;
|
.await;
|
||||||
if let Err(e) = result {
|
match result {
|
||||||
let note = format!("{e:#}");
|
Ok(()) => {
|
||||||
let _ = coord.approvals.mark_failed(approval.id, ¬e);
|
notify_manager(
|
||||||
return Err(e);
|
coord,
|
||||||
|
&HelperEvent::ApprovalResolved {
|
||||||
|
id: approval.id,
|
||||||
|
agent: approval.agent.clone(),
|
||||||
|
commit_ref: approval.commit_ref.clone(),
|
||||||
|
status: ApprovalStatus::Approved,
|
||||||
|
note: None,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
let note = format!("{e:#}");
|
||||||
|
let _ = coord.approvals.mark_failed(approval.id, ¬e);
|
||||||
|
notify_manager(
|
||||||
|
coord,
|
||||||
|
&HelperEvent::ApprovalResolved {
|
||||||
|
id: approval.id,
|
||||||
|
agent: approval.agent.clone(),
|
||||||
|
commit_ref: approval.commit_ref.clone(),
|
||||||
|
status: ApprovalStatus::Failed,
|
||||||
|
note: Some(note),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deny(coord: &Coordinator, id: i64) -> Result<()> {
|
||||||
|
let approval = coord.approvals.get(id)?;
|
||||||
|
coord.approvals.mark_denied(id)?;
|
||||||
|
tracing::info!(%id, "approval denied");
|
||||||
|
if let Some(a) = approval {
|
||||||
|
notify_manager(
|
||||||
|
coord,
|
||||||
|
&HelperEvent::ApprovalResolved {
|
||||||
|
id: a.id,
|
||||||
|
agent: a.agent,
|
||||||
|
commit_ref: a.commit_ref,
|
||||||
|
status: ApprovalStatus::Denied,
|
||||||
|
note: None,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deny(coord: &Coordinator, id: i64) -> Result<()> {
|
fn notify_manager(coord: &Coordinator, event: &HelperEvent) {
|
||||||
coord.approvals.mark_denied(id)?;
|
let body = match serde_json::to_string(event) {
|
||||||
tracing::info!(%id, "approval denied");
|
Ok(s) => s,
|
||||||
Ok(())
|
Err(e) => {
|
||||||
|
tracing::warn!(error = ?e, "failed to encode helper event");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Err(e) = coord.broker.send(&Message {
|
||||||
|
from: SYSTEM_SENDER.to_owned(),
|
||||||
|
to: MANAGER_AGENT.to_owned(),
|
||||||
|
body,
|
||||||
|
}) {
|
||||||
|
tracing::warn!(error = ?e, "failed to push helper event to manager");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,6 @@ impl Approvals {
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)] // used by Phase 5b commit verification
|
|
||||||
pub fn get(&self, id: i64) -> Result<Option<Approval>> {
|
pub fn get(&self, id: i64) -> Result<Option<Approval>> {
|
||||||
let conn = self.conn.lock().unwrap();
|
let conn = self.conn.lock().unwrap();
|
||||||
conn.query_row(
|
conn.query_row(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue