cloud_node_discovery/providers/
upcloud.rs1#![cfg(feature = "upcloud")]
2use crate::Provider;
3use crate::{DiscoveryError, Node};
4use upcloud_sdk::client::Client;
5use upcloud_sdk::resources::server::ServerOperations;
6use upcloud_sdk::types::common::LabelFilter;
7
8use upcloud_sdk::error::Error as UpcloudError;
9
10use std::collections::HashMap;
11
12use async_trait::async_trait;
13
14pub struct UpcloudProvider {
15 client: Client,
16 zone: String,
17 label_key: String,
18 label_value: String,
19}
20
21impl UpcloudProvider {
22 pub async fn new(config: &HashMap<String, String>) -> Result<Self, DiscoveryError> {
23 let zone = config
25 .get("zone")
26 .ok_or_else(|| DiscoveryError::ConfigError("zone is required".to_string()))?
27 .clone();
28 let label_key = config
29 .get("label_key")
30 .ok_or_else(|| DiscoveryError::ConfigError("label_key is required".to_string()))?
31 .clone();
32 let label_value = config
33 .get("label_value")
34 .ok_or_else(|| DiscoveryError::ConfigError("label_value is required".to_string()))?
35 .clone();
36
37 let client = Client::new()?;
39
40 Ok(UpcloudProvider {
41 client,
42 zone,
43 label_key,
44 label_value,
45 })
46 }
47}
48
49#[async_trait]
50impl Provider for UpcloudProvider {
51 async fn discover(&self) -> Result<Vec<Node>, DiscoveryError> {
52 let label_filter = LabelFilter::new().with(&self.label_key, &self.label_value);
53 let servers_by_labels = self.client.list_servers_by_labels(&label_filter).await?;
54
55 let mut nodes = Vec::new();
57
58 for server in servers_by_labels.server {
59 let server_details = self.client.get_server(&server.uuid).await?;
60 let mut private_ip: &str = "";
62 let mut utility_ip: &str = "";
63 let mut public_ip: &str = "";
64 for interface_iter in server_details.networking.iter() {
65 for interface in interface_iter.interfaces.interface.iter() {
66 if interface.interface_type == "private" {
67 private_ip = interface.ip_addresses.ip_address[0].address.as_ref().unwrap().as_str();
68 }
69 if interface.interface_type == "utility" {
70 utility_ip = interface.ip_addresses.ip_address[0].address.as_ref().unwrap().as_str();
71 }
72 if interface.interface_type == "public" {
73 public_ip = interface.ip_addresses.ip_address[0].address.as_ref().unwrap().as_str();
74 }
75 }
76 }
77
78 let mut metadata = HashMap::new();
80 for x in server.labels.iter() {
81 for label in x.label.iter() {
82 metadata.insert(label.key.to_string(), label.value.to_string());
83 }
84 }
85
86 metadata.insert("uuid".to_string(), server.uuid.to_string());
88 metadata.insert("zone".to_string(), server.zone.clone());
89 metadata.insert("utility_ip".to_string(), utility_ip.to_string());
90 metadata.insert("public_ip".to_string(), public_ip.to_string());
91 metadata.insert("zone".to_string(), self.zone.clone());
92
93 nodes.push(Node {
94 address: private_ip.to_string(),
95 meta: metadata,
96 });
97 }
98
99 Ok(nodes)
100 }
101}
102
103impl From<UpcloudError> for DiscoveryError {
104 fn from(error: UpcloudError) -> Self {
105 DiscoveryError::ProviderError(error.to_string())
106 }
107}