swarmctl shares the create-agent, inference and permissions shapes with the controller
This commit is contained in:
parent
249aab6642
commit
0831b85b73
26 changed files with 675 additions and 434 deletions
|
|
@ -19,7 +19,8 @@ use backon::{ConstantBuilder, Retryable as _};
|
|||
use futures_util::StreamExt as _;
|
||||
use hive_types::Permission;
|
||||
use problem_details::ProblemDetails;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Serialize;
|
||||
use swarm_controller_api::permissions::Permissions;
|
||||
use swarm_queue_client::agent_permissions;
|
||||
use swarm_wire::agent_permissions::{
|
||||
AgentPermissions, Import, ImportReply, hive_from_import_subject, import_subject_wildcard,
|
||||
|
|
@ -34,28 +35,14 @@ use crate::wanted::WantedWriter;
|
|||
/// `wanted::MAX_ATTEMPTS`.
|
||||
const MAX_ATTEMPTS: usize = 5;
|
||||
|
||||
/// One agent's permissions. A field left out is not set by the swarm, and the
|
||||
/// compiled-in default applies; an empty list grants nothing.
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Permissions {
|
||||
/// Permission names, `snake_case`: `messaging`, `meta`, `inbox`,
|
||||
/// `execution`, `web_tools`, `manage_root_agent`.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
#[schema(value_type = Option<Vec<String>>, example = json!(["messaging", "meta", "inbox", "execution"]))]
|
||||
permissions: Option<Vec<Permission>>,
|
||||
}
|
||||
|
||||
impl Permissions {
|
||||
/// The value to store, or why it is refused.
|
||||
fn into_stored(self) -> Result<AgentPermissions, String> {
|
||||
if let Some(perms) = &self.permissions {
|
||||
unique(perms)?;
|
||||
}
|
||||
Ok(AgentPermissions {
|
||||
permissions: self.permissions,
|
||||
})
|
||||
/// The permissions to store, or why they are refused.
|
||||
fn into_stored(req: Permissions) -> Result<AgentPermissions, String> {
|
||||
if let Some(perms) = &req.permissions {
|
||||
unique(perms)?;
|
||||
}
|
||||
Ok(AgentPermissions {
|
||||
permissions: req.permissions,
|
||||
})
|
||||
}
|
||||
|
||||
/// Refuse a list that names a permission twice.
|
||||
|
|
@ -70,11 +57,10 @@ pub(crate) fn unique(perms: &[Permission]) -> Result<(), String> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
impl From<AgentPermissions> for Permissions {
|
||||
fn from(v: AgentPermissions) -> Self {
|
||||
Self {
|
||||
permissions: v.permissions,
|
||||
}
|
||||
/// The stored permissions as the API shows them.
|
||||
fn view(v: AgentPermissions) -> Permissions {
|
||||
Permissions {
|
||||
permissions: v.permissions,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -122,7 +108,7 @@ pub(crate) async fn get_agent_permissions(
|
|||
let (current, _, _) = read_or_default::<AgentPermissions>(&store, &agent)
|
||||
.await
|
||||
.map_err(|e| queue_problem(&e))?;
|
||||
Ok(Json(current.into()))
|
||||
Ok(Json(view(current)))
|
||||
}
|
||||
|
||||
/// Set the permissions the swarm grants one agent.
|
||||
|
|
@ -153,9 +139,7 @@ pub(crate) async fn put_agent_permissions(
|
|||
Json(req): Json<Permissions>,
|
||||
) -> Result<Json<Permissions>, ProblemDetails> {
|
||||
let agent = agent_name(&name).map_err(refused)?;
|
||||
let value = req
|
||||
.into_stored()
|
||||
.map_err(|why| error_problem(StatusCode::BAD_REQUEST, &why))?;
|
||||
let value = into_stored(req).map_err(|why| error_problem(StatusCode::BAD_REQUEST, &why))?;
|
||||
let client = queue(&state).map_err(refused)?;
|
||||
if !live(&state).await?.contains(&agent) {
|
||||
return Err(error_problem(
|
||||
|
|
@ -174,7 +158,7 @@ pub(crate) async fn put_agent_permissions(
|
|||
.map_err(|e| queue_problem(&e))?
|
||||
{
|
||||
tracing::info!(%agent, ?value, "set agent permissions");
|
||||
return Ok(Json(value.into()));
|
||||
return Ok(Json(view(value)));
|
||||
}
|
||||
}
|
||||
Err(queue_problem(&anyhow::anyhow!(
|
||||
|
|
@ -808,7 +792,7 @@ mod tests {
|
|||
let create = |name: &str, permissions| {
|
||||
crate::routes::agents::create_agent(
|
||||
State(state.clone()),
|
||||
axum::Json(crate::routes::agents::CreateAgentRequest {
|
||||
axum::Json(swarm_controller_api::agents::CreateAgentRequest {
|
||||
name: name.to_owned(),
|
||||
hive: "pr1ma".to_owned(),
|
||||
limits: None,
|
||||
|
|
@ -870,7 +854,7 @@ mod tests {
|
|||
.expect("destroyed");
|
||||
let _ = crate::routes::agents::create_agent(
|
||||
State(state.clone()),
|
||||
axum::Json(crate::routes::agents::CreateAgentRequest {
|
||||
axum::Json(swarm_controller_api::agents::CreateAgentRequest {
|
||||
name: "atlas".to_owned(),
|
||||
hive: "pr1ma".to_owned(),
|
||||
limits: None,
|
||||
|
|
|
|||
Loading…
Reference in a new issue