statehub_api/v0/state/
impls.rs

1//
2// Copyright (c) 2021 RepliXio Ltd. All rights reserved.
3// Use is subject to license terms.
4//
5
6use std::cmp;
7use std::iter;
8
9use super::*;
10
11impl fmt::Display for State {
12    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13        if f.alternate() {
14            f.debug_struct("State")
15                .field("name", &self.name.0)
16                .field("aws", &self.locations.aws)
17                .field("azure", &self.locations.azure)
18                .finish()
19        } else {
20            self.name.fmt(f)
21        }
22    }
23}
24
25impl From<String> for StateName {
26    fn from(name: String) -> Self {
27        Self(name)
28    }
29}
30
31impl From<&str> for StateName {
32    fn from(text: &str) -> Self {
33        text.to_string().into()
34    }
35}
36
37impl fmt::Display for StateName {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        self.0.fmt(f)
40    }
41}
42
43impl str::FromStr for StateName {
44    type Err = Infallible;
45
46    fn from_str(text: &str) -> Result<Self, Self::Err> {
47        Ok(text.into())
48    }
49}
50
51impl AsRef<str> for StateName {
52    fn as_ref(&self) -> &str {
53        self.0.as_ref()
54    }
55}
56
57impl ops::Deref for StateName {
58    type Target = str;
59
60    fn deref(&self) -> &Self::Target {
61        self.0.deref()
62    }
63}
64
65impl PartialEq<&str> for StateName {
66    fn eq(&self, other: &&str) -> bool {
67        self.0.eq(other)
68    }
69}
70
71impl State {
72    pub fn is_available_in(&self, location: &Location) -> bool {
73        self.locations.contains(location)
74    }
75
76    pub fn is_ready(&self) -> bool {
77        self.condition == Condition::Green
78    }
79
80    pub fn all_locations(&self) -> Vec<Location> {
81        let aws = self.locations.aws.iter().map(|aws| aws.region.into());
82        let azure = self.locations.azure.iter().map(|azure| azure.region.into());
83        aws.chain(azure).collect()
84    }
85
86    pub fn collect_volumes(&self) -> HashMap<String, HashMap<Location, &VolumeLocation>> {
87        let aws = self.locations.aws.iter().flat_map(|location| {
88            location
89                .volumes
90                .iter()
91                .map(move |volume| (volume, location.region.into()))
92        });
93        let azure = self.locations.azure.iter().flat_map(|location| {
94            location
95                .volumes
96                .iter()
97                .map(move |volume| (volume, location.region.into()))
98        });
99
100        let mut volumes = HashMap::<_, HashMap<_, _>>::new();
101        for (volume, location) in aws.chain(azure) {
102            volumes
103                .entry(volume.name.clone())
104                .or_default()
105                .insert(location, volume);
106        }
107        volumes
108    }
109
110    pub fn count_volumes(&self) -> usize {
111        let aws = self
112            .locations
113            .aws
114            .iter()
115            .map(|aws| aws.volumes.len())
116            .max()
117            .unwrap_or_default();
118        let azure = self
119            .locations
120            .azure
121            .iter()
122            .map(|azure| azure.volumes.len())
123            .max()
124            .unwrap_or_default();
125        cmp::max(aws, azure)
126    }
127}
128
129impl StateLocationStatus {
130    pub fn as_str(&self) -> &'static str {
131        match self {
132            Self::Ok => "ok",
133            Self::Provisioning => "provisioning",
134            Self::Recovering => "recovering",
135            Self::Deleting => "deleting",
136            Self::Error => "error",
137        }
138    }
139
140    pub fn is_deleting(&self) -> bool {
141        *self == Self::Deleting
142    }
143
144    pub fn is_final(&self) -> bool {
145        match self {
146            Self::Ok => true,
147            Self::Provisioning => false,
148            Self::Recovering => false,
149            Self::Deleting => false,
150            Self::Error => true,
151        }
152    }
153}
154
155impl Default for VolumeBindingMode {
156    fn default() -> Self {
157        Self::WaitForFirstConsumer
158    }
159}
160
161impl From<AwsRegion> for CreateStateLocationAwsDto {
162    fn from(region: AwsRegion) -> Self {
163        Self { region }
164    }
165}
166
167impl From<AzureRegion> for CreateStateLocationAzureDto {
168    fn from(region: AzureRegion) -> Self {
169        Self { region }
170    }
171}
172
173impl iter::FromIterator<Location> for CreateStateLocationsDto {
174    fn from_iter<T>(iter: T) -> Self
175    where
176        T: IntoIterator<Item = Location>,
177    {
178        iter.into_iter().fold(Self::default(), |mut dto, location| {
179            match location {
180                Location::Aws(region) => dto.aws.push(region.into()),
181                Location::Azure(region) => dto.azure.push(region.into()),
182                // Location::Gcp(region) => dto.gcp.push(region),
183            }
184            dto
185        })
186    }
187}
188
189impl StateLocations {
190    pub fn contains(&self, location: &Location) -> bool {
191        match location {
192            Location::Aws(region) => self.aws.iter().any(|aws| aws.region == *region),
193            Location::Azure(region) => self.azure.iter().any(|azure| azure.region == *region),
194        }
195    }
196}
197
198impl Default for Condition {
199    fn default() -> Self {
200        Self::Green
201    }
202}
203
204impl Default for ProvisioningStatus {
205    fn default() -> Self {
206        Self::Ready
207    }
208}
209
210impl StorageClass {
211    pub fn new_if_not_default(
212        state: &str,
213        storage_class: Option<String>,
214        fs_type: Option<VolumeFileSystem>,
215    ) -> Option<Self> {
216        if storage_class.is_none() && fs_type.is_none() {
217            return None;
218        }
219
220        let name = storage_class.unwrap_or_else(|| state.to_string());
221        let fs_type = fs_type.unwrap_or_default().to_string();
222
223        let storage_class = Self {
224            name,
225            fs_type,
226            ..Self::default()
227        };
228
229        Some(storage_class)
230    }
231}