1use std::fmt::Display;
2
3use crate::{detector::Detector, env_vars, smbios};
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
7pub enum ComputeEnvironment {
8 AwsEc2,
11 AwsEcs,
13 AwsLambda,
15 AwsKubernetes,
17 AwsNomad,
19
20 AzureContainerApps,
23 AzureContainerAppsJob,
25 AzureContainerInstance,
27 AzureKubernetes,
29 AzureVM,
31 AzureNomad,
33
34 GcpCloudRunGen1,
37 GcpCloudRunGen2,
39 GcpCloudRunJob,
41 GcpComputeEngine,
43 GcpKubernetes,
45 GcpNomad,
47
48 Kubernetes,
51 Nomad,
53 Qemu,
55
56 #[cfg(test)]
57 Testing,
58}
59
60impl ComputeEnvironment {
61 pub(crate) fn iter() -> ComputeEnvironmentIter {
62 ComputeEnvironmentIter { idx: 0 }
63 }
64
65 pub(crate) fn detector(&self) -> Detector {
66 match self {
67 Self::AwsEc2 => Detector::new(*self, smbios::AWS, env_vars::EMPTY),
68 Self::AwsEcs => Detector::new(*self, smbios::EMPTY, env_vars::AWS_ECS),
69 Self::AwsLambda => Detector::new(*self, smbios::EMPTY, env_vars::AWS_LAMBDA),
70 Self::AwsKubernetes => Detector::new(*self, smbios::AWS, env_vars::KUBERNETES),
71 Self::AwsNomad => Detector::new(*self, smbios::AWS, env_vars::NOMAD),
72 Self::AzureContainerApps => {
73 Detector::new(*self, smbios::AZURE, env_vars::AZURE_CONTAINER_APPS)
74 }
75 Self::AzureContainerAppsJob => {
76 Detector::new(*self, smbios::AZURE, env_vars::AZURE_CONTAINER_APPS_JOB)
77 }
78 Self::AzureContainerInstance => {
79 Detector::new(*self, smbios::EMPTY, env_vars::AZURE_CONTAINER_INSTANCE)
80 }
81 Self::AzureKubernetes => Detector::new(*self, smbios::AZURE, env_vars::KUBERNETES),
82 Self::AzureVM => Detector::new(*self, smbios::AZURE, env_vars::EMPTY),
83 Self::AzureNomad => Detector::new(*self, smbios::AZURE, env_vars::NOMAD),
84 Self::GcpCloudRunGen1 => {
85 Detector::new(*self, smbios::EMPTY, env_vars::GCP_CLOUD_RUN_SERVICE)
86 }
87 Self::GcpCloudRunGen2 => {
88 Detector::new(*self, smbios::GCP, env_vars::GCP_CLOUD_RUN_SERVICE)
89 }
90 Self::GcpCloudRunJob => Detector::new(*self, smbios::GCP, env_vars::GCP_CLOUD_RUN_JOB),
91 Self::GcpComputeEngine => Detector::new(*self, smbios::GCP, env_vars::EMPTY),
92 Self::GcpKubernetes => Detector::new(*self, smbios::GCP, env_vars::KUBERNETES),
93 Self::GcpNomad => Detector::new(*self, smbios::GCP, env_vars::NOMAD),
94 Self::Kubernetes => Detector::new(*self, smbios::EMPTY, env_vars::KUBERNETES),
95 Self::Nomad => Detector::new(*self, smbios::EMPTY, env_vars::NOMAD),
96 Self::Qemu => Detector::new(*self, smbios::QEMU, env_vars::EMPTY),
97
98 #[cfg(test)]
99 Self::Testing => Detector::new(*self, smbios::EMPTY, env_vars::EMPTY),
100 }
101 }
102
103 pub fn as_str(&self) -> &'static str {
105 match self {
106 Self::AwsEc2 => "AWS EC2",
107 Self::AwsEcs => "AWS ECS",
108 Self::AwsLambda => "AWS Lambda",
109 Self::AwsKubernetes => "Kubernetes on AWS",
110 Self::AwsNomad => "Nomad on AWS",
111 Self::AzureContainerApps => "Azure Container Apps",
112 Self::AzureContainerAppsJob => "Azure Container Apps Job",
113 Self::AzureContainerInstance => "Azure Container Instance",
114 Self::AzureKubernetes => "Kubernetes on Azure",
115 Self::AzureVM => "Azure VM",
116 Self::AzureNomad => "Nomad on Azure",
117 Self::GcpCloudRunGen1 => "Google Cloud Run (Gen1)",
118 Self::GcpCloudRunGen2 => "Google Cloud Run (Gen2)",
119 Self::GcpCloudRunJob => "Google Cloud Run (Job)",
120 Self::GcpComputeEngine => "Google Compute Engine",
121 Self::GcpKubernetes => "Kubernetes on Google Cloud",
122 Self::GcpNomad => "Nomad on Google Cloud",
123 Self::Kubernetes => "Kubernetes",
124 Self::Nomad => "Nomad",
125 Self::Qemu => "QEMU",
126
127 #[cfg(test)]
128 Self::Testing => "Testing",
129 }
130 }
131
132 pub fn platform_code(&self) -> &'static str {
148 match self {
149 Self::AwsEc2 => "aws_ec2",
150 Self::AwsEcs => "aws_ecs",
151 Self::AwsLambda => "aws_lambda",
152 Self::AwsKubernetes => "aws_eks",
154 Self::AwsNomad => "nomad",
155 Self::AzureContainerApps => "azure_container_apps",
156 Self::AzureContainerAppsJob => "azure_container_apps",
157 Self::AzureContainerInstance => "azure_container_instances",
158 Self::AzureKubernetes => "azure_aks",
160 Self::AzureVM => "azure_vm",
161 Self::AzureNomad => "nomad",
162 Self::GcpCloudRunGen1 => "gcp_cloud_run",
163 Self::GcpCloudRunGen2 => "gcp_cloud_run",
164 Self::GcpCloudRunJob => "gcp_cloud_run",
165 Self::GcpComputeEngine => "gcp_compute_engine",
166 Self::GcpKubernetes => "gcp_kubernetes_engine",
168 Self::GcpNomad => "nomad",
169 Self::Kubernetes => "kubernetes",
170 Self::Nomad => "nomad",
171 Self::Qemu => "qemu",
172
173 #[cfg(test)]
174 Self::Testing => "testing",
175 }
176 }
177
178 pub fn cloud_provider(&self) -> Option<CloudProvider> {
180 match self {
181 Self::AwsEc2
182 | Self::AwsEcs
183 | Self::AwsLambda
184 | Self::AwsKubernetes
185 | Self::AwsNomad => Some(CloudProvider::Aws),
186 Self::AzureContainerApps
187 | Self::AzureContainerAppsJob
188 | Self::AzureContainerInstance
189 | Self::AzureKubernetes
190 | Self::AzureVM
191 | Self::AzureNomad => Some(CloudProvider::Azure),
192 Self::GcpCloudRunGen1
193 | Self::GcpCloudRunGen2
194 | Self::GcpCloudRunJob
195 | Self::GcpComputeEngine
196 | Self::GcpKubernetes
197 | Self::GcpNomad => Some(CloudProvider::GoogleCloud),
198 Self::Kubernetes | Self::Nomad | Self::Qemu => None,
199
200 #[cfg(test)]
201 Self::Testing => None,
202 }
203 }
204}
205
206impl Display for ComputeEnvironment {
207 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
208 f.write_str(self.as_str())
209 }
210}
211
212pub(crate) struct ComputeEnvironmentIter {
213 idx: usize,
214}
215
216impl ComputeEnvironmentIter {
217 fn get(&self, idx: usize) -> Option<ComputeEnvironment> {
218 match idx {
219 0usize => Some(ComputeEnvironment::AwsEc2),
220 1usize => Some(ComputeEnvironment::AwsEcs),
221 2usize => Some(ComputeEnvironment::AwsLambda),
222 3usize => Some(ComputeEnvironment::AwsKubernetes),
223 4usize => Some(ComputeEnvironment::AwsNomad),
224 5usize => Some(ComputeEnvironment::AzureContainerApps),
225 6usize => Some(ComputeEnvironment::AzureContainerAppsJob),
226 7usize => Some(ComputeEnvironment::AzureContainerInstance),
227 8usize => Some(ComputeEnvironment::AzureKubernetes),
228 9usize => Some(ComputeEnvironment::AzureVM),
229 10usize => Some(ComputeEnvironment::AzureNomad),
230 11usize => Some(ComputeEnvironment::GcpCloudRunGen1),
231 12usize => Some(ComputeEnvironment::GcpCloudRunGen2),
232 13usize => Some(ComputeEnvironment::GcpCloudRunJob),
233 14usize => Some(ComputeEnvironment::GcpComputeEngine),
234 15usize => Some(ComputeEnvironment::GcpKubernetes),
235 16usize => Some(ComputeEnvironment::GcpNomad),
236 17usize => Some(ComputeEnvironment::Kubernetes),
237 18usize => Some(ComputeEnvironment::Nomad),
238 19usize => Some(ComputeEnvironment::Qemu),
239 _ => None,
240 }
241 }
242}
243
244impl Iterator for ComputeEnvironmentIter {
245 type Item = ComputeEnvironment;
246
247 fn next(&mut self) -> Option<Self::Item> {
248 let ret = self.get(self.idx);
249 self.idx += 1;
250 ret
251 }
252}
253
254#[derive(Clone, Copy, PartialEq, Eq)]
256pub enum CloudProvider {
257 Aws,
259 Azure,
261 GoogleCloud,
263}
264
265impl CloudProvider {
266 pub fn as_str(&self) -> &'static str {
268 match self {
269 Self::Aws => "AWS",
270 Self::Azure => "Azure",
271 Self::GoogleCloud => "Google Cloud",
272 }
273 }
274 pub fn code(&self) -> &'static str {
280 match self {
281 Self::Aws => "aws",
282 Self::Azure => "azure",
283 Self::GoogleCloud => "gcp",
284 }
285 }
286}
287
288impl Display for CloudProvider {
289 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
290 f.write_str(self.as_str())
291 }
292}
293
294#[cfg(test)]
295mod tests {
296 use std::cmp::Ordering;
297 use std::collections::HashMap;
298
299 use rstest::{fixture, rstest};
300
301 use crate::specificity::Specificity as _;
302
303 use super::*;
304
305 #[fixture]
306 fn expected_matrix() -> HashMap<(ComputeEnvironment, ComputeEnvironment), Option<Ordering>> {
307 let envs: HashMap<_, _> = ComputeEnvironment::iter().enumerate().collect();
308 let matrix = include_str!("tests/specificity_matrix.txt");
309 matrix
310 .split('\n')
311 .enumerate()
312 .flat_map(|(y, line)| {
313 let envs = &envs;
314 line.chars().enumerate().map(move |(x, c)| {
315 (
316 (*envs.get(&y).unwrap(), *envs.get(&x).unwrap()),
317 match c {
318 '-' => Some(Ordering::Less),
319 '=' => Some(Ordering::Equal),
320 '+' => Some(Ordering::Greater),
321 _ => None,
322 },
323 )
324 })
325 })
326 .collect()
327 }
328
329 #[rstest]
330 fn test_specificity(
331 #[values(
332 ComputeEnvironment::AwsEc2,
333 ComputeEnvironment::AwsEcs,
334 ComputeEnvironment::AwsLambda,
335 ComputeEnvironment::AwsKubernetes,
336 ComputeEnvironment::AwsNomad,
337 ComputeEnvironment::AzureContainerApps,
338 ComputeEnvironment::AzureContainerAppsJob,
339 ComputeEnvironment::AzureContainerInstance,
340 ComputeEnvironment::AzureKubernetes,
341 ComputeEnvironment::AzureVM,
342 ComputeEnvironment::AzureNomad,
343 ComputeEnvironment::GcpCloudRunGen1,
344 ComputeEnvironment::GcpCloudRunGen2,
345 ComputeEnvironment::GcpCloudRunJob,
346 ComputeEnvironment::GcpComputeEngine,
347 ComputeEnvironment::GcpKubernetes,
348 ComputeEnvironment::GcpNomad,
349 ComputeEnvironment::Kubernetes,
350 ComputeEnvironment::Nomad,
351 ComputeEnvironment::Qemu
352 )]
353 left: ComputeEnvironment,
354 #[values(
355 ComputeEnvironment::AwsEc2,
356 ComputeEnvironment::AwsEcs,
357 ComputeEnvironment::AwsLambda,
358 ComputeEnvironment::AwsKubernetes,
359 ComputeEnvironment::AwsNomad,
360 ComputeEnvironment::AzureContainerApps,
361 ComputeEnvironment::AzureContainerAppsJob,
362 ComputeEnvironment::AzureContainerInstance,
363 ComputeEnvironment::AzureKubernetes,
364 ComputeEnvironment::AzureVM,
365 ComputeEnvironment::AzureNomad,
366 ComputeEnvironment::GcpCloudRunGen1,
367 ComputeEnvironment::GcpCloudRunGen2,
368 ComputeEnvironment::GcpCloudRunJob,
369 ComputeEnvironment::GcpComputeEngine,
370 ComputeEnvironment::GcpKubernetes,
371 ComputeEnvironment::GcpNomad,
372 ComputeEnvironment::Kubernetes,
373 ComputeEnvironment::Nomad,
374 ComputeEnvironment::Qemu
375 )]
376 right: ComputeEnvironment,
377 expected_matrix: HashMap<(ComputeEnvironment, ComputeEnvironment), Option<Ordering>>,
378 ) {
379 let expected = expected_matrix.get(&(left, right)).cloned().flatten();
380
381 let result = left.detector().specificity_cmp(&right.detector());
382
383 assert_eq!(expected, result);
384 }
385}