resource_tracker/collector/clouds/
aws.rs1use crate::metrics::CloudInfo;
2
3use super::{imds_get, imds_get_headers, new_imds_agent};
4
5fn fetch_imdsv2_token(agent: &ureq::Agent) -> Option<String> {
6 agent
7 .put("http://169.254.169.254/latest/api/token")
8 .header("X-aws-ec2-metadata-token-ttl-seconds", "21600")
9 .send_empty()
10 .ok()
11 .and_then(|mut r| {
12 if !r.status().is_success() {
13 return None;
14 }
15 r.body_mut().read_to_string().ok()
16 })
17 .map(|s| s.trim().to_string())
18 .filter(|s| !s.is_empty())
19}
20
21fn imds_get_with_token(agent: &ureq::Agent, path: &str, token: Option<&str>) -> Option<String> {
22 let url = format!("http://169.254.169.254{path}");
23 match token {
24 Some(t) => imds_get_headers(agent, &url, &[("X-aws-ec2-metadata-token", t)]),
25 None => imds_get(agent, &url),
26 }
27}
28
29const META_ROOT: &str = "http://169.254.169.254/latest/meta-data/";
30
31pub fn probe() -> Option<CloudInfo> {
42 let agent = new_imds_agent();
43 let token = fetch_imdsv2_token(&agent);
44
45 let read_token: Option<&str> = if token.is_some() {
46 token.as_deref()
47 } else if imds_get(&agent, META_ROOT).is_some() {
48 None
49 } else {
50 return None;
51 };
52
53 let domain = imds_get_with_token(&agent, "/latest/meta-data/services/domain", read_token);
55 if domain.as_deref() != Some("amazonaws.com") {
56 return None;
57 }
58
59 let cloud_region_id =
60 imds_get_with_token(&agent, "/latest/meta-data/placement/region", read_token);
61 let cloud_zone_id = imds_get_with_token(
62 &agent,
63 "/latest/meta-data/placement/availability-zone",
64 read_token,
65 );
66 let cloud_instance_type =
67 imds_get_with_token(&agent, "/latest/meta-data/instance-type", read_token);
68 let cloud_account_id = imds_get_with_token(
69 &agent,
70 "/latest/meta-data/identity-credentials/ec2/info",
71 read_token,
72 )
73 .and_then(|body| {
74 let marker = "\"AccountId\":\"";
75 let start = body.find(marker)? + marker.len();
76 let end = body[start..].find('"')? + start;
77 Some(body[start..end].to_string())
78 });
79
80 Some(CloudInfo {
81 cloud_vendor_id: Some("aws".to_string()),
82 cloud_account_id,
83 cloud_region_id,
84 cloud_zone_id,
85 cloud_instance_type,
86 })
87}