aleph_types/message/execution/
volume.rs1use crate::item_hash::ItemHash;
2use crate::memory_size::gigabyte_to_mebibyte;
3use crate::toolkit::serde::default_true;
4use memsizes::MiB;
5use serde::{Deserialize, Serialize};
6use std::path::PathBuf;
7
8#[derive(thiserror::Error, Debug)]
9pub enum VolumeError {
10 #[error("value {size} is out of range ({min}..={max})")]
11 OutOfRange { size: u64, min: u64, max: u64 },
12}
13
14pub trait IsReadOnly {
15 fn is_read_only() -> bool;
16}
17
18#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
19pub struct BaseVolume {
20 #[serde(default, skip_serializing_if = "Option::is_none")]
21 pub comment: Option<String>,
22 #[serde(default, skip_serializing_if = "Option::is_none")]
23 pub mount: Option<PathBuf>,
24}
25
26#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
27pub struct ImmutableVolume {
28 #[serde(flatten)]
29 pub base: BaseVolume,
30 #[serde(rename = "ref")]
31 pub reference: ItemHash,
32 #[serde(default = "default_true")]
33 pub use_latest: bool,
34}
35
36impl IsReadOnly for ImmutableVolume {
37 fn is_read_only() -> bool {
38 true
39 }
40}
41
42#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
43#[serde(try_from = "u64", into = "u64")]
44pub struct EphemeralVolumeSize(MiB);
45
46impl EphemeralVolumeSize {
47 const MIN: u64 = 1;
48 const MAX: u64 = 1000;
49}
50
51impl TryFrom<u64> for EphemeralVolumeSize {
52 type Error = VolumeError;
53
54 fn try_from(size: u64) -> Result<Self, Self::Error> {
55 if (Self::MIN..=Self::MAX).contains(&size) {
56 Ok(Self(MiB::from(size)))
57 } else {
58 Err(VolumeError::OutOfRange {
59 size,
60 min: Self::MIN,
61 max: Self::MAX,
62 })
63 }
64 }
65}
66
67impl From<EphemeralVolumeSize> for u64 {
68 fn from(size: EphemeralVolumeSize) -> Self {
69 size.0.count()
70 }
71}
72
73impl From<MiB> for EphemeralVolumeSize {
74 fn from(size: MiB) -> Self {
75 Self(size)
76 }
77}
78
79impl From<EphemeralVolumeSize> for MiB {
80 fn from(value: EphemeralVolumeSize) -> Self {
81 value.0
82 }
83}
84
85#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
87pub struct EphemeralVolume {
88 #[serde(flatten)]
89 pub base: BaseVolume,
90 ephemeral: bool,
91 pub size_mib: EphemeralVolumeSize,
92}
93
94impl EphemeralVolume {
95 pub fn new(size_mib: u64, mount: impl Into<PathBuf>) -> Result<Self, VolumeError> {
97 Ok(Self {
98 base: BaseVolume {
99 comment: None,
100 mount: Some(mount.into()),
101 },
102 ephemeral: true,
103 size_mib: EphemeralVolumeSize::try_from(size_mib)?,
104 })
105 }
106}
107
108impl IsReadOnly for EphemeralVolume {
109 fn is_read_only() -> bool {
110 false
111 }
112}
113
114#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
116pub struct ParentVolume {
117 #[serde(rename = "ref")]
118 pub reference: ItemHash,
119 #[serde(default = "default_true")]
120 pub use_latest: bool,
121}
122
123#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
125#[serde(rename_all = "lowercase")]
126pub enum VolumePersistence {
127 Host,
128 Store,
129}
130
131#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
132#[serde(try_from = "u64", into = "u64")]
133pub struct PersistentVolumeSize(MiB);
134
135impl PersistentVolumeSize {
136 const MIN: u64 = 1;
137 const MAX: u64 = gigabyte_to_mebibyte(2048);
138}
139
140impl TryFrom<u64> for PersistentVolumeSize {
141 type Error = VolumeError;
142
143 fn try_from(size: u64) -> Result<Self, Self::Error> {
144 if (Self::MIN..=Self::MAX).contains(&size) {
145 Ok(Self(MiB::from(size)))
146 } else {
147 Err(VolumeError::OutOfRange {
148 size,
149 min: Self::MIN,
150 max: Self::MAX,
151 })
152 }
153 }
154}
155
156impl From<PersistentVolumeSize> for u64 {
157 fn from(size: PersistentVolumeSize) -> Self {
158 size.0.count()
159 }
160}
161
162impl From<MiB> for PersistentVolumeSize {
163 fn from(size: MiB) -> Self {
164 Self(size)
165 }
166}
167
168impl From<PersistentVolumeSize> for MiB {
169 fn from(value: PersistentVolumeSize) -> Self {
170 value.0
171 }
172}
173
174#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
175pub struct PersistentVolume {
176 #[serde(flatten)]
177 pub base: BaseVolume,
178 #[serde(default, skip_serializing_if = "Option::is_none")]
179 pub parent: Option<ParentVolume>,
180 #[serde(default, skip_serializing_if = "Option::is_none")]
181 pub persistence: Option<VolumePersistence>,
182 #[serde(default, skip_serializing_if = "Option::is_none")]
183 pub name: Option<String>,
184 pub size_mib: PersistentVolumeSize,
185}
186
187impl IsReadOnly for PersistentVolume {
188 fn is_read_only() -> bool {
189 false
190 }
191}
192
193#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
194#[serde(untagged)]
195pub enum MachineVolume {
196 Immutable(ImmutableVolume),
197 Ephemeral(EphemeralVolume),
198 Persistent(PersistentVolume),
199}
200
201#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
206pub struct RootfsVolume {
207 pub parent: ParentVolume,
208 pub persistence: VolumePersistence,
209 pub size_mib: PersistentVolumeSize,
210 #[serde(default, skip_serializing_if = "Option::is_none")]
211 pub forgotten_by: Option<Vec<ItemHash>>,
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217
218 #[test]
219 fn test_is_read_only() {
221 assert!(ImmutableVolume::is_read_only());
222 assert!(!EphemeralVolume::is_read_only());
223 assert!(!PersistentVolume::is_read_only());
224 }
225}