Response
The server sends the id, one of five refusals, or an error, as the first response; after the id it sends active whenever an exchange is in flight where none was and inactive carrying the rotating secrets whenever the last in flight is answered, and nothing else until the finish but the proxy’s error, relayed, when the secrets could not be collected; the finish carries no error.
The server sends the id; or one of five refusals — the volume that refused the run, named, and why; or an error; and, after the id, zero or more periods of activity: for each, the word that an MCP exchange is in flight where none was, and the word that the last in flight was answered, carrying the rotating secrets the program handed back, for the life of the run. The response finish ends the scope. No frame bearing the scope follows the finish.
[0][id JSON …] once, when the container is running
[1][volume-held JSON …] once, when an operation holds a named volume
[2][volume-mounted JSON …] once, when a running container holds a named volume and the server mounts a volume of its mode once
[3][volume-fuse-served JSON …] once, when a FUSE serve holds a named volume and the server does not mount a volume of its mode beside one
[4][volume-mount-unsupported JSON …] once, when the server does not mount a volume of a named volume's mode
[5][volume-mode JSON …] once, when a named volume is not in the mode its mount names
[6][error JSON …] once, when it is not running for another reason, or after the id when the proxy ends the begin with an error
[7] active: an exchange is in flight where none was
[8][values JSON …] inactive: the last exchange in flight was answered, and these are the rotating secrets
- The sequence. Before the id, the server sends no response.
The first response is the id, one of the five refusals, or an
error. A refusal and an error before the id are each followed by
the response finish, and the container is not running and will not
be. After the id, the server sends zero or more periods of
activity, and no other response until the finish but, at most
once, the error with which the proxy ended the begin scope, the
byte
6followed by it, which the response finish follows. A period of activity is exactly one response whose payload is the byte7and nothing else, followed by exactly one response whose first byte is8, or, where the proxy could not collect the rotating secrets, by the error. The finish carries no error: a run that ended after its id ended by the client’s stop, by the container’s own end, by the proxy’s error, or by the client’s connection ending. A response finish that no response precedes states that the request was not served, as Endpoints provides, or that the run ended before the server had an id to send. - The id. A payload whose first byte is
0carries the id after that byte as JSON, an object with the memberid, a string. The server sends it after every FUSE mount is complete and after the container is registered and, where its program declared a secret, fed, as containers::tools::run states. - The refusals, and their order. The server decides
the bytes
1to5for each distinctvolume_namethe request names, in the order first named, in the order Capabilities states, the first rule that applies deciding; a refusal of any volume gives back every volume held for the request before it. Every refusal is sent before the server fetches or deploys anything, the finish follows it, and the container was not started. - Volume held. A payload whose first byte is
1carries, after that byte as JSON, an object with the membername, a string: thevolume_nameof a volume the request named that is under a volumes::stat, volumes::read, volumes::write, volumes::filetree, volumes::edit or volumes::delete at the time of the request. - Volume mounted. A payload whose first byte is
2carries, after that byte as JSON, an object with the membername, a string: thevolume_nameof a volume the request named that a running container of the client holds at the time of the request, on a server whose mode object for the volume’s mode hasmount_manyfalse. A volume a running container holds does not refuse a run wheremount_manyistrue. - Volume FUSE served. A payload whose first byte is
3carries, after that byte as JSON, an object with the membername, a string: thevolume_nameof a volume the request named that a volumes::fuse_serve of the client holds at the time of the request, on a server whose mode object for the volume’s mode hasmount_and_fuse_servefalse. A volume a FUSE serve holds does not refuse a run wheremount_and_fuse_serveistrue. - Volume mount unsupported. A payload whose first byte is
4carries, after that byte as JSON, an object with the membername, a string: thevolume_nameof a volume the request named whosemodethe server holds out no mode object for, or whose mode object hasmountfalse. The volume is as it was. - Volume mode. A payload whose first byte is
5carries, after that byte as JSON, an object with the membersname, a string, andmode, a string: thevolume_nameof a volume the request named under amodethe volume is not in, and the mode the volume is in, as the client’s listing reports it, one ofpersistent,ephemeralandread_only. The volume is as it was. A request naming one volume under two modes is answered the same way, with the mode the volume is in. - The error. A payload whose first byte is
6carries an error after that byte, exactly one JSON value in the form defined on the volumes::list response page. Before the id, this revision prescribes nothing about its content. After the id, the server sends it only when the proxy ends the begin scope with an error, as the begin response states, and the bytes after the byte6are the proxy’s error verbatim: it names a secret and carries no value. - Active and inactive. A payload that is the byte
7and nothing else states that an MCP exchange is in flight where none was: one of the four exchanges the client opens into the container’s own MCP server — on an mcp-list-tools, mcp-list-resources, mcp-call-tool or mcp-read-resource channel; an mcp-notifications channel is no exchange — is about to be delivered, and none was in flight. A payload whose first byte is8states that the last exchange in flight was answered and the program handed back its rotating secrets. The server sends each exactly as the proxy sent it on the begin response, where the proxy produces both and relays neither from the program. The server sends no byte7before the id, none while a period of activity is open, and no byte8while none is. - The values. The bytes after the byte
8are a JSON object whose every member is the name of a secret the container’s program declaredrotating, to the value the program leaves in it, any JSON value: everyrotatingname the program declared, and no other; the empty object for a program that declared nonerotating. The server sends the object exactly as the proxy sent it and reads none of it. From the byte8the container holds no values, and the proxy delivers no exchange to a program that declared a secret until the client feeds them again on the secrets channel. - Malformed. A payload with no byte, a payload whose first byte
is none of
0to8, a payload whose bytes after0do not parse as the id, a payload whose bytes after1,2,3,4or5do not parse as that refusal, a payload whose bytes after8do not parse as the values, and a payload whose bytes after6are not one JSON value are malformed. A payload whose first byte is7is read by that byte alone; bytes after it are not read.
The response is defined by diverge-sdk-rs/src/provider/endpoints/containers/tools/run/server/response/frame.rs:
//! What a server's response frame carries for a tool container run.
use std::fmt;
use crate::wire::decode::Decode;
use crate::wire::encode::{Encode, Writer};
use crate::shared::containers::response::{
Id, VolumeFuseServed, VolumeHeld, VolumeMode, VolumeMountUnsupported, VolumeMounted,
};
use crate::shared::containers::secrets::Values;
use crate::shared::error::Error;
/// A run's answer: the container's id, then the proxy's word whenever
/// the container goes active and inactive, for as long as the scope
/// lives — or the volume that refused it, or a failure.
///
/// A payload leads with one byte saying which — `0` for
/// [`Id`](Self::Id), `1` for [`VolumeHeld`](Self::VolumeHeld), `2`
/// for [`VolumeMounted`](Self::VolumeMounted), `3` for
/// [`VolumeFuseServed`](Self::VolumeFuseServed), `4` for
/// [`VolumeMountUnsupported`](Self::VolumeMountUnsupported), `5` for
/// [`VolumeMode`](Self::VolumeMode), `6` for
/// [`Error`](Self::Error), `7` for [`Active`](Self::Active), `8` for
/// [`Inactive`](Self::Inactive) — and the rest is that variant's own
/// JSON, or nothing: the one bare word carries nothing after the
/// byte.
///
/// # The id, then the activity
///
/// | the scope | means |
/// |-----------|-------|
/// | an id, then quiet, and stays open | the container is running, and no exchange has been in flight |
/// | an id, an active, and stays open | the container is running and serving: one or more MCP exchanges are in flight |
/// | …an active, an inactive, and stays open | the last in flight has been answered, its rotating secrets handed back; the container is idle until the next |
/// | a volume held, then a finish | it never started: that volume is under a stat, a read, a write, a filetree, an edit or a delete |
/// | a volume mounted, then a finish | it never started: a running container has that volume, and the provider mounts a volume of its mode once |
/// | a volume FUSE served, then a finish | it never started: a FUSE serve has that volume, and the provider does not mount a volume of its mode beside one |
/// | a volume mount unsupported, then a finish | it never started: the provider does not mount a volume of that volume's mode |
/// | a volume mode, then a finish | it never started: that volume is not in the mode its mount names |
/// | FUSE mounts unsupported, then a finish | it never started: the request names a FUSE mount, and the provider mounts none |
/// | an error, then a finish | it never came up, or it is gone |
/// | a finish, with no error | the run is over — a stop, or the container's own end |
///
/// # One mode, and who may hold it
///
/// A mount states the mode it means the volume to have, and a volume
/// in another mode refuses the run,
/// [`VolumeMode`](Self::VolumeMode), with the mode it is in — before
/// anything is fetched or deployed, and after the hold is taken and
/// given back, so an edit cannot slip between the look and the
/// answer. Who else may hold the volume meanwhile is the provider's
/// capability for the volume's mode, stated in its
/// [`info`](crate::provider::endpoints::info): a running container
/// that has it refuses the run, [`VolumeMounted`](Self::VolumeMounted),
/// on a provider whose `mount_many` for the mode is `false`; a FUSE
/// serve that has it refuses the run,
/// [`VolumeFuseServed`](Self::VolumeFuseServed), where
/// `mount_and_fuse_serve` is `false`; a mode the provider does not
/// mount at all refuses it,
/// [`VolumeMountUnsupported`](Self::VolumeMountUnsupported); and no
/// volume is mounted while a stat, a read, a write, a filetree, an
/// edit or a delete has it to itself: a request that names one so
/// held is answered [`VolumeHeld`](Self::VolumeHeld). Each
/// refusal is its own variant, because a caller acts on it
/// differently from a failure: edit the volume or the mount, stop the
/// container or the FUSE serve, wait for the operation, name another
/// volume or ask another provider, and ask again. The hold is the
/// volume's `mount`, taken by the run handler and given back on every
/// ending.
///
/// # The proxy marks the activity, and only the proxy can
///
/// An exchange is one of the four MCP calls a caller opens into the
/// container — `tools/list`, `resources/list`, `tools/call`,
/// `resources/read`; notifications are no exchange. The proxy counts
/// them in flight and says so on its begin stream — see
/// [the begin's frame](crate::container_proxy::outside::endpoints::tools::begin::server::response::Frame)
/// — which the provider relays here as [`Active`](Self::Active) when
/// the count goes from none to one and [`Inactive`](Self::Inactive)
/// when it goes from one to none, the latter carrying the rotating
/// secrets the program handed back, for the caller to write into the
/// places they were locked from. Before the next exchange is
/// delivered the caller feeds the values again, on its own
/// [`Secrets`](super::super::super::client::channel_request::Frame::Secrets)
/// channel, and the proxy holds the exchange until it has.
///
/// Everything else a caller reads from the container — the tree, the
/// family's own exchange — is a channel it opens, not this stream.
/// Which is why this carries no readiness signal either: a provider
/// knows when a CONTAINER has started, and that is not the same fact
/// as the thing inside it having bound its port. The channels find
/// out, one exchange at a time.
#[derive(Debug, Clone, PartialEq)]
pub enum Frame {
/// The container's id. Tag `0`.
///
/// Arrives once, whenever the provider has it. See [`Id`].
Id(Id),
/// The run was refused: a volume it names is under a stat, a
/// read, a write, a filetree, an edit or a delete. Tag `1`.
///
/// The first and only response of its scope; the finish follows.
/// Nothing was fetched and nothing was deployed.
VolumeHeld(VolumeHeld),
/// The run was refused: a running container has a volume it
/// names, and the provider mounts a volume of that mode once.
/// Tag `2`.
///
/// The first and only response of its scope; the finish follows.
/// Nothing was fetched and nothing was deployed.
VolumeMounted(VolumeMounted),
/// The run was refused: a FUSE serve has a volume it names, and
/// the provider does not mount a volume of that mode beside one.
/// Tag `3`.
///
/// The first and only response of its scope; the finish follows.
/// Nothing was fetched and nothing was deployed.
VolumeFuseServed(VolumeFuseServed),
/// The run was refused: the provider does not mount a volume of
/// the mode a volume it names is in. Tag `4`.
///
/// The first and only response of its scope; the finish follows.
/// Nothing was fetched and nothing was deployed.
VolumeMountUnsupported(VolumeMountUnsupported),
/// The run was refused: a volume it names is not in the mode the
/// mount means it to have. Tag `5`.
///
/// The first and only response of its scope; the finish follows.
/// Nothing was fetched and nothing was deployed, and the volume is
/// as it was.
VolumeMode(VolumeMode),
/// A failure. Tag `6`.
///
/// The container is not running and will not be — the image
/// would not pull, the container would not start, whatever the
/// provider knows. It is the one variant that ends the scope
/// rather than adding to it. See
/// [`shared::error::Error`](crate::shared::error::Error) for why
/// it says so little.
Error(Error),
/// An exchange is in flight where none was. Tag `7`, and nothing
/// after it.
///
/// The proxy's word that the container is serving, and holds its
/// secrets' values until the matching [`Inactive`](Self::Inactive).
/// After the id, never twice without an `Inactive` between.
Active,
/// The last exchange in flight has been answered, and these are
/// the rotating secrets. Tag `8`.
///
/// The proxy's word that the container is idle, and the
/// [`Values`] it collected from the program: every `rotating`
/// secret the program declared, each by name to the value it
/// leaves in it, as JSON after the byte; empty for a program that
/// declared none rotating. The caller writes each into the place
/// it was locked from. Never without an [`Active`](Self::Active)
/// before it.
Inactive(Values),
}
/// Tag for [`Frame::Id`].
const ID: u8 = 0;
/// Tag for [`Frame::VolumeHeld`].
const VOLUME_HELD: u8 = 1;
/// Tag for [`Frame::VolumeMounted`].
const VOLUME_MOUNTED: u8 = 2;
/// Tag for [`Frame::VolumeFuseServed`].
const VOLUME_FUSE_SERVED: u8 = 3;
/// Tag for [`Frame::VolumeMountUnsupported`].
const VOLUME_MOUNT_UNSUPPORTED: u8 = 4;
/// Tag for [`Frame::VolumeMode`].
const VOLUME_MODE: u8 = 5;
/// Tag for [`Frame::Error`].
const ERROR: u8 = 6;
/// Tag for [`Frame::Active`]. Public, so a relay writes the one byte
/// that is the whole frame.
pub const ACTIVE: u8 = 7;
/// Tag for [`Frame::Inactive`]. Public, so a relay that carries the
/// values' JSON without reading it can frame it.
pub const INACTIVE: u8 = 8;
impl Encode for Frame {
/// One failure per variant that carries JSON; the one bare word
/// cannot fail.
type Error = FrameEncodeError;
// Spelled out rather than `Self::Error`: this enum has a variant
// called `Error`, so the associated type is ambiguous by that name.
fn encode(
&self,
out: &mut Writer<'_>,
) -> Result<(), FrameEncodeError> {
match self {
Frame::Id(id) => {
out.extend_from_slice(&[ID]);
serde_json::to_writer(out, id).map_err(FrameEncodeError::Id)
}
Frame::VolumeHeld(refused) => {
out.extend_from_slice(&[VOLUME_HELD]);
serde_json::to_writer(out, refused).map_err(FrameEncodeError::VolumeHeld)
}
Frame::VolumeMounted(refused) => {
out.extend_from_slice(&[VOLUME_MOUNTED]);
serde_json::to_writer(out, refused).map_err(FrameEncodeError::VolumeMounted)
}
Frame::VolumeFuseServed(refused) => {
out.extend_from_slice(&[VOLUME_FUSE_SERVED]);
serde_json::to_writer(out, refused).map_err(FrameEncodeError::VolumeFuseServed)
}
Frame::VolumeMountUnsupported(refused) => {
out.extend_from_slice(&[VOLUME_MOUNT_UNSUPPORTED]);
serde_json::to_writer(out, refused).map_err(FrameEncodeError::VolumeMountUnsupported)
}
Frame::VolumeMode(refused) => {
out.extend_from_slice(&[VOLUME_MODE]);
serde_json::to_writer(out, refused).map_err(FrameEncodeError::VolumeMode)
}
Frame::Error(error) => {
out.extend_from_slice(&[ERROR]);
error.encode(out).map_err(FrameEncodeError::Error)
}
Frame::Active => {
out.extend_from_slice(&[ACTIVE]);
Ok(())
}
Frame::Inactive(values) => {
out.extend_from_slice(&[INACTIVE]);
serde_json::to_writer(out, values).map_err(FrameEncodeError::Inactive)
}
}
}
}
/// A tool container run response that could not be written.
#[derive(Debug)]
pub enum FrameEncodeError {
/// The id did not serialize.
Id(serde_json::Error),
/// The held refusal did not serialize.
VolumeHeld(serde_json::Error),
/// The mounted refusal did not serialize.
VolumeMounted(serde_json::Error),
/// The FUSE-served refusal did not serialize.
VolumeFuseServed(serde_json::Error),
/// The mount-unsupported refusal did not serialize.
VolumeMountUnsupported(serde_json::Error),
/// The mode refusal did not serialize.
VolumeMode(serde_json::Error),
/// The error did not serialize.
Error(serde_json::Error),
/// The rotating secrets did not serialize. The message is the
/// serializer's, which quotes no value.
Inactive(serde_json::Error),
}
impl fmt::Display for FrameEncodeError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FrameEncodeError::Id(error) => {
write!(f, "container id did not serialize: {error}")
}
FrameEncodeError::VolumeHeld(error) => {
write!(f, "volume-held refusal did not serialize: {error}")
}
FrameEncodeError::VolumeMounted(error) => {
write!(f, "volume-mounted refusal did not serialize: {error}")
}
FrameEncodeError::VolumeFuseServed(error) => {
write!(f, "volume-fuse-served refusal did not serialize: {error}")
}
FrameEncodeError::VolumeMountUnsupported(error) => {
write!(f, "volume-mount-unsupported refusal did not serialize: {error}")
}
FrameEncodeError::VolumeMode(error) => {
write!(f, "volume-mode refusal did not serialize: {error}")
}
FrameEncodeError::Error(error) => {
write!(f, "tools run error did not serialize: {error}")
}
FrameEncodeError::Inactive(error) => {
write!(f, "tools run inactive secrets did not serialize: {error}")
}
}
}
}
impl std::error::Error for FrameEncodeError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
FrameEncodeError::Id(error) => Some(error),
FrameEncodeError::VolumeHeld(error) => Some(error),
FrameEncodeError::VolumeMounted(error) => Some(error),
FrameEncodeError::VolumeFuseServed(error) => Some(error),
FrameEncodeError::VolumeMountUnsupported(error) => Some(error),
FrameEncodeError::VolumeMode(error) => Some(error),
FrameEncodeError::Error(error) => Some(error),
FrameEncodeError::Inactive(error) => Some(error),
}
}
}
impl Decode<'_> for Frame {
/// Nine ways to fail, and each names which variant failed.
type Error = FrameError;
// Spelled out for the same reason as `encode` above.
fn decode(bytes: &[u8]) -> Result<Self, FrameError> {
let (tag, rest) = bytes.split_first().ok_or(FrameError::Empty)?;
match *tag {
ID => serde_json::from_slice(rest)
.map(Frame::Id)
.map_err(FrameError::Id),
VOLUME_HELD => serde_json::from_slice(rest)
.map(Frame::VolumeHeld)
.map_err(FrameError::VolumeHeld),
VOLUME_MOUNTED => serde_json::from_slice(rest)
.map(Frame::VolumeMounted)
.map_err(FrameError::VolumeMounted),
VOLUME_FUSE_SERVED => serde_json::from_slice(rest)
.map(Frame::VolumeFuseServed)
.map_err(FrameError::VolumeFuseServed),
VOLUME_MOUNT_UNSUPPORTED => serde_json::from_slice(rest)
.map(Frame::VolumeMountUnsupported)
.map_err(FrameError::VolumeMountUnsupported),
VOLUME_MODE => serde_json::from_slice(rest)
.map(Frame::VolumeMode)
.map_err(FrameError::VolumeMode),
ERROR => Error::decode(rest)
.map(Frame::Error)
.map_err(FrameError::Error),
ACTIVE => Ok(Frame::Active),
INACTIVE => serde_json::from_slice(rest)
.map(Frame::Inactive)
.map_err(FrameError::Inactive),
tag => Err(FrameError::UnknownTag(tag)),
}
}
}
/// A tool container run response frame that could not be read.
#[derive(Debug)]
pub enum FrameError {
/// No bytes at all, so not even a tag.
Empty,
/// A tag that is none of this frame's nine.
UnknownTag(u8),
/// The id did not parse.
Id(serde_json::Error),
/// The held refusal did not parse.
VolumeHeld(serde_json::Error),
/// The mounted refusal did not parse.
VolumeMounted(serde_json::Error),
/// The FUSE-served refusal did not parse.
VolumeFuseServed(serde_json::Error),
/// The mount-unsupported refusal did not parse.
VolumeMountUnsupported(serde_json::Error),
/// The mode refusal did not parse.
VolumeMode(serde_json::Error),
/// The error did not parse.
Error(serde_json::Error),
/// The rotating secrets did not parse. The message is the
/// parser's, which quotes no value.
Inactive(serde_json::Error),
}
impl fmt::Display for FrameError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FrameError::Empty => {
f.write_str("tools run response frame is empty")
}
FrameError::UnknownTag(tag) => {
write!(f, "unknown tools run response frame tag {tag}")
}
FrameError::Id(error) => {
write!(f, "container id did not parse: {error}")
}
FrameError::VolumeHeld(error) => {
write!(f, "volume-held refusal did not parse: {error}")
}
FrameError::VolumeMounted(error) => {
write!(f, "volume-mounted refusal did not parse: {error}")
}
FrameError::VolumeFuseServed(error) => {
write!(f, "volume-fuse-served refusal did not parse: {error}")
}
FrameError::VolumeMountUnsupported(error) => {
write!(f, "volume-mount-unsupported refusal did not parse: {error}")
}
FrameError::VolumeMode(error) => {
write!(f, "volume-mode refusal did not parse: {error}")
}
FrameError::Error(error) => {
write!(f, "tools run error did not parse: {error}")
}
FrameError::Inactive(error) => {
write!(f, "tools run inactive secrets did not parse: {error}")
}
}
}
}
impl std::error::Error for FrameError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
FrameError::Id(error) => Some(error),
FrameError::VolumeHeld(error) => Some(error),
FrameError::VolumeMounted(error) => Some(error),
FrameError::VolumeFuseServed(error) => Some(error),
FrameError::VolumeMountUnsupported(error) => Some(error),
FrameError::VolumeMode(error) => Some(error),
FrameError::Error(error) => Some(error),
FrameError::Inactive(error) => Some(error),
FrameError::Empty | FrameError::UnknownTag(_) => None,
}
}
}
and by diverge-sdk-rs/src/shared/containers/response/id.rs:
//! The container's id.
use serde::{Deserialize, Serialize};
/// What the provider decided to call this container.
///
/// An object rather than a bare string, so a provider that later has
/// something else to say about the container's identity has somewhere
/// to say it. A JSON string is a shape that can only ever be one
/// field.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
pub struct Id {
/// The id itself.
///
/// Opaque, and the provider's to mint. A caller that wants to name
/// this container anywhere else — a
/// [`transfer`](crate::shared::containers::transfer) into it, a
/// [`fuse_serve`](crate::provider::endpoints::containers::fuse_serve) of it —
/// has this and nothing else to name it with. It is a capability:
/// holding it is what lets its runner name it, so it has to be
/// unguessable, and nothing a caller could choose would be.
///
/// Nothing here constrains its shape. It means nothing to anyone
/// who was not given it, and nothing outside the provider that
/// minted it.
pub id: String,
}
and by diverge-sdk-rs/src/shared/containers/response/volume_held.rs:
//! A run refused because a volume it names is held to itself by an
//! operation: a stat, a read, a write, a filetree, an edit or a
//! delete.
use serde::{Deserialize, Serialize};
/// The volume a run request named that is held exclusively at the
/// time — under a stat, a read, a write, a filetree, an edit or a
/// delete of the same caller — and so refused the run.
///
/// No volume is mounted while something examines, reads, writes,
/// walks, resizes or removes it, whatever its
/// [`Mode`](crate::provider::endpoints::volumes::Mode). A provider
/// holds every volume a run names, shared, from the moment it accepts
/// the request until the run ends, and a request naming one that is
/// held exclusively is answered with this — the first and only
/// response of its scope, then the finish — with nothing fetched and
/// nothing deployed; a caller waits for the operation to end and asks
/// again. A volume another RUN or a FUSE serve has is not this: that
/// is [`VolumeMounted`](super::VolumeMounted) or
/// [`VolumeFuseServed`](super::VolumeFuseServed), each where the
/// provider's capability for the mode refuses a second holder. On the
/// server half the hold is the volume's `mount`, which the run
/// handler takes before anything else and gives back on every ending.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct VolumeHeld {
/// The `volume_name` of the volume, as the request named it.
pub name: String,
}
and by diverge-sdk-rs/src/shared/containers/response/volume_mounted.rs:
//! A run refused because a running container has a volume it names,
//! on a provider that mounts a volume of that mode once.
use serde::{Deserialize, Serialize};
/// The volume a run request named that a running container has
/// mounted at the time, on a provider whose `mount_many` for the
/// volume's mode is `false` — see
/// [`VolumeCapabilities`](crate::provider::endpoints::info::server::response::VolumeCapabilities)
/// — and so refused the run.
///
/// The first and only response of its scope, then the finish, with
/// nothing fetched and nothing deployed. The volume and the container
/// that has it are as they were; a caller stops that container, names
/// another volume, or asks another provider, and asks again. Every
/// [`Mode`](crate::provider::endpoints::volumes::Mode) allows more
/// than one running container at once; which modes this provider
/// mounts more than once is its capability for each.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct VolumeMounted {
/// The `volume_name` of the volume, as the request named it.
pub name: String,
}
and by diverge-sdk-rs/src/shared/containers/response/volume_fuse_served.rs:
//! A run refused because a FUSE serve has a volume it names, on a
//! provider that does not mount a volume of that mode beside one.
use serde::{Deserialize, Serialize};
/// The volume a run request named that a
/// [`fuse_serve`](crate::provider::endpoints::volumes::fuse_serve)
/// holds at the time, on a provider whose `mount_and_fuse_serve` for
/// the volume's mode is `false` — see
/// [`VolumeCapabilities`](crate::provider::endpoints::info::server::response::VolumeCapabilities)
/// — and so refused the run.
///
/// The first and only response of its scope, then the finish, with
/// nothing fetched and nothing deployed. The volume and the FUSE serve
/// that has it are as they were; a caller stops that FUSE serve, names
/// another volume, or asks another provider, and asks again.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct VolumeFuseServed {
/// The `volume_name` of the volume, as the request named it.
pub name: String,
}
and by diverge-sdk-rs/src/shared/containers/response/volume_mount_unsupported.rs:
//! A run refused because the provider does not mount a volume of the
//! mode a volume it names is in.
use serde::{Deserialize, Serialize};
/// The volume a run request named whose
/// [`Mode`](crate::provider::endpoints::volumes::Mode) the provider
/// does not mount into containers at all: its `mount` for the mode is
/// `false` — see
/// [`VolumeCapabilities`](crate::provider::endpoints::info::server::response::VolumeCapabilities)
/// — and so refused the run.
///
/// The first and only response of its scope, then the finish, with
/// nothing fetched and nothing deployed. Nothing about the volume is
/// the cause: the same volume in a mode the provider mounts, after an
/// [`edit`](crate::provider::endpoints::volumes::edit), or another
/// provider, is what a caller asks next. A volume in a mode the
/// provider has no capability for at all is never listed, so a
/// request cannot name one.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct VolumeMountUnsupported {
/// The `volume_name` of the volume, as the request named it.
pub name: String,
}
and by diverge-sdk-rs/src/shared/containers/response/volume_mode.rs:
//! A run, or a FUSE serve, refused because a volume it names is not in
//! the mode it meant.
use serde::{Deserialize, Serialize};
use crate::provider::endpoints::volumes::Mode;
/// The volume a request named under one mode that is in another, and
/// so refused the request: a run, whose every mount states the mode it
/// means the volume to have, or a FUSE serve, whose request does.
///
/// Nothing changed: the volume is in the mode reported here, as its
/// listing reports it, and only an
/// [`edit`](crate::provider::endpoints::volumes::edit) changes it. The
/// provider answers this after it has held the volume and given the
/// hold back, so that an edit cannot land between the look and the
/// answer — the first and only response of its scope, then the
/// finish — with nothing fetched and nothing deployed for it. The
/// mode the request meant is the request's to read back.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct VolumeMode {
/// The `volume_name` of the volume, as the request named it.
pub name: String,
/// The mode the volume is in.
pub mode: Mode,
}
and by diverge-sdk-rs/src/shared/containers/secrets/values.rs:
//! The secrets' values, by name.
use indexmap::IndexMap;
use serde_json::Value;
/// Secrets by name to value, any JSON: what the caller feeds a
/// container, and what the program hands back. Fed, it carries every
/// name the program declared, in the order declared — a `fixed` one
/// a value read from its key, a `rotating` one the value locked to
/// the container. Collected at an inactive, it carries every
/// `rotating` name the program declared, each with the value the
/// program leaves in it; a `fixed` name in it is ignored, and a
/// `rotating` name missing from it is the collect's error, never a
/// write-back. A value is never read by anything between the vault
/// and the program.
pub type Values = IndexMap<String, Value>;