1use chrono::{DateTime, Utc};
2use derive_builder::{Builder, UninitializedFieldError};
3use indexmap::IndexMap;
4use miette::Diagnostic;
5use serde::{Deserialize, Serialize};
6use serde_json::{Map, Value};
7use std::fmt::Display;
8use strum::{Display as StrumDisplay, EnumString};
9use thiserror::Error;
10use url::Url;
11use uuid::Uuid;
12
13#[doc = "Error type for All zfs related builders"]
14#[derive(Debug, Error, Diagnostic)]
15#[non_exhaustive]
16pub enum ManifestBuilderError {
17 UninitializedField(&'static str),
20 ValidationError(String),
22}
23
24impl From<String> for ManifestBuilderError {
25 fn from(s: String) -> Self {
26 Self::ValidationError(s)
27 }
28}
29impl From<UninitializedFieldError> for ManifestBuilderError {
30 fn from(value: UninitializedFieldError) -> Self {
31 Self::UninitializedField(value.field_name())
32 }
33}
34impl Display for ManifestBuilderError {
35 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36 match self {
37 ManifestBuilderError::UninitializedField(value) => {
38 write!(f, "field {} must be initialized", value)
39 }
40 ManifestBuilderError::ValidationError(s) => write!(f, "validation error: {}", s),
41 }
42 }
43}
44
45#[derive(Deserialize, Serialize, Debug, Clone, Builder)]
46#[builder(build_fn(error = "ManifestBuilderError"))]
47pub struct Manifest {
48 #[builder(setter(skip), default = "2")]
50 pub v: i32,
51
52 #[builder(setter(skip), default = "uuid::Builder::nil().into_uuid()")]
54 pub uuid: Uuid,
55
56 #[builder(setter(skip), default = "uuid::Builder::nil().into_uuid()")]
58 pub owner: Uuid,
59
60 #[builder(setter(into))]
62 pub name: String,
63
64 #[builder(setter(into))]
66 pub version: String,
67
68 #[builder(setter(into, strip_option), default)]
70 pub description: Option<String>,
71
72 #[builder(setter(into, strip_option), default)]
74 pub homepage: Option<Url>,
75
76 #[builder(setter(into, strip_option), default)]
78 pub eula: Option<Url>,
79
80 #[builder(setter(into, strip_option), default)]
82 pub icon: Option<bool>,
83
84 #[builder(default)]
86 pub state: ImageState,
87
88 #[builder(setter(into, strip_option), default)]
90 pub error: Option<Map<String, Value>>,
91
92 #[builder(default = "false")]
94 pub disabled: bool,
95
96 #[builder(default = "false")]
98 pub public: bool,
99
100 #[builder(setter(into, strip_option), default)]
102 pub published_at: Option<DateTime<Utc>>,
103
104 #[serde(rename = "type")]
106 #[builder(setter(into), default)]
107 pub image_type: ImageType,
108
109 #[builder(setter(into), default)]
111 pub os: ImageOs,
112
113 #[builder(setter(into, strip_option), default)]
115 pub origin: Option<Uuid>,
116
117 #[builder(default)]
119 pub files: Vec<Map<String, Value>>,
120
121 #[builder(setter(into, strip_option), default)]
123 pub acl: Option<Vec<Uuid>>,
124
125 #[builder(setter(into, strip_option), default)]
127 pub requirements: Option<ImageRequirements>,
128
129 #[builder(setter(into, strip_option), default)]
131 pub users: Option<Vec<ImageUsers>>,
132
133 #[builder(setter(into, strip_option), default)]
135 pub billing_tags: Option<Vec<String>>,
136
137 #[builder(setter(into, strip_option), default)]
139 pub traits: Option<Vec<String>>,
140
141 #[builder(setter(into, strip_option), default)]
143 pub tags: Option<IndexMap<String, String>>,
144
145 #[builder(setter(into, strip_option), default)]
147 pub generate_password: Option<bool>,
148
149 #[builder(setter(into, strip_option), default)]
151 pub inherited_directories: Option<Vec<String>>,
152
153 #[builder(setter(into, strip_option), default)]
155 pub channels: Option<Vec<String>>,
156
157 #[serde(flatten)]
158 #[builder(setter(into, strip_option), default)]
159 pub vm_image_properties: Option<ImageVMProperties>,
160}
161
162#[derive(Default, Deserialize, Serialize, Debug, Clone, StrumDisplay, PartialEq, Eq)]
163#[serde(rename_all = "snake_case")]
164pub enum ImageState {
165 Active,
166 Unactivated,
167 Disabled,
168 #[default]
169 Creating,
170 Failed,
171}
172
173#[derive(Default, Deserialize, Serialize, Debug, Clone, StrumDisplay, PartialEq, Eq)]
174#[serde(rename_all = "kebab-case")]
175pub enum ImageType {
176 #[strum(serialize = "zone-dataset")]
177 #[default]
178 ZoneDataset,
179 #[strum(serialize = "lx-dataset")]
180 LxDataset,
181 #[strum(serialize = "lxd")]
182 Lxd,
183 #[strum(serialize = "zvol")]
184 Zvol,
185 #[strum(serialize = "other")]
186 Other,
187}
188
189#[derive(Default, Deserialize, Serialize, Debug, Clone, StrumDisplay, PartialEq, Eq)]
190#[serde(rename_all = "kebab-case")]
191pub enum ImageOs {
192 #[default]
193 Smartos,
194 Windows,
195 Linux,
196 Bsd,
197 Illumos,
198 Other,
199}
200
201#[derive(Deserialize, Serialize, Debug, Clone, Builder)]
202pub struct ImageRequirements {
203 #[builder(setter(into, strip_option), default)]
205 pub networks: Option<Vec<RequirementNetworks>>,
206
207 #[builder(setter(into, strip_option), default)]
209 pub brand: Option<String>,
210
211 #[builder(setter(into, strip_option), default)]
213 pub ssh_key: Option<bool>,
214
215 #[builder(setter(into, strip_option), default)]
217 pub min_ram: Option<i64>,
218
219 #[builder(setter(into, strip_option), default)]
221 pub max_ram: Option<i64>,
222
223 #[builder(setter(into, strip_option), default)]
225 pub min_platform: Option<IndexMap<String, String>>,
226
227 #[builder(setter(into, strip_option), default)]
229 pub max_platform: Option<IndexMap<String, String>>,
230
231 #[builder(setter(into, strip_option), default)]
233 pub bootrom: Option<ImageRequirementBootRom>,
234}
235
236#[derive(Deserialize, Serialize, Debug, Clone, Builder)]
237pub struct RequirementNetworks {
238 name: String,
239 description: String,
240}
241
242#[derive(Deserialize, Serialize, Debug, Clone, StrumDisplay)]
243#[serde(rename_all = "kebab-case")]
244pub enum ImageRequirementBootRom {
245 Bios,
246 Uefi,
247}
248
249#[derive(Deserialize, Serialize, Debug, Clone)]
250pub struct ImageUsers {
251 name: String,
252}
253
254#[derive(Deserialize, Serialize, Debug, Clone, Builder)]
255#[builder(build_fn(error = "ManifestBuilderError"))]
256pub struct ImageVMProperties {
257 #[builder(setter(into))]
259 pub nic_driver: NetDrivers,
260
261 #[builder(setter(into))]
263 pub disk_driver: DiskDrivers,
264
265 #[builder(setter(into))]
267 pub cpu_type: String,
268
269 pub image_size: u64,
271}
272
273#[derive(Deserialize, Serialize, Debug, Clone, EnumString, StrumDisplay)]
274#[serde(rename_all = "kebab-case")]
275#[strum(serialize_all = "kebab-case")]
276pub enum NetDrivers {
277 Virtio,
278 E1000g0,
279}
280
281#[derive(Deserialize, Serialize, Debug, Clone, EnumString, StrumDisplay)]
282#[serde(rename_all = "kebab-case")]
283#[strum(serialize_all = "kebab-case")]
284pub enum DiskDrivers {
285 Virtio,
286 Sata,
287}
288
289#[derive(Deserialize, Serialize, Debug, Clone, Builder)]
290pub struct ImageFile {
291 pub sha1: String,
293
294 pub size: i64,
296
297 pub compression: ImageFileCompression,
299
300 #[builder(setter(into, strip_option), default)]
302 pub dataset_guid: Option<String>,
303
304 #[builder(setter(into, strip_option), default)]
306 pub stor: Option<String>,
307
308 #[builder(setter(into, strip_option), default)]
310 pub digest: Option<String>,
311
312 #[serde(rename = "uncompressedDigest")]
314 #[builder(setter(into, strip_option), default)]
315 pub uncompressed_digest: Option<String>,
316}
317
318#[derive(Deserialize, Serialize, Debug, Clone, StrumDisplay)]
319#[serde(rename_all = "kebab-case")]
320pub enum ImageFileCompression {
321 Bzip2,
322 Gzip,
323 None,
324}