spacegate_config/service/k8s/
mod.rs1use 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;
11pub 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}