kube_client/api/util/
mod.rs1use crate::{
2 api::{Api, Resource},
3 Error, Result,
4};
5use k8s_openapi::api::{
6 authentication::v1::TokenRequest,
7 core::v1::{Node, ServiceAccount},
8};
9use kube_core::{params::PostParams, util::Restart};
10use serde::de::DeserializeOwned;
11
12mod csr;
13
14impl<K> Api<K>
15where
16 K: Restart + Resource + DeserializeOwned,
17{
18 pub async fn restart(&self, name: &str) -> Result<K> {
20 let mut req = self.request.restart(name).map_err(Error::BuildRequest)?;
21 req.extensions_mut().insert("restart");
22 self.client.request::<K>(req).await
23 }
24}
25
26impl Api<Node> {
27 pub async fn cordon(&self, name: &str) -> Result<Node> {
29 let mut req = self.request.cordon(name).map_err(Error::BuildRequest)?;
30 req.extensions_mut().insert("cordon");
31 self.client.request::<Node>(req).await
32 }
33
34 pub async fn uncordon(&self, name: &str) -> Result<Node> {
36 let mut req = self.request.uncordon(name).map_err(Error::BuildRequest)?;
37 req.extensions_mut().insert("cordon");
38 self.client.request::<Node>(req).await
39 }
40}
41
42impl Api<ServiceAccount> {
43 pub async fn create_token_request(
45 &self,
46 name: &str,
47 pp: &PostParams,
48 token_request: &TokenRequest,
49 ) -> Result<TokenRequest> {
50 let bytes = serde_json::to_vec(token_request).map_err(Error::SerdeError)?;
51 let mut req = self
52 .request
53 .create_subresource("token", name, pp, bytes)
54 .map_err(Error::BuildRequest)?;
55 req.extensions_mut().insert("create_token_request");
56 self.client.request::<TokenRequest>(req).await
57 }
58}
59
60#[cfg(test)]
63#[cfg(feature = "client")]
64mod test {
65 use crate::{
66 api::{Api, DeleteParams, ListParams, PostParams},
67 Client,
68 };
69 use k8s_openapi::api::{
70 authentication::v1::{TokenRequest, TokenRequestSpec, TokenReview, TokenReviewSpec},
71 core::v1::{Node, ServiceAccount},
72 };
73 use serde_json::json;
74
75 #[tokio::test]
76 #[ignore = "needs kubeconfig"]
77 async fn node_cordon_and_uncordon_works() -> Result<(), Box<dyn std::error::Error>> {
78 let client = Client::try_default().await?;
79
80 let node_name = "fakenode";
81 let fake_node = serde_json::from_value(json!({
82 "apiVersion": "v1",
83 "kind": "Node",
84 "metadata": {
85 "name": node_name,
86 },
87 }))?;
88
89 let nodes: Api<Node> = Api::all(client.clone());
90 nodes.create(&PostParams::default(), &fake_node).await?;
91
92 let schedulables = ListParams::default().fields("spec.unschedulable==false");
93 let nodes_init = nodes.list(&schedulables).await?;
94 let num_nodes_before_cordon = nodes_init.items.len();
95
96 nodes.cordon(node_name).await?;
97 let nodes_after_cordon = nodes.list(&schedulables).await?;
98 assert_eq!(nodes_after_cordon.items.len(), num_nodes_before_cordon - 1);
99
100 nodes.uncordon(node_name).await?;
101 let nodes_after_uncordon = nodes.list(&schedulables).await?;
102 assert_eq!(nodes_after_uncordon.items.len(), num_nodes_before_cordon);
103 nodes.delete(node_name, &DeleteParams::default()).await?;
104 Ok(())
105 }
106
107 #[tokio::test]
108 #[ignore = "requires a cluster"]
109 async fn create_token_request() -> Result<(), Box<dyn std::error::Error>> {
110 let client = Client::try_default().await?;
111
112 let serviceaccount_name = "fakesa";
113 let serviceaccount_namespace = "default";
114 let audiences = vec!["api".to_string()];
115
116 let serviceaccounts: Api<ServiceAccount> = Api::namespaced(client.clone(), serviceaccount_namespace);
117 let tokenreviews: Api<TokenReview> = Api::all(client);
118
119 let fake_sa = serde_json::from_value(json!({
121 "apiVersion": "v1",
122 "kind": "ServiceAccount",
123 "metadata": {
124 "name": serviceaccount_name,
125 },
126 }))?;
127 serviceaccounts.create(&PostParams::default(), &fake_sa).await?;
128
129 let tokenrequest = serviceaccounts
131 .create_token_request(serviceaccount_name, &PostParams::default(), &TokenRequest {
132 metadata: Default::default(),
133 spec: TokenRequestSpec {
134 audiences: audiences.clone(),
135 bound_object_ref: None,
136 expiration_seconds: None,
137 },
138 status: None,
139 })
140 .await?;
141 let token = tokenrequest.status.unwrap().token;
142 assert!(!token.is_empty());
143
144 let tokenreview = tokenreviews
146 .create(&PostParams::default(), &TokenReview {
147 metadata: Default::default(),
148 spec: TokenReviewSpec {
149 audiences: Some(audiences.clone()),
150 token: Some(token),
151 },
152 status: None,
153 })
154 .await?;
155 let tokenreviewstatus = tokenreview.status.unwrap();
156 assert_eq!(tokenreviewstatus.audiences, Some(audiences));
157 assert_eq!(tokenreviewstatus.authenticated, Some(true));
158 assert_eq!(tokenreviewstatus.error, None);
159 assert_eq!(
160 tokenreviewstatus.user.unwrap().username,
161 Some(format!(
162 "system:serviceaccount:{serviceaccount_namespace}:{serviceaccount_name}"
163 ))
164 );
165
166 serviceaccounts
168 .delete(serviceaccount_name, &DeleteParams::default())
169 .await?;
170
171 Ok(())
172 }
173}