cloud_detect/providers/
alibaba.rs1use std::path::Path;
4use std::time::Duration;
5
6use async_trait::async_trait;
7use tokio::fs;
8use tokio::sync::mpsc::Sender;
9use tracing::{debug, error, info, instrument};
10
11use crate::{Provider, ProviderId};
12
13const METADATA_URI: &str = "http://100.100.100.200";
14const METADATA_PATH: &str = "/latest/meta-data/latest/meta-data/instance/virtualization-solution";
15const VENDOR_FILE: &str = "/sys/class/dmi/id/product_name";
16pub(crate) const IDENTIFIER: ProviderId = ProviderId::Alibaba;
17
18pub(crate) struct Alibaba;
19
20#[async_trait]
21impl Provider for Alibaba {
22 fn identifier(&self) -> ProviderId {
23 IDENTIFIER
24 }
25
26 #[instrument(skip_all)]
28 async fn identify(&self, tx: Sender<ProviderId>, timeout: Duration) {
29 info!("Checking Alibaba Cloud");
30 if self.check_vendor_file(VENDOR_FILE).await
31 || self.check_metadata_server(METADATA_URI, timeout).await
32 {
33 info!("Identified Alibaba Cloud");
34 let res = tx.send(IDENTIFIER).await;
35
36 if let Err(err) = res {
37 error!("Error sending message: {:?}", err);
38 }
39 }
40 }
41}
42
43impl Alibaba {
44 #[instrument(skip_all)]
46 async fn check_metadata_server(&self, metadata_uri: &str, timeout: Duration) -> bool {
47 let url = format!("{metadata_uri}{METADATA_PATH}");
48 debug!("Checking {} metadata using url: {}", IDENTIFIER, url);
49
50 let client = if let Ok(client) = reqwest::Client::builder().timeout(timeout).build() {
51 client
52 } else {
53 error!("Error creating client");
54 return false;
55 };
56
57 match client.get(url).send().await {
58 Ok(resp) => match resp.text().await {
59 Ok(text) => text.contains("ECS Virt"),
60 Err(err) => {
61 error!("Error reading response: {:?}", err);
62 false
63 }
64 },
65 Err(err) => {
66 error!("Error making request: {:?}", err);
67 false
68 }
69 }
70 }
71
72 #[instrument(skip_all)]
74 async fn check_vendor_file<P: AsRef<Path>>(&self, vendor_file: P) -> bool {
75 debug!(
76 "Checking {} vendor file: {}",
77 IDENTIFIER,
78 vendor_file.as_ref().display()
79 );
80
81 if vendor_file.as_ref().is_file() {
82 return match fs::read_to_string(vendor_file).await {
83 Ok(content) => content.contains("Alibaba Cloud ECS"),
84 Err(err) => {
85 error!("Error reading file: {:?}", err);
86 false
87 }
88 };
89 }
90
91 false
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use std::io::Write;
98
99 use anyhow::Result;
100 use tempfile::NamedTempFile;
101 use wiremock::matchers::path;
102 use wiremock::{Mock, MockServer, ResponseTemplate};
103
104 use super::*;
105
106 #[tokio::test]
107 async fn test_check_metadata_server_success() {
108 let mock_server = MockServer::start().await;
109 Mock::given(path(METADATA_PATH))
110 .respond_with(ResponseTemplate::new(200).set_body_string("ECS Virt"))
111 .expect(1)
112 .mount(&mock_server)
113 .await;
114
115 let provider = Alibaba;
116 let metadata_uri = mock_server.uri();
117 let result = provider
118 .check_metadata_server(&metadata_uri, Duration::from_secs(1))
119 .await;
120
121 assert!(result);
122 }
123
124 #[tokio::test]
125 async fn test_check_metadata_server_failure() {
126 let mock_server = MockServer::start().await;
127 Mock::given(path(METADATA_PATH))
128 .respond_with(ResponseTemplate::new(200).set_body_string("ABC"))
129 .expect(1)
130 .mount(&mock_server)
131 .await;
132
133 let provider = Alibaba;
134 let metadata_uri = mock_server.uri();
135 let result = provider
136 .check_metadata_server(&metadata_uri, Duration::from_secs(1))
137 .await;
138
139 assert!(!result);
140 }
141
142 #[tokio::test]
143 async fn test_check_vendor_file_success() -> Result<()> {
144 let mut vendor_file = NamedTempFile::new()?;
145 vendor_file.write_all(b"Alibaba Cloud ECS")?;
146
147 let provider = Alibaba;
148 let result = provider.check_vendor_file(vendor_file.path()).await;
149
150 assert!(result);
151
152 Ok(())
153 }
154
155 #[tokio::test]
156 async fn test_check_vendor_file_failure() -> Result<()> {
157 let vendor_file = NamedTempFile::new()?;
158
159 let provider = Alibaba;
160 let result = provider.check_vendor_file(vendor_file.path()).await;
161
162 assert!(!result);
163
164 Ok(())
165 }
166}