Skip to main content

microsandbox_types/cloud/
snapshots.rs

1//! Cloud snapshot request, resource, and operation wire contracts.
2
3use std::collections::BTreeMap;
4use std::path::PathBuf;
5
6use chrono::{DateTime, Utc};
7use serde::{Deserialize, Serialize};
8
9use super::CloudErrorDetails;
10use crate::snapshot::cloud_manifest::Manifest as SnapshotManifest;
11
12//--------------------------------------------------------------------------------------------------
13// Types: Snapshots
14//--------------------------------------------------------------------------------------------------
15
16/// Kind of cloud snapshot artifact or capture operation.
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
18#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
19#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
20#[serde(rename_all = "snake_case")]
21pub enum CloudSnapshotKind {
22    /// Capture disk state only.
23    Disk,
24}
25
26/// Settings shared by every cloud snapshot capture kind.
27#[derive(Debug, Clone, Serialize, Deserialize)]
28#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
29#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
30pub struct CloudSnapshotSpec {
31    /// Immutable identifier of the sandbox to capture.
32    pub sandbox_id: String,
33    /// Snapshot name.
34    pub name: String,
35    /// Directory on a mounted host volume to write the artifact into. `None`
36    /// stores the snapshot in managed snapshot storage.
37    #[serde(default, skip_serializing_if = "Option::is_none")]
38    #[cfg_attr(feature = "ts", ts(type = "string | null"))]
39    #[cfg_attr(feature = "utoipa", schema(value_type = Option<String>))]
40    pub dest_dir: Option<PathBuf>,
41    /// User-defined labels stored on the snapshot.
42    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
43    pub labels: BTreeMap<String, String>,
44    /// Replace an existing snapshot with the same name.
45    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
46    pub force: bool,
47    /// Record payload integrity metadata during capture.
48    #[serde(default, skip_serializing_if = "std::ops::Not::not")]
49    pub record_integrity: bool,
50}
51
52/// Wire shape of a cloud snapshot create request body.
53#[derive(Debug, Clone, Serialize, Deserialize)]
54#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
55#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
56#[serde(tag = "kind", rename_all = "snake_case")]
57pub enum CloudCreateSnapshotRequest {
58    /// Capture disk state only.
59    Disk {
60        /// Settings shared by every snapshot kind.
61        #[serde(flatten)]
62        snapshot: CloudSnapshotSpec,
63    },
64}
65
66/// Fields shared by every completed cloud snapshot kind.
67#[derive(Debug, Clone, Serialize, Deserialize)]
68#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
69#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
70pub struct CloudSnapshotDetails {
71    /// Snapshot name.
72    pub name: String,
73    /// Where the snapshot artifact resides.
74    pub location: CloudSnapshotLocation,
75    /// Identifier of the sandbox the snapshot was captured from, when known.
76    #[serde(default)]
77    pub sandbox_id: Option<String>,
78    /// Snapshot identity: the `sha256:` digest of the canonical descriptor.
79    pub digest: String,
80    /// Stored payload size in bytes.
81    pub size_bytes: u64,
82    /// Canonical snapshot descriptor.
83    pub manifest: SnapshotManifest,
84    /// User-defined labels stored on the snapshot.
85    pub labels: BTreeMap<String, String>,
86    /// Creation timestamp.
87    #[cfg_attr(feature = "ts", ts(type = "string"))]
88    pub created_at: DateTime<Utc>,
89}
90
91/// Wire shape of a completed cloud snapshot.
92#[derive(Debug, Clone, Serialize, Deserialize)]
93#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
94#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
95#[serde(tag = "kind", rename_all = "snake_case")]
96pub enum CloudSnapshot {
97    /// A disk-only snapshot.
98    Disk {
99        /// Fields shared by every snapshot kind.
100        #[serde(flatten)]
101        snapshot: CloudSnapshotDetails,
102    },
103}
104
105/// Public locator for a managed or host-volume cloud snapshot.
106#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
107#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
108#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
109#[serde(tag = "type", rename_all = "snake_case")]
110pub enum CloudSnapshotLocation {
111    /// Held in managed snapshot storage.
112    Managed {
113        /// Identifier of the stored artifact.
114        id: String,
115    },
116    /// Stored in a directory on a mounted host volume.
117    HostVolume {
118        /// Artifact directory path on the host volume.
119        path: String,
120    },
121}
122
123/// Wire shape of the asynchronous snapshot operation returned by snapshot
124/// capture endpoints.
125#[derive(Debug, Clone, Serialize, Deserialize)]
126#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
127#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
128pub struct CloudSnapshotOperation {
129    /// Server-side operation identifier.
130    pub id: String,
131    /// Kind of snapshot being captured.
132    pub kind: CloudSnapshotKind,
133    /// Current operation status.
134    pub status: CloudSnapshotOperationStatus,
135    /// The resulting snapshot, present once the operation succeeds.
136    #[serde(default)]
137    pub result: Option<CloudSnapshot>,
138    /// Error details for a failed operation.
139    #[serde(default)]
140    pub error: Option<CloudErrorDetails>,
141    /// Creation timestamp.
142    #[cfg_attr(feature = "ts", ts(type = "string"))]
143    pub created_at: DateTime<Utc>,
144    /// Timestamp of the most recent status change.
145    #[cfg_attr(feature = "ts", ts(type = "string"))]
146    pub updated_at: DateTime<Utc>,
147    /// Timestamp of the terminal status, when the operation has finished.
148    #[serde(default)]
149    #[cfg_attr(feature = "ts", ts(type = "string | null"))]
150    pub completed_at: Option<DateTime<Utc>>,
151}
152
153/// Status of an asynchronous cloud snapshot operation.
154#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
155#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
156#[cfg_attr(feature = "ts", derive(ts_rs::TS))]
157#[serde(rename_all = "snake_case")]
158pub enum CloudSnapshotOperationStatus {
159    /// Accepted but not yet started.
160    Queued,
161    /// The operation is running.
162    InProgress,
163    /// The snapshot is complete and available.
164    Succeeded,
165    /// The operation failed.
166    Failed,
167}
168
169//--------------------------------------------------------------------------------------------------
170// Methods
171//--------------------------------------------------------------------------------------------------
172
173impl CloudCreateSnapshotRequest {
174    /// Return the requested snapshot kind.
175    pub const fn kind(&self) -> CloudSnapshotKind {
176        match self {
177            Self::Disk { .. } => CloudSnapshotKind::Disk,
178        }
179    }
180
181    /// Return settings shared by every snapshot kind.
182    pub const fn snapshot_spec(&self) -> &CloudSnapshotSpec {
183        match self {
184            Self::Disk { snapshot } => snapshot,
185        }
186    }
187
188    /// Return mutable settings shared by every snapshot kind.
189    pub const fn snapshot_spec_mut(&mut self) -> &mut CloudSnapshotSpec {
190        match self {
191            Self::Disk { snapshot } => snapshot,
192        }
193    }
194}
195
196impl CloudSnapshot {
197    /// Return the completed snapshot kind.
198    pub const fn kind(&self) -> CloudSnapshotKind {
199        match self {
200            Self::Disk { .. } => CloudSnapshotKind::Disk,
201        }
202    }
203
204    /// Return fields shared by every snapshot kind.
205    pub const fn details(&self) -> &CloudSnapshotDetails {
206        match self {
207            Self::Disk { snapshot } => snapshot,
208        }
209    }
210
211    /// Consume this snapshot and return its shared fields.
212    pub fn into_details(self) -> CloudSnapshotDetails {
213        match self {
214            Self::Disk { snapshot } => snapshot,
215        }
216    }
217}