cloud_meta/cloud/
azure.rs

1use std::collections::HashMap;
2use http::uri::{Uri, Parts};
3use hyper::{Body, Method, Request};
4use hyper::body::{to_bytes, Bytes};
5use hyper::client::{Client, HttpConnector};
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8use crate::Error;
9
10pub struct Azure {
11    client:   Client<HttpConnector, Body>,
12    endpoint: Parts,
13    version:  String,
14}
15
16#[derive(Debug, Deserialize, Serialize)]
17#[serde(rename_all = "camelCase")]
18pub struct Instance {
19    pub compute: Compute,
20    pub network: Value,
21}
22
23#[derive(Debug, Deserialize, Serialize)]
24#[serde(rename_all = "camelCase")]
25pub struct Compute {
26    pub vm_id:   String,
27    pub name:    String,
28    pub os_type: String,
29    pub vm_size: String,
30
31    #[serde(flatten)]
32    pub extra: HashMap<String, Value>,
33}
34
35impl Azure {
36    pub fn new(client: Client<HttpConnector, Body>) -> Self {
37        let endpoint = "http://169.254.169.254";
38        let version  = "2021-05-01";
39        Self {
40            client:   client,
41            endpoint: Uri::from_static(endpoint).into_parts(),
42            version:  version.to_owned(),
43        }
44    }
45
46    pub async fn instance(&self) -> Result<Instance, Error> {
47        let bytes = self.get("instance").await?;
48        Ok(serde_json::from_slice(&bytes)?)
49    }
50
51    pub async fn get(&self, path: &str) -> Result<Bytes, Error> {
52        let version = &self.version;
53        let path    = format!("/metadata/{path}?api-version={version}");
54
55        let mut endpoint = Parts::default();
56        endpoint.scheme         = self.endpoint.scheme.clone();
57        endpoint.authority      = self.endpoint.authority.clone();
58        endpoint.path_and_query = Some(path.try_into()?);
59
60        let mut request = Request::new(Body::empty());
61        *request.method_mut() = Method::GET;
62        *request.uri_mut() = endpoint.try_into()?;
63
64        let header = "Metadata";
65        let value  = "true".as_bytes().try_into()?;
66        request.headers_mut().insert(header, value);
67
68        let response = self.client.request(request).await?;
69        if !response.status().is_success() {
70            return Err(response.status().into());
71        }
72
73        Ok(to_bytes(response).await?)
74    }
75}