oct_cloud/aws/
types.rs

1use aws_sdk_route53::types::RrType;
2use serde::{Deserialize, Serialize};
3use std::fmt;
4
5/// Represents an AWS resource record type.
6#[derive(Debug, Clone, PartialEq, Eq, Copy, Serialize, Deserialize)]
7pub enum RecordType {
8    A,
9    NS,
10    SOA,
11    TXT,
12}
13
14impl From<&str> for RecordType {
15    fn from(s: &str) -> Self {
16        match s {
17            "A" => Self::A,
18            "NS" => Self::NS,
19            "SOA" => Self::SOA,
20            "TXT" => Self::TXT,
21            _ => panic!("Invalid record type: {s}"),
22        }
23    }
24}
25
26impl From<RrType> for RecordType {
27    fn from(rr_type: RrType) -> Self {
28        match rr_type {
29            RrType::A => Self::A,
30            RrType::Ns => Self::NS,
31            RrType::Soa => Self::SOA,
32            RrType::Txt => Self::TXT,
33            _ => panic!("Invalid record type: {rr_type}"),
34        }
35    }
36}
37
38impl From<RecordType> for RrType {
39    fn from(value: RecordType) -> Self {
40        match value {
41            RecordType::A => Self::A,
42            RecordType::NS => Self::Ns,
43            RecordType::SOA => Self::Soa,
44            RecordType::TXT => Self::Txt,
45        }
46    }
47}
48
49impl RecordType {
50    pub fn as_str(&self) -> &str {
51        match self {
52            RecordType::A => "A",
53            RecordType::NS => "NS",
54            RecordType::SOA => "SOA",
55            RecordType::TXT => "TXT",
56        }
57    }
58}
59
60impl fmt::Display for RecordType {
61    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62        f.write_str(self.as_str())
63    }
64}
65
66/// Represents an AWS instance type.
67#[derive(Debug, PartialEq, Eq)]
68pub struct InstanceInfo {
69    /// The number of CPUs for the instance type.
70    pub cpus: u32,
71    /// The amount of memory (in MB) for the instance type.
72    pub memory: u64,
73}
74
75#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
76pub enum InstanceType {
77    T3Nano,
78    T3Micro,
79    T3Small,
80    T3Medium,
81    T3Large,
82    T3Xlarge,
83    T32xlarge,
84}
85
86impl InstanceType {
87    pub fn as_str(&self) -> &str {
88        match self {
89            InstanceType::T3Nano => "t3.nano",
90            InstanceType::T3Micro => "t3.micro",
91            InstanceType::T3Small => "t3.small",
92            InstanceType::T3Medium => "t3.medium",
93            InstanceType::T3Large => "t3.large",
94            InstanceType::T3Xlarge => "t3.xlarge",
95            InstanceType::T32xlarge => "t3.2xlarge",
96        }
97    }
98
99    /// Tries to get the smallest possible instance type for to fit requested resources
100    // NOTE: The instances list must be sorted by size from smallest to largest
101    pub fn from_resources(cpus: u32, memory: u64) -> Option<Self> {
102        let instances = [
103            Self::T3Nano,
104            Self::T3Micro,
105            Self::T3Small,
106            Self::T3Medium,
107            Self::T3Large,
108            Self::T3Xlarge,
109            Self::T32xlarge,
110        ];
111
112        for instance in instances {
113            let info = instance.get_info();
114            if cpus <= info.cpus && memory <= info.memory {
115                return Some(instance);
116            }
117        }
118
119        None
120    }
121
122    pub fn get_info(&self) -> InstanceInfo {
123        match self {
124            Self::T3Nano => InstanceInfo {
125                cpus: 2000,
126                memory: 512,
127            },
128            Self::T3Micro => InstanceInfo {
129                cpus: 2000,
130                memory: 1024,
131            },
132            Self::T3Small => InstanceInfo {
133                cpus: 2000,
134                memory: 2048,
135            },
136            Self::T3Medium => InstanceInfo {
137                cpus: 2000,
138                memory: 4096,
139            },
140            Self::T3Large => InstanceInfo {
141                cpus: 2000,
142                memory: 8192,
143            },
144            Self::T3Xlarge => InstanceInfo {
145                cpus: 4000,
146                memory: 16384,
147            },
148            Self::T32xlarge => InstanceInfo {
149                cpus: 8000,
150                memory: 32768,
151            },
152        }
153    }
154}
155
156impl From<&str> for InstanceType {
157    /// Creates an `InstanceType` from a string.
158    ///
159    /// # Panics
160    ///
161    /// Panics if the string is not a valid instance type.
162    fn from(value: &str) -> Self {
163        match value {
164            "t3.nano" => Self::T3Nano,
165            "t3.micro" => Self::T3Micro,
166            "t3.small" => Self::T3Small,
167            "t3.medium" => Self::T3Medium,
168            "t3.large" => Self::T3Large,
169            "t3.xlarge" => Self::T3Xlarge,
170            "t3.2xlarge" => Self::T32xlarge,
171            _ => panic!("Invalid instance type: {value}"),
172        }
173    }
174}
175
176#[cfg(test)]
177mod tests {
178    use aws_sdk_route53::types::RrType;
179
180    use super::*;
181
182    #[test]
183    fn test_display() {
184        assert_eq!(RecordType::A.to_string(), "A");
185        assert_eq!(RecordType::NS.to_string(), "NS");
186        assert_eq!(RecordType::SOA.to_string(), "SOA");
187        assert_eq!(RecordType::TXT.to_string(), "TXT");
188    }
189
190    #[test]
191    fn test_rr_type_from_record_type() {
192        assert_eq!(RrType::from(RecordType::A), RrType::A);
193        assert_eq!(RrType::from(RecordType::NS), RrType::Ns);
194        assert_eq!(RrType::from(RecordType::SOA), RrType::Soa);
195        assert_eq!(RrType::from(RecordType::TXT), RrType::Txt);
196    }
197
198    #[test]
199    fn test_record_type_from_str() {
200        assert_eq!(RecordType::from("A"), RecordType::A);
201        assert_eq!(RecordType::from("NS"), RecordType::NS);
202        assert_eq!(RecordType::from("SOA"), RecordType::SOA);
203        assert_eq!(RecordType::from("TXT"), RecordType::TXT);
204    }
205
206    #[test]
207    #[should_panic(expected = "Invalid record type: invalid")]
208    fn test_record_type_from_str_invalid() {
209        let _ = RecordType::from("invalid");
210    }
211
212    #[test]
213    fn test_record_type_from_rr_type() {
214        assert_eq!(
215            RecordType::from(aws_sdk_route53::types::RrType::A),
216            RecordType::A
217        );
218        assert_eq!(
219            RecordType::from(aws_sdk_route53::types::RrType::Ns),
220            RecordType::NS
221        );
222        assert_eq!(
223            RecordType::from(aws_sdk_route53::types::RrType::Soa),
224            RecordType::SOA
225        );
226        assert_eq!(
227            RecordType::from(aws_sdk_route53::types::RrType::Txt),
228            RecordType::TXT
229        );
230    }
231    #[test]
232    #[should_panic(expected = "Invalid record type: AAAA")]
233    fn test_record_type_from_rr_type_invalid() {
234        let _ = RecordType::from(aws_sdk_route53::types::RrType::Aaaa);
235    }
236
237    #[test]
238    fn test_record_type_as_str() {
239        assert_eq!(RecordType::A.as_str(), "A");
240        assert_eq!(RecordType::NS.as_str(), "NS");
241        assert_eq!(RecordType::SOA.as_str(), "SOA");
242        assert_eq!(RecordType::TXT.as_str(), "TXT");
243    }
244
245    #[test]
246    fn test_instance_type_as_str() {
247        assert_eq!(InstanceType::T3Nano.as_str(), "t3.nano");
248        assert_eq!(InstanceType::T32xlarge.as_str(), "t3.2xlarge");
249    }
250
251    #[test]
252    fn test_instance_type_get_info() {
253        assert_eq!(
254            InstanceType::T3Nano.get_info(),
255            InstanceInfo {
256                cpus: 2000,
257                memory: 512
258            }
259        );
260        assert_eq!(
261            InstanceType::T32xlarge.get_info(),
262            InstanceInfo {
263                cpus: 8000,
264                memory: 32768
265            }
266        );
267    }
268
269    #[test]
270    fn test_instance_type_from_str() {
271        assert_eq!(InstanceType::from("t3.nano"), InstanceType::T3Nano);
272        assert_eq!(InstanceType::from("t3.2xlarge"), InstanceType::T32xlarge);
273    }
274
275    #[test]
276    #[should_panic(expected = "Invalid instance type: invalid")]
277    fn test_instance_type_from_str_invalid() {
278        let _ = InstanceType::from("invalid");
279    }
280
281    #[test]
282    fn test_from_resources_fits_t3_nano_small_request() {
283        assert_eq!(
284            InstanceType::from_resources(500, 512),
285            Some(InstanceType::T3Nano)
286        );
287    }
288
289    #[test]
290    fn test_from_resources_fits_t3_nano_exact_request() {
291        assert_eq!(
292            InstanceType::from_resources(2000, 512),
293            Some(InstanceType::T3Nano)
294        );
295    }
296
297    #[test]
298    fn test_from_resources_fits_t3_micro_mem_overflow() {
299        assert_eq!(
300            InstanceType::from_resources(2000, 513),
301            Some(InstanceType::T3Micro)
302        );
303    }
304
305    #[test]
306    fn test_from_resources_fits_t3_medium_cpu_overflow() {
307        assert_eq!(
308            InstanceType::from_resources(2001, 8192),
309            Some(InstanceType::T3Xlarge)
310        );
311    }
312
313    #[test]
314    fn test_from_resources_fits_t3_xlarge_exact() {
315        assert_eq!(
316            InstanceType::from_resources(4000, 16384),
317            Some(InstanceType::T3Xlarge)
318        );
319    }
320
321    #[test]
322    fn test_from_resources_fits_t3_2xlarge_mem_overflow() {
323        assert_eq!(
324            InstanceType::from_resources(4000, 16385),
325            Some(InstanceType::T32xlarge)
326        );
327    }
328
329    #[test]
330    fn test_from_resources_fits_t3_2xlarge_exact_request() {
331        assert_eq!(
332            InstanceType::from_resources(8000, 32768),
333            Some(InstanceType::T32xlarge)
334        );
335    }
336
337    #[test]
338    fn test_from_resources_no_fit_cpu_overflow() {
339        assert_eq!(InstanceType::from_resources(8001, 32768), None);
340    }
341
342    #[test]
343    fn test_from_resources_no_fit_mem_overflow() {
344        assert_eq!(InstanceType::from_resources(8000, 32769), None);
345    }
346
347    #[test]
348    fn test_from_resources_no_fit_large_request() {
349        assert_eq!(InstanceType::from_resources(u32::MAX, u64::MAX), None);
350    }
351}