aquafire / coredns_configurator.rs

Last active 6 months ago

Like 0
coredns_configurator.rs Raw
1use futures::{StreamExt, TryStreamExt};
2use k8s_openapi::api::core::v1::Service;
3use kube::{
4 Client,
5 api::{Api, ListParams, ResourceExt, WatchEvent, WatchParams},
6};
7use std::collections::HashMap;
8use std::sync::Arc;
9
10const LOCAL_DOMAINS_LABEL: &'static str = "dns.tensor.ru/local";
11const LOCAL_DOMAINS_ANNOTATION: &'static str = "dns.tensor.ru/local-domains";
12const HOSTS_DIR: &'static str = "/data";
13
14use tokio::fs::OpenOptions;
15use tokio::io::AsyncWriteExt;
16use tokio::sync::Mutex;
17
18struct Informer {
19 domains: Mutex<HashMap<String, Vec<String>>>,
20 client: Arc<Client>,
21}
22
23impl Informer {
24 async fn add_service(&mut self, service: Service) {
25 let annotations = service.annotations();
26 if let Some(local_domains) = annotations.get(LOCAL_DOMAINS_ANNOTATION) {
27 let domains_list: Vec<String> = local_domains
28 .split_whitespace()
29 .map(|a| a.to_string())
30 .collect();
31 if let Some(spec) = service.spec {
32 if let Some(cluster_ip) = spec.cluster_ip
33 && domains_list.len() > 0
34 {
35 println!("Service added {} -> {:?}", cluster_ip, domains_list);
36 let mut lock = self.domains.lock().await;
37 lock.insert(cluster_ip, domains_list);
38 }
39 }
40 }
41 }
42
43 async fn delete_service(&mut self, service: Service) {
44 if let Some(spec) = service.spec {
45 if let Some(cluster_ip) = spec.cluster_ip {
46 let mut lock = self.domains.lock().await;
47 match lock.remove(&cluster_ip) {
48 Some(domains) => {
49 println!("Service deleted {} -> {:?}", cluster_ip, domains);
50 }
51 None => {}
52 }
53 }
54 }
55 }
56
57 pub async fn fill(&mut self) {
58 let client: Client = (*self.client).clone();
59 let services: Api<Service> = Api::all(client);
60 let lp = ListParams {
61 label_selector: Some(LOCAL_DOMAINS_LABEL.to_string()),
62 ..Default::default()
63 };
64 while let Ok(services_list) = services.list(&lp).await {
65 for service in services_list {
66 self.add_service(service).await;
67 }
68 }
69 let _ = self.write_hosts_file().await;
70 }
71
72 pub async fn get_cache(&self) -> HashMap<String, Vec<String>> {
73 let lock = self.domains.lock().await;
74 lock.clone()
75 }
76
77 pub async fn watch(mut self) -> Result<(), Box<dyn std::error::Error>> {
78 let client: Client = (*self.client).clone();
79 let services: Api<Service> = Api::all(client);
80 let wp = WatchParams {
81 label_selector: Some("dns.tensor.ru/local".to_string()),
82 ..Default::default()
83 };
84 let mut stream = services.watch(&wp, "0").await?.boxed();
85
86 while let Some(status) = stream.try_next().await? {
87 match status {
88 WatchEvent::Added(s) | WatchEvent::Modified(s) => {
89 self.add_service(s).await;
90 self.write_hosts_file().await?;
91 }
92 WatchEvent::Deleted(s) => {
93 self.delete_service(s).await;
94 self.write_hosts_file().await?;
95 }
96 WatchEvent::Bookmark(s) => {}
97 WatchEvent::Error(s) => println!("{}", s),
98 }
99 }
100
101 Ok(())
102 }
103
104 async fn write_hosts_file(&self) -> Result<(), Box<dyn std::error::Error>> {
105 let mut file = OpenOptions::new()
106 .write(true)
107 .create(true)
108 .truncate(true)
109 .open(format!("{}/hosts", HOSTS_DIR))
110 .await?;
111
112 // Собираем все строки в один буфер
113 let mut content = String::new();
114 let lock = self.domains.lock().await;
115 for (k, v) in lock.iter() {
116 content.push_str(&format!("{} {}\n", k, v.join(" ")));
117 }
118 file.write_all(content.as_bytes()).await?;
119 file.flush().await?;
120 Ok(())
121 }
122}
123
124#[tokio::main]
125async fn main() -> Result<(), Box<dyn std::error::Error>> {
126 let mut informer = Informer {
127 domains: Mutex::new(HashMap::new()),
128 client: Arc::new(Client::try_default().await?),
129 };
130 informer.fill().await;
131 println!("{:?}", informer.get_cache().await);
132
133 let handle = tokio::spawn(async move {
134 if let Err(e) = informer.watch().await {
135 eprintln!("Watcher error: {}", e);
136 }
137 });
138
139 // Ждем выполнения фоновой задачи (в этот момент main не завершится)
140 handle.await?;
141
142 Ok(())
143}