oxide_api/
types.rs

1//! The data types sent to and returned from the API client.
2use std::fmt;
3
4use parse_display::{Display, FromStr};
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7use tabled::Tabled;
8
9#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
10#[serde(rename_all = "snake_case")]
11#[serde(tag = "type", content = "start")]
12pub enum BinRangedouble {
13    RangeTo(f64),
14    Range { end: f64, start: f64 },
15    RangeFrom(f64),
16}
17
18impl fmt::Display for BinRangedouble {
19    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
20        let j = serde_json::json!(self);
21        let mut tag: String = serde_json::from_value(j["type"].clone()).unwrap_or_default();
22        let mut content: String = serde_json::from_value(j["start"].clone()).unwrap_or_default();
23        if content.is_empty() {
24            let map: std::collections::HashMap<String, String> =
25                serde_json::from_value(j["start"].clone()).unwrap_or_default();
26            if let Some((_, v)) = map.iter().next() {
27                content = v.to_string();
28            }
29        }
30        if tag == "internet_gateway" {
31            tag = "inetgw".to_string();
32        }
33        write!(f, "{}={}", tag, content)
34    }
35}
36
37impl std::str::FromStr for BinRangedouble {
38    type Err = anyhow::Error;
39    fn from_str(s: &str) -> Result<Self, Self::Err> {
40        let parts = s.split('=').collect::<Vec<&str>>();
41        if parts.len() != 2 {
42            anyhow::bail!("invalid format for BinRangedouble, got {}", s);
43        }
44        let tag = parts[0].to_string();
45        let content = parts[1].to_string();
46        let mut j = String::new();
47        if tag == "range_to" {
48            j = format!(
49                r#"{{
50"type": "range_to",
51"start": {}
52        }}"#,
53                serde_json::json!(f64::from_str(&content).unwrap())
54            );
55        }
56        if tag == "range" {
57            j = format!(
58                r#"{{
59"type": "range",
60"start": {}
61        }}"#,
62                serde_json::json!(f64::from_str(&content).unwrap())
63            );
64        }
65        if tag == "range" {
66            j = format!(
67                r#"{{
68"type": "range",
69"start": {}
70        }}"#,
71                serde_json::json!(f64::from_str(&content).unwrap())
72            );
73        }
74        if tag == "range_from" {
75            j = format!(
76                r#"{{
77"type": "range_from",
78"start": {}
79        }}"#,
80                serde_json::json!(f64::from_str(&content).unwrap())
81            );
82        }
83        let result = serde_json::from_str(&j)?;
84        Ok(result)
85    }
86}
87impl BinRangedouble {
88    pub fn variants() -> Vec<String> {
89        vec![
90            "range".to_string(),
91            "range_from".to_string(),
92            "range_to".to_string(),
93        ]
94    }
95}
96/**
97 * The types for BinRangedouble.
98 */
99#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
100#[serde(rename_all = "snake_case")]
101pub enum BinRangedoubleType {
102    Range,
103    RangeFrom,
104    RangeTo,
105}
106
107impl std::fmt::Display for BinRangedoubleType {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        match &*self {
110            BinRangedoubleType::Range => "range",
111            BinRangedoubleType::RangeFrom => "range_from",
112            BinRangedoubleType::RangeTo => "range_to",
113        }
114        .fmt(f)
115    }
116}
117
118impl Default for BinRangedoubleType {
119    fn default() -> BinRangedoubleType {
120        BinRangedoubleType::Range
121    }
122}
123impl std::str::FromStr for BinRangedoubleType {
124    type Err = anyhow::Error;
125    fn from_str(s: &str) -> Result<Self, Self::Err> {
126        if s == "range" {
127            return Ok(BinRangedoubleType::Range);
128        }
129        if s == "range_from" {
130            return Ok(BinRangedoubleType::RangeFrom);
131        }
132        if s == "range_to" {
133            return Ok(BinRangedoubleType::RangeTo);
134        }
135        anyhow::bail!("invalid string for BinRangedoubleType: {}", s);
136    }
137}
138
139#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
140#[serde(rename_all = "snake_case")]
141#[serde(tag = "type", content = "start")]
142pub enum BinRangeint64 {
143    RangeTo(i64),
144    Range { end: i64, start: i64 },
145    RangeFrom(i64),
146}
147
148impl fmt::Display for BinRangeint64 {
149    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
150        let j = serde_json::json!(self);
151        let mut tag: String = serde_json::from_value(j["type"].clone()).unwrap_or_default();
152        let mut content: String = serde_json::from_value(j["start"].clone()).unwrap_or_default();
153        if content.is_empty() {
154            let map: std::collections::HashMap<String, String> =
155                serde_json::from_value(j["start"].clone()).unwrap_or_default();
156            if let Some((_, v)) = map.iter().next() {
157                content = v.to_string();
158            }
159        }
160        if tag == "internet_gateway" {
161            tag = "inetgw".to_string();
162        }
163        write!(f, "{}={}", tag, content)
164    }
165}
166
167impl std::str::FromStr for BinRangeint64 {
168    type Err = anyhow::Error;
169    fn from_str(s: &str) -> Result<Self, Self::Err> {
170        let parts = s.split('=').collect::<Vec<&str>>();
171        if parts.len() != 2 {
172            anyhow::bail!("invalid format for BinRangeint64, got {}", s);
173        }
174        let tag = parts[0].to_string();
175        let content = parts[1].to_string();
176        let mut j = String::new();
177        if tag == "range_to" {
178            j = format!(
179                r#"{{
180"type": "range_to",
181"start": {}
182        }}"#,
183                serde_json::json!(i64::from_str(&content).unwrap())
184            );
185        }
186        if tag == "range" {
187            j = format!(
188                r#"{{
189"type": "range",
190"start": {}
191        }}"#,
192                serde_json::json!(i64::from_str(&content).unwrap())
193            );
194        }
195        if tag == "range" {
196            j = format!(
197                r#"{{
198"type": "range",
199"start": {}
200        }}"#,
201                serde_json::json!(i64::from_str(&content).unwrap())
202            );
203        }
204        if tag == "range_from" {
205            j = format!(
206                r#"{{
207"type": "range_from",
208"start": {}
209        }}"#,
210                serde_json::json!(i64::from_str(&content).unwrap())
211            );
212        }
213        let result = serde_json::from_str(&j)?;
214        Ok(result)
215    }
216}
217impl BinRangeint64 {
218    pub fn variants() -> Vec<String> {
219        vec![
220            "range".to_string(),
221            "range_from".to_string(),
222            "range_to".to_string(),
223        ]
224    }
225}
226/**
227 * The types for BinRangeint64.
228 */
229#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
230#[serde(rename_all = "snake_case")]
231pub enum BinRangeint64Type {
232    Range,
233    RangeFrom,
234    RangeTo,
235}
236
237impl std::fmt::Display for BinRangeint64Type {
238    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
239        match &*self {
240            BinRangeint64Type::Range => "range",
241            BinRangeint64Type::RangeFrom => "range_from",
242            BinRangeint64Type::RangeTo => "range_to",
243        }
244        .fmt(f)
245    }
246}
247
248impl Default for BinRangeint64Type {
249    fn default() -> BinRangeint64Type {
250        BinRangeint64Type::Range
251    }
252}
253impl std::str::FromStr for BinRangeint64Type {
254    type Err = anyhow::Error;
255    fn from_str(s: &str) -> Result<Self, Self::Err> {
256        if s == "range" {
257            return Ok(BinRangeint64Type::Range);
258        }
259        if s == "range_from" {
260            return Ok(BinRangeint64Type::RangeFrom);
261        }
262        if s == "range_to" {
263            return Ok(BinRangeint64Type::RangeTo);
264        }
265        anyhow::bail!("invalid string for BinRangeint64Type: {}", s);
266    }
267}
268
269/// Type storing bin edges and a count of samples within it.
270#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
271pub struct Bindouble {
272    /**
273     * The total count of samples in this bin.
274     */
275    #[serde(default)]
276    pub count: u64,
277
278    #[serde()]
279    pub range: BinRangedouble,
280}
281
282/// Type storing bin edges and a count of samples within it.
283#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
284pub struct Binint64 {
285    /**
286     * The total count of samples in this bin.
287     */
288    #[serde(default)]
289    pub count: u64,
290
291    #[serde()]
292    pub range: BinRangeint64,
293}
294
295/// A cumulative or counter data type.
296#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
297pub struct Cumulativedouble {
298    #[serde()]
299    pub start_time: crate::utils::DisplayOptionDateTime,
300
301    #[serde(
302        default,
303        skip_serializing_if = "crate::utils::zero_f64",
304        deserialize_with = "crate::utils::deserialize_null_f64::deserialize"
305    )]
306    pub value: f64,
307}
308
309/// A cumulative or counter data type.
310#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
311pub struct Cumulativeint64 {
312    #[serde()]
313    pub start_time: crate::utils::DisplayOptionDateTime,
314
315    #[serde(
316        default,
317        skip_serializing_if = "crate::utils::zero_i64",
318        deserialize_with = "crate::utils::deserialize_null_i64::deserialize"
319    )]
320    pub value: i64,
321}
322
323#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
324#[serde(rename_all = "snake_case")]
325pub enum Datum {
326    Bool,
327    Bytes,
328    CumulativeF64,
329    CumulativeI64,
330    F64,
331    HistogramF64,
332    HistogramI64,
333    I64,
334    String,
335    #[serde(rename = "")]
336    Noop,
337    #[serde(other)]
338    FallthroughString,
339}
340
341impl std::fmt::Display for Datum {
342    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
343        match &*self {
344            Datum::Bool => "bool",
345            Datum::Bytes => "bytes",
346            Datum::CumulativeF64 => "cumulative_f_64",
347            Datum::CumulativeI64 => "cumulative_i_64",
348            Datum::F64 => "f_64",
349            Datum::HistogramF64 => "histogram_f_64",
350            Datum::HistogramI64 => "histogram_i_64",
351            Datum::I64 => "i_64",
352            Datum::String => "string",
353            Datum::Noop => "",
354            Datum::FallthroughString => "*",
355        }
356        .fmt(f)
357    }
358}
359
360impl Default for Datum {
361    fn default() -> Datum {
362        Datum::Bool
363    }
364}
365impl std::str::FromStr for Datum {
366    type Err = anyhow::Error;
367    fn from_str(s: &str) -> Result<Self, Self::Err> {
368        if s == "bool" {
369            return Ok(Datum::Bool);
370        }
371        if s == "bytes" {
372            return Ok(Datum::Bytes);
373        }
374        if s == "cumulative_f_64" {
375            return Ok(Datum::CumulativeF64);
376        }
377        if s == "cumulative_i_64" {
378            return Ok(Datum::CumulativeI64);
379        }
380        if s == "f_64" {
381            return Ok(Datum::F64);
382        }
383        if s == "histogram_f_64" {
384            return Ok(Datum::HistogramF64);
385        }
386        if s == "histogram_i_64" {
387            return Ok(Datum::HistogramI64);
388        }
389        if s == "i_64" {
390            return Ok(Datum::I64);
391        }
392        if s == "string" {
393            return Ok(Datum::String);
394        }
395        anyhow::bail!("invalid string for Datum: {}", s);
396    }
397}
398impl Datum {
399    pub fn is_noop(&self) -> bool {
400        matches!(self, Datum::Noop)
401    }
402}
403
404/**
405 * The type of an individual datum of a metric.
406 */
407#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
408#[serde(rename_all = "snake_case")]
409pub enum DatumType {
410    Bool,
411    Bytes,
412    CumulativeF64,
413    CumulativeI64,
414    F64,
415    HistogramF64,
416    HistogramI64,
417    I64,
418    String,
419    #[serde(rename = "")]
420    Noop,
421    #[serde(other)]
422    FallthroughString,
423}
424
425impl std::fmt::Display for DatumType {
426    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
427        match &*self {
428            DatumType::Bool => "bool",
429            DatumType::Bytes => "bytes",
430            DatumType::CumulativeF64 => "cumulative_f_64",
431            DatumType::CumulativeI64 => "cumulative_i_64",
432            DatumType::F64 => "f_64",
433            DatumType::HistogramF64 => "histogram_f_64",
434            DatumType::HistogramI64 => "histogram_i_64",
435            DatumType::I64 => "i_64",
436            DatumType::String => "string",
437            DatumType::Noop => "",
438            DatumType::FallthroughString => "*",
439        }
440        .fmt(f)
441    }
442}
443
444impl Default for DatumType {
445    fn default() -> DatumType {
446        DatumType::Bool
447    }
448}
449impl std::str::FromStr for DatumType {
450    type Err = anyhow::Error;
451    fn from_str(s: &str) -> Result<Self, Self::Err> {
452        if s == "bool" {
453            return Ok(DatumType::Bool);
454        }
455        if s == "bytes" {
456            return Ok(DatumType::Bytes);
457        }
458        if s == "cumulative_f_64" {
459            return Ok(DatumType::CumulativeF64);
460        }
461        if s == "cumulative_i_64" {
462            return Ok(DatumType::CumulativeI64);
463        }
464        if s == "f_64" {
465            return Ok(DatumType::F64);
466        }
467        if s == "histogram_f_64" {
468            return Ok(DatumType::HistogramF64);
469        }
470        if s == "histogram_i_64" {
471            return Ok(DatumType::HistogramI64);
472        }
473        if s == "i_64" {
474            return Ok(DatumType::I64);
475        }
476        if s == "string" {
477            return Ok(DatumType::String);
478        }
479        anyhow::bail!("invalid string for DatumType: {}", s);
480    }
481}
482impl DatumType {
483    pub fn is_noop(&self) -> bool {
484        matches!(self, DatumType::Noop)
485    }
486}
487
488#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
489pub struct DerEncodedKeyPair {
490    /**
491     * request signing private key (base64 encoded der file)
492     */
493    #[serde(
494        default,
495        skip_serializing_if = "String::is_empty",
496        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
497    )]
498    pub private_key: String,
499
500    /**
501     * request signing public certificate (base64 encoded der file)
502     */
503    #[serde(
504        default,
505        skip_serializing_if = "String::is_empty",
506        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
507    )]
508    pub public_cert: String,
509}
510
511#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
512pub struct DeviceAccessTokenRequest {
513    #[serde(
514        default,
515        skip_serializing_if = "String::is_empty",
516        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
517    )]
518    pub client_id: String,
519
520    #[serde(
521        default,
522        skip_serializing_if = "String::is_empty",
523        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
524    )]
525    pub device_code: String,
526
527    #[serde(
528        default,
529        skip_serializing_if = "String::is_empty",
530        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
531    )]
532    pub grant_type: String,
533}
534
535#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
536pub struct DeviceAuthRequest {
537    #[serde(
538        default,
539        skip_serializing_if = "String::is_empty",
540        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
541    )]
542    pub client_id: String,
543}
544
545#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
546pub struct DeviceAuthVerify {
547    #[serde(
548        default,
549        skip_serializing_if = "String::is_empty",
550        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
551    )]
552    pub user_code: String,
553}
554
555#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
556#[serde(rename_all = "snake_case")]
557#[serde(tag = "type", content = "value")]
558pub enum Digest {
559    Sha256(String),
560}
561
562impl fmt::Display for Digest {
563    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
564        let j = serde_json::json!(self);
565        let mut tag: String = serde_json::from_value(j["type"].clone()).unwrap_or_default();
566        let mut content: String = serde_json::from_value(j["value"].clone()).unwrap_or_default();
567        if content.is_empty() {
568            let map: std::collections::HashMap<String, String> =
569                serde_json::from_value(j["value"].clone()).unwrap_or_default();
570            if let Some((_, v)) = map.iter().next() {
571                content = v.to_string();
572            }
573        }
574        if tag == "internet_gateway" {
575            tag = "inetgw".to_string();
576        }
577        write!(f, "{}={}", tag, content)
578    }
579}
580
581impl std::str::FromStr for Digest {
582    type Err = anyhow::Error;
583    fn from_str(s: &str) -> Result<Self, Self::Err> {
584        let parts = s.split('=').collect::<Vec<&str>>();
585        if parts.len() != 2 {
586            anyhow::bail!("invalid format for Digest, got {}", s);
587        }
588        let tag = parts[0].to_string();
589        let content = parts[1].to_string();
590        let mut j = String::new();
591        if tag == "sha_256" {
592            j = format!(
593                r#"{{
594"type": "sha_256",
595"value": "{}"
596        }}"#,
597                content
598            );
599        }
600        let result = serde_json::from_str(&j)?;
601        Ok(result)
602    }
603}
604impl Digest {
605    pub fn variants() -> Vec<String> {
606        vec!["sha_256".to_string()]
607    }
608}
609/**
610 * The types for Digest.
611 */
612#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
613#[serde(rename_all = "snake_case")]
614pub enum DigestType {
615    Sha256,
616}
617
618impl std::fmt::Display for DigestType {
619    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
620        match &*self {
621            DigestType::Sha256 => "sha_256",
622        }
623        .fmt(f)
624    }
625}
626
627impl Default for DigestType {
628    fn default() -> DigestType {
629        DigestType::Sha256
630    }
631}
632impl std::str::FromStr for DigestType {
633    type Err = anyhow::Error;
634    fn from_str(s: &str) -> Result<Self, Self::Err> {
635        if s == "sha_256" {
636            return Ok(DigestType::Sha256);
637        }
638        anyhow::bail!("invalid string for DigestType: {}", s);
639    }
640}
641
642#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
643#[serde(rename_all = "snake_case")]
644#[serde(tag = "state", content = "instance")]
645pub enum DiskState {
646    Creating,
647    Detached,
648    Attaching(String),
649    Attached(String),
650    Detaching(String),
651    Destroyed,
652    Faulted,
653}
654
655impl fmt::Display for DiskState {
656    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
657        let j = serde_json::json!(self);
658        let mut tag: String = serde_json::from_value(j["state"].clone()).unwrap_or_default();
659        let mut content: String = serde_json::from_value(j["instance"].clone()).unwrap_or_default();
660        if content.is_empty() {
661            let map: std::collections::HashMap<String, String> =
662                serde_json::from_value(j["instance"].clone()).unwrap_or_default();
663            if let Some((_, v)) = map.iter().next() {
664                content = v.to_string();
665            }
666        }
667        if tag == "internet_gateway" {
668            tag = "inetgw".to_string();
669        }
670        write!(f, "{}={}", tag, content)
671    }
672}
673
674impl std::str::FromStr for DiskState {
675    type Err = anyhow::Error;
676    fn from_str(s: &str) -> Result<Self, Self::Err> {
677        let parts = s.split('=').collect::<Vec<&str>>();
678        if parts.len() != 2 {
679            anyhow::bail!("invalid format for DiskState, got {}", s);
680        }
681        let tag = parts[0].to_string();
682        let content = parts[1].to_string();
683        let mut j = String::new();
684        if tag == "attaching" {
685            j = format!(
686                r#"{{
687"state": "attaching",
688"instance": "{}"
689        }}"#,
690                content
691            );
692        }
693        if tag == "attached" {
694            j = format!(
695                r#"{{
696"state": "attached",
697"instance": "{}"
698        }}"#,
699                content
700            );
701        }
702        if tag == "detaching" {
703            j = format!(
704                r#"{{
705"state": "detaching",
706"instance": "{}"
707        }}"#,
708                content
709            );
710        }
711        let result = serde_json::from_str(&j)?;
712        Ok(result)
713    }
714}
715impl DiskState {
716    pub fn variants() -> Vec<String> {
717        vec![
718            "attached".to_string(),
719            "attaching".to_string(),
720            "creating".to_string(),
721            "destroyed".to_string(),
722            "detached".to_string(),
723            "detaching".to_string(),
724            "faulted".to_string(),
725        ]
726    }
727}
728/**
729 * The types for DiskState.
730 */
731#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
732#[serde(rename_all = "snake_case")]
733pub enum DiskStateType {
734    Attached,
735    Attaching,
736    Creating,
737    Destroyed,
738    Detached,
739    Detaching,
740    Faulted,
741}
742
743impl std::fmt::Display for DiskStateType {
744    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
745        match &*self {
746            DiskStateType::Attached => "attached",
747            DiskStateType::Attaching => "attaching",
748            DiskStateType::Creating => "creating",
749            DiskStateType::Destroyed => "destroyed",
750            DiskStateType::Detached => "detached",
751            DiskStateType::Detaching => "detaching",
752            DiskStateType::Faulted => "faulted",
753        }
754        .fmt(f)
755    }
756}
757
758impl Default for DiskStateType {
759    fn default() -> DiskStateType {
760        DiskStateType::Attached
761    }
762}
763impl std::str::FromStr for DiskStateType {
764    type Err = anyhow::Error;
765    fn from_str(s: &str) -> Result<Self, Self::Err> {
766        if s == "attached" {
767            return Ok(DiskStateType::Attached);
768        }
769        if s == "attaching" {
770            return Ok(DiskStateType::Attaching);
771        }
772        if s == "creating" {
773            return Ok(DiskStateType::Creating);
774        }
775        if s == "destroyed" {
776            return Ok(DiskStateType::Destroyed);
777        }
778        if s == "detached" {
779            return Ok(DiskStateType::Detached);
780        }
781        if s == "detaching" {
782            return Ok(DiskStateType::Detaching);
783        }
784        if s == "faulted" {
785            return Ok(DiskStateType::Faulted);
786        }
787        anyhow::bail!("invalid string for DiskStateType: {}", s);
788    }
789}
790
791/// Client view of a [`Disk`]
792#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
793pub struct Disk {
794    /**
795     * unique, immutable, system-controlled identifier for each resource
796     */
797    #[serde(
798        default,
799        skip_serializing_if = "String::is_empty",
800        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
801    )]
802    pub id: String,
803
804    /**
805     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
806     */
807    #[serde(
808        default,
809        skip_serializing_if = "String::is_empty",
810        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
811    )]
812    pub name: String,
813
814    /**
815     * human-readable free-form text about a resource
816     */
817    #[serde(
818        default,
819        skip_serializing_if = "String::is_empty",
820        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
821    )]
822    pub description: String,
823
824    /**
825     * A count of bytes, typically used either for memory or storage capacity
826     *  
827     *  The maximum supported byte count is [`i64::MAX`].  This makes it somewhat inconvenient to define constructors: a u32 constructor can be infallible, but an i64 constructor can fail (if the value is negative) and a u64 constructor can fail (if the value is larger than i64::MAX).  We provide all of these for consumers' convenience.
828     */
829    #[serde(default)]
830    pub block_size: u64,
831
832    #[serde(
833        default,
834        skip_serializing_if = "String::is_empty",
835        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
836    )]
837    pub device_path: String,
838
839    #[serde(
840        default,
841        skip_serializing_if = "String::is_empty",
842        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
843    )]
844    pub image_id: String,
845
846    #[serde(
847        default,
848        skip_serializing_if = "String::is_empty",
849        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
850    )]
851    pub project_id: String,
852
853    /**
854     * A count of bytes, typically used either for memory or storage capacity
855     *  
856     *  The maximum supported byte count is [`i64::MAX`].  This makes it somewhat inconvenient to define constructors: a u32 constructor can be infallible, but an i64 constructor can fail (if the value is negative) and a u64 constructor can fail (if the value is larger than i64::MAX).  We provide all of these for consumers' convenience.
857     */
858    #[serde(default)]
859    pub size: u64,
860
861    #[serde(
862        default,
863        skip_serializing_if = "String::is_empty",
864        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
865    )]
866    pub snapshot_id: String,
867
868    #[serde()]
869    pub state: DiskState,
870
871    /**
872     * timestamp when this resource was created
873     */
874    #[serde()]
875    pub time_created: crate::utils::DisplayOptionDateTime,
876
877    /**
878     * timestamp when this resource was last modified
879     */
880    #[serde()]
881    pub time_modified: crate::utils::DisplayOptionDateTime,
882}
883
884#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
885#[serde(rename_all = "snake_case")]
886#[serde(tag = "type")]
887pub enum DiskSource {
888    Blank { block_size: i64 },
889    Snapshot { snapshot_id: String },
890    Image { image_id: String },
891    GlobalImage { image_id: String },
892}
893
894impl fmt::Display for DiskSource {
895    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
896        let j = serde_json::json!(self);
897        let mut tag: String = serde_json::from_value(j["type"].clone()).unwrap_or_default();
898
899        let mut value = "image_id";
900        if tag == *"blank" {
901            value = "block_size";
902        };
903        if tag == *"snapshot" {
904            value = "snapshot_id";
905        };
906
907        let mut content: String = match serde_json::from_value(j[value].clone()) {
908            Ok(v) => v,
909            Err(_) => {
910                let int: i64 = serde_json::from_value(j[value].clone()).unwrap_or_default();
911                format!("{}", int)
912            }
913        };
914        if content.is_empty() {
915            let map: std::collections::HashMap<String, String> =
916                serde_json::from_value(j[value].clone()).unwrap_or_default();
917            if let Some((_, v)) = map.iter().next() {
918                content = v.to_string();
919            }
920        }
921        if tag == "internet_gateway" {
922            tag = "inetgw".to_string();
923        }
924        write!(f, "{}={}", tag, content)
925    }
926}
927
928impl std::str::FromStr for DiskSource {
929    type Err = anyhow::Error;
930    fn from_str(s: &str) -> Result<Self, Self::Err> {
931        let parts = s.split('=').collect::<Vec<&str>>();
932        if parts.len() != 2 {
933            anyhow::bail!("invalid format for DiskSource, got {}", s);
934        }
935        let tag = parts[0].to_string();
936        let content = parts[1].to_string();
937        let mut j = String::new();
938        if tag == "blank" {
939            j = format!(
940                r#"{{
941"type": "blank",
942"block_size": {}
943        }}"#,
944                serde_json::json!(i64::from_str(&content).unwrap())
945            );
946        }
947        if tag == "snapshot" {
948            j = format!(
949                r#"{{
950"type": "snapshot",
951"snapshot_id": "{}"
952        }}"#,
953                content
954            );
955        }
956        if tag == "image" {
957            j = format!(
958                r#"{{
959"type": "image",
960"image_id": "{}"
961        }}"#,
962                content
963            );
964        }
965        if tag == "global_image" {
966            j = format!(
967                r#"{{
968"type": "global_image",
969"image_id": "{}"
970        }}"#,
971                content
972            );
973        }
974        let result = serde_json::from_str(&j)?;
975        Ok(result)
976    }
977}
978impl DiskSource {
979    pub fn variants() -> Vec<String> {
980        vec![
981            "blank".to_string(),
982            "global_image".to_string(),
983            "image".to_string(),
984            "snapshot".to_string(),
985        ]
986    }
987}
988/**
989 * The types for DiskSource.
990 */
991#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
992#[serde(rename_all = "snake_case")]
993pub enum DiskSourceType {
994    Blank,
995    GlobalImage,
996    Image,
997    Snapshot,
998}
999
1000impl std::fmt::Display for DiskSourceType {
1001    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1002        match &*self {
1003            DiskSourceType::Blank => "blank",
1004            DiskSourceType::GlobalImage => "global_image",
1005            DiskSourceType::Image => "image",
1006            DiskSourceType::Snapshot => "snapshot",
1007        }
1008        .fmt(f)
1009    }
1010}
1011
1012impl Default for DiskSourceType {
1013    fn default() -> DiskSourceType {
1014        DiskSourceType::Blank
1015    }
1016}
1017impl std::str::FromStr for DiskSourceType {
1018    type Err = anyhow::Error;
1019    fn from_str(s: &str) -> Result<Self, Self::Err> {
1020        if s == "blank" {
1021            return Ok(DiskSourceType::Blank);
1022        }
1023        if s == "global_image" {
1024            return Ok(DiskSourceType::GlobalImage);
1025        }
1026        if s == "image" {
1027            return Ok(DiskSourceType::Image);
1028        }
1029        if s == "snapshot" {
1030            return Ok(DiskSourceType::Snapshot);
1031        }
1032        anyhow::bail!("invalid string for DiskSourceType: {}", s);
1033    }
1034}
1035
1036/// Create-time parameters for a [`Disk`](omicron_common::api::external::Disk)
1037#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
1038pub struct DiskCreate {
1039    /**
1040     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
1041     */
1042    #[serde(
1043        default,
1044        skip_serializing_if = "String::is_empty",
1045        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1046    )]
1047    pub name: String,
1048
1049    #[serde(
1050        default,
1051        skip_serializing_if = "String::is_empty",
1052        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1053    )]
1054    pub description: String,
1055
1056    #[serde()]
1057    pub disk_source: DiskSource,
1058
1059    /**
1060     * A count of bytes, typically used either for memory or storage capacity
1061     *  
1062     *  The maximum supported byte count is [`i64::MAX`].  This makes it somewhat inconvenient to define constructors: a u32 constructor can be infallible, but an i64 constructor can fail (if the value is negative) and a u64 constructor can fail (if the value is larger than i64::MAX).  We provide all of these for consumers' convenience.
1063     */
1064    #[serde(default)]
1065    pub size: u64,
1066}
1067
1068/// Parameters for the [`Disk`](omicron_common::api::external::Disk) to be attached or detached to an instance
1069#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
1070pub struct DiskIdentifier {
1071    /**
1072     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
1073     */
1074    #[serde(
1075        default,
1076        skip_serializing_if = "String::is_empty",
1077        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1078    )]
1079    pub name: String,
1080}
1081
1082/// A single page of results
1083#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
1084pub struct DiskResultsPage {
1085    /**
1086     * list of items on this page of results
1087     */
1088    #[serde(
1089        default,
1090        skip_serializing_if = "Vec::is_empty",
1091        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
1092    )]
1093    #[header(hidden = true)]
1094    pub items: Vec<Disk>,
1095
1096    /**
1097     * token used to fetch the next page of results (if any)
1098     */
1099    #[serde(
1100        default,
1101        skip_serializing_if = "String::is_empty",
1102        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1103    )]
1104    pub next_page: String,
1105}
1106
1107/// OS image distribution
1108#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
1109pub struct Distribution {
1110    /**
1111     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
1112     */
1113    #[serde(
1114        default,
1115        skip_serializing_if = "String::is_empty",
1116        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1117    )]
1118    pub name: String,
1119
1120    /**
1121     * The version of the distribution (e.g. "3.10" or "18.04")
1122     */
1123    #[serde(
1124        default,
1125        skip_serializing_if = "String::is_empty",
1126        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1127    )]
1128    pub version: String,
1129}
1130
1131impl fmt::Display for Distribution {
1132    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1133        write!(f, "{}-{}", self.name, self.version)
1134    }
1135}
1136
1137#[derive(Debug, Deserialize, thiserror::Error, PartialEq, Serialize)]
1138pub enum Error {
1139    /// An object needed as part of this operation was not found.
1140    #[error("Object Not Found: {message}")]
1141    ObjectNotFound { message: String },
1142    /// An object already exists with the specified name or identifier.
1143    #[error("Object Already Exists: {message}")]
1144    ObjectAlreadyExists { message: String },
1145    /// The request was well-formed, but the operation cannot be completed given
1146    /// the current state of the system.
1147    #[error("Invalid Request: {message}")]
1148    InvalidRequest { message: String },
1149    /// Authentication credentials were required but either missing or invalid.
1150    /// The HTTP status code is called "Unauthorized", but it's more accurate to
1151    /// call it "Unauthenticated".
1152    #[error("Missing or invalid credentials")]
1153    Unauthenticated { internal_message: String },
1154    /// The specified input field is not valid.
1155    #[error("Invalid Value: {message}")]
1156    InvalidValue { message: String },
1157    /// The request is not authorized to perform the requested operation.
1158    #[error("Forbidden")]
1159    Forbidden,
1160
1161    /// The system encountered an unhandled operational error.
1162    #[error("Internal Error: {internal_message}")]
1163    InternalError { internal_message: String },
1164    /// The system (or part of it) is unavailable.
1165    #[error("Service Unavailable: {internal_message}")]
1166    ServiceUnavailable { internal_message: String },
1167    /// Method Not Allowed
1168    #[error("Method Not Allowed: {internal_message}")]
1169    MethodNotAllowed { internal_message: String },
1170}
1171
1172impl Error {
1173    /// Returns whether the error is likely transient and could reasonably be
1174    /// retried
1175    pub fn retryable(&self) -> bool {
1176        match self {
1177            Error::ServiceUnavailable { .. } => true,
1178
1179            Error::ObjectNotFound { .. }
1180            | Error::ObjectAlreadyExists { .. }
1181            | Error::Unauthenticated { .. }
1182            | Error::InvalidRequest { .. }
1183            | Error::InvalidValue { .. }
1184            | Error::Forbidden
1185            | Error::MethodNotAllowed { .. }
1186            | Error::InternalError { .. } => false,
1187        }
1188    }
1189}
1190
1191impl From<ErrorResponse> for Error {
1192    /// Converts an `Error` error into an `HttpError`.  This defines how
1193    /// errors that are represented internally using `Error` are ultimately
1194    /// exposed to clients over HTTP.
1195    fn from(error: ErrorResponse) -> Error {
1196        if error.error_code == "ObjectNotFound" {
1197            return Error::ObjectNotFound {
1198                message: error.message,
1199            };
1200        }
1201
1202        if error.error_code == "ObjectAlreadyExists" {
1203            return Error::ObjectAlreadyExists {
1204                message: error.message,
1205            };
1206        }
1207
1208        if error.error_code == "Unauthorized" {
1209            return Error::Unauthenticated {
1210                internal_message: error.message,
1211            };
1212        }
1213
1214        if error.error_code == "InvalidRequest" {
1215            return Error::InvalidRequest {
1216                message: error.message,
1217            };
1218        }
1219
1220        if error.error_code == "InvalidValue" {
1221            return Error::InvalidValue {
1222                message: error.message,
1223            };
1224        }
1225
1226        if error.error_code == "Forbidden" {
1227            return Error::Forbidden;
1228        }
1229
1230        if error.error_code == "MethodNotAllowed" {
1231            return Error::MethodNotAllowed {
1232                internal_message: error.message,
1233            };
1234        }
1235
1236        if error.error_code == "ServiceUnavailable" {
1237            return Error::ServiceUnavailable {
1238                internal_message: error.message,
1239            };
1240        }
1241
1242        Error::InternalError {
1243            internal_message: error.message,
1244        }
1245    }
1246}
1247
1248/// Identifies a type of API resource
1249#[derive(
1250    Clone,
1251    Copy,
1252    Debug,
1253    serde_with::DeserializeFromStr,
1254    Display,
1255    Eq,
1256    FromStr,
1257    Ord,
1258    PartialEq,
1259    PartialOrd,
1260    serde_with::SerializeDisplay,
1261)]
1262#[display(style = "kebab-case")]
1263pub enum ResourceType {
1264    Fleet,
1265    Organization,
1266    Project,
1267    Dataset,
1268    Disk,
1269    Instance,
1270    NetworkInterface,
1271    Rack,
1272    Sled,
1273    SagaDbg,
1274    Volume,
1275    Vpc,
1276    VpcFirewallRule,
1277    VpcSubnet,
1278    VpcRouter,
1279    RouterRoute,
1280    Oximeter,
1281    MetricProducer,
1282    Role,
1283    User,
1284    Zpool,
1285}
1286
1287/// Error information from a response.
1288#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
1289pub struct ErrorResponse {
1290    #[serde(
1291        default,
1292        skip_serializing_if = "String::is_empty",
1293        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1294    )]
1295    pub error_code: String,
1296
1297    #[serde(
1298        default,
1299        skip_serializing_if = "String::is_empty",
1300        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1301    )]
1302    pub message: String,
1303
1304    #[serde(
1305        default,
1306        skip_serializing_if = "String::is_empty",
1307        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1308    )]
1309    pub request_id: String,
1310}
1311
1312/**
1313 * The kind of an external IP address for an instance
1314 */
1315#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
1316#[serde(rename_all = "snake_case")]
1317pub enum IpKind {
1318    Ephemeral,
1319    Floating,
1320    #[serde(rename = "")]
1321    Noop,
1322    #[serde(other)]
1323    FallthroughString,
1324}
1325
1326impl std::fmt::Display for IpKind {
1327    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1328        match &*self {
1329            IpKind::Ephemeral => "ephemeral",
1330            IpKind::Floating => "floating",
1331            IpKind::Noop => "",
1332            IpKind::FallthroughString => "*",
1333        }
1334        .fmt(f)
1335    }
1336}
1337
1338impl Default for IpKind {
1339    fn default() -> IpKind {
1340        IpKind::Ephemeral
1341    }
1342}
1343impl std::str::FromStr for IpKind {
1344    type Err = anyhow::Error;
1345    fn from_str(s: &str) -> Result<Self, Self::Err> {
1346        if s == "ephemeral" {
1347            return Ok(IpKind::Ephemeral);
1348        }
1349        if s == "floating" {
1350            return Ok(IpKind::Floating);
1351        }
1352        anyhow::bail!("invalid string for IpKind: {}", s);
1353    }
1354}
1355impl IpKind {
1356    pub fn is_noop(&self) -> bool {
1357        matches!(self, IpKind::Noop)
1358    }
1359}
1360
1361#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
1362pub struct ExternalIp {
1363    #[serde(
1364        default,
1365        skip_serializing_if = "String::is_empty",
1366        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1367    )]
1368    pub ip: String,
1369
1370    /**
1371     * The kind of an external IP address for an instance
1372     */
1373    #[serde(default, skip_serializing_if = "IpKind::is_noop")]
1374    pub kind: IpKind,
1375}
1376
1377#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
1378#[serde(rename_all = "snake_case")]
1379#[serde(tag = "type", content = "pool_name")]
1380pub enum ExternalIpCreate {
1381    Ephemeral(String),
1382}
1383
1384impl fmt::Display for ExternalIpCreate {
1385    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1386        let j = serde_json::json!(self);
1387        let mut tag: String = serde_json::from_value(j["type"].clone()).unwrap_or_default();
1388        let mut content: String =
1389            serde_json::from_value(j["pool_name"].clone()).unwrap_or_default();
1390        if content.is_empty() {
1391            let map: std::collections::HashMap<String, String> =
1392                serde_json::from_value(j["pool_name"].clone()).unwrap_or_default();
1393            if let Some((_, v)) = map.iter().next() {
1394                content = v.to_string();
1395            }
1396        }
1397        if tag == "internet_gateway" {
1398            tag = "inetgw".to_string();
1399        }
1400        write!(f, "{}={}", tag, content)
1401    }
1402}
1403
1404impl std::str::FromStr for ExternalIpCreate {
1405    type Err = anyhow::Error;
1406    fn from_str(s: &str) -> Result<Self, Self::Err> {
1407        let parts = s.split('=').collect::<Vec<&str>>();
1408        if parts.len() != 2 {
1409            anyhow::bail!("invalid format for ExternalIpCreate, got {}", s);
1410        }
1411        let tag = parts[0].to_string();
1412        let content = parts[1].to_string();
1413        let mut j = String::new();
1414        if tag == "ephemeral" {
1415            j = format!(
1416                r#"{{
1417"type": "ephemeral",
1418"pool_name": "{}"
1419        }}"#,
1420                content
1421            );
1422        }
1423        let result = serde_json::from_str(&j)?;
1424        Ok(result)
1425    }
1426}
1427impl ExternalIpCreate {
1428    pub fn variants() -> Vec<String> {
1429        vec!["ephemeral".to_string()]
1430    }
1431}
1432/**
1433 * The types for ExternalIpCreate.
1434 */
1435#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
1436#[serde(rename_all = "snake_case")]
1437pub enum ExternalIpCreateType {
1438    Ephemeral,
1439}
1440
1441impl std::fmt::Display for ExternalIpCreateType {
1442    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1443        match &*self {
1444            ExternalIpCreateType::Ephemeral => "ephemeral",
1445        }
1446        .fmt(f)
1447    }
1448}
1449
1450impl Default for ExternalIpCreateType {
1451    fn default() -> ExternalIpCreateType {
1452        ExternalIpCreateType::Ephemeral
1453    }
1454}
1455impl std::str::FromStr for ExternalIpCreateType {
1456    type Err = anyhow::Error;
1457    fn from_str(s: &str) -> Result<Self, Self::Err> {
1458        if s == "ephemeral" {
1459            return Ok(ExternalIpCreateType::Ephemeral);
1460        }
1461        anyhow::bail!("invalid string for ExternalIpCreateType: {}", s);
1462    }
1463}
1464
1465/// A single page of results
1466#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
1467pub struct ExternalIpResultsPage {
1468    /**
1469     * list of items on this page of results
1470     */
1471    #[serde(
1472        default,
1473        skip_serializing_if = "Vec::is_empty",
1474        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
1475    )]
1476    #[header(hidden = true)]
1477    pub items: Vec<ExternalIp>,
1478
1479    /**
1480     * token used to fetch the next page of results (if any)
1481     */
1482    #[serde(
1483        default,
1484        skip_serializing_if = "String::is_empty",
1485        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1486    )]
1487    pub next_page: String,
1488}
1489
1490/**
1491 * The source from which a field is derived, the target or metric.
1492 */
1493#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
1494#[serde(rename_all = "snake_case")]
1495pub enum FieldSource {
1496    Metric,
1497    Target,
1498    #[serde(rename = "")]
1499    Noop,
1500    #[serde(other)]
1501    FallthroughString,
1502}
1503
1504impl std::fmt::Display for FieldSource {
1505    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1506        match &*self {
1507            FieldSource::Metric => "metric",
1508            FieldSource::Target => "target",
1509            FieldSource::Noop => "",
1510            FieldSource::FallthroughString => "*",
1511        }
1512        .fmt(f)
1513    }
1514}
1515
1516impl Default for FieldSource {
1517    fn default() -> FieldSource {
1518        FieldSource::Metric
1519    }
1520}
1521impl std::str::FromStr for FieldSource {
1522    type Err = anyhow::Error;
1523    fn from_str(s: &str) -> Result<Self, Self::Err> {
1524        if s == "metric" {
1525            return Ok(FieldSource::Metric);
1526        }
1527        if s == "target" {
1528            return Ok(FieldSource::Target);
1529        }
1530        anyhow::bail!("invalid string for FieldSource: {}", s);
1531    }
1532}
1533impl FieldSource {
1534    pub fn is_noop(&self) -> bool {
1535        matches!(self, FieldSource::Noop)
1536    }
1537}
1538
1539/**
1540 * The `FieldType` identifies the data type of a target or metric field.
1541 */
1542#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
1543#[serde(rename_all = "snake_case")]
1544pub enum FieldType {
1545    Bool,
1546    I64,
1547    IpAddr,
1548    String,
1549    Uuid,
1550    #[serde(rename = "")]
1551    Noop,
1552    #[serde(other)]
1553    FallthroughString,
1554}
1555
1556impl std::fmt::Display for FieldType {
1557    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1558        match &*self {
1559            FieldType::Bool => "bool",
1560            FieldType::I64 => "i_64",
1561            FieldType::IpAddr => "ip_addr",
1562            FieldType::String => "string",
1563            FieldType::Uuid => "uuid",
1564            FieldType::Noop => "",
1565            FieldType::FallthroughString => "*",
1566        }
1567        .fmt(f)
1568    }
1569}
1570
1571impl Default for FieldType {
1572    fn default() -> FieldType {
1573        FieldType::Bool
1574    }
1575}
1576impl std::str::FromStr for FieldType {
1577    type Err = anyhow::Error;
1578    fn from_str(s: &str) -> Result<Self, Self::Err> {
1579        if s == "bool" {
1580            return Ok(FieldType::Bool);
1581        }
1582        if s == "i_64" {
1583            return Ok(FieldType::I64);
1584        }
1585        if s == "ip_addr" {
1586            return Ok(FieldType::IpAddr);
1587        }
1588        if s == "string" {
1589            return Ok(FieldType::String);
1590        }
1591        if s == "uuid" {
1592            return Ok(FieldType::Uuid);
1593        }
1594        anyhow::bail!("invalid string for FieldType: {}", s);
1595    }
1596}
1597impl FieldType {
1598    pub fn is_noop(&self) -> bool {
1599        matches!(self, FieldType::Noop)
1600    }
1601}
1602
1603/// The name and type information for a field of a timeseries schema.
1604#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
1605pub struct FieldSchema {
1606    #[serde(
1607        default,
1608        skip_serializing_if = "String::is_empty",
1609        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1610    )]
1611    pub name: String,
1612
1613    /**
1614     * The source from which a field is derived, the target or metric.
1615     */
1616    #[serde(default, skip_serializing_if = "FieldSource::is_noop")]
1617    pub source: FieldSource,
1618
1619    /**
1620     * The `FieldType` identifies the data type of a target or metric field.
1621     */
1622    #[serde(default, skip_serializing_if = "FieldType::is_noop")]
1623    pub ty: FieldType,
1624}
1625
1626#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
1627#[serde(rename_all = "snake_case")]
1628pub enum FleetRole {
1629    Admin,
1630    Collaborator,
1631    Viewer,
1632    #[serde(rename = "")]
1633    Noop,
1634    #[serde(other)]
1635    FallthroughString,
1636}
1637
1638impl std::fmt::Display for FleetRole {
1639    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1640        match &*self {
1641            FleetRole::Admin => "admin",
1642            FleetRole::Collaborator => "collaborator",
1643            FleetRole::Viewer => "viewer",
1644            FleetRole::Noop => "",
1645            FleetRole::FallthroughString => "*",
1646        }
1647        .fmt(f)
1648    }
1649}
1650
1651impl Default for FleetRole {
1652    fn default() -> FleetRole {
1653        FleetRole::Admin
1654    }
1655}
1656impl std::str::FromStr for FleetRole {
1657    type Err = anyhow::Error;
1658    fn from_str(s: &str) -> Result<Self, Self::Err> {
1659        if s == "admin" {
1660            return Ok(FleetRole::Admin);
1661        }
1662        if s == "collaborator" {
1663            return Ok(FleetRole::Collaborator);
1664        }
1665        if s == "viewer" {
1666            return Ok(FleetRole::Viewer);
1667        }
1668        anyhow::bail!("invalid string for FleetRole: {}", s);
1669    }
1670}
1671impl FleetRole {
1672    pub fn is_noop(&self) -> bool {
1673        matches!(self, FleetRole::Noop)
1674    }
1675}
1676
1677/// Describes the assignment of a particular role on a particular resource to a particular identity (user, group, etc.)
1678///
1679/// The resource is not part of this structure.  Rather, [`RoleAssignment`]s are put into a [`Policy`] and that Policy is applied to a particular resource.
1680#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
1681pub struct FleetRoleAssignment {
1682    #[serde(
1683        default,
1684        skip_serializing_if = "String::is_empty",
1685        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1686    )]
1687    pub identity_id: String,
1688
1689    /**
1690     * Describes what kind of identity is described by an id
1691     */
1692    #[serde(default, skip_serializing_if = "IdentityType::is_noop")]
1693    pub identity_type: IdentityType,
1694
1695    #[serde(default, skip_serializing_if = "FleetRole::is_noop")]
1696    pub role_name: FleetRole,
1697}
1698
1699/// Client view of a [`Policy`], which describes how this resource may be accessed
1700///
1701/// Note that the Policy only describes access granted explicitly for this resource.  The policies of parent resources can also cause a user to have access to this resource.
1702#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
1703pub struct FleetRolePolicy {
1704    /**
1705     * Roles directly assigned on this resource
1706     */
1707    #[serde(
1708        default,
1709        skip_serializing_if = "Vec::is_empty",
1710        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
1711    )]
1712    #[header(hidden = true)]
1713    pub role_assignments: Vec<FleetRoleAssignment>,
1714}
1715
1716/**
1717 * Describes what kind of identity is described by an id
1718 */
1719#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
1720#[serde(rename_all = "snake_case")]
1721pub enum IdentityType {
1722    SiloGroup,
1723    SiloUser,
1724    #[serde(rename = "")]
1725    Noop,
1726    #[serde(other)]
1727    FallthroughString,
1728}
1729
1730impl std::fmt::Display for IdentityType {
1731    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1732        match &*self {
1733            IdentityType::SiloGroup => "silo_group",
1734            IdentityType::SiloUser => "silo_user",
1735            IdentityType::Noop => "",
1736            IdentityType::FallthroughString => "*",
1737        }
1738        .fmt(f)
1739    }
1740}
1741
1742impl Default for IdentityType {
1743    fn default() -> IdentityType {
1744        IdentityType::SiloGroup
1745    }
1746}
1747impl std::str::FromStr for IdentityType {
1748    type Err = anyhow::Error;
1749    fn from_str(s: &str) -> Result<Self, Self::Err> {
1750        if s == "silo_group" {
1751            return Ok(IdentityType::SiloGroup);
1752        }
1753        if s == "silo_user" {
1754            return Ok(IdentityType::SiloUser);
1755        }
1756        anyhow::bail!("invalid string for IdentityType: {}", s);
1757    }
1758}
1759impl IdentityType {
1760    pub fn is_noop(&self) -> bool {
1761        matches!(self, IdentityType::Noop)
1762    }
1763}
1764
1765/// Client view of global Images
1766#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
1767pub struct GlobalImage {
1768    /**
1769     * unique, immutable, system-controlled identifier for each resource
1770     */
1771    #[serde(
1772        default,
1773        skip_serializing_if = "String::is_empty",
1774        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1775    )]
1776    pub id: String,
1777
1778    /**
1779     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
1780     */
1781    #[serde(
1782        default,
1783        skip_serializing_if = "String::is_empty",
1784        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1785    )]
1786    pub name: String,
1787
1788    /**
1789     * human-readable free-form text about a resource
1790     */
1791    #[serde(
1792        default,
1793        skip_serializing_if = "String::is_empty",
1794        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1795    )]
1796    pub description: String,
1797
1798    /**
1799     * A count of bytes, typically used either for memory or storage capacity
1800     *  
1801     *  The maximum supported byte count is [`i64::MAX`].  This makes it somewhat inconvenient to define constructors: a u32 constructor can be infallible, but an i64 constructor can fail (if the value is negative) and a u64 constructor can fail (if the value is larger than i64::MAX).  We provide all of these for consumers' convenience.
1802     */
1803    #[serde(default)]
1804    pub block_size: u64,
1805
1806    /**
1807     * Hash of the image contents, if applicable
1808     */
1809    #[serde(default, skip_serializing_if = "Option::is_none")]
1810    #[header(hidden = true)]
1811    pub digest: Option<Digest>,
1812
1813    /**
1814     * Image distribution
1815     */
1816    #[serde(
1817        default,
1818        skip_serializing_if = "String::is_empty",
1819        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1820    )]
1821    pub distribution: String,
1822
1823    /**
1824     * A count of bytes, typically used either for memory or storage capacity
1825     *  
1826     *  The maximum supported byte count is [`i64::MAX`].  This makes it somewhat inconvenient to define constructors: a u32 constructor can be infallible, but an i64 constructor can fail (if the value is negative) and a u64 constructor can fail (if the value is larger than i64::MAX).  We provide all of these for consumers' convenience.
1827     */
1828    #[serde(default)]
1829    pub size: u64,
1830
1831    /**
1832     * timestamp when this resource was created
1833     */
1834    #[serde()]
1835    pub time_created: crate::utils::DisplayOptionDateTime,
1836
1837    /**
1838     * timestamp when this resource was last modified
1839     */
1840    #[serde()]
1841    pub time_modified: crate::utils::DisplayOptionDateTime,
1842
1843    /**
1844     * URL source of this image, if any
1845     */
1846    #[serde(
1847        default,
1848        skip_serializing_if = "String::is_empty",
1849        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1850    )]
1851    pub url: String,
1852
1853    /**
1854     * Image version
1855     */
1856    #[serde(
1857        default,
1858        skip_serializing_if = "String::is_empty",
1859        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1860    )]
1861    pub version: String,
1862}
1863
1864#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
1865#[serde(rename_all = "snake_case")]
1866#[serde(tag = "type", content = "id")]
1867pub enum ImageSource {
1868    Url(String),
1869    Snapshot(String),
1870    YouCanBootAnythingAsLongItsAlpine,
1871}
1872
1873impl fmt::Display for ImageSource {
1874    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1875        let j = serde_json::json!(self);
1876        let mut tag: String = serde_json::from_value(j["type"].clone()).unwrap_or_default();
1877        let mut content: String = serde_json::from_value(j["id"].clone()).unwrap_or_default();
1878        if content.is_empty() {
1879            let map: std::collections::HashMap<String, String> =
1880                serde_json::from_value(j["id"].clone()).unwrap_or_default();
1881            if let Some((_, v)) = map.iter().next() {
1882                content = v.to_string();
1883            }
1884        }
1885        if tag == "internet_gateway" {
1886            tag = "inetgw".to_string();
1887        }
1888        write!(f, "{}={}", tag, content)
1889    }
1890}
1891
1892impl std::str::FromStr for ImageSource {
1893    type Err = anyhow::Error;
1894    fn from_str(s: &str) -> Result<Self, Self::Err> {
1895        let parts = s.split('=').collect::<Vec<&str>>();
1896        if parts.len() != 2 {
1897            anyhow::bail!("invalid format for ImageSource, got {}", s);
1898        }
1899        let tag = parts[0].to_string();
1900        let content = parts[1].to_string();
1901        let mut j = String::new();
1902        if tag == "url" {
1903            j = format!(
1904                r#"{{
1905"type": "url",
1906"id": "{}"
1907        }}"#,
1908                content
1909            );
1910        }
1911        if tag == "snapshot" {
1912            j = format!(
1913                r#"{{
1914"type": "snapshot",
1915"id": "{}"
1916        }}"#,
1917                content
1918            );
1919        }
1920        let result = serde_json::from_str(&j)?;
1921        Ok(result)
1922    }
1923}
1924impl ImageSource {
1925    pub fn variants() -> Vec<String> {
1926        vec![
1927            "snapshot".to_string(),
1928            "url".to_string(),
1929            "you_can_boot_anything_as_long_its_alpine".to_string(),
1930        ]
1931    }
1932}
1933/**
1934 * The types for ImageSource.
1935 */
1936#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
1937#[serde(rename_all = "snake_case")]
1938pub enum ImageSourceType {
1939    Snapshot,
1940    Url,
1941    YouCanBootAnythingAsLongItsAlpine,
1942}
1943
1944impl std::fmt::Display for ImageSourceType {
1945    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1946        match &*self {
1947            ImageSourceType::Snapshot => "snapshot",
1948            ImageSourceType::Url => "url",
1949            ImageSourceType::YouCanBootAnythingAsLongItsAlpine => {
1950                "you_can_boot_anything_as_long_its_alpine"
1951            }
1952        }
1953        .fmt(f)
1954    }
1955}
1956
1957impl Default for ImageSourceType {
1958    fn default() -> ImageSourceType {
1959        ImageSourceType::Snapshot
1960    }
1961}
1962impl std::str::FromStr for ImageSourceType {
1963    type Err = anyhow::Error;
1964    fn from_str(s: &str) -> Result<Self, Self::Err> {
1965        if s == "snapshot" {
1966            return Ok(ImageSourceType::Snapshot);
1967        }
1968        if s == "url" {
1969            return Ok(ImageSourceType::Url);
1970        }
1971        if s == "you_can_boot_anything_as_long_its_alpine" {
1972            return Ok(ImageSourceType::YouCanBootAnythingAsLongItsAlpine);
1973        }
1974        anyhow::bail!("invalid string for ImageSourceType: {}", s);
1975    }
1976}
1977
1978/// Create-time parameters for an [`GlobalImage`](crate::external_api::views::GlobalImage)
1979#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
1980pub struct GlobalImageCreate {
1981    /**
1982     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
1983     */
1984    #[serde(
1985        default,
1986        skip_serializing_if = "String::is_empty",
1987        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1988    )]
1989    pub name: String,
1990
1991    #[serde(
1992        default,
1993        skip_serializing_if = "String::is_empty",
1994        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
1995    )]
1996    pub description: String,
1997
1998    #[serde(
1999        default,
2000        skip_serializing_if = "crate::utils::zero_i64",
2001        deserialize_with = "crate::utils::deserialize_null_i64::deserialize"
2002    )]
2003    pub block_size: i64,
2004
2005    /**
2006     * OS image distribution
2007     */
2008    #[serde()]
2009    pub distribution: Distribution,
2010
2011    #[serde()]
2012    pub source: ImageSource,
2013}
2014
2015/// A single page of results
2016#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
2017pub struct GlobalImageResultsPage {
2018    /**
2019     * list of items on this page of results
2020     */
2021    #[serde(
2022        default,
2023        skip_serializing_if = "Vec::is_empty",
2024        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
2025    )]
2026    #[header(hidden = true)]
2027    pub items: Vec<GlobalImage>,
2028
2029    /**
2030     * token used to fetch the next page of results (if any)
2031     */
2032    #[serde(
2033        default,
2034        skip_serializing_if = "String::is_empty",
2035        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2036    )]
2037    pub next_page: String,
2038}
2039
2040/// A simple type for managing a histogram metric.
2041///
2042/// A histogram maintains the count of any number of samples, over a set of bins. Bins are specified on construction via their _left_ edges, inclusive. There can't be any "gaps" in the bins, and an additional bin may be added to the left, right, or both so that the bins extend to the entire range of the support.
2043///
2044/// Note that any gaps, unsorted bins, or non-finite values will result in an error.
2045///
2046/// Example ------- ```rust use oximeter::histogram::{BinRange, Histogram};
2047///
2048/// let edges = [0i64, 10, 20]; let mut hist = Histogram::new(&edges).unwrap(); assert_eq!(hist.n_bins(), 4); // One additional bin for the range (20..) assert_eq!(hist.n_samples(), 0); hist.sample(4); hist.sample(100); assert_eq!(hist.n_samples(), 2);
2049///
2050/// let data = hist.iter().collect::<Vec<_>>(); assert_eq!(data[0].range, BinRange::range(i64::MIN, 0)); // An additional bin for `..0` assert_eq!(data[0].count, 0); // Nothing is in this bin
2051///
2052/// assert_eq!(data[1].range, BinRange::range(0, 10)); // The range `0..10` assert_eq!(data[1].count, 1); // 4 is sampled into this bin ```
2053///
2054/// Notes -----
2055///
2056/// Histograms may be constructed either from their left bin edges, or from a sequence of ranges. In either case, the left-most bin may be converted upon construction. In particular, if the left-most value is not equal to the minimum of the support, a new bin will be added from the minimum to that provided value. If the left-most value _is_ the support's minimum, because the provided bin was unbounded below, such as `(..0)`, then that bin will be converted into one bounded below, `(MIN..0)` in this case.
2057///
2058/// The short of this is that, most of the time, it shouldn't matter. If one specifies the extremes of the support as their bins, be aware that the left-most may be converted from a `BinRange::RangeTo` into a `BinRange::Range`. In other words, the first bin of a histogram is _always_ a `Bin::Range` or a `Bin::RangeFrom` after construction. In fact, every bin is one of those variants, the `BinRange::RangeTo` is only provided as a convenience during construction.
2059#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
2060pub struct Histogramdouble {
2061    #[serde(
2062        default,
2063        skip_serializing_if = "Vec::is_empty",
2064        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
2065    )]
2066    #[header(hidden = true)]
2067    pub bins: Vec<Bindouble>,
2068
2069    #[serde(default)]
2070    pub n_samples: u64,
2071
2072    #[serde()]
2073    pub start_time: crate::utils::DisplayOptionDateTime,
2074}
2075
2076/// A simple type for managing a histogram metric.
2077///
2078/// A histogram maintains the count of any number of samples, over a set of bins. Bins are specified on construction via their _left_ edges, inclusive. There can't be any "gaps" in the bins, and an additional bin may be added to the left, right, or both so that the bins extend to the entire range of the support.
2079///
2080/// Note that any gaps, unsorted bins, or non-finite values will result in an error.
2081///
2082/// Example ------- ```rust use oximeter::histogram::{BinRange, Histogram};
2083///
2084/// let edges = [0i64, 10, 20]; let mut hist = Histogram::new(&edges).unwrap(); assert_eq!(hist.n_bins(), 4); // One additional bin for the range (20..) assert_eq!(hist.n_samples(), 0); hist.sample(4); hist.sample(100); assert_eq!(hist.n_samples(), 2);
2085///
2086/// let data = hist.iter().collect::<Vec<_>>(); assert_eq!(data[0].range, BinRange::range(i64::MIN, 0)); // An additional bin for `..0` assert_eq!(data[0].count, 0); // Nothing is in this bin
2087///
2088/// assert_eq!(data[1].range, BinRange::range(0, 10)); // The range `0..10` assert_eq!(data[1].count, 1); // 4 is sampled into this bin ```
2089///
2090/// Notes -----
2091///
2092/// Histograms may be constructed either from their left bin edges, or from a sequence of ranges. In either case, the left-most bin may be converted upon construction. In particular, if the left-most value is not equal to the minimum of the support, a new bin will be added from the minimum to that provided value. If the left-most value _is_ the support's minimum, because the provided bin was unbounded below, such as `(..0)`, then that bin will be converted into one bounded below, `(MIN..0)` in this case.
2093///
2094/// The short of this is that, most of the time, it shouldn't matter. If one specifies the extremes of the support as their bins, be aware that the left-most may be converted from a `BinRange::RangeTo` into a `BinRange::Range`. In other words, the first bin of a histogram is _always_ a `Bin::Range` or a `Bin::RangeFrom` after construction. In fact, every bin is one of those variants, the `BinRange::RangeTo` is only provided as a convenience during construction.
2095#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
2096pub struct Histogramint64 {
2097    #[serde(
2098        default,
2099        skip_serializing_if = "Vec::is_empty",
2100        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
2101    )]
2102    #[header(hidden = true)]
2103    pub bins: Vec<Binint64>,
2104
2105    #[serde(default)]
2106    pub n_samples: u64,
2107
2108    #[serde()]
2109    pub start_time: crate::utils::DisplayOptionDateTime,
2110}
2111
2112#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
2113#[serde(rename_all = "snake_case")]
2114pub enum IdentityProviderType {
2115    Saml,
2116    #[serde(rename = "")]
2117    Noop,
2118    #[serde(other)]
2119    FallthroughString,
2120}
2121
2122impl std::fmt::Display for IdentityProviderType {
2123    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2124        match &*self {
2125            IdentityProviderType::Saml => "saml",
2126            IdentityProviderType::Noop => "",
2127            IdentityProviderType::FallthroughString => "*",
2128        }
2129        .fmt(f)
2130    }
2131}
2132
2133impl Default for IdentityProviderType {
2134    fn default() -> IdentityProviderType {
2135        IdentityProviderType::Saml
2136    }
2137}
2138impl std::str::FromStr for IdentityProviderType {
2139    type Err = anyhow::Error;
2140    fn from_str(s: &str) -> Result<Self, Self::Err> {
2141        if s == "saml" {
2142            return Ok(IdentityProviderType::Saml);
2143        }
2144        anyhow::bail!("invalid string for IdentityProviderType: {}", s);
2145    }
2146}
2147impl IdentityProviderType {
2148    pub fn is_noop(&self) -> bool {
2149        matches!(self, IdentityProviderType::Noop)
2150    }
2151}
2152
2153/// Client view of an [`IdentityProvider`]
2154#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
2155pub struct IdentityProvider {
2156    /**
2157     * unique, immutable, system-controlled identifier for each resource
2158     */
2159    #[serde(
2160        default,
2161        skip_serializing_if = "String::is_empty",
2162        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2163    )]
2164    pub id: String,
2165
2166    /**
2167     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
2168     */
2169    #[serde(
2170        default,
2171        skip_serializing_if = "String::is_empty",
2172        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2173    )]
2174    pub name: String,
2175
2176    /**
2177     * human-readable free-form text about a resource
2178     */
2179    #[serde(
2180        default,
2181        skip_serializing_if = "String::is_empty",
2182        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2183    )]
2184    pub description: String,
2185
2186    #[serde(default, skip_serializing_if = "IdentityProviderType::is_noop")]
2187    pub provider_type: IdentityProviderType,
2188
2189    /**
2190     * timestamp when this resource was created
2191     */
2192    #[serde()]
2193    pub time_created: crate::utils::DisplayOptionDateTime,
2194
2195    /**
2196     * timestamp when this resource was last modified
2197     */
2198    #[serde()]
2199    pub time_modified: crate::utils::DisplayOptionDateTime,
2200}
2201
2202/// A single page of results
2203#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
2204pub struct IdentityProviderResultsPage {
2205    /**
2206     * list of items on this page of results
2207     */
2208    #[serde(
2209        default,
2210        skip_serializing_if = "Vec::is_empty",
2211        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
2212    )]
2213    #[header(hidden = true)]
2214    pub items: Vec<IdentityProvider>,
2215
2216    /**
2217     * token used to fetch the next page of results (if any)
2218     */
2219    #[serde(
2220        default,
2221        skip_serializing_if = "String::is_empty",
2222        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2223    )]
2224    pub next_page: String,
2225}
2226
2227#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
2228#[serde(rename_all = "snake_case")]
2229pub enum IdentityProviderTypeSaml {
2230    Saml,
2231    #[serde(rename = "")]
2232    Noop,
2233    #[serde(other)]
2234    FallthroughString,
2235}
2236
2237impl std::fmt::Display for IdentityProviderTypeSaml {
2238    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2239        match &*self {
2240            IdentityProviderTypeSaml::Saml => "saml",
2241            IdentityProviderTypeSaml::Noop => "",
2242            IdentityProviderTypeSaml::FallthroughString => "*",
2243        }
2244        .fmt(f)
2245    }
2246}
2247
2248impl Default for IdentityProviderTypeSaml {
2249    fn default() -> IdentityProviderTypeSaml {
2250        IdentityProviderTypeSaml::Saml
2251    }
2252}
2253impl std::str::FromStr for IdentityProviderTypeSaml {
2254    type Err = anyhow::Error;
2255    fn from_str(s: &str) -> Result<Self, Self::Err> {
2256        if s == "saml" {
2257            return Ok(IdentityProviderTypeSaml::Saml);
2258        }
2259        anyhow::bail!("invalid string for IdentityProviderTypeSaml: {}", s);
2260    }
2261}
2262impl IdentityProviderTypeSaml {
2263    pub fn is_noop(&self) -> bool {
2264        matches!(self, IdentityProviderTypeSaml::Noop)
2265    }
2266}
2267
2268#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
2269#[serde(rename_all = "snake_case")]
2270#[serde(tag = "type", content = "data")]
2271pub enum IdpMetadataSource {
2272    Url(String),
2273    Base64EncodedXml(String),
2274}
2275
2276impl fmt::Display for IdpMetadataSource {
2277    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2278        let j = serde_json::json!(self);
2279        let mut tag: String = serde_json::from_value(j["type"].clone()).unwrap_or_default();
2280        let mut content: String = serde_json::from_value(j["data"].clone()).unwrap_or_default();
2281        if content.is_empty() {
2282            let map: std::collections::HashMap<String, String> =
2283                serde_json::from_value(j["data"].clone()).unwrap_or_default();
2284            if let Some((_, v)) = map.iter().next() {
2285                content = v.to_string();
2286            }
2287        }
2288        if tag == "internet_gateway" {
2289            tag = "inetgw".to_string();
2290        }
2291        write!(f, "{}={}", tag, content)
2292    }
2293}
2294
2295impl std::str::FromStr for IdpMetadataSource {
2296    type Err = anyhow::Error;
2297    fn from_str(s: &str) -> Result<Self, Self::Err> {
2298        let parts = s.split('=').collect::<Vec<&str>>();
2299        if parts.len() != 2 {
2300            anyhow::bail!("invalid format for IdpMetadataSource, got {}", s);
2301        }
2302        let tag = parts[0].to_string();
2303        let content = parts[1].to_string();
2304        let mut j = String::new();
2305        if tag == "url" {
2306            j = format!(
2307                r#"{{
2308"type": "url",
2309"data": "{}"
2310        }}"#,
2311                content
2312            );
2313        }
2314        if tag == "base_64_encoded_xml" {
2315            j = format!(
2316                r#"{{
2317"type": "base_64_encoded_xml",
2318"data": "{}"
2319        }}"#,
2320                content
2321            );
2322        }
2323        let result = serde_json::from_str(&j)?;
2324        Ok(result)
2325    }
2326}
2327impl IdpMetadataSource {
2328    pub fn variants() -> Vec<String> {
2329        vec!["base_64_encoded_xml".to_string(), "url".to_string()]
2330    }
2331}
2332/**
2333 * The types for IdpMetadataSource.
2334 */
2335#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
2336#[serde(rename_all = "snake_case")]
2337pub enum IdpMetadataSourceType {
2338    Base64EncodedXml,
2339    Url,
2340}
2341
2342impl std::fmt::Display for IdpMetadataSourceType {
2343    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2344        match &*self {
2345            IdpMetadataSourceType::Base64EncodedXml => "base_64_encoded_xml",
2346            IdpMetadataSourceType::Url => "url",
2347        }
2348        .fmt(f)
2349    }
2350}
2351
2352impl Default for IdpMetadataSourceType {
2353    fn default() -> IdpMetadataSourceType {
2354        IdpMetadataSourceType::Base64EncodedXml
2355    }
2356}
2357impl std::str::FromStr for IdpMetadataSourceType {
2358    type Err = anyhow::Error;
2359    fn from_str(s: &str) -> Result<Self, Self::Err> {
2360        if s == "base_64_encoded_xml" {
2361            return Ok(IdpMetadataSourceType::Base64EncodedXml);
2362        }
2363        if s == "url" {
2364            return Ok(IdpMetadataSourceType::Url);
2365        }
2366        anyhow::bail!("invalid string for IdpMetadataSourceType: {}", s);
2367    }
2368}
2369
2370/// Client view of project Images
2371#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
2372pub struct Image {
2373    /**
2374     * unique, immutable, system-controlled identifier for each resource
2375     */
2376    #[serde(
2377        default,
2378        skip_serializing_if = "String::is_empty",
2379        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2380    )]
2381    pub id: String,
2382
2383    /**
2384     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
2385     */
2386    #[serde(
2387        default,
2388        skip_serializing_if = "String::is_empty",
2389        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2390    )]
2391    pub name: String,
2392
2393    /**
2394     * human-readable free-form text about a resource
2395     */
2396    #[serde(
2397        default,
2398        skip_serializing_if = "String::is_empty",
2399        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2400    )]
2401    pub description: String,
2402
2403    /**
2404     * A count of bytes, typically used either for memory or storage capacity
2405     *  
2406     *  The maximum supported byte count is [`i64::MAX`].  This makes it somewhat inconvenient to define constructors: a u32 constructor can be infallible, but an i64 constructor can fail (if the value is negative) and a u64 constructor can fail (if the value is larger than i64::MAX).  We provide all of these for consumers' convenience.
2407     */
2408    #[serde(default)]
2409    pub block_size: u64,
2410
2411    /**
2412     * Hash of the image contents, if applicable
2413     */
2414    #[serde(default, skip_serializing_if = "Option::is_none")]
2415    #[header(hidden = true)]
2416    pub digest: Option<Digest>,
2417
2418    /**
2419     * The project the disk belongs to
2420     */
2421    #[serde(
2422        default,
2423        skip_serializing_if = "String::is_empty",
2424        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2425    )]
2426    pub project_id: String,
2427
2428    /**
2429     * A count of bytes, typically used either for memory or storage capacity
2430     *  
2431     *  The maximum supported byte count is [`i64::MAX`].  This makes it somewhat inconvenient to define constructors: a u32 constructor can be infallible, but an i64 constructor can fail (if the value is negative) and a u64 constructor can fail (if the value is larger than i64::MAX).  We provide all of these for consumers' convenience.
2432     */
2433    #[serde(default)]
2434    pub size: u64,
2435
2436    /**
2437     * timestamp when this resource was created
2438     */
2439    #[serde()]
2440    pub time_created: crate::utils::DisplayOptionDateTime,
2441
2442    /**
2443     * timestamp when this resource was last modified
2444     */
2445    #[serde()]
2446    pub time_modified: crate::utils::DisplayOptionDateTime,
2447
2448    /**
2449     * URL source of this image, if any
2450     */
2451    #[serde(
2452        default,
2453        skip_serializing_if = "String::is_empty",
2454        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2455    )]
2456    pub url: String,
2457
2458    /**
2459     * Version of this, if any
2460     */
2461    #[serde(
2462        default,
2463        skip_serializing_if = "String::is_empty",
2464        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2465    )]
2466    pub version: String,
2467}
2468
2469/// Create-time parameters for an [`Image`](crate::external_api::views::Image)
2470#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
2471pub struct ImageCreate {
2472    /**
2473     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
2474     */
2475    #[serde(
2476        default,
2477        skip_serializing_if = "String::is_empty",
2478        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2479    )]
2480    pub name: String,
2481
2482    #[serde(
2483        default,
2484        skip_serializing_if = "String::is_empty",
2485        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2486    )]
2487    pub description: String,
2488
2489    #[serde(
2490        default,
2491        skip_serializing_if = "crate::utils::zero_i64",
2492        deserialize_with = "crate::utils::deserialize_null_i64::deserialize"
2493    )]
2494    pub block_size: i64,
2495
2496    #[serde()]
2497    pub source: ImageSource,
2498}
2499
2500/// A single page of results
2501#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
2502pub struct ImageResultsPage {
2503    /**
2504     * list of items on this page of results
2505     */
2506    #[serde(
2507        default,
2508        skip_serializing_if = "Vec::is_empty",
2509        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
2510    )]
2511    #[header(hidden = true)]
2512    pub items: Vec<Image>,
2513
2514    /**
2515     * token used to fetch the next page of results (if any)
2516     */
2517    #[serde(
2518        default,
2519        skip_serializing_if = "String::is_empty",
2520        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2521    )]
2522    pub next_page: String,
2523}
2524
2525/**
2526 * Running state of an Instance (primarily: booted or stopped)
2527 *   
2528 *   This typically reflects whether it's starting, running, stopping, or stopped, but also includes states related to the Instance's lifecycle
2529 */
2530#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
2531#[serde(rename_all = "snake_case")]
2532pub enum InstanceState {
2533    Creating,
2534    Destroyed,
2535    Failed,
2536    Migrating,
2537    Rebooting,
2538    Repairing,
2539    Running,
2540    Starting,
2541    Stopped,
2542    Stopping,
2543    #[serde(rename = "")]
2544    Noop,
2545    #[serde(other)]
2546    FallthroughString,
2547}
2548
2549impl std::fmt::Display for InstanceState {
2550    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2551        match &*self {
2552            InstanceState::Creating => "creating",
2553            InstanceState::Destroyed => "destroyed",
2554            InstanceState::Failed => "failed",
2555            InstanceState::Migrating => "migrating",
2556            InstanceState::Rebooting => "rebooting",
2557            InstanceState::Repairing => "repairing",
2558            InstanceState::Running => "running",
2559            InstanceState::Starting => "starting",
2560            InstanceState::Stopped => "stopped",
2561            InstanceState::Stopping => "stopping",
2562            InstanceState::Noop => "",
2563            InstanceState::FallthroughString => "*",
2564        }
2565        .fmt(f)
2566    }
2567}
2568
2569impl Default for InstanceState {
2570    fn default() -> InstanceState {
2571        InstanceState::Creating
2572    }
2573}
2574impl std::str::FromStr for InstanceState {
2575    type Err = anyhow::Error;
2576    fn from_str(s: &str) -> Result<Self, Self::Err> {
2577        if s == "creating" {
2578            return Ok(InstanceState::Creating);
2579        }
2580        if s == "destroyed" {
2581            return Ok(InstanceState::Destroyed);
2582        }
2583        if s == "failed" {
2584            return Ok(InstanceState::Failed);
2585        }
2586        if s == "migrating" {
2587            return Ok(InstanceState::Migrating);
2588        }
2589        if s == "rebooting" {
2590            return Ok(InstanceState::Rebooting);
2591        }
2592        if s == "repairing" {
2593            return Ok(InstanceState::Repairing);
2594        }
2595        if s == "running" {
2596            return Ok(InstanceState::Running);
2597        }
2598        if s == "starting" {
2599            return Ok(InstanceState::Starting);
2600        }
2601        if s == "stopped" {
2602            return Ok(InstanceState::Stopped);
2603        }
2604        if s == "stopping" {
2605            return Ok(InstanceState::Stopping);
2606        }
2607        anyhow::bail!("invalid string for InstanceState: {}", s);
2608    }
2609}
2610impl InstanceState {
2611    pub fn is_noop(&self) -> bool {
2612        matches!(self, InstanceState::Noop)
2613    }
2614}
2615
2616/// Client view of an [`Instance`]
2617#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
2618pub struct Instance {
2619    /**
2620     * unique, immutable, system-controlled identifier for each resource
2621     */
2622    #[serde(
2623        default,
2624        skip_serializing_if = "String::is_empty",
2625        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2626    )]
2627    pub id: String,
2628
2629    /**
2630     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
2631     */
2632    #[serde(
2633        default,
2634        skip_serializing_if = "String::is_empty",
2635        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2636    )]
2637    pub name: String,
2638
2639    /**
2640     * human-readable free-form text about a resource
2641     */
2642    #[serde(
2643        default,
2644        skip_serializing_if = "String::is_empty",
2645        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2646    )]
2647    pub description: String,
2648
2649    /**
2650     * RFC1035-compliant hostname for the Instance.
2651     */
2652    #[serde(
2653        default,
2654        skip_serializing_if = "String::is_empty",
2655        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2656    )]
2657    pub hostname: String,
2658
2659    /**
2660     * A count of bytes, typically used either for memory or storage capacity
2661     *  
2662     *  The maximum supported byte count is [`i64::MAX`].  This makes it somewhat inconvenient to define constructors: a u32 constructor can be infallible, but an i64 constructor can fail (if the value is negative) and a u64 constructor can fail (if the value is larger than i64::MAX).  We provide all of these for consumers' convenience.
2663     */
2664    #[serde(default)]
2665    pub memory: u64,
2666
2667    /**
2668     * The number of CPUs in an Instance
2669     */
2670    #[serde()]
2671    pub ncpus: u16,
2672
2673    /**
2674     * id for the project containing this Instance
2675     */
2676    #[serde(
2677        default,
2678        skip_serializing_if = "String::is_empty",
2679        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2680    )]
2681    pub project_id: String,
2682
2683    /**
2684     * Running state of an Instance (primarily: booted or stopped)
2685     *  
2686     *  This typically reflects whether it's starting, running, stopping, or stopped, but also includes states related to the Instance's lifecycle
2687     */
2688    #[serde(default, skip_serializing_if = "InstanceState::is_noop")]
2689    pub run_state: InstanceState,
2690
2691    /**
2692     * timestamp when this resource was created
2693     */
2694    #[serde()]
2695    pub time_created: crate::utils::DisplayOptionDateTime,
2696
2697    /**
2698     * timestamp when this resource was last modified
2699     */
2700    #[serde()]
2701    pub time_modified: crate::utils::DisplayOptionDateTime,
2702
2703    #[serde()]
2704    pub time_run_state_updated: crate::utils::DisplayOptionDateTime,
2705}
2706
2707#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
2708#[serde(rename_all = "snake_case")]
2709#[serde(tag = "type", content = "name")]
2710pub enum InstanceDiskAttachment {
2711    Create {
2712        description: String,
2713        disk_source: DiskSource,
2714        name: String,
2715        size: u64,
2716    },
2717    Attach(String),
2718}
2719
2720impl fmt::Display for InstanceDiskAttachment {
2721    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2722        let j = serde_json::json!(self);
2723        let mut tag: String = serde_json::from_value(j["type"].clone()).unwrap_or_default();
2724        let mut content: String = serde_json::from_value(j["name"].clone()).unwrap_or_default();
2725        if content.is_empty() {
2726            let map: std::collections::HashMap<String, String> =
2727                serde_json::from_value(j["name"].clone()).unwrap_or_default();
2728            if let Some((_, v)) = map.iter().next() {
2729                content = v.to_string();
2730            }
2731        }
2732        if tag == "internet_gateway" {
2733            tag = "inetgw".to_string();
2734        }
2735        write!(f, "{}={}", tag, content)
2736    }
2737}
2738
2739impl std::str::FromStr for InstanceDiskAttachment {
2740    type Err = anyhow::Error;
2741    fn from_str(s: &str) -> Result<Self, Self::Err> {
2742        let parts = s.split('=').collect::<Vec<&str>>();
2743        if parts.len() != 2 {
2744            anyhow::bail!("invalid format for InstanceDiskAttachment, got {}", s);
2745        }
2746        let tag = parts[0].to_string();
2747        let content = parts[1].to_string();
2748        let mut j = String::new();
2749        if tag == "create" {
2750            j = format!(
2751                r#"{{
2752"type": "create",
2753"name": "{}"
2754        }}"#,
2755                content
2756            );
2757        }
2758        if tag == "create" {
2759            j = format!(
2760                r#"{{
2761"type": "create",
2762"name": {}
2763        }}"#,
2764                serde_json::json!(DiskSource::from_str(&content).unwrap())
2765            );
2766        }
2767        if tag == "create" {
2768            j = format!(
2769                r#"{{
2770"type": "create",
2771"name": "{}"
2772        }}"#,
2773                content
2774            );
2775        }
2776        if tag == "create" {
2777            j = format!(
2778                r#"{{
2779"type": "create",
2780"name": {}
2781        }}"#,
2782                serde_json::json!(u64::from_str(&content).unwrap())
2783            );
2784        }
2785        if tag == "attach" {
2786            j = format!(
2787                r#"{{
2788"type": "attach",
2789"name": "{}"
2790        }}"#,
2791                content
2792            );
2793        }
2794        let result = serde_json::from_str(&j)?;
2795        Ok(result)
2796    }
2797}
2798impl InstanceDiskAttachment {
2799    pub fn variants() -> Vec<String> {
2800        vec!["attach".to_string(), "create".to_string()]
2801    }
2802}
2803/**
2804 * The types for InstanceDiskAttachment.
2805 */
2806#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
2807#[serde(rename_all = "snake_case")]
2808pub enum InstanceDiskAttachmentType {
2809    Attach,
2810    Create,
2811}
2812
2813impl std::fmt::Display for InstanceDiskAttachmentType {
2814    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2815        match &*self {
2816            InstanceDiskAttachmentType::Attach => "attach",
2817            InstanceDiskAttachmentType::Create => "create",
2818        }
2819        .fmt(f)
2820    }
2821}
2822
2823impl Default for InstanceDiskAttachmentType {
2824    fn default() -> InstanceDiskAttachmentType {
2825        InstanceDiskAttachmentType::Attach
2826    }
2827}
2828impl std::str::FromStr for InstanceDiskAttachmentType {
2829    type Err = anyhow::Error;
2830    fn from_str(s: &str) -> Result<Self, Self::Err> {
2831        if s == "attach" {
2832            return Ok(InstanceDiskAttachmentType::Attach);
2833        }
2834        if s == "create" {
2835            return Ok(InstanceDiskAttachmentType::Create);
2836        }
2837        anyhow::bail!("invalid string for InstanceDiskAttachmentType: {}", s);
2838    }
2839}
2840
2841#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
2842#[serde(rename_all = "snake_case")]
2843#[serde(tag = "type", content = "params")]
2844pub enum InstanceNetworkInterfaceAttachment {
2845    Create(Vec<NetworkInterfaceCreate>),
2846    Default,
2847    None,
2848}
2849
2850impl fmt::Display for InstanceNetworkInterfaceAttachment {
2851    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2852        let j = serde_json::json!(self);
2853        let mut tag: String = serde_json::from_value(j["type"].clone()).unwrap_or_default();
2854        let mut content: String = serde_json::from_value(j["params"].clone()).unwrap_or_default();
2855        if content.is_empty() {
2856            let map: std::collections::HashMap<String, String> =
2857                serde_json::from_value(j["params"].clone()).unwrap_or_default();
2858            if let Some((_, v)) = map.iter().next() {
2859                content = v.to_string();
2860            }
2861        }
2862        if tag == "internet_gateway" {
2863            tag = "inetgw".to_string();
2864        }
2865        write!(f, "{}={}", tag, content)
2866    }
2867}
2868
2869impl std::str::FromStr for InstanceNetworkInterfaceAttachment {
2870    type Err = anyhow::Error;
2871    fn from_str(s: &str) -> Result<Self, Self::Err> {
2872        let parts = s.split('=').collect::<Vec<&str>>();
2873        if parts.len() != 2 {
2874            anyhow::bail!(
2875                "invalid format for InstanceNetworkInterfaceAttachment, got {}",
2876                s
2877            );
2878        }
2879        let tag = parts[0].to_string();
2880        let content = parts[1].to_string();
2881        let mut j = String::new();
2882        if tag == "create" {
2883            j = format!(
2884                r#"{{
2885"type": "create",
2886"params": "{}"
2887        }}"#,
2888                content
2889            );
2890        }
2891        let result = serde_json::from_str(&j)?;
2892        Ok(result)
2893    }
2894}
2895impl InstanceNetworkInterfaceAttachment {
2896    pub fn variants() -> Vec<String> {
2897        vec![
2898            "create".to_string(),
2899            "default".to_string(),
2900            "none".to_string(),
2901        ]
2902    }
2903}
2904/**
2905 * The types for InstanceNetworkInterfaceAttachment.
2906 */
2907#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
2908#[serde(rename_all = "snake_case")]
2909pub enum InstanceNetworkInterfaceAttachmentType {
2910    Create,
2911    Default,
2912    None,
2913}
2914
2915impl std::fmt::Display for InstanceNetworkInterfaceAttachmentType {
2916    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2917        match &*self {
2918            InstanceNetworkInterfaceAttachmentType::Create => "create",
2919            InstanceNetworkInterfaceAttachmentType::Default => "default",
2920            InstanceNetworkInterfaceAttachmentType::None => "none",
2921        }
2922        .fmt(f)
2923    }
2924}
2925
2926impl Default for InstanceNetworkInterfaceAttachmentType {
2927    fn default() -> InstanceNetworkInterfaceAttachmentType {
2928        InstanceNetworkInterfaceAttachmentType::Create
2929    }
2930}
2931impl std::str::FromStr for InstanceNetworkInterfaceAttachmentType {
2932    type Err = anyhow::Error;
2933    fn from_str(s: &str) -> Result<Self, Self::Err> {
2934        if s == "create" {
2935            return Ok(InstanceNetworkInterfaceAttachmentType::Create);
2936        }
2937        if s == "default" {
2938            return Ok(InstanceNetworkInterfaceAttachmentType::Default);
2939        }
2940        if s == "none" {
2941            return Ok(InstanceNetworkInterfaceAttachmentType::None);
2942        }
2943        anyhow::bail!(
2944            "invalid string for InstanceNetworkInterfaceAttachmentType: {}",
2945            s
2946        );
2947    }
2948}
2949
2950/// Create-time parameters for an [`Instance`](omicron_common::api::external::Instance)
2951#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
2952pub struct InstanceCreate {
2953    /**
2954     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
2955     */
2956    #[serde(
2957        default,
2958        skip_serializing_if = "String::is_empty",
2959        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2960    )]
2961    pub name: String,
2962
2963    #[serde(
2964        default,
2965        skip_serializing_if = "String::is_empty",
2966        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2967    )]
2968    pub description: String,
2969
2970    /**
2971     * The disks to be created or attached for this instance.
2972     */
2973    #[serde(
2974        default,
2975        skip_serializing_if = "Vec::is_empty",
2976        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
2977    )]
2978    #[header(hidden = true)]
2979    pub disks: Vec<InstanceDiskAttachment>,
2980
2981    /**
2982     * The external IP addresses provided to this instance.
2983     *  
2984     *  By default, all instances have outbound connectivity, but no inbound connectivity. These external addresses can be used to provide a fixed, known IP address for making inbound connections to the instance.
2985     */
2986    #[serde(
2987        default,
2988        skip_serializing_if = "Vec::is_empty",
2989        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
2990    )]
2991    #[header(hidden = true)]
2992    pub external_ips: Vec<ExternalIpCreate>,
2993
2994    #[serde(
2995        default,
2996        skip_serializing_if = "String::is_empty",
2997        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
2998    )]
2999    pub hostname: String,
3000
3001    /**
3002     * A count of bytes, typically used either for memory or storage capacity
3003     *  
3004     *  The maximum supported byte count is [`i64::MAX`].  This makes it somewhat inconvenient to define constructors: a u32 constructor can be infallible, but an i64 constructor can fail (if the value is negative) and a u64 constructor can fail (if the value is larger than i64::MAX).  We provide all of these for consumers' convenience.
3005     */
3006    #[serde(default)]
3007    pub memory: u64,
3008
3009    /**
3010     * The number of CPUs in an Instance
3011     */
3012    #[serde()]
3013    pub ncpus: u16,
3014
3015    /**
3016     * Create-time parameters for an [`Instance`](omicron_common::api::external::Instance)
3017     */
3018    #[serde(default, skip_serializing_if = "Option::is_none")]
3019    #[header(hidden = true)]
3020    pub network_interfaces: Option<InstanceNetworkInterfaceAttachment>,
3021
3022    /**
3023     * Should this instance be started upon creation; true by default.
3024     */
3025    #[serde(default = "crate::utils::bool_true")]
3026    pub start: bool,
3027
3028    /**
3029     * User data for instance initialization systems (such as cloud-init). Must be a Base64-encoded string, as specified in RFC 4648 § 4 (+ and / characters with padding). Maximum 32 KiB unencoded data.
3030     */
3031    #[serde(
3032        default,
3033        skip_serializing_if = "String::is_empty",
3034        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3035    )]
3036    pub user_data: String,
3037}
3038
3039/// Migration parameters for an [`Instance`](omicron_common::api::external::Instance)
3040#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3041pub struct InstanceMigrate {
3042    #[serde(
3043        default,
3044        skip_serializing_if = "String::is_empty",
3045        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3046    )]
3047    pub dst_sled_id: String,
3048}
3049
3050/// A single page of results
3051#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3052pub struct InstanceResultsPage {
3053    /**
3054     * list of items on this page of results
3055     */
3056    #[serde(
3057        default,
3058        skip_serializing_if = "Vec::is_empty",
3059        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
3060    )]
3061    #[header(hidden = true)]
3062    pub items: Vec<Instance>,
3063
3064    /**
3065     * token used to fetch the next page of results (if any)
3066     */
3067    #[serde(
3068        default,
3069        skip_serializing_if = "String::is_empty",
3070        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3071    )]
3072    pub next_page: String,
3073}
3074
3075/// Contents of an Instance's serial console buffer.
3076#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3077pub struct InstanceSerialConsoleData {
3078    /**
3079     * The bytes starting from the requested offset up to either the end of the buffer or the request's `max_bytes`. Provided as a u8 array rather than a string, as it may not be UTF-8.
3080     */
3081    #[serde(
3082        default,
3083        skip_serializing_if = "Vec::is_empty",
3084        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
3085    )]
3086    #[header(hidden = true)]
3087    pub data: Vec<u8>,
3088
3089    /**
3090     * The absolute offset since boot (suitable for use as `byte_offset` in a subsequent request) of the last byte returned in `data`.
3091     */
3092    #[serde(default)]
3093    pub last_byte_offset: u64,
3094}
3095
3096/// An `IpNet` represents an IP network, either IPv4 or IPv6.
3097#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Hash, JsonSchema, Serialize)]
3098pub enum IpNet {
3099    V4(Ipv4Net),
3100    V6(Ipv6Net),
3101}
3102
3103impl From<Ipv4Net> for IpNet {
3104    fn from(n: Ipv4Net) -> IpNet {
3105        IpNet::V4(n)
3106    }
3107}
3108
3109impl From<std::net::Ipv4Addr> for IpNet {
3110    fn from(n: std::net::Ipv4Addr) -> IpNet {
3111        IpNet::V4(Ipv4Net(ipnetwork::Ipv4Network::from(n)))
3112    }
3113}
3114
3115impl From<Ipv6Net> for IpNet {
3116    fn from(n: Ipv6Net) -> IpNet {
3117        IpNet::V6(n)
3118    }
3119}
3120
3121impl From<std::net::Ipv6Addr> for IpNet {
3122    fn from(n: std::net::Ipv6Addr) -> IpNet {
3123        IpNet::V6(Ipv6Net(ipnetwork::Ipv6Network::from(n)))
3124    }
3125}
3126
3127impl std::fmt::Display for IpNet {
3128    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3129        match self {
3130            IpNet::V4(inner) => write!(f, "{}", inner),
3131            IpNet::V6(inner) => write!(f, "{}", inner),
3132        }
3133    }
3134}
3135
3136impl std::str::FromStr for IpNet {
3137    type Err = String;
3138
3139    fn from_str(s: &str) -> Result<Self, Self::Err> {
3140        let net = s
3141            .parse::<ipnetwork::IpNetwork>()
3142            .map_err(|e| e.to_string())?;
3143        match net {
3144            ipnetwork::IpNetwork::V4(net) => Ok(IpNet::from(Ipv4Net(net))),
3145            ipnetwork::IpNetwork::V6(net) => Ok(IpNet::from(Ipv6Net(net))),
3146        }
3147    }
3148}
3149
3150/// Identity-related metadata that's included in nearly all public API objects
3151#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3152pub struct IpPool {
3153    /**
3154     * unique, immutable, system-controlled identifier for each resource
3155     */
3156    #[serde(
3157        default,
3158        skip_serializing_if = "String::is_empty",
3159        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3160    )]
3161    pub id: String,
3162
3163    /**
3164     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
3165     */
3166    #[serde(
3167        default,
3168        skip_serializing_if = "String::is_empty",
3169        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3170    )]
3171    pub name: String,
3172
3173    /**
3174     * human-readable free-form text about a resource
3175     */
3176    #[serde(
3177        default,
3178        skip_serializing_if = "String::is_empty",
3179        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3180    )]
3181    pub description: String,
3182
3183    #[serde(
3184        default,
3185        skip_serializing_if = "String::is_empty",
3186        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3187    )]
3188    pub project_id: String,
3189
3190    /**
3191     * timestamp when this resource was created
3192     */
3193    #[serde()]
3194    pub time_created: crate::utils::DisplayOptionDateTime,
3195
3196    /**
3197     * timestamp when this resource was last modified
3198     */
3199    #[serde()]
3200    pub time_modified: crate::utils::DisplayOptionDateTime,
3201}
3202
3203/// Create-time parameters for an IP Pool.
3204///
3205/// See [`IpPool`](crate::external_api::views::IpPool)
3206#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3207pub struct IpPoolCreate {
3208    /**
3209     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
3210     */
3211    #[serde(
3212        default,
3213        skip_serializing_if = "String::is_empty",
3214        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3215    )]
3216    pub name: String,
3217
3218    #[serde(
3219        default,
3220        skip_serializing_if = "String::is_empty",
3221        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3222    )]
3223    pub description: String,
3224
3225    /**
3226     * Create-time parameters for an IP Pool.
3227     *  
3228     *  See [`IpPool`](crate::external_api::views::IpPool)
3229     */
3230    #[serde(
3231        default,
3232        skip_serializing_if = "String::is_empty",
3233        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3234    )]
3235    pub organization: String,
3236
3237    /**
3238     * Create-time parameters for an IP Pool.
3239     *  
3240     *  See [`IpPool`](crate::external_api::views::IpPool)
3241     */
3242    #[serde(
3243        default,
3244        skip_serializing_if = "String::is_empty",
3245        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3246    )]
3247    pub project: String,
3248}
3249
3250#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, Default, JsonSchema)]
3251pub enum IpRange {
3252    Ipv4Range,
3253    #[default]
3254    Ipv6Range,
3255}
3256
3257impl fmt::Display for IpRange {
3258    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3259        write!(f, "{}", serde_json::json!(self))
3260    }
3261}
3262
3263impl std::str::FromStr for IpRange {
3264    type Err = anyhow::Error;
3265    fn from_str(s: &str) -> Result<Self, Self::Err> {
3266        Ok(serde_json::from_str(s)?)
3267    }
3268}
3269#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3270pub struct IpPoolRange {
3271    #[serde(
3272        default,
3273        skip_serializing_if = "String::is_empty",
3274        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3275    )]
3276    pub id: String,
3277
3278    #[serde()]
3279    pub range: IpRange,
3280
3281    #[serde()]
3282    pub time_created: crate::utils::DisplayOptionDateTime,
3283}
3284
3285/// A single page of results
3286#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3287pub struct IpPoolRangeResultsPage {
3288    /**
3289     * list of items on this page of results
3290     */
3291    #[serde(
3292        default,
3293        skip_serializing_if = "Vec::is_empty",
3294        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
3295    )]
3296    #[header(hidden = true)]
3297    pub items: Vec<IpPoolRange>,
3298
3299    /**
3300     * token used to fetch the next page of results (if any)
3301     */
3302    #[serde(
3303        default,
3304        skip_serializing_if = "String::is_empty",
3305        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3306    )]
3307    pub next_page: String,
3308}
3309
3310/// A single page of results
3311#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3312pub struct IpPoolResultsPage {
3313    /**
3314     * list of items on this page of results
3315     */
3316    #[serde(
3317        default,
3318        skip_serializing_if = "Vec::is_empty",
3319        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
3320    )]
3321    #[header(hidden = true)]
3322    pub items: Vec<IpPool>,
3323
3324    /**
3325     * token used to fetch the next page of results (if any)
3326     */
3327    #[serde(
3328        default,
3329        skip_serializing_if = "String::is_empty",
3330        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3331    )]
3332    pub next_page: String,
3333}
3334
3335/// Parameters for updating an IP Pool
3336#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3337pub struct IpPoolUpdate {
3338    #[serde(
3339        default,
3340        skip_serializing_if = "String::is_empty",
3341        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3342    )]
3343    pub name: String,
3344
3345    #[serde(
3346        default,
3347        skip_serializing_if = "String::is_empty",
3348        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3349    )]
3350    pub description: String,
3351}
3352
3353/// An `Ipv4Net` represents a IPv4 subnetwork, including the address and network mask.
3354#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Serialize)]
3355pub struct Ipv4Net(pub ipnetwork::Ipv4Network);
3356
3357impl Ipv4Net {
3358    /// Return `true` if this IPv4 subnetwork is from an RFC 1918 private
3359    /// address space.
3360    pub fn is_private(&self) -> bool {
3361        self.0.network().is_private()
3362    }
3363}
3364
3365impl std::ops::Deref for Ipv4Net {
3366    type Target = ipnetwork::Ipv4Network;
3367    fn deref(&self) -> &Self::Target {
3368        &self.0
3369    }
3370}
3371
3372impl std::fmt::Display for Ipv4Net {
3373    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
3374        write!(f, "{}", self.0)
3375    }
3376}
3377
3378impl std::str::FromStr for Ipv4Net {
3379    type Err = String;
3380
3381    fn from_str(s: &str) -> Result<Self, Self::Err> {
3382        let net = s
3383            .parse::<ipnetwork::IpNetwork>()
3384            .map_err(|e| e.to_string())?;
3385        match net {
3386            ipnetwork::IpNetwork::V4(net) => Ok(Ipv4Net(net)),
3387            ipnetwork::IpNetwork::V6(..) => Err(format!("IPv6 subnet {} not supported here", s)),
3388        }
3389    }
3390}
3391
3392impl JsonSchema for Ipv4Net {
3393    fn schema_name() -> String {
3394        "Ipv4Net".to_string()
3395    }
3396
3397    fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
3398        schemars::schema::Schema::Object(
3399            schemars::schema::SchemaObject {
3400                metadata: Some(Box::new(schemars::schema::Metadata {
3401                    title: Some("An IPv4 subnet".to_string()),
3402                    description: Some("An IPv4 subnet, including prefix and subnet mask".to_string()),
3403                    examples: vec!["192.168.1.0/24".into()],
3404                    ..Default::default()
3405                })),
3406                instance_type: Some(schemars::schema::SingleOrVec::Single(Box::new(schemars::schema::InstanceType::String))),
3407                string: Some(Box::new(schemars::schema::StringValidation {
3408                    // Fully-specified IPv4 address. Up to 15 chars for address, plus slash and up to 2 subnet digits.
3409                    max_length: Some(18),
3410                    min_length: None,
3411                    // Addresses must be from an RFC 1918 private address space
3412                    pattern: Some(
3413                        concat!(
3414                            // 10.x.x.x/8
3415                            r#"(^(10\.(25[0-5]|[1-2][0-4][0-9]|[1-9][0-9]|[0-9]\.){2}(25[0-5]|[1-2][0-4][0-9]|[1-9][0-9]|[0-9])/(1[0-9]|2[0-8]|[8-9]))$)|"#,
3416                            // 172.16.x.x/12
3417                            r#"(^(172\.16\.(25[0-5]|[1-2][0-4][0-9]|[1-9][0-9]|[0-9])\.(25[0-5]|[1-2][0-4][0-9]|[1-9][0-9]|[0-9])/(1[2-9]|2[0-8]))$)|"#,
3418                            // 192.168.x.x/16
3419                            r#"(^(192\.168\.(25[0-5]|[1-2][0-4][0-9]|[1-9][0-9]|[0-9])\.(25[0-5]|[1-2][0-4][0-9]|[1-9][0-9]|[0-9])/(1[6-9]|2[0-8]))$)"#,
3420                        ).to_string(),
3421                    ),
3422                })),
3423                ..Default::default()
3424            }
3425        )
3426    }
3427}
3428/// A non-decreasing IPv4 address range, inclusive of both ends.
3429///
3430/// The first address must be less than or equal to the last address.
3431#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
3432pub struct Ipv4Range {
3433    #[serde()]
3434    pub first: std::net::Ipv4Addr,
3435
3436    #[serde()]
3437    pub last: std::net::Ipv4Addr,
3438}
3439
3440/// An `Ipv6Net` represents a IPv6 subnetwork, including the address and network mask.
3441#[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Serialize)]
3442pub struct Ipv6Net(pub ipnetwork::Ipv6Network);
3443
3444impl Ipv6Net {
3445    /// The length for all VPC IPv6 prefixes
3446    pub const VPC_IPV6_PREFIX_LENGTH: u8 = 48;
3447
3448    /// The prefix length for all VPC Sunets
3449    pub const VPC_SUBNET_IPV6_PREFIX_LENGTH: u8 = 64;
3450
3451    /// Return `true` if this subnetwork is in the IPv6 Unique Local Address
3452    /// range defined in RFC 4193, e.g., `fd00:/8`
3453    pub fn is_unique_local(&self) -> bool {
3454        // TODO: Delegate to `Ipv6Addr::is_unique_local()` when stabilized.
3455        self.0.network().octets()[0] == 0xfd
3456    }
3457
3458    /// Return `true` if this subnetwork is a valid VPC prefix.
3459    ///
3460    /// This checks that the subnet is a unique local address, and has the VPC
3461    /// prefix length required.
3462    pub fn is_vpc_prefix(&self) -> bool {
3463        self.is_unique_local() && self.0.prefix() == Self::VPC_IPV6_PREFIX_LENGTH
3464    }
3465
3466    /// Return `true` if this subnetwork is a valid VPC Subnet, given the VPC's
3467    /// prefix.
3468    pub fn is_vpc_subnet(&self, vpc_prefix: &Ipv6Net) -> bool {
3469        self.is_unique_local()
3470            && self.is_subnet_of(vpc_prefix.0)
3471            && self.prefix() == Self::VPC_SUBNET_IPV6_PREFIX_LENGTH
3472    }
3473}
3474
3475impl std::ops::Deref for Ipv6Net {
3476    type Target = ipnetwork::Ipv6Network;
3477    fn deref(&self) -> &Self::Target {
3478        &self.0
3479    }
3480}
3481
3482impl std::fmt::Display for Ipv6Net {
3483    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
3484        write!(f, "{}", self.0)
3485    }
3486}
3487
3488impl std::str::FromStr for Ipv6Net {
3489    type Err = String;
3490
3491    fn from_str(s: &str) -> Result<Self, Self::Err> {
3492        let net = s
3493            .parse::<ipnetwork::IpNetwork>()
3494            .map_err(|e| e.to_string())?;
3495        match net {
3496            ipnetwork::IpNetwork::V4(..) => Err(format!("IPv4 subnet {} not supported here", s)),
3497            ipnetwork::IpNetwork::V6(net) => Ok(Ipv6Net(net)),
3498        }
3499    }
3500}
3501
3502impl JsonSchema for Ipv6Net {
3503    fn schema_name() -> String {
3504        "Ipv6Net".to_string()
3505    }
3506
3507    fn json_schema(_: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
3508        schemars::schema::Schema::Object(
3509            schemars::schema::SchemaObject {
3510                metadata: Some(Box::new(schemars::schema::Metadata {
3511                    title: Some("An IPv6 subnet".to_string()),
3512                    description: Some("An IPv6 subnet, including prefix and subnet mask".to_string()),
3513                    examples: vec!["fd12:3456::/64".into()],
3514                    ..Default::default()
3515                })),
3516                instance_type: Some(schemars::schema::SingleOrVec::Single(Box::new(schemars::schema::InstanceType::String))),
3517                string: Some(Box::new(schemars::schema::StringValidation {
3518                    // Fully-specified IPv6 address. 4 hex chars per segment, 8 segments, 7
3519                    // ":"-separators, slash and up to 3 subnet digits
3520                    max_length: Some(43),
3521                    min_length: None,
3522                    pattern: Some(
3523                        // Conforming to unique local addressing scheme, `fd00::/8`.
3524                        concat!(
3525                            r#"^(fd|FD)[0-9a-fA-F]{2}:((([0-9a-fA-F]{1,4}\:){6}[0-9a-fA-F]{1,4})|(([0-9a-fA-F]{1,4}:){1,6}:))/(6[4-9]|[7-9][0-9]|1[0-1][0-9]|12[0-6])$"#,
3526                        ).to_string(),
3527                    ),
3528                })),
3529                ..Default::default()
3530            }
3531        )
3532    }
3533}
3534/// A non-decreasing IPv6 address range, inclusive of both ends.
3535///
3536/// The first address must be less than or equal to the last address.
3537#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
3538pub struct Ipv6Range {
3539    #[serde()]
3540    pub first: std::net::Ipv6Addr,
3541
3542    #[serde()]
3543    pub last: std::net::Ipv6Addr,
3544}
3545
3546/// A `Measurement` is a timestamped datum from a single metric
3547#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3548pub struct Measurement {
3549    #[serde()]
3550    pub datum: Datum,
3551
3552    #[serde()]
3553    pub timestamp: crate::utils::DisplayOptionDateTime,
3554}
3555
3556/// A single page of results
3557#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3558pub struct MeasurementResultsPage {
3559    /**
3560     * list of items on this page of results
3561     */
3562    #[serde(
3563        default,
3564        skip_serializing_if = "Vec::is_empty",
3565        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
3566    )]
3567    #[header(hidden = true)]
3568    pub items: Vec<Measurement>,
3569
3570    /**
3571     * token used to fetch the next page of results (if any)
3572     */
3573    #[serde(
3574        default,
3575        skip_serializing_if = "String::is_empty",
3576        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3577    )]
3578    pub next_page: String,
3579}
3580
3581/// A `NetworkInterface` represents a virtual network interface device.
3582#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3583pub struct NetworkInterface {
3584    /**
3585     * unique, immutable, system-controlled identifier for each resource
3586     */
3587    #[serde(
3588        default,
3589        skip_serializing_if = "String::is_empty",
3590        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3591    )]
3592    pub id: String,
3593
3594    /**
3595     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
3596     */
3597    #[serde(
3598        default,
3599        skip_serializing_if = "String::is_empty",
3600        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3601    )]
3602    pub name: String,
3603
3604    /**
3605     * human-readable free-form text about a resource
3606     */
3607    #[serde(
3608        default,
3609        skip_serializing_if = "String::is_empty",
3610        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3611    )]
3612    pub description: String,
3613
3614    /**
3615     * The Instance to which the interface belongs.
3616     */
3617    #[serde(
3618        default,
3619        skip_serializing_if = "String::is_empty",
3620        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3621    )]
3622    pub instance_id: String,
3623
3624    /**
3625     * The IP address assigned to this interface.
3626     */
3627    #[serde(
3628        default,
3629        skip_serializing_if = "String::is_empty",
3630        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3631    )]
3632    pub ip: String,
3633
3634    /**
3635     * A Media Access Control address, in EUI-48 format
3636     */
3637    #[serde(
3638        default,
3639        skip_serializing_if = "String::is_empty",
3640        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3641    )]
3642    pub mac: String,
3643
3644    /**
3645     * True if this interface is the primary for the instance to which it's attached.
3646     */
3647    #[serde(
3648        default,
3649        deserialize_with = "crate::utils::deserialize_null_boolean::deserialize"
3650    )]
3651    pub primary: bool,
3652
3653    /**
3654     * The subnet to which the interface belongs.
3655     */
3656    #[serde(
3657        default,
3658        skip_serializing_if = "String::is_empty",
3659        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3660    )]
3661    pub subnet_id: String,
3662
3663    /**
3664     * timestamp when this resource was created
3665     */
3666    #[serde()]
3667    pub time_created: crate::utils::DisplayOptionDateTime,
3668
3669    /**
3670     * timestamp when this resource was last modified
3671     */
3672    #[serde()]
3673    pub time_modified: crate::utils::DisplayOptionDateTime,
3674
3675    /**
3676     * The VPC to which the interface belongs.
3677     */
3678    #[serde(
3679        default,
3680        skip_serializing_if = "String::is_empty",
3681        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3682    )]
3683    pub vpc_id: String,
3684}
3685
3686/// Create-time parameters for a [`NetworkInterface`](omicron_common::api::external::NetworkInterface)
3687#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3688pub struct NetworkInterfaceCreate {
3689    /**
3690     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
3691     */
3692    #[serde(
3693        default,
3694        skip_serializing_if = "String::is_empty",
3695        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3696    )]
3697    pub name: String,
3698
3699    #[serde(
3700        default,
3701        skip_serializing_if = "String::is_empty",
3702        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3703    )]
3704    pub description: String,
3705
3706    /**
3707     * The IP address for the interface. One will be auto-assigned if not provided.
3708     */
3709    #[serde(
3710        default,
3711        skip_serializing_if = "String::is_empty",
3712        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3713    )]
3714    pub ip: String,
3715
3716    /**
3717     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
3718     */
3719    #[serde(
3720        default,
3721        skip_serializing_if = "String::is_empty",
3722        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3723    )]
3724    pub subnet_name: String,
3725
3726    /**
3727     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
3728     */
3729    #[serde(
3730        default,
3731        skip_serializing_if = "String::is_empty",
3732        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3733    )]
3734    pub vpc_name: String,
3735}
3736
3737/// A single page of results
3738#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3739pub struct NetworkInterfaceResultsPage {
3740    /**
3741     * list of items on this page of results
3742     */
3743    #[serde(
3744        default,
3745        skip_serializing_if = "Vec::is_empty",
3746        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
3747    )]
3748    #[header(hidden = true)]
3749    pub items: Vec<NetworkInterface>,
3750
3751    /**
3752     * token used to fetch the next page of results (if any)
3753     */
3754    #[serde(
3755        default,
3756        skip_serializing_if = "String::is_empty",
3757        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3758    )]
3759    pub next_page: String,
3760}
3761
3762/// Parameters for updating a [`NetworkInterface`](omicron_common::api::external::NetworkInterface).
3763///
3764/// Note that modifying IP addresses for an interface is not yet supported, a new interface must be created instead.
3765#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3766pub struct NetworkInterfaceUpdate {
3767    #[serde(
3768        default,
3769        skip_serializing_if = "String::is_empty",
3770        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3771    )]
3772    pub name: String,
3773
3774    #[serde(
3775        default,
3776        skip_serializing_if = "String::is_empty",
3777        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3778    )]
3779    pub description: String,
3780
3781    /**
3782     * Make a secondary interface the instance's primary interface.
3783     *  
3784     *  If applied to a secondary interface, that interface will become the primary on the next reboot of the instance. Note that this may have implications for routing between instances, as the new primary interface will be on a distinct subnet from the previous primary interface.
3785     *  
3786     *  Note that this can only be used to select a new primary interface for an instance. Requests to change the primary interface into a secondary will return an error.
3787     */
3788    #[serde(
3789        default,
3790        deserialize_with = "crate::utils::deserialize_null_boolean::deserialize"
3791    )]
3792    pub primary: bool,
3793}
3794
3795/// Client view of an [`Organization`]
3796#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3797pub struct Organization {
3798    /**
3799     * unique, immutable, system-controlled identifier for each resource
3800     */
3801    #[serde(
3802        default,
3803        skip_serializing_if = "String::is_empty",
3804        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3805    )]
3806    pub id: String,
3807
3808    /**
3809     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
3810     */
3811    #[serde(
3812        default,
3813        skip_serializing_if = "String::is_empty",
3814        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3815    )]
3816    pub name: String,
3817
3818    /**
3819     * human-readable free-form text about a resource
3820     */
3821    #[serde(
3822        default,
3823        skip_serializing_if = "String::is_empty",
3824        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3825    )]
3826    pub description: String,
3827
3828    /**
3829     * timestamp when this resource was created
3830     */
3831    #[serde()]
3832    pub time_created: crate::utils::DisplayOptionDateTime,
3833
3834    /**
3835     * timestamp when this resource was last modified
3836     */
3837    #[serde()]
3838    pub time_modified: crate::utils::DisplayOptionDateTime,
3839}
3840
3841/// Create-time parameters for an [`Organization`](crate::external_api::views::Organization)
3842#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3843pub struct OrganizationCreate {
3844    /**
3845     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
3846     */
3847    #[serde(
3848        default,
3849        skip_serializing_if = "String::is_empty",
3850        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3851    )]
3852    pub name: String,
3853
3854    #[serde(
3855        default,
3856        skip_serializing_if = "String::is_empty",
3857        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3858    )]
3859    pub description: String,
3860}
3861
3862/// A single page of results
3863#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3864pub struct OrganizationResultsPage {
3865    /**
3866     * list of items on this page of results
3867     */
3868    #[serde(
3869        default,
3870        skip_serializing_if = "Vec::is_empty",
3871        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
3872    )]
3873    #[header(hidden = true)]
3874    pub items: Vec<Organization>,
3875
3876    /**
3877     * token used to fetch the next page of results (if any)
3878     */
3879    #[serde(
3880        default,
3881        skip_serializing_if = "String::is_empty",
3882        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3883    )]
3884    pub next_page: String,
3885}
3886
3887#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
3888#[serde(rename_all = "snake_case")]
3889pub enum OrganizationRole {
3890    Admin,
3891    Collaborator,
3892    Viewer,
3893    #[serde(rename = "")]
3894    Noop,
3895    #[serde(other)]
3896    FallthroughString,
3897}
3898
3899impl std::fmt::Display for OrganizationRole {
3900    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3901        match &*self {
3902            OrganizationRole::Admin => "admin",
3903            OrganizationRole::Collaborator => "collaborator",
3904            OrganizationRole::Viewer => "viewer",
3905            OrganizationRole::Noop => "",
3906            OrganizationRole::FallthroughString => "*",
3907        }
3908        .fmt(f)
3909    }
3910}
3911
3912impl Default for OrganizationRole {
3913    fn default() -> OrganizationRole {
3914        OrganizationRole::Admin
3915    }
3916}
3917impl std::str::FromStr for OrganizationRole {
3918    type Err = anyhow::Error;
3919    fn from_str(s: &str) -> Result<Self, Self::Err> {
3920        if s == "admin" {
3921            return Ok(OrganizationRole::Admin);
3922        }
3923        if s == "collaborator" {
3924            return Ok(OrganizationRole::Collaborator);
3925        }
3926        if s == "viewer" {
3927            return Ok(OrganizationRole::Viewer);
3928        }
3929        anyhow::bail!("invalid string for OrganizationRole: {}", s);
3930    }
3931}
3932impl OrganizationRole {
3933    pub fn is_noop(&self) -> bool {
3934        matches!(self, OrganizationRole::Noop)
3935    }
3936}
3937
3938/// Describes the assignment of a particular role on a particular resource to a particular identity (user, group, etc.)
3939///
3940/// The resource is not part of this structure.  Rather, [`RoleAssignment`]s are put into a [`Policy`] and that Policy is applied to a particular resource.
3941#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3942pub struct OrganizationRoleAssignment {
3943    #[serde(
3944        default,
3945        skip_serializing_if = "String::is_empty",
3946        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3947    )]
3948    pub identity_id: String,
3949
3950    /**
3951     * Describes what kind of identity is described by an id
3952     */
3953    #[serde(default, skip_serializing_if = "IdentityType::is_noop")]
3954    pub identity_type: IdentityType,
3955
3956    #[serde(default, skip_serializing_if = "OrganizationRole::is_noop")]
3957    pub role_name: OrganizationRole,
3958}
3959
3960/// Client view of a [`Policy`], which describes how this resource may be accessed
3961///
3962/// Note that the Policy only describes access granted explicitly for this resource.  The policies of parent resources can also cause a user to have access to this resource.
3963#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3964pub struct OrganizationRolePolicy {
3965    /**
3966     * Roles directly assigned on this resource
3967     */
3968    #[serde(
3969        default,
3970        skip_serializing_if = "Vec::is_empty",
3971        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
3972    )]
3973    #[header(hidden = true)]
3974    pub role_assignments: Vec<OrganizationRoleAssignment>,
3975}
3976
3977/// Updateable properties of an [`Organization`](crate::external_api::views::Organization)
3978#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3979pub struct OrganizationUpdate {
3980    #[serde(
3981        default,
3982        skip_serializing_if = "String::is_empty",
3983        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3984    )]
3985    pub name: String,
3986
3987    #[serde(
3988        default,
3989        skip_serializing_if = "String::is_empty",
3990        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
3991    )]
3992    pub description: String,
3993}
3994
3995/// Client view of a [`Project`]
3996#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
3997pub struct Project {
3998    /**
3999     * unique, immutable, system-controlled identifier for each resource
4000     */
4001    #[serde(
4002        default,
4003        skip_serializing_if = "String::is_empty",
4004        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4005    )]
4006    pub id: String,
4007
4008    /**
4009     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
4010     */
4011    #[serde(
4012        default,
4013        skip_serializing_if = "String::is_empty",
4014        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4015    )]
4016    pub name: String,
4017
4018    /**
4019     * human-readable free-form text about a resource
4020     */
4021    #[serde(
4022        default,
4023        skip_serializing_if = "String::is_empty",
4024        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4025    )]
4026    pub description: String,
4027
4028    #[serde(
4029        default,
4030        skip_serializing_if = "String::is_empty",
4031        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4032    )]
4033    pub organization_id: String,
4034
4035    /**
4036     * timestamp when this resource was created
4037     */
4038    #[serde()]
4039    pub time_created: crate::utils::DisplayOptionDateTime,
4040
4041    /**
4042     * timestamp when this resource was last modified
4043     */
4044    #[serde()]
4045    pub time_modified: crate::utils::DisplayOptionDateTime,
4046}
4047
4048/// Create-time parameters for a [`Project`](crate::external_api::views::Project)
4049#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
4050pub struct ProjectCreate {
4051    /**
4052     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
4053     */
4054    #[serde(
4055        default,
4056        skip_serializing_if = "String::is_empty",
4057        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4058    )]
4059    pub name: String,
4060
4061    #[serde(
4062        default,
4063        skip_serializing_if = "String::is_empty",
4064        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4065    )]
4066    pub description: String,
4067}
4068
4069/// A single page of results
4070#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
4071pub struct ProjectResultsPage {
4072    /**
4073     * list of items on this page of results
4074     */
4075    #[serde(
4076        default,
4077        skip_serializing_if = "Vec::is_empty",
4078        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
4079    )]
4080    #[header(hidden = true)]
4081    pub items: Vec<Project>,
4082
4083    /**
4084     * token used to fetch the next page of results (if any)
4085     */
4086    #[serde(
4087        default,
4088        skip_serializing_if = "String::is_empty",
4089        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4090    )]
4091    pub next_page: String,
4092}
4093
4094#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
4095#[serde(rename_all = "snake_case")]
4096pub enum ProjectRole {
4097    Admin,
4098    Collaborator,
4099    Viewer,
4100    #[serde(rename = "")]
4101    Noop,
4102    #[serde(other)]
4103    FallthroughString,
4104}
4105
4106impl std::fmt::Display for ProjectRole {
4107    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4108        match &*self {
4109            ProjectRole::Admin => "admin",
4110            ProjectRole::Collaborator => "collaborator",
4111            ProjectRole::Viewer => "viewer",
4112            ProjectRole::Noop => "",
4113            ProjectRole::FallthroughString => "*",
4114        }
4115        .fmt(f)
4116    }
4117}
4118
4119impl Default for ProjectRole {
4120    fn default() -> ProjectRole {
4121        ProjectRole::Admin
4122    }
4123}
4124impl std::str::FromStr for ProjectRole {
4125    type Err = anyhow::Error;
4126    fn from_str(s: &str) -> Result<Self, Self::Err> {
4127        if s == "admin" {
4128            return Ok(ProjectRole::Admin);
4129        }
4130        if s == "collaborator" {
4131            return Ok(ProjectRole::Collaborator);
4132        }
4133        if s == "viewer" {
4134            return Ok(ProjectRole::Viewer);
4135        }
4136        anyhow::bail!("invalid string for ProjectRole: {}", s);
4137    }
4138}
4139impl ProjectRole {
4140    pub fn is_noop(&self) -> bool {
4141        matches!(self, ProjectRole::Noop)
4142    }
4143}
4144
4145/// Describes the assignment of a particular role on a particular resource to a particular identity (user, group, etc.)
4146///
4147/// The resource is not part of this structure.  Rather, [`RoleAssignment`]s are put into a [`Policy`] and that Policy is applied to a particular resource.
4148#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
4149pub struct ProjectRoleAssignment {
4150    #[serde(
4151        default,
4152        skip_serializing_if = "String::is_empty",
4153        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4154    )]
4155    pub identity_id: String,
4156
4157    /**
4158     * Describes what kind of identity is described by an id
4159     */
4160    #[serde(default, skip_serializing_if = "IdentityType::is_noop")]
4161    pub identity_type: IdentityType,
4162
4163    #[serde(default, skip_serializing_if = "ProjectRole::is_noop")]
4164    pub role_name: ProjectRole,
4165}
4166
4167/// Client view of a [`Policy`], which describes how this resource may be accessed
4168///
4169/// Note that the Policy only describes access granted explicitly for this resource.  The policies of parent resources can also cause a user to have access to this resource.
4170#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
4171pub struct ProjectRolePolicy {
4172    /**
4173     * Roles directly assigned on this resource
4174     */
4175    #[serde(
4176        default,
4177        skip_serializing_if = "Vec::is_empty",
4178        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
4179    )]
4180    #[header(hidden = true)]
4181    pub role_assignments: Vec<ProjectRoleAssignment>,
4182}
4183
4184/// Updateable properties of a [`Project`](crate::external_api::views::Project)
4185#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
4186pub struct ProjectUpdate {
4187    #[serde(
4188        default,
4189        skip_serializing_if = "String::is_empty",
4190        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4191    )]
4192    pub name: String,
4193
4194    #[serde(
4195        default,
4196        skip_serializing_if = "String::is_empty",
4197        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4198    )]
4199    pub description: String,
4200}
4201
4202/// Client view of an [`Rack`]
4203#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
4204pub struct Rack {
4205    /**
4206     * unique, immutable, system-controlled identifier for each resource
4207     */
4208    #[serde(
4209        default,
4210        skip_serializing_if = "String::is_empty",
4211        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4212    )]
4213    pub id: String,
4214
4215    /**
4216     * timestamp when this resource was created
4217     */
4218    #[serde()]
4219    pub time_created: crate::utils::DisplayOptionDateTime,
4220
4221    /**
4222     * timestamp when this resource was last modified
4223     */
4224    #[serde()]
4225    pub time_modified: crate::utils::DisplayOptionDateTime,
4226}
4227
4228/// A single page of results
4229#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
4230pub struct RackResultsPage {
4231    /**
4232     * list of items on this page of results
4233     */
4234    #[serde(
4235        default,
4236        skip_serializing_if = "Vec::is_empty",
4237        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
4238    )]
4239    #[header(hidden = true)]
4240    pub items: Vec<Rack>,
4241
4242    /**
4243     * token used to fetch the next page of results (if any)
4244     */
4245    #[serde(
4246        default,
4247        skip_serializing_if = "String::is_empty",
4248        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4249    )]
4250    pub next_page: String,
4251}
4252
4253/// Client view of a [`Role`]
4254#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
4255pub struct Role {
4256    /**
4257     * Role names consist of two string components separated by dot (".").
4258     */
4259    #[serde(
4260        default,
4261        skip_serializing_if = "String::is_empty",
4262        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4263    )]
4264    pub name: String,
4265
4266    #[serde(
4267        default,
4268        skip_serializing_if = "String::is_empty",
4269        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4270    )]
4271    pub description: String,
4272}
4273
4274/// A single page of results
4275#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
4276pub struct RoleResultsPage {
4277    /**
4278     * list of items on this page of results
4279     */
4280    #[serde(
4281        default,
4282        skip_serializing_if = "Vec::is_empty",
4283        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
4284    )]
4285    #[header(hidden = true)]
4286    pub items: Vec<Role>,
4287
4288    /**
4289     * token used to fetch the next page of results (if any)
4290     */
4291    #[serde(
4292        default,
4293        skip_serializing_if = "String::is_empty",
4294        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4295    )]
4296    pub next_page: String,
4297}
4298
4299#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
4300#[serde(rename_all = "snake_case")]
4301#[serde(tag = "type", content = "value")]
4302pub enum RouteDestination {
4303    Ip(String),
4304    IpNet(IpNet),
4305    Vpc(String),
4306    Subnet(String),
4307}
4308
4309impl fmt::Display for RouteDestination {
4310    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4311        let j = serde_json::json!(self);
4312        let mut tag: String = serde_json::from_value(j["type"].clone()).unwrap_or_default();
4313        let mut content: String = serde_json::from_value(j["value"].clone()).unwrap_or_default();
4314        if content.is_empty() {
4315            let map: std::collections::HashMap<String, String> =
4316                serde_json::from_value(j["value"].clone()).unwrap_or_default();
4317            if let Some((_, v)) = map.iter().next() {
4318                content = v.to_string();
4319            }
4320        }
4321        if tag == "internet_gateway" {
4322            tag = "inetgw".to_string();
4323        }
4324        write!(f, "{}={}", tag, content)
4325    }
4326}
4327
4328impl std::str::FromStr for RouteDestination {
4329    type Err = anyhow::Error;
4330    fn from_str(s: &str) -> Result<Self, Self::Err> {
4331        let parts = s.split('=').collect::<Vec<&str>>();
4332        if parts.len() != 2 {
4333            anyhow::bail!("invalid format for RouteDestination, got {}", s);
4334        }
4335        let tag = parts[0].to_string();
4336        let content = parts[1].to_string();
4337        let mut j = String::new();
4338        if tag == "ip" {
4339            j = format!(
4340                r#"{{
4341"type": "ip",
4342"value": "{}"
4343        }}"#,
4344                content
4345            );
4346        }
4347        if tag == "ip_net" {
4348            j = format!(
4349                r#"{{
4350"type": "ip_net",
4351"value": {}
4352        }}"#,
4353                serde_json::json!(IpNet::from_str(&content).unwrap())
4354            );
4355        }
4356        if tag == "vpc" {
4357            j = format!(
4358                r#"{{
4359"type": "vpc",
4360"value": "{}"
4361        }}"#,
4362                content
4363            );
4364        }
4365        if tag == "subnet" {
4366            j = format!(
4367                r#"{{
4368"type": "subnet",
4369"value": "{}"
4370        }}"#,
4371                content
4372            );
4373        }
4374        let result = serde_json::from_str(&j)?;
4375        Ok(result)
4376    }
4377}
4378impl RouteDestination {
4379    pub fn variants() -> Vec<String> {
4380        vec![
4381            "ip".to_string(),
4382            "ip_net".to_string(),
4383            "subnet".to_string(),
4384            "vpc".to_string(),
4385        ]
4386    }
4387}
4388/**
4389 * The types for RouteDestination.
4390 */
4391#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
4392#[serde(rename_all = "snake_case")]
4393pub enum RouteDestinationType {
4394    Ip,
4395    IpNet,
4396    Subnet,
4397    Vpc,
4398}
4399
4400impl std::fmt::Display for RouteDestinationType {
4401    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4402        match &*self {
4403            RouteDestinationType::Ip => "ip",
4404            RouteDestinationType::IpNet => "ip_net",
4405            RouteDestinationType::Subnet => "subnet",
4406            RouteDestinationType::Vpc => "vpc",
4407        }
4408        .fmt(f)
4409    }
4410}
4411
4412impl Default for RouteDestinationType {
4413    fn default() -> RouteDestinationType {
4414        RouteDestinationType::Ip
4415    }
4416}
4417impl std::str::FromStr for RouteDestinationType {
4418    type Err = anyhow::Error;
4419    fn from_str(s: &str) -> Result<Self, Self::Err> {
4420        if s == "ip" {
4421            return Ok(RouteDestinationType::Ip);
4422        }
4423        if s == "ip_net" {
4424            return Ok(RouteDestinationType::IpNet);
4425        }
4426        if s == "subnet" {
4427            return Ok(RouteDestinationType::Subnet);
4428        }
4429        if s == "vpc" {
4430            return Ok(RouteDestinationType::Vpc);
4431        }
4432        anyhow::bail!("invalid string for RouteDestinationType: {}", s);
4433    }
4434}
4435
4436#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
4437#[serde(rename_all = "snake_case")]
4438#[serde(tag = "type", content = "value")]
4439pub enum RouteTarget {
4440    Ip(String),
4441    Vpc(String),
4442    Subnet(String),
4443    Instance(String),
4444    InternetGateway(String),
4445}
4446
4447impl fmt::Display for RouteTarget {
4448    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4449        let j = serde_json::json!(self);
4450        let mut tag: String = serde_json::from_value(j["type"].clone()).unwrap_or_default();
4451        let mut content: String = serde_json::from_value(j["value"].clone()).unwrap_or_default();
4452        if content.is_empty() {
4453            let map: std::collections::HashMap<String, String> =
4454                serde_json::from_value(j["value"].clone()).unwrap_or_default();
4455            if let Some((_, v)) = map.iter().next() {
4456                content = v.to_string();
4457            }
4458        }
4459        if tag == "internet_gateway" {
4460            tag = "inetgw".to_string();
4461        }
4462        write!(f, "{}={}", tag, content)
4463    }
4464}
4465
4466impl std::str::FromStr for RouteTarget {
4467    type Err = anyhow::Error;
4468    fn from_str(s: &str) -> Result<Self, Self::Err> {
4469        let parts = s.split('=').collect::<Vec<&str>>();
4470        if parts.len() != 2 {
4471            anyhow::bail!("invalid format for RouteTarget, got {}", s);
4472        }
4473        let tag = parts[0].to_string();
4474        let content = parts[1].to_string();
4475        let mut j = String::new();
4476        if tag == "ip" {
4477            j = format!(
4478                r#"{{
4479"type": "ip",
4480"value": "{}"
4481        }}"#,
4482                content
4483            );
4484        }
4485        if tag == "vpc" {
4486            j = format!(
4487                r#"{{
4488"type": "vpc",
4489"value": "{}"
4490        }}"#,
4491                content
4492            );
4493        }
4494        if tag == "subnet" {
4495            j = format!(
4496                r#"{{
4497"type": "subnet",
4498"value": "{}"
4499        }}"#,
4500                content
4501            );
4502        }
4503        if tag == "instance" {
4504            j = format!(
4505                r#"{{
4506"type": "instance",
4507"value": "{}"
4508        }}"#,
4509                content
4510            );
4511        }
4512        if tag == "inetgw" {
4513            j = format!(
4514                r#"{{
4515"type": "internet_gateway",
4516"value": "{}"
4517        }}"#,
4518                content
4519            );
4520        }
4521        let result = serde_json::from_str(&j)?;
4522        Ok(result)
4523    }
4524}
4525impl RouteTarget {
4526    pub fn variants() -> Vec<String> {
4527        vec![
4528            "instance".to_string(),
4529            "inetgw".to_string(),
4530            "ip".to_string(),
4531            "subnet".to_string(),
4532            "vpc".to_string(),
4533        ]
4534    }
4535}
4536/**
4537 * The types for RouteTarget.
4538 */
4539#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
4540#[serde(rename_all = "snake_case")]
4541pub enum RouteTargetType {
4542    Instance,
4543    InternetGateway,
4544    Ip,
4545    Subnet,
4546    Vpc,
4547}
4548
4549impl std::fmt::Display for RouteTargetType {
4550    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4551        match &*self {
4552            RouteTargetType::Instance => "instance",
4553            RouteTargetType::InternetGateway => "internet_gateway",
4554            RouteTargetType::Ip => "ip",
4555            RouteTargetType::Subnet => "subnet",
4556            RouteTargetType::Vpc => "vpc",
4557        }
4558        .fmt(f)
4559    }
4560}
4561
4562impl Default for RouteTargetType {
4563    fn default() -> RouteTargetType {
4564        RouteTargetType::Instance
4565    }
4566}
4567impl std::str::FromStr for RouteTargetType {
4568    type Err = anyhow::Error;
4569    fn from_str(s: &str) -> Result<Self, Self::Err> {
4570        if s == "instance" {
4571            return Ok(RouteTargetType::Instance);
4572        }
4573        if s == "internet_gateway" {
4574            return Ok(RouteTargetType::InternetGateway);
4575        }
4576        if s == "ip" {
4577            return Ok(RouteTargetType::Ip);
4578        }
4579        if s == "subnet" {
4580            return Ok(RouteTargetType::Subnet);
4581        }
4582        if s == "vpc" {
4583            return Ok(RouteTargetType::Vpc);
4584        }
4585        anyhow::bail!("invalid string for RouteTargetType: {}", s);
4586    }
4587}
4588
4589/**
4590 * The classification of a [`RouterRoute`] as defined by the system. The kind determines certain attributes such as if the route is modifiable and describes how or where the route was created.
4591 *   
4592 *   See [RFD-21](https://rfd.shared.oxide.computer/rfd/0021#concept-router) for more context
4593 */
4594#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
4595#[serde(rename_all = "snake_case")]
4596pub enum RouterRouteKind {
4597    Custom,
4598    Default,
4599    VpcPeering,
4600    VpcSubnet,
4601    #[serde(rename = "")]
4602    Noop,
4603    #[serde(other)]
4604    FallthroughString,
4605}
4606
4607impl std::fmt::Display for RouterRouteKind {
4608    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4609        match &*self {
4610            RouterRouteKind::Custom => "custom",
4611            RouterRouteKind::Default => "default",
4612            RouterRouteKind::VpcPeering => "vpc_peering",
4613            RouterRouteKind::VpcSubnet => "vpc_subnet",
4614            RouterRouteKind::Noop => "",
4615            RouterRouteKind::FallthroughString => "*",
4616        }
4617        .fmt(f)
4618    }
4619}
4620
4621impl Default for RouterRouteKind {
4622    fn default() -> RouterRouteKind {
4623        RouterRouteKind::Custom
4624    }
4625}
4626impl std::str::FromStr for RouterRouteKind {
4627    type Err = anyhow::Error;
4628    fn from_str(s: &str) -> Result<Self, Self::Err> {
4629        if s == "custom" {
4630            return Ok(RouterRouteKind::Custom);
4631        }
4632        if s == "default" {
4633            return Ok(RouterRouteKind::Default);
4634        }
4635        if s == "vpc_peering" {
4636            return Ok(RouterRouteKind::VpcPeering);
4637        }
4638        if s == "vpc_subnet" {
4639            return Ok(RouterRouteKind::VpcSubnet);
4640        }
4641        anyhow::bail!("invalid string for RouterRouteKind: {}", s);
4642    }
4643}
4644impl RouterRouteKind {
4645    pub fn is_noop(&self) -> bool {
4646        matches!(self, RouterRouteKind::Noop)
4647    }
4648}
4649
4650/// A route defines a rule that governs where traffic should be sent based on its destination.
4651#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
4652pub struct RouterRoute {
4653    /**
4654     * unique, immutable, system-controlled identifier for each resource
4655     */
4656    #[serde(
4657        default,
4658        skip_serializing_if = "String::is_empty",
4659        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4660    )]
4661    pub id: String,
4662
4663    /**
4664     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
4665     */
4666    #[serde(
4667        default,
4668        skip_serializing_if = "String::is_empty",
4669        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4670    )]
4671    pub name: String,
4672
4673    /**
4674     * human-readable free-form text about a resource
4675     */
4676    #[serde(
4677        default,
4678        skip_serializing_if = "String::is_empty",
4679        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4680    )]
4681    pub description: String,
4682
4683    #[serde()]
4684    pub destination: RouteDestination,
4685
4686    /**
4687     * The classification of a [`RouterRoute`] as defined by the system. The kind determines certain attributes such as if the route is modifiable and describes how or where the route was created.
4688     *  
4689     *  See [RFD-21](https://rfd.shared.oxide.computer/rfd/0021#concept-router) for more context
4690     */
4691    #[serde(default, skip_serializing_if = "RouterRouteKind::is_noop")]
4692    pub kind: RouterRouteKind,
4693
4694    #[serde()]
4695    pub target: RouteTarget,
4696
4697    /**
4698     * timestamp when this resource was created
4699     */
4700    #[serde()]
4701    pub time_created: crate::utils::DisplayOptionDateTime,
4702
4703    /**
4704     * timestamp when this resource was last modified
4705     */
4706    #[serde()]
4707    pub time_modified: crate::utils::DisplayOptionDateTime,
4708
4709    /**
4710     * The VPC Router to which the route belongs.
4711     */
4712    #[serde(
4713        default,
4714        skip_serializing_if = "String::is_empty",
4715        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4716    )]
4717    pub vpc_router_id: String,
4718}
4719
4720/// Create-time parameters for a [`RouterRoute`]
4721#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
4722pub struct RouterRouteCreateParams {
4723    /**
4724     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
4725     */
4726    #[serde(
4727        default,
4728        skip_serializing_if = "String::is_empty",
4729        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4730    )]
4731    pub name: String,
4732
4733    #[serde(
4734        default,
4735        skip_serializing_if = "String::is_empty",
4736        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4737    )]
4738    pub description: String,
4739
4740    #[serde()]
4741    pub destination: RouteDestination,
4742
4743    #[serde()]
4744    pub target: RouteTarget,
4745}
4746
4747/// A single page of results
4748#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
4749pub struct RouterRouteResultsPage {
4750    /**
4751     * list of items on this page of results
4752     */
4753    #[serde(
4754        default,
4755        skip_serializing_if = "Vec::is_empty",
4756        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
4757    )]
4758    #[header(hidden = true)]
4759    pub items: Vec<RouterRoute>,
4760
4761    /**
4762     * token used to fetch the next page of results (if any)
4763     */
4764    #[serde(
4765        default,
4766        skip_serializing_if = "String::is_empty",
4767        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4768    )]
4769    pub next_page: String,
4770}
4771
4772/// Updateable properties of a [`RouterRoute`]
4773#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
4774pub struct RouterRouteUpdateParams {
4775    #[serde(
4776        default,
4777        skip_serializing_if = "String::is_empty",
4778        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4779    )]
4780    pub name: String,
4781
4782    #[serde(
4783        default,
4784        skip_serializing_if = "String::is_empty",
4785        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4786    )]
4787    pub description: String,
4788
4789    #[serde()]
4790    pub destination: RouteDestination,
4791
4792    #[serde()]
4793    pub target: RouteTarget,
4794}
4795
4796#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
4797#[serde(rename_all = "snake_case")]
4798#[serde(tag = "state")]
4799pub enum SagaState {
4800    Running,
4801    Succeeded,
4802    Failed {
4803        error_info: SagaErrorInfo,
4804        error_node_name: String,
4805    },
4806}
4807
4808impl fmt::Display for SagaState {
4809    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4810        write!(f, "{}", serde_json::json!(self))
4811    }
4812}
4813
4814impl std::str::FromStr for SagaState {
4815    type Err = anyhow::Error;
4816    fn from_str(s: &str) -> Result<Self, Self::Err> {
4817        Ok(serde_json::from_str(s)?)
4818    }
4819}
4820impl SagaState {
4821    pub fn variants() -> Vec<String> {
4822        vec![
4823            "failed".to_string(),
4824            "running".to_string(),
4825            "succeeded".to_string(),
4826        ]
4827    }
4828}
4829/**
4830 * The types for SagaState.
4831 */
4832#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
4833#[serde(rename_all = "snake_case")]
4834pub enum SagaStateType {
4835    Failed,
4836    Running,
4837    Succeeded,
4838}
4839
4840impl std::fmt::Display for SagaStateType {
4841    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4842        match &*self {
4843            SagaStateType::Failed => "failed",
4844            SagaStateType::Running => "running",
4845            SagaStateType::Succeeded => "succeeded",
4846        }
4847        .fmt(f)
4848    }
4849}
4850
4851impl Default for SagaStateType {
4852    fn default() -> SagaStateType {
4853        SagaStateType::Failed
4854    }
4855}
4856impl std::str::FromStr for SagaStateType {
4857    type Err = anyhow::Error;
4858    fn from_str(s: &str) -> Result<Self, Self::Err> {
4859        if s == "failed" {
4860            return Ok(SagaStateType::Failed);
4861        }
4862        if s == "running" {
4863            return Ok(SagaStateType::Running);
4864        }
4865        if s == "succeeded" {
4866            return Ok(SagaStateType::Succeeded);
4867        }
4868        anyhow::bail!("invalid string for SagaStateType: {}", s);
4869    }
4870}
4871
4872#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
4873pub struct Saga {
4874    #[serde(
4875        default,
4876        skip_serializing_if = "String::is_empty",
4877        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
4878    )]
4879    pub id: String,
4880
4881    #[serde()]
4882    pub state: SagaState,
4883}
4884
4885#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
4886#[serde(rename_all = "snake_case")]
4887#[serde(tag = "error", content = "message")]
4888pub enum SagaErrorInfo {
4889    ActionFailed(serde_json::Value),
4890    DeserializeFailed(String),
4891    InjectedError,
4892    SerializeFailed(String),
4893    SubsagaCreateFailed(String),
4894}
4895
4896impl fmt::Display for SagaErrorInfo {
4897    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
4898        let j = serde_json::json!(self);
4899        let mut tag: String = serde_json::from_value(j["error"].clone()).unwrap_or_default();
4900        let mut content: String = serde_json::from_value(j["message"].clone()).unwrap_or_default();
4901        if content.is_empty() {
4902            let map: std::collections::HashMap<String, String> =
4903                serde_json::from_value(j["message"].clone()).unwrap_or_default();
4904            if let Some((_, v)) = map.iter().next() {
4905                content = v.to_string();
4906            }
4907        }
4908        if tag == "internet_gateway" {
4909            tag = "inetgw".to_string();
4910        }
4911        write!(f, "{}={}", tag, content)
4912    }
4913}
4914
4915impl std::str::FromStr for SagaErrorInfo {
4916    type Err = anyhow::Error;
4917    fn from_str(s: &str) -> Result<Self, Self::Err> {
4918        let parts = s.split('=').collect::<Vec<&str>>();
4919        if parts.len() != 2 {
4920            anyhow::bail!("invalid format for SagaErrorInfo, got {}", s);
4921        }
4922        let tag = parts[0].to_string();
4923        let content = parts[1].to_string();
4924        let mut j = String::new();
4925        if tag == "action_failed" {
4926            j = format!(
4927                r#"{{
4928"error": "action_failed",
4929"message": {}
4930        }}"#,
4931                serde_json::json!(serde_json::Value::from_str(&content).unwrap())
4932            );
4933        }
4934        if tag == "deserialize_failed" {
4935            j = format!(
4936                r#"{{
4937"error": "deserialize_failed",
4938"message": "{}"
4939        }}"#,
4940                content
4941            );
4942        }
4943        if tag == "serialize_failed" {
4944            j = format!(
4945                r#"{{
4946"error": "serialize_failed",
4947"message": "{}"
4948        }}"#,
4949                content
4950            );
4951        }
4952        if tag == "subsaga_create_failed" {
4953            j = format!(
4954                r#"{{
4955"error": "subsaga_create_failed",
4956"message": "{}"
4957        }}"#,
4958                content
4959            );
4960        }
4961        let result = serde_json::from_str(&j)?;
4962        Ok(result)
4963    }
4964}
4965impl SagaErrorInfo {
4966    pub fn variants() -> Vec<String> {
4967        vec![
4968            "action_failed".to_string(),
4969            "deserialize_failed".to_string(),
4970            "injected_error".to_string(),
4971            "serialize_failed".to_string(),
4972            "subsaga_create_failed".to_string(),
4973        ]
4974    }
4975}
4976/**
4977 * The types for SagaErrorInfo.
4978 */
4979#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
4980#[serde(rename_all = "snake_case")]
4981pub enum SagaErrorInfoType {
4982    ActionFailed,
4983    DeserializeFailed,
4984    InjectedError,
4985    SerializeFailed,
4986    SubsagaCreateFailed,
4987}
4988
4989impl std::fmt::Display for SagaErrorInfoType {
4990    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4991        match &*self {
4992            SagaErrorInfoType::ActionFailed => "action_failed",
4993            SagaErrorInfoType::DeserializeFailed => "deserialize_failed",
4994            SagaErrorInfoType::InjectedError => "injected_error",
4995            SagaErrorInfoType::SerializeFailed => "serialize_failed",
4996            SagaErrorInfoType::SubsagaCreateFailed => "subsaga_create_failed",
4997        }
4998        .fmt(f)
4999    }
5000}
5001
5002impl Default for SagaErrorInfoType {
5003    fn default() -> SagaErrorInfoType {
5004        SagaErrorInfoType::ActionFailed
5005    }
5006}
5007impl std::str::FromStr for SagaErrorInfoType {
5008    type Err = anyhow::Error;
5009    fn from_str(s: &str) -> Result<Self, Self::Err> {
5010        if s == "action_failed" {
5011            return Ok(SagaErrorInfoType::ActionFailed);
5012        }
5013        if s == "deserialize_failed" {
5014            return Ok(SagaErrorInfoType::DeserializeFailed);
5015        }
5016        if s == "injected_error" {
5017            return Ok(SagaErrorInfoType::InjectedError);
5018        }
5019        if s == "serialize_failed" {
5020            return Ok(SagaErrorInfoType::SerializeFailed);
5021        }
5022        if s == "subsaga_create_failed" {
5023            return Ok(SagaErrorInfoType::SubsagaCreateFailed);
5024        }
5025        anyhow::bail!("invalid string for SagaErrorInfoType: {}", s);
5026    }
5027}
5028
5029/// A single page of results
5030#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5031pub struct SagaResultsPage {
5032    /**
5033     * list of items on this page of results
5034     */
5035    #[serde(
5036        default,
5037        skip_serializing_if = "Vec::is_empty",
5038        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
5039    )]
5040    #[header(hidden = true)]
5041    pub items: Vec<Saga>,
5042
5043    /**
5044     * token used to fetch the next page of results (if any)
5045     */
5046    #[serde(
5047        default,
5048        skip_serializing_if = "String::is_empty",
5049        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5050    )]
5051    pub next_page: String,
5052}
5053
5054/// Identity-related metadata that's included in nearly all public API objects
5055#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5056pub struct SamlIdentityProvider {
5057    /**
5058     * unique, immutable, system-controlled identifier for each resource
5059     */
5060    #[serde(
5061        default,
5062        skip_serializing_if = "String::is_empty",
5063        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5064    )]
5065    pub id: String,
5066
5067    /**
5068     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
5069     */
5070    #[serde(
5071        default,
5072        skip_serializing_if = "String::is_empty",
5073        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5074    )]
5075    pub name: String,
5076
5077    /**
5078     * human-readable free-form text about a resource
5079     */
5080    #[serde(
5081        default,
5082        skip_serializing_if = "String::is_empty",
5083        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5084    )]
5085    pub description: String,
5086
5087    /**
5088     * service provider endpoint where the response will be sent
5089     */
5090    #[serde(
5091        default,
5092        skip_serializing_if = "String::is_empty",
5093        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5094    )]
5095    pub acs_url: String,
5096
5097    /**
5098     * idp's entity id
5099     */
5100    #[serde(
5101        default,
5102        skip_serializing_if = "String::is_empty",
5103        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5104    )]
5105    pub idp_entity_id: String,
5106
5107    /**
5108     * optional request signing public certificate (base64 encoded der file)
5109     */
5110    #[serde(
5111        default,
5112        skip_serializing_if = "String::is_empty",
5113        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5114    )]
5115    pub public_cert: String,
5116
5117    /**
5118     * service provider endpoint where the idp should send log out requests
5119     */
5120    #[serde(
5121        default,
5122        skip_serializing_if = "String::is_empty",
5123        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5124    )]
5125    pub slo_url: String,
5126
5127    /**
5128     * sp's client id
5129     */
5130    #[serde(
5131        default,
5132        skip_serializing_if = "String::is_empty",
5133        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5134    )]
5135    pub sp_client_id: String,
5136
5137    /**
5138     * customer's technical contact for saml configuration
5139     */
5140    #[serde(
5141        default,
5142        skip_serializing_if = "String::is_empty",
5143        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5144    )]
5145    pub technical_contact_email: String,
5146
5147    /**
5148     * timestamp when this resource was created
5149     */
5150    #[serde()]
5151    pub time_created: crate::utils::DisplayOptionDateTime,
5152
5153    /**
5154     * timestamp when this resource was last modified
5155     */
5156    #[serde()]
5157    pub time_modified: crate::utils::DisplayOptionDateTime,
5158}
5159
5160/// Create-time identity-related parameters
5161#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
5162pub struct SamlIdentityProviderCreate {
5163    /**
5164     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
5165     */
5166    #[serde(
5167        default,
5168        skip_serializing_if = "String::is_empty",
5169        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5170    )]
5171    pub name: String,
5172
5173    #[serde(
5174        default,
5175        skip_serializing_if = "String::is_empty",
5176        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5177    )]
5178    pub description: String,
5179
5180    /**
5181     * service provider endpoint where the response will be sent
5182     */
5183    #[serde(
5184        default,
5185        skip_serializing_if = "String::is_empty",
5186        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5187    )]
5188    pub acs_url: String,
5189
5190    /**
5191     * If set, SAML attributes with this name will be considered to denote a user's group membership, where the attribute value(s) should be a comma-separated list of group names.
5192     */
5193    #[serde(
5194        default,
5195        skip_serializing_if = "String::is_empty",
5196        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5197    )]
5198    pub group_attribute_name: String,
5199
5200    /**
5201     * idp's entity id
5202     */
5203    #[serde(
5204        default,
5205        skip_serializing_if = "String::is_empty",
5206        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5207    )]
5208    pub idp_entity_id: String,
5209
5210    #[serde()]
5211    pub idp_metadata_source: IdpMetadataSource,
5212
5213    /**
5214     * optional request signing key pair
5215     */
5216    #[serde(default, skip_serializing_if = "Option::is_none")]
5217    #[header(hidden = true)]
5218    pub signing_keypair: Option<DerEncodedKeyPair>,
5219
5220    /**
5221     * service provider endpoint where the idp should send log out requests
5222     */
5223    #[serde(
5224        default,
5225        skip_serializing_if = "String::is_empty",
5226        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5227    )]
5228    pub slo_url: String,
5229
5230    /**
5231     * sp's client id
5232     */
5233    #[serde(
5234        default,
5235        skip_serializing_if = "String::is_empty",
5236        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5237    )]
5238    pub sp_client_id: String,
5239
5240    /**
5241     * customer's technical contact for saml configuration
5242     */
5243    #[serde(
5244        default,
5245        skip_serializing_if = "String::is_empty",
5246        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5247    )]
5248    pub technical_contact_email: String,
5249}
5250
5251/**
5252 * How users will be provisioned in a silo during authentication.
5253 */
5254#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
5255#[serde(rename_all = "snake_case")]
5256pub enum UserProvisionType {
5257    Fixed,
5258    Jit,
5259    #[serde(rename = "")]
5260    Noop,
5261    #[serde(other)]
5262    FallthroughString,
5263}
5264
5265impl std::fmt::Display for UserProvisionType {
5266    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5267        match &*self {
5268            UserProvisionType::Fixed => "fixed",
5269            UserProvisionType::Jit => "jit",
5270            UserProvisionType::Noop => "",
5271            UserProvisionType::FallthroughString => "*",
5272        }
5273        .fmt(f)
5274    }
5275}
5276
5277impl Default for UserProvisionType {
5278    fn default() -> UserProvisionType {
5279        UserProvisionType::Fixed
5280    }
5281}
5282impl std::str::FromStr for UserProvisionType {
5283    type Err = anyhow::Error;
5284    fn from_str(s: &str) -> Result<Self, Self::Err> {
5285        if s == "fixed" {
5286            return Ok(UserProvisionType::Fixed);
5287        }
5288        if s == "jit" {
5289            return Ok(UserProvisionType::Jit);
5290        }
5291        anyhow::bail!("invalid string for UserProvisionType: {}", s);
5292    }
5293}
5294impl UserProvisionType {
5295    pub fn is_noop(&self) -> bool {
5296        matches!(self, UserProvisionType::Noop)
5297    }
5298}
5299
5300/// Client view of a ['Silo']
5301#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5302pub struct Silo {
5303    /**
5304     * unique, immutable, system-controlled identifier for each resource
5305     */
5306    #[serde(
5307        default,
5308        skip_serializing_if = "String::is_empty",
5309        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5310    )]
5311    pub id: String,
5312
5313    /**
5314     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
5315     */
5316    #[serde(
5317        default,
5318        skip_serializing_if = "String::is_empty",
5319        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5320    )]
5321    pub name: String,
5322
5323    /**
5324     * human-readable free-form text about a resource
5325     */
5326    #[serde(
5327        default,
5328        skip_serializing_if = "String::is_empty",
5329        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5330    )]
5331    pub description: String,
5332
5333    /**
5334     * A silo where discoverable is false can be retrieved only by its id - it will not be part of the "list all silos" output.
5335     */
5336    #[serde(
5337        default,
5338        deserialize_with = "crate::utils::deserialize_null_boolean::deserialize"
5339    )]
5340    pub discoverable: bool,
5341
5342    /**
5343     * timestamp when this resource was created
5344     */
5345    #[serde()]
5346    pub time_created: crate::utils::DisplayOptionDateTime,
5347
5348    /**
5349     * timestamp when this resource was last modified
5350     */
5351    #[serde()]
5352    pub time_modified: crate::utils::DisplayOptionDateTime,
5353
5354    /**
5355     * How users will be provisioned in a silo during authentication.
5356     */
5357    #[serde(default, skip_serializing_if = "UserProvisionType::is_noop")]
5358    pub user_provision_type: UserProvisionType,
5359}
5360
5361/// Create-time parameters for a [`Silo`](crate::external_api::views::Silo)
5362#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5363pub struct SiloCreate {
5364    /**
5365     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
5366     */
5367    #[serde(
5368        default,
5369        skip_serializing_if = "String::is_empty",
5370        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5371    )]
5372    pub name: String,
5373
5374    #[serde(
5375        default,
5376        skip_serializing_if = "String::is_empty",
5377        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5378    )]
5379    pub description: String,
5380
5381    /**
5382     * If set, this group will be created during Silo creation and granted the "Silo Admin" role. Identity providers can assert that users belong to this group and those users can log in and further initialize the Silo.
5383     *  
5384     *  Note that if configuring a SAML based identity provider, group_attribute_name must be set for users to be considered part of a group. See [`SamlIdentityProviderCreate`] for more information.
5385     */
5386    #[serde(
5387        default,
5388        skip_serializing_if = "String::is_empty",
5389        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5390    )]
5391    pub admin_group_name: String,
5392
5393    #[serde(
5394        default,
5395        deserialize_with = "crate::utils::deserialize_null_boolean::deserialize"
5396    )]
5397    pub discoverable: bool,
5398
5399    /**
5400     * How users will be provisioned in a silo during authentication.
5401     */
5402    #[serde(default, skip_serializing_if = "UserProvisionType::is_noop")]
5403    pub user_provision_type: UserProvisionType,
5404}
5405
5406/// A single page of results
5407#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5408pub struct SiloResultsPage {
5409    /**
5410     * list of items on this page of results
5411     */
5412    #[serde(
5413        default,
5414        skip_serializing_if = "Vec::is_empty",
5415        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
5416    )]
5417    #[header(hidden = true)]
5418    pub items: Vec<Silo>,
5419
5420    /**
5421     * token used to fetch the next page of results (if any)
5422     */
5423    #[serde(
5424        default,
5425        skip_serializing_if = "String::is_empty",
5426        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5427    )]
5428    pub next_page: String,
5429}
5430
5431#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
5432#[serde(rename_all = "snake_case")]
5433pub enum SiloRole {
5434    Admin,
5435    Collaborator,
5436    Viewer,
5437    #[serde(rename = "")]
5438    Noop,
5439    #[serde(other)]
5440    FallthroughString,
5441}
5442
5443impl std::fmt::Display for SiloRole {
5444    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5445        match &*self {
5446            SiloRole::Admin => "admin",
5447            SiloRole::Collaborator => "collaborator",
5448            SiloRole::Viewer => "viewer",
5449            SiloRole::Noop => "",
5450            SiloRole::FallthroughString => "*",
5451        }
5452        .fmt(f)
5453    }
5454}
5455
5456impl Default for SiloRole {
5457    fn default() -> SiloRole {
5458        SiloRole::Admin
5459    }
5460}
5461impl std::str::FromStr for SiloRole {
5462    type Err = anyhow::Error;
5463    fn from_str(s: &str) -> Result<Self, Self::Err> {
5464        if s == "admin" {
5465            return Ok(SiloRole::Admin);
5466        }
5467        if s == "collaborator" {
5468            return Ok(SiloRole::Collaborator);
5469        }
5470        if s == "viewer" {
5471            return Ok(SiloRole::Viewer);
5472        }
5473        anyhow::bail!("invalid string for SiloRole: {}", s);
5474    }
5475}
5476impl SiloRole {
5477    pub fn is_noop(&self) -> bool {
5478        matches!(self, SiloRole::Noop)
5479    }
5480}
5481
5482/// Describes the assignment of a particular role on a particular resource to a particular identity (user, group, etc.)
5483///
5484/// The resource is not part of this structure.  Rather, [`RoleAssignment`]s are put into a [`Policy`] and that Policy is applied to a particular resource.
5485#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5486pub struct SiloRoleAssignment {
5487    #[serde(
5488        default,
5489        skip_serializing_if = "String::is_empty",
5490        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5491    )]
5492    pub identity_id: String,
5493
5494    /**
5495     * Describes what kind of identity is described by an id
5496     */
5497    #[serde(default, skip_serializing_if = "IdentityType::is_noop")]
5498    pub identity_type: IdentityType,
5499
5500    #[serde(default, skip_serializing_if = "SiloRole::is_noop")]
5501    pub role_name: SiloRole,
5502}
5503
5504/// Client view of a [`Policy`], which describes how this resource may be accessed
5505///
5506/// Note that the Policy only describes access granted explicitly for this resource.  The policies of parent resources can also cause a user to have access to this resource.
5507#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5508pub struct SiloRolePolicy {
5509    /**
5510     * Roles directly assigned on this resource
5511     */
5512    #[serde(
5513        default,
5514        skip_serializing_if = "Vec::is_empty",
5515        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
5516    )]
5517    #[header(hidden = true)]
5518    pub role_assignments: Vec<SiloRoleAssignment>,
5519}
5520
5521/// Client view of an [`Sled`]
5522#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5523pub struct Sled {
5524    /**
5525     * unique, immutable, system-controlled identifier for each resource
5526     */
5527    #[serde(
5528        default,
5529        skip_serializing_if = "String::is_empty",
5530        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5531    )]
5532    pub id: String,
5533
5534    #[serde(
5535        default,
5536        skip_serializing_if = "String::is_empty",
5537        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5538    )]
5539    pub service_address: String,
5540
5541    /**
5542     * timestamp when this resource was created
5543     */
5544    #[serde()]
5545    pub time_created: crate::utils::DisplayOptionDateTime,
5546
5547    /**
5548     * timestamp when this resource was last modified
5549     */
5550    #[serde()]
5551    pub time_modified: crate::utils::DisplayOptionDateTime,
5552}
5553
5554/// A single page of results
5555#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5556pub struct SledResultsPage {
5557    /**
5558     * list of items on this page of results
5559     */
5560    #[serde(
5561        default,
5562        skip_serializing_if = "Vec::is_empty",
5563        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
5564    )]
5565    #[header(hidden = true)]
5566    pub items: Vec<Sled>,
5567
5568    /**
5569     * token used to fetch the next page of results (if any)
5570     */
5571    #[serde(
5572        default,
5573        skip_serializing_if = "String::is_empty",
5574        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5575    )]
5576    pub next_page: String,
5577}
5578
5579/// Client view of a Snapshot
5580#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5581pub struct Snapshot {
5582    /**
5583     * unique, immutable, system-controlled identifier for each resource
5584     */
5585    #[serde(
5586        default,
5587        skip_serializing_if = "String::is_empty",
5588        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5589    )]
5590    pub id: String,
5591
5592    /**
5593     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
5594     */
5595    #[serde(
5596        default,
5597        skip_serializing_if = "String::is_empty",
5598        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5599    )]
5600    pub name: String,
5601
5602    /**
5603     * human-readable free-form text about a resource
5604     */
5605    #[serde(
5606        default,
5607        skip_serializing_if = "String::is_empty",
5608        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5609    )]
5610    pub description: String,
5611
5612    #[serde(
5613        default,
5614        skip_serializing_if = "String::is_empty",
5615        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5616    )]
5617    pub disk_id: String,
5618
5619    #[serde(
5620        default,
5621        skip_serializing_if = "String::is_empty",
5622        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5623    )]
5624    pub project_id: String,
5625
5626    /**
5627     * A count of bytes, typically used either for memory or storage capacity
5628     *  
5629     *  The maximum supported byte count is [`i64::MAX`].  This makes it somewhat inconvenient to define constructors: a u32 constructor can be infallible, but an i64 constructor can fail (if the value is negative) and a u64 constructor can fail (if the value is larger than i64::MAX).  We provide all of these for consumers' convenience.
5630     */
5631    #[serde(default)]
5632    pub size: u64,
5633
5634    /**
5635     * timestamp when this resource was created
5636     */
5637    #[serde()]
5638    pub time_created: crate::utils::DisplayOptionDateTime,
5639
5640    /**
5641     * timestamp when this resource was last modified
5642     */
5643    #[serde()]
5644    pub time_modified: crate::utils::DisplayOptionDateTime,
5645}
5646
5647/// Create-time parameters for a [`Snapshot`](crate::external_api::views::Snapshot)
5648#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5649pub struct SnapshotCreate {
5650    /**
5651     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
5652     */
5653    #[serde(
5654        default,
5655        skip_serializing_if = "String::is_empty",
5656        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5657    )]
5658    pub name: String,
5659
5660    #[serde(
5661        default,
5662        skip_serializing_if = "String::is_empty",
5663        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5664    )]
5665    pub description: String,
5666
5667    /**
5668     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
5669     */
5670    #[serde(
5671        default,
5672        skip_serializing_if = "String::is_empty",
5673        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5674    )]
5675    pub disk: String,
5676}
5677
5678/// A single page of results
5679#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5680pub struct SnapshotResultsPage {
5681    /**
5682     * list of items on this page of results
5683     */
5684    #[serde(
5685        default,
5686        skip_serializing_if = "Vec::is_empty",
5687        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
5688    )]
5689    #[header(hidden = true)]
5690    pub items: Vec<Snapshot>,
5691
5692    /**
5693     * token used to fetch the next page of results (if any)
5694     */
5695    #[serde(
5696        default,
5697        skip_serializing_if = "String::is_empty",
5698        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5699    )]
5700    pub next_page: String,
5701}
5702
5703#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5704pub struct SpoofLoginBody {
5705    #[serde(
5706        default,
5707        skip_serializing_if = "String::is_empty",
5708        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5709    )]
5710    pub username: String,
5711}
5712
5713/// Client view of a [`SshKey`]
5714#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5715pub struct SshKey {
5716    /**
5717     * unique, immutable, system-controlled identifier for each resource
5718     */
5719    #[serde(
5720        default,
5721        skip_serializing_if = "String::is_empty",
5722        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5723    )]
5724    pub id: String,
5725
5726    /**
5727     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
5728     */
5729    #[serde(
5730        default,
5731        skip_serializing_if = "String::is_empty",
5732        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5733    )]
5734    pub name: String,
5735
5736    /**
5737     * human-readable free-form text about a resource
5738     */
5739    #[serde(
5740        default,
5741        skip_serializing_if = "String::is_empty",
5742        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5743    )]
5744    pub description: String,
5745
5746    /**
5747     * SSH public key, e.g., `"ssh-ed25519 AAAAC3NzaC..."`
5748     */
5749    #[serde(
5750        default,
5751        skip_serializing_if = "String::is_empty",
5752        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5753    )]
5754    pub public_key: String,
5755
5756    /**
5757     * The user to whom this key belongs
5758     */
5759    #[serde(
5760        default,
5761        skip_serializing_if = "String::is_empty",
5762        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5763    )]
5764    pub silo_user_id: String,
5765
5766    /**
5767     * timestamp when this resource was created
5768     */
5769    #[serde()]
5770    pub time_created: crate::utils::DisplayOptionDateTime,
5771
5772    /**
5773     * timestamp when this resource was last modified
5774     */
5775    #[serde()]
5776    pub time_modified: crate::utils::DisplayOptionDateTime,
5777}
5778
5779/// Create-time parameters for an [`SshKey`](crate::external_api::views::SshKey)
5780#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5781pub struct SshKeyCreate {
5782    /**
5783     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
5784     */
5785    #[serde(
5786        default,
5787        skip_serializing_if = "String::is_empty",
5788        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5789    )]
5790    pub name: String,
5791
5792    #[serde(
5793        default,
5794        skip_serializing_if = "String::is_empty",
5795        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5796    )]
5797    pub description: String,
5798
5799    /**
5800     * SSH public key, e.g., `"ssh-ed25519 AAAAC3NzaC..."`
5801     */
5802    #[serde(
5803        default,
5804        skip_serializing_if = "String::is_empty",
5805        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5806    )]
5807    pub public_key: String,
5808}
5809
5810/// A single page of results
5811#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5812pub struct SshKeyResultsPage {
5813    /**
5814     * list of items on this page of results
5815     */
5816    #[serde(
5817        default,
5818        skip_serializing_if = "Vec::is_empty",
5819        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
5820    )]
5821    #[header(hidden = true)]
5822    pub items: Vec<SshKey>,
5823
5824    /**
5825     * token used to fetch the next page of results (if any)
5826     */
5827    #[serde(
5828        default,
5829        skip_serializing_if = "String::is_empty",
5830        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5831    )]
5832    pub next_page: String,
5833}
5834
5835/// The schema for a timeseries.
5836///
5837/// This includes the name of the timeseries, as well as the datum type of its metric and the schema for each field.
5838#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5839pub struct TimeseriesSchema {
5840    #[serde()]
5841    pub created: crate::utils::DisplayOptionDateTime,
5842
5843    /**
5844     * The type of an individual datum of a metric.
5845     */
5846    #[serde(default, skip_serializing_if = "DatumType::is_noop")]
5847    pub datum_type: DatumType,
5848
5849    #[serde(
5850        default,
5851        skip_serializing_if = "Vec::is_empty",
5852        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
5853    )]
5854    #[header(hidden = true)]
5855    pub field_schema: Vec<FieldSchema>,
5856
5857    /**
5858     * Names are constructed by concatenating the target and metric names with ':'. Target and metric names must be lowercase alphanumeric characters with '_' separating words.
5859     */
5860    #[serde(
5861        default,
5862        skip_serializing_if = "String::is_empty",
5863        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5864    )]
5865    pub timeseries_name: String,
5866}
5867
5868/// A single page of results
5869#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5870pub struct TimeseriesSchemaResultsPage {
5871    /**
5872     * list of items on this page of results
5873     */
5874    #[serde(
5875        default,
5876        skip_serializing_if = "Vec::is_empty",
5877        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
5878    )]
5879    #[header(hidden = true)]
5880    pub items: Vec<TimeseriesSchema>,
5881
5882    /**
5883     * token used to fetch the next page of results (if any)
5884     */
5885    #[serde(
5886        default,
5887        skip_serializing_if = "String::is_empty",
5888        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5889    )]
5890    pub next_page: String,
5891}
5892
5893/// Client view of a [`User`]
5894#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5895pub struct User {
5896    #[serde(
5897        default,
5898        skip_serializing_if = "String::is_empty",
5899        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5900    )]
5901    pub id: String,
5902
5903    /**
5904     * Human-readable name that can identify the user
5905     */
5906    #[serde(
5907        default,
5908        skip_serializing_if = "String::is_empty",
5909        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5910    )]
5911    pub display_name: String,
5912}
5913
5914/// Client view of a [`UserBuiltin`]
5915#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5916pub struct UserBuiltin {
5917    /**
5918     * unique, immutable, system-controlled identifier for each resource
5919     */
5920    #[serde(
5921        default,
5922        skip_serializing_if = "String::is_empty",
5923        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5924    )]
5925    pub id: String,
5926
5927    /**
5928     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
5929     */
5930    #[serde(
5931        default,
5932        skip_serializing_if = "String::is_empty",
5933        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5934    )]
5935    pub name: String,
5936
5937    /**
5938     * human-readable free-form text about a resource
5939     */
5940    #[serde(
5941        default,
5942        skip_serializing_if = "String::is_empty",
5943        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5944    )]
5945    pub description: String,
5946
5947    /**
5948     * timestamp when this resource was created
5949     */
5950    #[serde()]
5951    pub time_created: crate::utils::DisplayOptionDateTime,
5952
5953    /**
5954     * timestamp when this resource was last modified
5955     */
5956    #[serde()]
5957    pub time_modified: crate::utils::DisplayOptionDateTime,
5958}
5959
5960/// A single page of results
5961#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5962pub struct UserBuiltinResultsPage {
5963    /**
5964     * list of items on this page of results
5965     */
5966    #[serde(
5967        default,
5968        skip_serializing_if = "Vec::is_empty",
5969        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
5970    )]
5971    #[header(hidden = true)]
5972    pub items: Vec<UserBuiltin>,
5973
5974    /**
5975     * token used to fetch the next page of results (if any)
5976     */
5977    #[serde(
5978        default,
5979        skip_serializing_if = "String::is_empty",
5980        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
5981    )]
5982    pub next_page: String,
5983}
5984
5985/// A single page of results
5986#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
5987pub struct UserResultsPage {
5988    /**
5989     * list of items on this page of results
5990     */
5991    #[serde(
5992        default,
5993        skip_serializing_if = "Vec::is_empty",
5994        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
5995    )]
5996    #[header(hidden = true)]
5997    pub items: Vec<User>,
5998
5999    /**
6000     * token used to fetch the next page of results (if any)
6001     */
6002    #[serde(
6003        default,
6004        skip_serializing_if = "String::is_empty",
6005        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6006    )]
6007    pub next_page: String,
6008}
6009
6010/// Client view of a [`Vpc`]
6011#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
6012pub struct Vpc {
6013    /**
6014     * unique, immutable, system-controlled identifier for each resource
6015     */
6016    #[serde(
6017        default,
6018        skip_serializing_if = "String::is_empty",
6019        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6020    )]
6021    pub id: String,
6022
6023    /**
6024     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
6025     */
6026    #[serde(
6027        default,
6028        skip_serializing_if = "String::is_empty",
6029        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6030    )]
6031    pub name: String,
6032
6033    /**
6034     * human-readable free-form text about a resource
6035     */
6036    #[serde(
6037        default,
6038        skip_serializing_if = "String::is_empty",
6039        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6040    )]
6041    pub description: String,
6042
6043    /**
6044     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
6045     */
6046    #[serde(
6047        default,
6048        skip_serializing_if = "String::is_empty",
6049        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6050    )]
6051    pub dns_name: String,
6052
6053    /**
6054     * An IPv6 subnet, including prefix and subnet mask
6055     */
6056    #[serde(
6057        default,
6058        skip_serializing_if = "String::is_empty",
6059        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6060    )]
6061    pub ipv6_prefix: String,
6062
6063    /**
6064     * id for the project containing this VPC
6065     */
6066    #[serde(
6067        default,
6068        skip_serializing_if = "String::is_empty",
6069        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6070    )]
6071    pub project_id: String,
6072
6073    /**
6074     * id for the system router where subnet default routes are registered
6075     */
6076    #[serde(
6077        default,
6078        skip_serializing_if = "String::is_empty",
6079        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6080    )]
6081    pub system_router_id: String,
6082
6083    /**
6084     * timestamp when this resource was created
6085     */
6086    #[serde()]
6087    pub time_created: crate::utils::DisplayOptionDateTime,
6088
6089    /**
6090     * timestamp when this resource was last modified
6091     */
6092    #[serde()]
6093    pub time_modified: crate::utils::DisplayOptionDateTime,
6094}
6095
6096/// Create-time parameters for a [`Vpc`](crate::external_api::views::Vpc)
6097#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
6098pub struct VpcCreate {
6099    /**
6100     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
6101     */
6102    #[serde(
6103        default,
6104        skip_serializing_if = "String::is_empty",
6105        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6106    )]
6107    pub name: String,
6108
6109    #[serde(
6110        default,
6111        skip_serializing_if = "String::is_empty",
6112        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6113    )]
6114    pub description: String,
6115
6116    /**
6117     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
6118     */
6119    #[serde(
6120        default,
6121        skip_serializing_if = "String::is_empty",
6122        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6123    )]
6124    pub dns_name: String,
6125
6126    /**
6127     * The IPv6 prefix for this VPC.
6128     *  
6129     *  All IPv6 subnets created from this VPC must be taken from this range, which sould be a Unique Local Address in the range `fd00::/48`. The default VPC Subnet will have the first `/64` range from this prefix.
6130     */
6131    #[serde(
6132        default,
6133        skip_serializing_if = "String::is_empty",
6134        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6135    )]
6136    pub ipv6_prefix: String,
6137}
6138
6139#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
6140#[serde(rename_all = "snake_case")]
6141pub enum VpcFirewallRuleAction {
6142    Allow,
6143    Deny,
6144    #[serde(rename = "")]
6145    Noop,
6146    #[serde(other)]
6147    FallthroughString,
6148}
6149
6150impl std::fmt::Display for VpcFirewallRuleAction {
6151    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6152        match &*self {
6153            VpcFirewallRuleAction::Allow => "allow",
6154            VpcFirewallRuleAction::Deny => "deny",
6155            VpcFirewallRuleAction::Noop => "",
6156            VpcFirewallRuleAction::FallthroughString => "*",
6157        }
6158        .fmt(f)
6159    }
6160}
6161
6162impl Default for VpcFirewallRuleAction {
6163    fn default() -> VpcFirewallRuleAction {
6164        VpcFirewallRuleAction::Allow
6165    }
6166}
6167impl std::str::FromStr for VpcFirewallRuleAction {
6168    type Err = anyhow::Error;
6169    fn from_str(s: &str) -> Result<Self, Self::Err> {
6170        if s == "allow" {
6171            return Ok(VpcFirewallRuleAction::Allow);
6172        }
6173        if s == "deny" {
6174            return Ok(VpcFirewallRuleAction::Deny);
6175        }
6176        anyhow::bail!("invalid string for VpcFirewallRuleAction: {}", s);
6177    }
6178}
6179impl VpcFirewallRuleAction {
6180    pub fn is_noop(&self) -> bool {
6181        matches!(self, VpcFirewallRuleAction::Noop)
6182    }
6183}
6184
6185#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
6186#[serde(rename_all = "snake_case")]
6187pub enum VpcFirewallRuleDirection {
6188    Inbound,
6189    Outbound,
6190    #[serde(rename = "")]
6191    Noop,
6192    #[serde(other)]
6193    FallthroughString,
6194}
6195
6196impl std::fmt::Display for VpcFirewallRuleDirection {
6197    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6198        match &*self {
6199            VpcFirewallRuleDirection::Inbound => "inbound",
6200            VpcFirewallRuleDirection::Outbound => "outbound",
6201            VpcFirewallRuleDirection::Noop => "",
6202            VpcFirewallRuleDirection::FallthroughString => "*",
6203        }
6204        .fmt(f)
6205    }
6206}
6207
6208impl Default for VpcFirewallRuleDirection {
6209    fn default() -> VpcFirewallRuleDirection {
6210        VpcFirewallRuleDirection::Inbound
6211    }
6212}
6213impl std::str::FromStr for VpcFirewallRuleDirection {
6214    type Err = anyhow::Error;
6215    fn from_str(s: &str) -> Result<Self, Self::Err> {
6216        if s == "inbound" {
6217            return Ok(VpcFirewallRuleDirection::Inbound);
6218        }
6219        if s == "outbound" {
6220            return Ok(VpcFirewallRuleDirection::Outbound);
6221        }
6222        anyhow::bail!("invalid string for VpcFirewallRuleDirection: {}", s);
6223    }
6224}
6225impl VpcFirewallRuleDirection {
6226    pub fn is_noop(&self) -> bool {
6227        matches!(self, VpcFirewallRuleDirection::Noop)
6228    }
6229}
6230
6231/// Filter for a firewall rule. A given packet must match every field that is present for the rule to apply to it. A packet matches a field if any entry in that field matches the packet.
6232#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default)]
6233pub struct VpcFirewallRuleFilter {
6234    /**
6235     * If present, the sources (if incoming) or destinations (if outgoing) this rule applies to.
6236     */
6237    #[serde(
6238        default,
6239        skip_serializing_if = "Vec::is_empty",
6240        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
6241    )]
6242    pub hosts: Vec<VpcFirewallRuleHostFilter>,
6243
6244    /**
6245     * If present, the destination ports this rule applies to.
6246     */
6247    #[serde(
6248        default,
6249        skip_serializing_if = "Vec::is_empty",
6250        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
6251    )]
6252    pub ports: Vec<String>,
6253
6254    /**
6255     * If present, the networking protocols this rule applies to.
6256     */
6257    #[serde(
6258        default,
6259        skip_serializing_if = "Vec::is_empty",
6260        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
6261    )]
6262    pub protocols: Vec<VpcFirewallRuleProtocol>,
6263}
6264
6265#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
6266#[serde(rename_all = "snake_case")]
6267pub enum VpcFirewallRuleStatus {
6268    Disabled,
6269    Enabled,
6270    #[serde(rename = "")]
6271    Noop,
6272    #[serde(other)]
6273    FallthroughString,
6274}
6275
6276impl std::fmt::Display for VpcFirewallRuleStatus {
6277    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6278        match &*self {
6279            VpcFirewallRuleStatus::Disabled => "disabled",
6280            VpcFirewallRuleStatus::Enabled => "enabled",
6281            VpcFirewallRuleStatus::Noop => "",
6282            VpcFirewallRuleStatus::FallthroughString => "*",
6283        }
6284        .fmt(f)
6285    }
6286}
6287
6288impl Default for VpcFirewallRuleStatus {
6289    fn default() -> VpcFirewallRuleStatus {
6290        VpcFirewallRuleStatus::Disabled
6291    }
6292}
6293impl std::str::FromStr for VpcFirewallRuleStatus {
6294    type Err = anyhow::Error;
6295    fn from_str(s: &str) -> Result<Self, Self::Err> {
6296        if s == "disabled" {
6297            return Ok(VpcFirewallRuleStatus::Disabled);
6298        }
6299        if s == "enabled" {
6300            return Ok(VpcFirewallRuleStatus::Enabled);
6301        }
6302        anyhow::bail!("invalid string for VpcFirewallRuleStatus: {}", s);
6303    }
6304}
6305impl VpcFirewallRuleStatus {
6306    pub fn is_noop(&self) -> bool {
6307        matches!(self, VpcFirewallRuleStatus::Noop)
6308    }
6309}
6310
6311#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
6312#[serde(rename_all = "snake_case")]
6313#[serde(tag = "type", content = "value")]
6314pub enum VpcFirewallRuleTarget {
6315    Vpc(String),
6316    Subnet(String),
6317    Instance(String),
6318    Ip(String),
6319    IpNet(IpNet),
6320}
6321
6322impl fmt::Display for VpcFirewallRuleTarget {
6323    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6324        let j = serde_json::json!(self);
6325        let mut tag: String = serde_json::from_value(j["type"].clone()).unwrap_or_default();
6326        let mut content: String = serde_json::from_value(j["value"].clone()).unwrap_or_default();
6327        if content.is_empty() {
6328            let map: std::collections::HashMap<String, String> =
6329                serde_json::from_value(j["value"].clone()).unwrap_or_default();
6330            if let Some((_, v)) = map.iter().next() {
6331                content = v.to_string();
6332            }
6333        }
6334        if tag == "internet_gateway" {
6335            tag = "inetgw".to_string();
6336        }
6337        write!(f, "{}={}", tag, content)
6338    }
6339}
6340
6341impl std::str::FromStr for VpcFirewallRuleTarget {
6342    type Err = anyhow::Error;
6343    fn from_str(s: &str) -> Result<Self, Self::Err> {
6344        let parts = s.split('=').collect::<Vec<&str>>();
6345        if parts.len() != 2 {
6346            anyhow::bail!("invalid format for VpcFirewallRuleTarget, got {}", s);
6347        }
6348        let tag = parts[0].to_string();
6349        let content = parts[1].to_string();
6350        let mut j = String::new();
6351        if tag == "vpc" {
6352            j = format!(
6353                r#"{{
6354"type": "vpc",
6355"value": "{}"
6356        }}"#,
6357                content
6358            );
6359        }
6360        if tag == "subnet" {
6361            j = format!(
6362                r#"{{
6363"type": "subnet",
6364"value": "{}"
6365        }}"#,
6366                content
6367            );
6368        }
6369        if tag == "instance" {
6370            j = format!(
6371                r#"{{
6372"type": "instance",
6373"value": "{}"
6374        }}"#,
6375                content
6376            );
6377        }
6378        if tag == "ip" {
6379            j = format!(
6380                r#"{{
6381"type": "ip",
6382"value": "{}"
6383        }}"#,
6384                content
6385            );
6386        }
6387        if tag == "ip_net" {
6388            j = format!(
6389                r#"{{
6390"type": "ip_net",
6391"value": {}
6392        }}"#,
6393                serde_json::json!(IpNet::from_str(&content).unwrap())
6394            );
6395        }
6396        let result = serde_json::from_str(&j)?;
6397        Ok(result)
6398    }
6399}
6400impl VpcFirewallRuleTarget {
6401    pub fn variants() -> Vec<String> {
6402        vec![
6403            "instance".to_string(),
6404            "ip".to_string(),
6405            "ip_net".to_string(),
6406            "subnet".to_string(),
6407            "vpc".to_string(),
6408        ]
6409    }
6410}
6411/**
6412 * The types for VpcFirewallRuleTarget.
6413 */
6414#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
6415#[serde(rename_all = "snake_case")]
6416pub enum VpcFirewallRuleTargetType {
6417    Instance,
6418    Ip,
6419    IpNet,
6420    Subnet,
6421    Vpc,
6422}
6423
6424impl std::fmt::Display for VpcFirewallRuleTargetType {
6425    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6426        match &*self {
6427            VpcFirewallRuleTargetType::Instance => "instance",
6428            VpcFirewallRuleTargetType::Ip => "ip",
6429            VpcFirewallRuleTargetType::IpNet => "ip_net",
6430            VpcFirewallRuleTargetType::Subnet => "subnet",
6431            VpcFirewallRuleTargetType::Vpc => "vpc",
6432        }
6433        .fmt(f)
6434    }
6435}
6436
6437impl Default for VpcFirewallRuleTargetType {
6438    fn default() -> VpcFirewallRuleTargetType {
6439        VpcFirewallRuleTargetType::Instance
6440    }
6441}
6442impl std::str::FromStr for VpcFirewallRuleTargetType {
6443    type Err = anyhow::Error;
6444    fn from_str(s: &str) -> Result<Self, Self::Err> {
6445        if s == "instance" {
6446            return Ok(VpcFirewallRuleTargetType::Instance);
6447        }
6448        if s == "ip" {
6449            return Ok(VpcFirewallRuleTargetType::Ip);
6450        }
6451        if s == "ip_net" {
6452            return Ok(VpcFirewallRuleTargetType::IpNet);
6453        }
6454        if s == "subnet" {
6455            return Ok(VpcFirewallRuleTargetType::Subnet);
6456        }
6457        if s == "vpc" {
6458            return Ok(VpcFirewallRuleTargetType::Vpc);
6459        }
6460        anyhow::bail!("invalid string for VpcFirewallRuleTargetType: {}", s);
6461    }
6462}
6463
6464/// A single rule in a VPC firewall
6465#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
6466pub struct VpcFirewallRule {
6467    /**
6468     * unique, immutable, system-controlled identifier for each resource
6469     */
6470    #[serde(
6471        default,
6472        skip_serializing_if = "String::is_empty",
6473        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6474    )]
6475    pub id: String,
6476
6477    /**
6478     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
6479     */
6480    #[serde(
6481        default,
6482        skip_serializing_if = "String::is_empty",
6483        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6484    )]
6485    pub name: String,
6486
6487    /**
6488     * human-readable free-form text about a resource
6489     */
6490    #[serde(
6491        default,
6492        skip_serializing_if = "String::is_empty",
6493        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6494    )]
6495    pub description: String,
6496
6497    #[serde(default, skip_serializing_if = "VpcFirewallRuleAction::is_noop")]
6498    pub action: VpcFirewallRuleAction,
6499
6500    #[serde(default, skip_serializing_if = "VpcFirewallRuleDirection::is_noop")]
6501    pub direction: VpcFirewallRuleDirection,
6502
6503    /**
6504     * Filter for a firewall rule. A given packet must match every field that is present for the rule to apply to it. A packet matches a field if any entry in that field matches the packet.
6505     */
6506    #[serde()]
6507    #[header(hidden = true)]
6508    pub filters: VpcFirewallRuleFilter,
6509
6510    /**
6511     * the relative priority of this rule
6512     */
6513    #[serde()]
6514    pub priority: u16,
6515
6516    #[serde(default, skip_serializing_if = "VpcFirewallRuleStatus::is_noop")]
6517    pub status: VpcFirewallRuleStatus,
6518
6519    /**
6520     * list of sets of instances that the rule applies to
6521     */
6522    #[serde(
6523        default,
6524        skip_serializing_if = "Vec::is_empty",
6525        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
6526    )]
6527    #[header(hidden = true)]
6528    pub targets: Vec<VpcFirewallRuleTarget>,
6529
6530    /**
6531     * timestamp when this resource was created
6532     */
6533    #[serde()]
6534    pub time_created: crate::utils::DisplayOptionDateTime,
6535
6536    /**
6537     * timestamp when this resource was last modified
6538     */
6539    #[serde()]
6540    pub time_modified: crate::utils::DisplayOptionDateTime,
6541
6542    /**
6543     * the VPC to which this rule belongs
6544     */
6545    #[serde(
6546        default,
6547        skip_serializing_if = "String::is_empty",
6548        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6549    )]
6550    pub vpc_id: String,
6551}
6552
6553#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema)]
6554#[serde(rename_all = "snake_case")]
6555#[serde(tag = "type", content = "value")]
6556pub enum VpcFirewallRuleHostFilter {
6557    Vpc(String),
6558    Subnet(String),
6559    Instance(String),
6560    Ip(String),
6561    IpNet(IpNet),
6562}
6563
6564impl fmt::Display for VpcFirewallRuleHostFilter {
6565    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
6566        let j = serde_json::json!(self);
6567        let mut tag: String = serde_json::from_value(j["type"].clone()).unwrap_or_default();
6568        let mut content: String = serde_json::from_value(j["value"].clone()).unwrap_or_default();
6569        if content.is_empty() {
6570            let map: std::collections::HashMap<String, String> =
6571                serde_json::from_value(j["value"].clone()).unwrap_or_default();
6572            if let Some((_, v)) = map.iter().next() {
6573                content = v.to_string();
6574            }
6575        }
6576        if tag == "internet_gateway" {
6577            tag = "inetgw".to_string();
6578        }
6579        write!(f, "{}={}", tag, content)
6580    }
6581}
6582
6583impl std::str::FromStr for VpcFirewallRuleHostFilter {
6584    type Err = anyhow::Error;
6585    fn from_str(s: &str) -> Result<Self, Self::Err> {
6586        let parts = s.split('=').collect::<Vec<&str>>();
6587        if parts.len() != 2 {
6588            anyhow::bail!("invalid format for VpcFirewallRuleHostFilter, got {}", s);
6589        }
6590        let tag = parts[0].to_string();
6591        let content = parts[1].to_string();
6592        let mut j = String::new();
6593        if tag == "vpc" {
6594            j = format!(
6595                r#"{{
6596"type": "vpc",
6597"value": "{}"
6598        }}"#,
6599                content
6600            );
6601        }
6602        if tag == "subnet" {
6603            j = format!(
6604                r#"{{
6605"type": "subnet",
6606"value": "{}"
6607        }}"#,
6608                content
6609            );
6610        }
6611        if tag == "instance" {
6612            j = format!(
6613                r#"{{
6614"type": "instance",
6615"value": "{}"
6616        }}"#,
6617                content
6618            );
6619        }
6620        if tag == "ip" {
6621            j = format!(
6622                r#"{{
6623"type": "ip",
6624"value": "{}"
6625        }}"#,
6626                content
6627            );
6628        }
6629        if tag == "ip_net" {
6630            j = format!(
6631                r#"{{
6632"type": "ip_net",
6633"value": {}
6634        }}"#,
6635                serde_json::json!(IpNet::from_str(&content).unwrap())
6636            );
6637        }
6638        let result = serde_json::from_str(&j)?;
6639        Ok(result)
6640    }
6641}
6642impl VpcFirewallRuleHostFilter {
6643    pub fn variants() -> Vec<String> {
6644        vec![
6645            "instance".to_string(),
6646            "ip".to_string(),
6647            "ip_net".to_string(),
6648            "subnet".to_string(),
6649            "vpc".to_string(),
6650        ]
6651    }
6652}
6653/**
6654 * The types for VpcFirewallRuleHostFilter.
6655 */
6656#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
6657#[serde(rename_all = "snake_case")]
6658pub enum VpcFirewallRuleHostFilterType {
6659    Instance,
6660    Ip,
6661    IpNet,
6662    Subnet,
6663    Vpc,
6664}
6665
6666impl std::fmt::Display for VpcFirewallRuleHostFilterType {
6667    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6668        match &*self {
6669            VpcFirewallRuleHostFilterType::Instance => "instance",
6670            VpcFirewallRuleHostFilterType::Ip => "ip",
6671            VpcFirewallRuleHostFilterType::IpNet => "ip_net",
6672            VpcFirewallRuleHostFilterType::Subnet => "subnet",
6673            VpcFirewallRuleHostFilterType::Vpc => "vpc",
6674        }
6675        .fmt(f)
6676    }
6677}
6678
6679impl Default for VpcFirewallRuleHostFilterType {
6680    fn default() -> VpcFirewallRuleHostFilterType {
6681        VpcFirewallRuleHostFilterType::Instance
6682    }
6683}
6684impl std::str::FromStr for VpcFirewallRuleHostFilterType {
6685    type Err = anyhow::Error;
6686    fn from_str(s: &str) -> Result<Self, Self::Err> {
6687        if s == "instance" {
6688            return Ok(VpcFirewallRuleHostFilterType::Instance);
6689        }
6690        if s == "ip" {
6691            return Ok(VpcFirewallRuleHostFilterType::Ip);
6692        }
6693        if s == "ip_net" {
6694            return Ok(VpcFirewallRuleHostFilterType::IpNet);
6695        }
6696        if s == "subnet" {
6697            return Ok(VpcFirewallRuleHostFilterType::Subnet);
6698        }
6699        if s == "vpc" {
6700            return Ok(VpcFirewallRuleHostFilterType::Vpc);
6701        }
6702        anyhow::bail!("invalid string for VpcFirewallRuleHostFilterType: {}", s);
6703    }
6704}
6705
6706/**
6707 * The protocols that may be specified in a firewall rule's filter
6708 */
6709#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
6710#[serde(rename_all = "snake_case")]
6711pub enum VpcFirewallRuleProtocol {
6712    Icmp,
6713    Tcp,
6714    Udp,
6715    #[serde(rename = "")]
6716    Noop,
6717    #[serde(other)]
6718    FallthroughString,
6719}
6720
6721impl std::fmt::Display for VpcFirewallRuleProtocol {
6722    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6723        match &*self {
6724            VpcFirewallRuleProtocol::Icmp => "icmp",
6725            VpcFirewallRuleProtocol::Tcp => "tcp",
6726            VpcFirewallRuleProtocol::Udp => "udp",
6727            VpcFirewallRuleProtocol::Noop => "",
6728            VpcFirewallRuleProtocol::FallthroughString => "*",
6729        }
6730        .fmt(f)
6731    }
6732}
6733
6734impl Default for VpcFirewallRuleProtocol {
6735    fn default() -> VpcFirewallRuleProtocol {
6736        VpcFirewallRuleProtocol::Icmp
6737    }
6738}
6739impl std::str::FromStr for VpcFirewallRuleProtocol {
6740    type Err = anyhow::Error;
6741    fn from_str(s: &str) -> Result<Self, Self::Err> {
6742        if s == "icmp" {
6743            return Ok(VpcFirewallRuleProtocol::Icmp);
6744        }
6745        if s == "tcp" {
6746            return Ok(VpcFirewallRuleProtocol::Tcp);
6747        }
6748        if s == "udp" {
6749            return Ok(VpcFirewallRuleProtocol::Udp);
6750        }
6751        anyhow::bail!("invalid string for VpcFirewallRuleProtocol: {}", s);
6752    }
6753}
6754impl VpcFirewallRuleProtocol {
6755    pub fn is_noop(&self) -> bool {
6756        matches!(self, VpcFirewallRuleProtocol::Noop)
6757    }
6758}
6759
6760/// A single rule in a VPC firewall
6761#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
6762pub struct VpcFirewallRuleUpdate {
6763    /**
6764     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
6765     */
6766    #[serde(
6767        default,
6768        skip_serializing_if = "String::is_empty",
6769        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6770    )]
6771    pub name: String,
6772
6773    /**
6774     * human-readable free-form text about a resource
6775     */
6776    #[serde(
6777        default,
6778        skip_serializing_if = "String::is_empty",
6779        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6780    )]
6781    pub description: String,
6782
6783    #[serde(default, skip_serializing_if = "VpcFirewallRuleAction::is_noop")]
6784    pub action: VpcFirewallRuleAction,
6785
6786    #[serde(default, skip_serializing_if = "VpcFirewallRuleDirection::is_noop")]
6787    pub direction: VpcFirewallRuleDirection,
6788
6789    /**
6790     * Filter for a firewall rule. A given packet must match every field that is present for the rule to apply to it. A packet matches a field if any entry in that field matches the packet.
6791     */
6792    #[serde()]
6793    #[header(hidden = true)]
6794    pub filters: VpcFirewallRuleFilter,
6795
6796    /**
6797     * the relative priority of this rule
6798     */
6799    #[serde()]
6800    pub priority: u16,
6801
6802    #[serde(default, skip_serializing_if = "VpcFirewallRuleStatus::is_noop")]
6803    pub status: VpcFirewallRuleStatus,
6804
6805    /**
6806     * list of sets of instances that the rule applies to
6807     */
6808    #[serde(
6809        default,
6810        skip_serializing_if = "Vec::is_empty",
6811        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
6812    )]
6813    #[header(hidden = true)]
6814    pub targets: Vec<VpcFirewallRuleTarget>,
6815}
6816
6817/// Updateable properties of a `Vpc`'s firewall Note that VpcFirewallRules are implicitly created along with a Vpc, so there is no explicit creation.
6818#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
6819pub struct VpcFirewallRuleUpdateParams {
6820    #[serde(
6821        default,
6822        skip_serializing_if = "Vec::is_empty",
6823        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
6824    )]
6825    #[header(hidden = true)]
6826    pub rules: Vec<VpcFirewallRuleUpdate>,
6827}
6828
6829/// Collection of a Vpc's firewall rules
6830#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
6831pub struct VpcFirewallRules {
6832    #[serde(
6833        default,
6834        skip_serializing_if = "Vec::is_empty",
6835        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
6836    )]
6837    #[header(hidden = true)]
6838    pub rules: Vec<VpcFirewallRule>,
6839}
6840
6841/// A single page of results
6842#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
6843pub struct VpcResultsPage {
6844    /**
6845     * list of items on this page of results
6846     */
6847    #[serde(
6848        default,
6849        skip_serializing_if = "Vec::is_empty",
6850        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
6851    )]
6852    #[header(hidden = true)]
6853    pub items: Vec<Vpc>,
6854
6855    /**
6856     * token used to fetch the next page of results (if any)
6857     */
6858    #[serde(
6859        default,
6860        skip_serializing_if = "String::is_empty",
6861        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6862    )]
6863    pub next_page: String,
6864}
6865
6866#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
6867#[serde(rename_all = "snake_case")]
6868pub enum VpcRouterKind {
6869    Custom,
6870    System,
6871    #[serde(rename = "")]
6872    Noop,
6873    #[serde(other)]
6874    FallthroughString,
6875}
6876
6877impl std::fmt::Display for VpcRouterKind {
6878    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6879        match &*self {
6880            VpcRouterKind::Custom => "custom",
6881            VpcRouterKind::System => "system",
6882            VpcRouterKind::Noop => "",
6883            VpcRouterKind::FallthroughString => "*",
6884        }
6885        .fmt(f)
6886    }
6887}
6888
6889impl Default for VpcRouterKind {
6890    fn default() -> VpcRouterKind {
6891        VpcRouterKind::Custom
6892    }
6893}
6894impl std::str::FromStr for VpcRouterKind {
6895    type Err = anyhow::Error;
6896    fn from_str(s: &str) -> Result<Self, Self::Err> {
6897        if s == "custom" {
6898            return Ok(VpcRouterKind::Custom);
6899        }
6900        if s == "system" {
6901            return Ok(VpcRouterKind::System);
6902        }
6903        anyhow::bail!("invalid string for VpcRouterKind: {}", s);
6904    }
6905}
6906impl VpcRouterKind {
6907    pub fn is_noop(&self) -> bool {
6908        matches!(self, VpcRouterKind::Noop)
6909    }
6910}
6911
6912/// A VPC router defines a series of rules that indicate where traffic should be sent depending on its destination.
6913#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
6914pub struct VpcRouter {
6915    /**
6916     * unique, immutable, system-controlled identifier for each resource
6917     */
6918    #[serde(
6919        default,
6920        skip_serializing_if = "String::is_empty",
6921        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6922    )]
6923    pub id: String,
6924
6925    /**
6926     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
6927     */
6928    #[serde(
6929        default,
6930        skip_serializing_if = "String::is_empty",
6931        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6932    )]
6933    pub name: String,
6934
6935    /**
6936     * human-readable free-form text about a resource
6937     */
6938    #[serde(
6939        default,
6940        skip_serializing_if = "String::is_empty",
6941        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6942    )]
6943    pub description: String,
6944
6945    #[serde(default, skip_serializing_if = "VpcRouterKind::is_noop")]
6946    pub kind: VpcRouterKind,
6947
6948    /**
6949     * timestamp when this resource was created
6950     */
6951    #[serde()]
6952    pub time_created: crate::utils::DisplayOptionDateTime,
6953
6954    /**
6955     * timestamp when this resource was last modified
6956     */
6957    #[serde()]
6958    pub time_modified: crate::utils::DisplayOptionDateTime,
6959
6960    /**
6961     * The VPC to which the router belongs.
6962     */
6963    #[serde(
6964        default,
6965        skip_serializing_if = "String::is_empty",
6966        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6967    )]
6968    pub vpc_id: String,
6969}
6970
6971/// Create-time parameters for a [`VpcRouter`](crate::external_api::views::VpcRouter)
6972#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
6973pub struct VpcRouterCreate {
6974    /**
6975     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
6976     */
6977    #[serde(
6978        default,
6979        skip_serializing_if = "String::is_empty",
6980        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6981    )]
6982    pub name: String,
6983
6984    #[serde(
6985        default,
6986        skip_serializing_if = "String::is_empty",
6987        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
6988    )]
6989    pub description: String,
6990}
6991
6992/// A single page of results
6993#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
6994pub struct VpcRouterResultsPage {
6995    /**
6996     * list of items on this page of results
6997     */
6998    #[serde(
6999        default,
7000        skip_serializing_if = "Vec::is_empty",
7001        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
7002    )]
7003    #[header(hidden = true)]
7004    pub items: Vec<VpcRouter>,
7005
7006    /**
7007     * token used to fetch the next page of results (if any)
7008     */
7009    #[serde(
7010        default,
7011        skip_serializing_if = "String::is_empty",
7012        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7013    )]
7014    pub next_page: String,
7015}
7016
7017/// Updateable properties of a [`VpcRouter`](crate::external_api::views::VpcRouter)
7018#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
7019pub struct VpcRouterUpdate {
7020    #[serde(
7021        default,
7022        skip_serializing_if = "String::is_empty",
7023        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7024    )]
7025    pub name: String,
7026
7027    #[serde(
7028        default,
7029        skip_serializing_if = "String::is_empty",
7030        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7031    )]
7032    pub description: String,
7033}
7034
7035/// A VPC subnet represents a logical grouping for instances that allows network traffic between them, within a IPv4 subnetwork or optionall an IPv6 subnetwork.
7036#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
7037pub struct VpcSubnet {
7038    /**
7039     * unique, immutable, system-controlled identifier for each resource
7040     */
7041    #[serde(
7042        default,
7043        skip_serializing_if = "String::is_empty",
7044        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7045    )]
7046    pub id: String,
7047
7048    /**
7049     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
7050     */
7051    #[serde(
7052        default,
7053        skip_serializing_if = "String::is_empty",
7054        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7055    )]
7056    pub name: String,
7057
7058    /**
7059     * human-readable free-form text about a resource
7060     */
7061    #[serde(
7062        default,
7063        skip_serializing_if = "String::is_empty",
7064        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7065    )]
7066    pub description: String,
7067
7068    /**
7069     * An IPv4 subnet, including prefix and subnet mask
7070     */
7071    #[serde(
7072        default,
7073        skip_serializing_if = "String::is_empty",
7074        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7075    )]
7076    pub ipv4_block: String,
7077
7078    /**
7079     * An IPv6 subnet, including prefix and subnet mask
7080     */
7081    #[serde(
7082        default,
7083        skip_serializing_if = "String::is_empty",
7084        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7085    )]
7086    pub ipv6_block: String,
7087
7088    /**
7089     * timestamp when this resource was created
7090     */
7091    #[serde()]
7092    pub time_created: crate::utils::DisplayOptionDateTime,
7093
7094    /**
7095     * timestamp when this resource was last modified
7096     */
7097    #[serde()]
7098    pub time_modified: crate::utils::DisplayOptionDateTime,
7099
7100    /**
7101     * The VPC to which the subnet belongs.
7102     */
7103    #[serde(
7104        default,
7105        skip_serializing_if = "String::is_empty",
7106        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7107    )]
7108    pub vpc_id: String,
7109}
7110
7111/// Create-time parameters for a [`VpcSubnet`](crate::external_api::views::VpcSubnet)
7112#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
7113pub struct VpcSubnetCreate {
7114    /**
7115     * Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
7116     */
7117    #[serde(
7118        default,
7119        skip_serializing_if = "String::is_empty",
7120        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7121    )]
7122    pub name: String,
7123
7124    #[serde(
7125        default,
7126        skip_serializing_if = "String::is_empty",
7127        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7128    )]
7129    pub description: String,
7130
7131    /**
7132     * An IPv4 subnet, including prefix and subnet mask
7133     */
7134    #[serde(
7135        default,
7136        skip_serializing_if = "String::is_empty",
7137        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7138    )]
7139    pub ipv4_block: String,
7140
7141    /**
7142     * The IPv6 address range for this subnet.
7143     *  
7144     *  It must be allocated from the RFC 4193 Unique Local Address range, with the prefix equal to the parent VPC's prefix. A random `/64` block will be assigned if one is not provided. It must not overlap with any existing subnet in the VPC.
7145     */
7146    #[serde(
7147        default,
7148        skip_serializing_if = "String::is_empty",
7149        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7150    )]
7151    pub ipv6_block: String,
7152}
7153
7154/// A single page of results
7155#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
7156pub struct VpcSubnetResultsPage {
7157    /**
7158     * list of items on this page of results
7159     */
7160    #[serde(
7161        default,
7162        skip_serializing_if = "Vec::is_empty",
7163        deserialize_with = "crate::utils::deserialize_null_vector::deserialize"
7164    )]
7165    #[header(hidden = true)]
7166    pub items: Vec<VpcSubnet>,
7167
7168    /**
7169     * token used to fetch the next page of results (if any)
7170     */
7171    #[serde(
7172        default,
7173        skip_serializing_if = "String::is_empty",
7174        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7175    )]
7176    pub next_page: String,
7177}
7178
7179/// Updateable properties of a [`VpcSubnet`](crate::external_api::views::VpcSubnet)
7180#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
7181pub struct VpcSubnetUpdate {
7182    #[serde(
7183        default,
7184        skip_serializing_if = "String::is_empty",
7185        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7186    )]
7187    pub name: String,
7188
7189    #[serde(
7190        default,
7191        skip_serializing_if = "String::is_empty",
7192        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7193    )]
7194    pub description: String,
7195}
7196
7197/// Updateable properties of a [`Vpc`](crate::external_api::views::Vpc)
7198#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Default, Tabled)]
7199pub struct VpcUpdate {
7200    #[serde(
7201        default,
7202        skip_serializing_if = "String::is_empty",
7203        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7204    )]
7205    pub name: String,
7206
7207    #[serde(
7208        default,
7209        skip_serializing_if = "String::is_empty",
7210        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7211    )]
7212    pub description: String,
7213
7214    #[serde(
7215        default,
7216        skip_serializing_if = "String::is_empty",
7217        deserialize_with = "crate::utils::deserialize_null_string::deserialize"
7218    )]
7219    pub dns_name: String,
7220}
7221
7222/**
7223 * Supported set of sort modes for scanning by id only.
7224 *   
7225 *   Currently, we only support scanning in ascending order.
7226 */
7227#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
7228#[serde(rename_all = "snake_case")]
7229pub enum IdSortMode {
7230    IdAscending,
7231    #[serde(rename = "")]
7232    Noop,
7233    #[serde(other)]
7234    FallthroughString,
7235}
7236
7237impl std::fmt::Display for IdSortMode {
7238    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7239        match &*self {
7240            IdSortMode::IdAscending => "id_ascending",
7241            IdSortMode::Noop => "",
7242            IdSortMode::FallthroughString => "*",
7243        }
7244        .fmt(f)
7245    }
7246}
7247
7248impl Default for IdSortMode {
7249    fn default() -> IdSortMode {
7250        IdSortMode::IdAscending
7251    }
7252}
7253impl std::str::FromStr for IdSortMode {
7254    type Err = anyhow::Error;
7255    fn from_str(s: &str) -> Result<Self, Self::Err> {
7256        if s == "id_ascending" {
7257            return Ok(IdSortMode::IdAscending);
7258        }
7259        anyhow::bail!("invalid string for IdSortMode: {}", s);
7260    }
7261}
7262impl IdSortMode {
7263    pub fn is_noop(&self) -> bool {
7264        matches!(self, IdSortMode::Noop)
7265    }
7266}
7267
7268/**
7269 * Supported set of sort modes for scanning by name only
7270 *   
7271 *   Currently, we only support scanning in ascending order.
7272 */
7273#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
7274#[serde(rename_all = "snake_case")]
7275pub enum NameSortMode {
7276    NameAscending,
7277    #[serde(rename = "")]
7278    Noop,
7279    #[serde(other)]
7280    FallthroughString,
7281}
7282
7283impl std::fmt::Display for NameSortMode {
7284    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7285        match &*self {
7286            NameSortMode::NameAscending => "name_ascending",
7287            NameSortMode::Noop => "",
7288            NameSortMode::FallthroughString => "*",
7289        }
7290        .fmt(f)
7291    }
7292}
7293
7294impl Default for NameSortMode {
7295    fn default() -> NameSortMode {
7296        NameSortMode::NameAscending
7297    }
7298}
7299impl std::str::FromStr for NameSortMode {
7300    type Err = anyhow::Error;
7301    fn from_str(s: &str) -> Result<Self, Self::Err> {
7302        if s == "name_ascending" {
7303            return Ok(NameSortMode::NameAscending);
7304        }
7305        anyhow::bail!("invalid string for NameSortMode: {}", s);
7306    }
7307}
7308impl NameSortMode {
7309    pub fn is_noop(&self) -> bool {
7310        matches!(self, NameSortMode::Noop)
7311    }
7312}
7313
7314/**
7315 * Supported set of sort modes for scanning by name or id
7316 */
7317#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
7318#[serde(rename_all = "snake_case")]
7319pub enum NameOrIdSortMode {
7320    IdAscending,
7321    NameAscending,
7322    NameDescending,
7323    #[serde(rename = "")]
7324    Noop,
7325    #[serde(other)]
7326    FallthroughString,
7327}
7328
7329impl std::fmt::Display for NameOrIdSortMode {
7330    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7331        match &*self {
7332            NameOrIdSortMode::IdAscending => "id_ascending",
7333            NameOrIdSortMode::NameAscending => "name_ascending",
7334            NameOrIdSortMode::NameDescending => "name_descending",
7335            NameOrIdSortMode::Noop => "",
7336            NameOrIdSortMode::FallthroughString => "*",
7337        }
7338        .fmt(f)
7339    }
7340}
7341
7342impl Default for NameOrIdSortMode {
7343    fn default() -> NameOrIdSortMode {
7344        NameOrIdSortMode::IdAscending
7345    }
7346}
7347impl std::str::FromStr for NameOrIdSortMode {
7348    type Err = anyhow::Error;
7349    fn from_str(s: &str) -> Result<Self, Self::Err> {
7350        if s == "id_ascending" {
7351            return Ok(NameOrIdSortMode::IdAscending);
7352        }
7353        if s == "name_ascending" {
7354            return Ok(NameOrIdSortMode::NameAscending);
7355        }
7356        if s == "name_descending" {
7357            return Ok(NameOrIdSortMode::NameDescending);
7358        }
7359        anyhow::bail!("invalid string for NameOrIdSortMode: {}", s);
7360    }
7361}
7362impl NameOrIdSortMode {
7363    pub fn is_noop(&self) -> bool {
7364        matches!(self, NameOrIdSortMode::Noop)
7365    }
7366}
7367
7368#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, JsonSchema, Tabled)]
7369#[serde(rename_all = "snake_case")]
7370pub enum DiskMetricName {
7371    Activated,
7372    Flush,
7373    Read,
7374    ReadBytes,
7375    Write,
7376    WriteBytes,
7377    #[serde(rename = "")]
7378    Noop,
7379    #[serde(other)]
7380    FallthroughString,
7381}
7382
7383impl std::fmt::Display for DiskMetricName {
7384    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
7385        match &*self {
7386            DiskMetricName::Activated => "activated",
7387            DiskMetricName::Flush => "flush",
7388            DiskMetricName::Read => "read",
7389            DiskMetricName::ReadBytes => "read_bytes",
7390            DiskMetricName::Write => "write",
7391            DiskMetricName::WriteBytes => "write_bytes",
7392            DiskMetricName::Noop => "",
7393            DiskMetricName::FallthroughString => "*",
7394        }
7395        .fmt(f)
7396    }
7397}
7398
7399impl Default for DiskMetricName {
7400    fn default() -> DiskMetricName {
7401        DiskMetricName::Activated
7402    }
7403}
7404impl std::str::FromStr for DiskMetricName {
7405    type Err = anyhow::Error;
7406    fn from_str(s: &str) -> Result<Self, Self::Err> {
7407        if s == "activated" {
7408            return Ok(DiskMetricName::Activated);
7409        }
7410        if s == "flush" {
7411            return Ok(DiskMetricName::Flush);
7412        }
7413        if s == "read" {
7414            return Ok(DiskMetricName::Read);
7415        }
7416        if s == "read_bytes" {
7417            return Ok(DiskMetricName::ReadBytes);
7418        }
7419        if s == "write" {
7420            return Ok(DiskMetricName::Write);
7421        }
7422        if s == "write_bytes" {
7423            return Ok(DiskMetricName::WriteBytes);
7424        }
7425        anyhow::bail!("invalid string for DiskMetricName: {}", s);
7426    }
7427}
7428impl DiskMetricName {
7429    pub fn is_noop(&self) -> bool {
7430        matches!(self, DiskMetricName::Noop)
7431    }
7432}
7433
7434pub type BlockSize = i64;
7435/// A count of bytes, typically used either for memory or storage capacity
7436///
7437/// The maximum supported byte count is [`i64::MAX`].  This makes it somewhat inconvenient to define constructors: a u32 constructor can be infallible, but an i64 constructor can fail (if the value is negative) and a u64 constructor can fail (if the value is larger than i64::MAX).  We provide all of these for consumers' convenience.
7438pub type ByteCount = u64;
7439/// The number of CPUs in an Instance
7440pub type InstanceCpuCount = u16;
7441/// An inclusive-inclusive range of IP ports. The second port may be omitted to represent a single port
7442pub type L4PortRange = String;
7443/// A Media Access Control address, in EUI-48 format
7444pub type MacAddr = String;
7445/// Names must begin with a lower case ASCII letter, be composed exclusively of lowercase ASCII, uppercase ASCII, numbers, and '-', and may not end with a '-'. Names cannot be a UUID though they may contain a UUID.
7446pub type Name = String;
7447/// Unique name for a saga [`Node`]
7448///
7449/// Each node requires a string name that's unique within its DAG.  The name is used to identify its output.  Nodes that depend on a given node (either directly or indirectly) can access the node's output using its name.
7450pub type NodeName = String;
7451/// Role names consist of two string components separated by dot (".").
7452pub type RoleName = String;
7453/// Names are constructed by concatenating the target and metric names with ':'. Target and metric names must be lowercase alphanumeric characters with '_' separating words.
7454pub type TimeseriesName = String;