aleph_types/message/execution/
volume.rs

1use crate::item_hash::ItemHash;
2use crate::storage_size::{MemorySize, MiB, gigabyte_to_mebibyte};
3use crate::toolkit::serde::default_true;
4use serde::{Deserialize, Serialize};
5use std::path::PathBuf;
6
7#[derive(thiserror::Error, Debug)]
8pub enum VolumeError {
9    #[error("value {size} is out of range ({min}..={max})")]
10    OutOfRange { size: u64, min: u64, max: u64 },
11}
12
13pub trait IsReadOnly {
14    fn is_read_only() -> bool;
15}
16
17#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
18pub struct BaseVolume {
19    #[serde(default)]
20    pub comment: Option<String>,
21    #[serde(default)]
22    pub mount: Option<PathBuf>,
23}
24
25#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
26pub struct ImmutableVolume {
27    #[serde(flatten)]
28    pub base: BaseVolume,
29    #[serde(default, rename = "ref")]
30    pub reference: Option<ItemHash>,
31    #[serde(default = "default_true")]
32    pub use_latest: bool,
33}
34
35impl IsReadOnly for ImmutableVolume {
36    fn is_read_only() -> bool {
37        true
38    }
39}
40
41#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
42#[serde(try_from = "u64", into = "u64")]
43pub struct EphemeralVolumeSize(MiB);
44
45impl EphemeralVolumeSize {
46    const MIN: u64 = 1;
47    const MAX: u64 = 1000;
48}
49
50impl TryFrom<u64> for EphemeralVolumeSize {
51    type Error = VolumeError;
52
53    fn try_from(size: u64) -> Result<Self, Self::Error> {
54        if (Self::MIN..=Self::MAX).contains(&size) {
55            Ok(Self(MiB::from_units(size)))
56        } else {
57            Err(VolumeError::OutOfRange {
58                size,
59                min: Self::MIN,
60                max: Self::MAX,
61            })
62        }
63    }
64}
65
66impl From<EphemeralVolumeSize> for u64 {
67    fn from(size: EphemeralVolumeSize) -> Self {
68        size.0.units()
69    }
70}
71
72/// Ephemeral volume.
73#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
74pub struct EphemeralVolume {
75    #[serde(flatten)]
76    pub base: BaseVolume,
77    ephemeral: bool,
78    size_mib: EphemeralVolumeSize,
79}
80
81impl IsReadOnly for EphemeralVolume {
82    fn is_read_only() -> bool {
83        false
84    }
85}
86
87/// A reference volume to copy as a persistent volume.
88#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
89pub struct ParentVolume {
90    #[serde(rename = "ref")]
91    pub reference: ItemHash,
92    #[serde(default = "default_true")]
93    pub use_latest: bool,
94}
95
96/// Where to persist the volume.
97#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
98#[serde(rename_all = "lowercase")]
99pub enum VolumePersistence {
100    Host,
101    Store,
102}
103
104#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
105#[serde(try_from = "u64", into = "u64")]
106pub struct PersistentVolumeSize(MiB);
107
108impl PersistentVolumeSize {
109    const MIN: u64 = 1;
110    const MAX: u64 = gigabyte_to_mebibyte(2048);
111}
112
113impl TryFrom<u64> for PersistentVolumeSize {
114    type Error = VolumeError;
115
116    fn try_from(size: u64) -> Result<Self, Self::Error> {
117        if (Self::MIN..=Self::MAX).contains(&size) {
118            Ok(Self(MiB::from_units(size)))
119        } else {
120            Err(VolumeError::OutOfRange {
121                size,
122                min: Self::MIN,
123                max: Self::MAX,
124            })
125        }
126    }
127}
128
129impl From<PersistentVolumeSize> for u64 {
130    fn from(size: PersistentVolumeSize) -> Self {
131        size.0.units()
132    }
133}
134
135impl From<MiB> for PersistentVolumeSize {
136    fn from(size: MiB) -> Self {
137        Self(size)
138    }
139}
140
141#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
142pub struct PersistentVolume {
143    #[serde(flatten)]
144    pub base: BaseVolume,
145    #[serde(default)]
146    pub parent: Option<ParentVolume>,
147    #[serde(default)]
148    pub persistence: Option<VolumePersistence>,
149    #[serde(default)]
150    pub name: Option<String>,
151    size_mib: PersistentVolumeSize,
152}
153
154impl IsReadOnly for PersistentVolume {
155    fn is_read_only() -> bool {
156        false
157    }
158}
159
160#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
161#[serde(untagged)]
162pub enum MachineVolume {
163    Immutable(ImmutableVolume),
164    Ephemeral(EphemeralVolume),
165    Persistent(PersistentVolume),
166}
167
168/// Root file system of a VM instance.
169///
170/// The root file system of an instance is built as a copy of a reference image, named parent
171/// image. The user determines a custom size and persistence model.
172#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
173pub struct RootfsVolume {
174    pub parent: ParentVolume,
175    pub persistence: VolumePersistence,
176    pub size_mib: PersistentVolumeSize,
177    #[serde(default)]
178    pub forgotten_by: Option<Vec<ItemHash>>,
179}
180
181#[cfg(test)]
182mod tests {
183    use super::*;
184
185    #[test]
186    /// Sanity test for the read-only property on each volume type.
187    fn test_is_read_only() {
188        assert!(ImmutableVolume::is_read_only());
189        assert!(!EphemeralVolume::is_read_only());
190        assert!(!PersistentVolume::is_read_only());
191    }
192}