Skip to main content

microsandbox_protocol/control/
types.rs

1//! Shared control records. Their field spellings also preserve legacy JSON.
2
3use serde::{Deserialize, Serialize};
4
5//--------------------------------------------------------------------------------------------------
6// Types
7//--------------------------------------------------------------------------------------------------
8
9/// Empty map payload for state and capability queries.
10#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
11pub struct Empty {}
12
13/// Facilities available for this runtime and VM configuration.
14#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
15pub struct Capabilities {
16    /// Runtime supports online root-disk growth over its extended control API.
17    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
18    pub root_disk_grow: bool,
19    /// Live CPU target changes are available.
20    pub cpu_resize: bool,
21    /// Live memory target changes are available.
22    pub memory_resize: bool,
23    /// Host secret changes are available.
24    pub secrets_update: bool,
25}
26
27/// Accepted and observed memory quantities, all in MiB.
28#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
29pub struct MemoryState {
30    /// Boot allocation.
31    pub boot_mib: u64,
32    /// Accepted target, which need not have converged yet.
33    pub target_mib: u64,
34    /// Current guest observation.
35    pub current_mib: u64,
36    /// Boot-time capacity ceiling.
37    pub max_mib: u64,
38}
39
40/// CPU capacity, accepted target, observation, and enforcement.
41#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
42pub struct CpuState {
43    /// CPUs possible for this VM boot.
44    pub possible: u32,
45    /// Accepted online target.
46    pub requested_online: u32,
47    /// Guest-reported online CPUs.
48    pub actual_online: u32,
49    /// Host-enforced online CPUs.
50    pub enforced: u32,
51}
52
53/// Native memory-target payload, without SDK convergence policy.
54#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
55pub struct MemoryTarget {
56    /// Requested total memory in MiB.
57    pub total_mib: u64,
58}
59
60/// Native CPU-target payload.
61#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
62pub struct CpuTarget {
63    /// Requested online CPUs.
64    pub online: u32,
65}
66
67/// Secret material that is redacted in diagnostics and cleared on drop.
68#[derive(Clone, Serialize, Deserialize, zeroize::Zeroize, zeroize::ZeroizeOnDrop)]
69#[serde(transparent)]
70pub struct SecretValue(pub String);
71
72/// One ordered host secret modification, preserving the JSON operation tags.
73#[derive(Debug, Clone, Serialize, Deserialize)]
74#[serde(tag = "change", rename_all = "snake_case")]
75pub enum SecretChange {
76    /// Replace an existing secret's value.
77    Rotate {
78        /// Secret identity.
79        name: String,
80        /// New secret material.
81        value: SecretValue,
82    },
83    /// Remove a secret; absence is a successful no-op.
84    Remove {
85        /// Secret identity.
86        name: String,
87    },
88    /// Replace an existing secret's allowed hosts.
89    SetAllowedHosts {
90        /// Secret identity.
91        name: String,
92        /// Replacement host patterns, in caller order.
93        hosts: Vec<String>,
94    },
95}
96
97/// Sequential, non-transactional secret modifications.
98#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct SecretsUpdate {
100    /// Apply in order and stop at the first operation failure.
101    pub changes: Vec<SecretChange>,
102}
103
104/// State mutation certainty reported by an operation error.
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
106#[serde(rename_all = "snake_case")]
107pub enum ErrorEffect {
108    /// This operation (or failed batch entry) did not change state.
109    None,
110    /// A change cannot be ruled out.
111    Unknown,
112}
113
114/// A recoverable peer error. Codes stay strings for future interoperability.
115#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
116pub struct ControlError {
117    /// Stable machine-readable code; preserve unknown future codes.
118    pub code: String,
119    /// Safe diagnostic text, never a request body or secret value.
120    pub message: String,
121    /// Certainty for this operation, not a retry instruction.
122    pub effect: ErrorEffect,
123}
124
125/// Completion of a sequential secret batch.
126#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
127#[serde(tag = "outcome", rename_all = "snake_case")]
128pub enum SecretsResult {
129    /// Every entry completed, including successful no-ops.
130    Complete {
131        /// Number of completed entries.
132        applied_count: u32,
133    },
134    /// Earlier entries completed; remaining entries were not attempted.
135    Failed {
136        /// Number of completed entries.
137        applied_count: u32,
138        /// Zero-based failed entry, equal to `applied_count`.
139        failed_index: u32,
140        /// Certainty here applies to the failed entry only.
141        error: ControlError,
142    },
143}
144
145/// Legacy JSON request, also used as a checked dispatch representation.
146#[derive(Debug, Clone, Serialize, Deserialize)]
147#[serde(tag = "op", rename_all = "snake_case")]
148pub enum ControlRequest {
149    /// Query available host operations.
150    Capabilities,
151    /// Set the memory target.
152    MemoryTarget {
153        /// Requested total memory in MiB.
154        total_mib: u64,
155    },
156    /// Observe memory state.
157    MemoryState,
158    /// Set the CPU target.
159    CpuTarget {
160        /// Requested online CPUs.
161        online: u32,
162    },
163    /// Observe CPU state.
164    CpuState,
165    /// Apply ordered secret modifications.
166    SecretsUpdate {
167        /// Caller-ordered changes.
168        changes: Vec<SecretChange>,
169    },
170}
171
172/// Existing JSON response with an additive discovery advertisement.
173///
174/// Omission of `control_protocols` identifies an ordinary legacy response.
175/// Raw JSON consumers must retain the original bytes to preserve unknown fields.
176#[derive(Debug, Clone, Default, Serialize, Deserialize)]
177pub struct JsonControlResponse {
178    /// Whether the operation succeeded.
179    pub ok: bool,
180    /// Legacy diagnostic; batch progress cannot be inferred from it.
181    #[serde(default, skip_serializing_if = "Option::is_none")]
182    pub error: Option<String>,
183    /// Present for memory operations.
184    #[serde(default, skip_serializing_if = "Option::is_none")]
185    pub memory: Option<MemoryState>,
186    /// Present for CPU operations.
187    #[serde(default, skip_serializing_if = "Option::is_none")]
188    pub cpu: Option<CpuState>,
189    /// Present for capability discovery.
190    #[serde(default, skip_serializing_if = "Option::is_none")]
191    pub capabilities: Option<Capabilities>,
192    /// Explicit operation formats, emitted only during discovery.
193    #[serde(default, skip_serializing_if = "Option::is_none")]
194    pub control_protocols: Option<Vec<String>>,
195}
196
197//--------------------------------------------------------------------------------------------------
198// Methods
199//--------------------------------------------------------------------------------------------------
200
201impl ControlError {
202    /// Construct an error known to precede mutation.
203    pub fn rejected(code: impl Into<String>, message: impl Into<String>) -> Self {
204        Self {
205            code: code.into(),
206            message: message.into(),
207            effect: ErrorEffect::None,
208        }
209    }
210}
211
212//--------------------------------------------------------------------------------------------------
213// Trait Implementations
214//--------------------------------------------------------------------------------------------------
215
216impl std::fmt::Debug for SecretValue {
217    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218        f.write_str("[redacted]")
219    }
220}