spacegate_config/service/k8s/
mod.rs

1use std::sync::Arc;
2
3use k8s_gateway_api::{GatewayClass, GatewayClassStatus};
4use k8s_openapi::{apimachinery::pkg::apis::meta::v1::Condition, NamespaceResourceScope};
5use spacegate_model::BoxResult;
6
7pub mod convert;
8pub mod create;
9pub mod delete;
10pub mod discovery;
11// TODO check listen
12pub mod listen;
13pub mod retrieve;
14pub mod update;
15
16pub struct K8s {
17    pub namespace: Arc<str>,
18    client: kube::Client,
19}
20
21impl K8s {
22    pub fn new(namespace: impl Into<Arc<str>>, client: kube::Client) -> Self {
23        Self {
24            namespace: namespace.into(),
25            client,
26        }
27    }
28
29    pub async fn with_default_client(namespace: impl Into<Arc<str>>) -> Result<Self, kube::Error> {
30        Ok(Self {
31            namespace: namespace.into(),
32            client: kube::Client::try_default().await?,
33        })
34    }
35
36    pub fn get_all_api<T: kube::Resource>(&self) -> kube::Api<T>
37    where
38        <T as kube::Resource>::DynamicType: Default,
39    {
40        kube::Api::all(self.client.clone())
41    }
42
43    pub fn get_namespace_api<T: kube::Resource<Scope = NamespaceResourceScope>>(&self) -> kube::Api<T>
44    where
45        <T as kube::Resource>::DynamicType: Default,
46    {
47        kube::Api::namespaced(self.client.clone(), &self.namespace)
48    }
49
50    pub fn get_specify_namespace_api<T: kube::Resource<Scope = NamespaceResourceScope>>(&self, ns: &str) -> kube::Api<T>
51    where
52        <T as kube::Resource>::DynamicType: Default,
53    {
54        kube::Api::namespaced(self.client.clone(), ns)
55    }
56
57    #[allow(unused, reason = "gateway permission")]
58    pub(crate) async fn accept_gateway_class(&self, name: &str) -> BoxResult<()> {
59        let condition = Condition {
60            last_transition_time: k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(chrono::Utc::now()),
61            message: "Accepted".to_string(),
62            reason: "None".to_string(),
63            status: "True".to_string(),
64            type_: "Accepted".to_string(),
65            observed_generation: None,
66        };
67        let gateway_class_api: kube::Api<GatewayClass> = self.get_all_api();
68        let mut gateway_class = gateway_class_api.get_status(name).await?;
69        gateway_class.status = if let Some(mut status) = gateway_class.status {
70            status.conditions = if let Some(mut conditions) = status.conditions {
71                if let Some(condition) = conditions.first() {
72                    if condition.status == "True" && condition.type_ == "Accepted" {
73                        return Ok(());
74                    }
75                }
76                conditions.insert(0, condition);
77                Some(conditions)
78            } else {
79                Some(vec![condition])
80            };
81
82            Some(status)
83        } else {
84            Some(GatewayClassStatus {
85                conditions: Some(vec![condition]),
86            })
87        };
88        gateway_class_api.replace_status(name, &kube::api::PostParams::default(), serde_json::to_vec(&gateway_class)?).await?;
89        Ok(())
90    }
91
92    #[allow(unused, reason = "gateway permission")]
93    pub(crate) async fn reject_gateway_class(&self, name: &str) -> BoxResult<()> {
94        let condition = Condition {
95            last_transition_time: k8s_openapi::apimachinery::pkg::apis::meta::v1::Time(chrono::Utc::now()),
96            message: "Load config or refresh config , waiting for complete".to_string(),
97            reason: "WaitingForController".to_string(),
98            status: "False".to_string(),
99            type_: "Progressing".to_string(),
100            observed_generation: None,
101        };
102        let gateway_class_api: kube::Api<GatewayClass> = self.get_all_api();
103        let mut gateway_class = gateway_class_api.get_status(name).await?;
104        gateway_class.status = if let Some(mut status) = gateway_class.status {
105            status.conditions = if let Some(mut conditions) = status.conditions {
106                if let Some(condition) = conditions.first() {
107                    if condition.status == "False" && condition.type_ == "Progressing" {
108                        return Ok(());
109                    }
110                }
111                conditions = vec![condition];
112                Some(conditions)
113            } else {
114                Some(vec![condition])
115            };
116
117            Some(status)
118        } else {
119            Some(GatewayClassStatus {
120                conditions: Some(vec![condition]),
121            })
122        };
123        gateway_class_api.replace_status(name, &kube::api::PostParams::default(), serde_json::to_vec(&gateway_class)?).await?;
124        Ok(())
125    }
126}