Skip to content

Commit

Permalink
Implement Api fns for arbitrary subresources and approval subresource…
Browse files Browse the repository at this point in the history
… for Api<CertificateSigningRequest> (#773)

* Implement CertificateSigningRequest/approve

Signed-off-by: ChinYing-Li <[email protected]>

* Implement Api<CertificateSigningRequest>.deny

Signed-off-by: ChinYing-Li <[email protected]>

* Remove unnecessary use statements in test

Signed-off-by: ChinYing-Li <[email protected]>

* Add patch_approval to Api<CertificateSigningRequest>

Signed-off-by: ChinYing-Li <[email protected]>

* Format the code

Signed-off-by: ChinYing-Li <[email protected]>

* Follow the convention in fn patch_approval

Signed-off-by: ChinYing-Li <[email protected]>

* Add Api<CertificateSigningRequest>::get_approval

Signed-off-by: ChinYing-Li <[email protected]>

* Implement Api<CertificateSigningRequest>::get_approval

Signed-off-by: ChinYing-Li <[email protected]>

* Test Api<CertificateSigningRequest>::get_approval in integration test

Signed-off-by: ChinYing-Li <[email protected]>
  • Loading branch information
ChinYing-Li authored Jan 9, 2022
1 parent 4d991fe commit f076f61
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 2 deletions.
48 changes: 48 additions & 0 deletions kube-client/src/api/subresource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,54 @@ where
}
}

/// Arbitrary subresources
impl<K> Api<K>
where
K: Clone + DeserializeOwned + Debug,
{
/// Display one or many sub-resources.
pub async fn get_subresource(&self, subresource_name: &str, name: &str) -> Result<K> {
let mut req = self
.request
.get_subresource(subresource_name, name)
.map_err(Error::BuildRequest)?;
req.extensions_mut().insert("get_subresource");
self.client.request::<K>(req).await
}

/// Patch an instance of the subresource
pub async fn patch_subresource<P: serde::Serialize + Debug>(
&self,
subresource_name: &str,
name: &str,
pp: &PatchParams,
patch: &Patch<P>,
) -> Result<K> {
let mut req = self
.request
.patch_subresource(subresource_name, name, pp, patch)
.map_err(Error::BuildRequest)?;
req.extensions_mut().insert("patch_subresource");
self.client.request::<K>(req).await
}

/// Replace an instance of the subresource
pub async fn replace_subresource(
&self,
subresource_name: &str,
name: &str,
pp: &PostParams,
data: Vec<u8>,
) -> Result<K> {
let mut req = self
.request
.replace_subresource(subresource_name, name, pp, data)
.map_err(Error::BuildRequest)?;
req.extensions_mut().insert("replace_subresource");
self.client.request::<K>(req).await
}
}

// ----------------------------------------------------------------------------

// TODO: Replace examples with owned custom resources. Bad practice to write to owned objects
Expand Down
29 changes: 27 additions & 2 deletions kube-client/src/api/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ use crate::{
api::{Api, Resource},
Error, Result,
};
use k8s_openapi::api::core::v1::Node;
use kube_core::util::Restart;
use k8s_openapi::api::{certificates::v1::CertificateSigningRequest, core::v1::Node};
use kube_core::{
params::{Patch, PatchParams},
util::Restart,
};
use serde::de::DeserializeOwned;

impl<K> Api<K>
Expand Down Expand Up @@ -34,6 +37,28 @@ impl Api<Node> {
}
}

impl Api<CertificateSigningRequest> {
/// Partially update approval of the specified CertificateSigningRequest.
pub async fn patch_approval<P: serde::Serialize>(
&self,
name: &str,
pp: &PatchParams,
patch: &Patch<P>,
) -> Result<CertificateSigningRequest> {
let mut req = self
.request
.patch_subresource("approval", name, pp, patch)
.map_err(Error::BuildRequest)?;
req.extensions_mut().insert("approval");
self.client.request::<CertificateSigningRequest>(req).await
}

/// Get the CertificateSigningRequest. May differ from get(name)
pub async fn get_approval(&self, name: &str) -> Result<CertificateSigningRequest> {
self.get_subresource("approval", name).await
}
}

// Tests that require a cluster and the complete feature set
// Can be run with `cargo test -p kube-client --lib -- --ignored`
#[cfg(test)]
Expand Down
60 changes: 60 additions & 0 deletions kube-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ mod test {
};
use futures::{StreamExt, TryStreamExt};
use k8s_openapi::api::core::v1::Pod;
use kube_core::params::{DeleteParams, Patch};
use serde_json::json;
use tower::ServiceBuilder;

Expand Down Expand Up @@ -462,4 +463,63 @@ mod test {

Ok(())
}

#[tokio::test]
#[ignore] // needs cluster (will create a CertificateSigningRequest)
async fn csr_can_be_approved() -> Result<(), Box<dyn std::error::Error>> {
use crate::api::PostParams;
use k8s_openapi::api::certificates::v1::{
CertificateSigningRequest, CertificateSigningRequestCondition, CertificateSigningRequestStatus,
};

let csr_name = "fake";
let dummy_csr: CertificateSigningRequest = serde_json::from_value(json!({
"apiVersion": "certificates.k8s.io/v1",
"kind": "CertificateSigningRequest",
"metadata": { "name": csr_name },
"spec": {
"request": "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ1ZqQ0NBVDRDQVFBd0VURVBNQTBHQTFVRUF3d0dZVzVuWld4aE1JSUJJakFOQmdrcWhraUc5dzBCQVFFRgpBQU9DQVE4QU1JSUJDZ0tDQVFFQTByczhJTHRHdTYxakx2dHhWTTJSVlRWMDNHWlJTWWw0dWluVWo4RElaWjBOCnR2MUZtRVFSd3VoaUZsOFEzcWl0Qm0wMUFSMkNJVXBGd2ZzSjZ4MXF3ckJzVkhZbGlBNVhwRVpZM3ExcGswSDQKM3Z3aGJlK1o2MVNrVHF5SVBYUUwrTWM5T1Nsbm0xb0R2N0NtSkZNMUlMRVI3QTVGZnZKOEdFRjJ6dHBoaUlFMwpub1dtdHNZb3JuT2wzc2lHQ2ZGZzR4Zmd4eW8ybmlneFNVekl1bXNnVm9PM2ttT0x1RVF6cXpkakJ3TFJXbWlECklmMXBMWnoyalVnald4UkhCM1gyWnVVV1d1T09PZnpXM01LaE8ybHEvZi9DdS8wYk83c0x0MCt3U2ZMSU91TFcKcW90blZtRmxMMytqTy82WDNDKzBERHk5aUtwbXJjVDBnWGZLemE1dHJRSURBUUFCb0FBd0RRWUpLb1pJaHZjTgpBUUVMQlFBRGdnRUJBR05WdmVIOGR4ZzNvK21VeVRkbmFjVmQ1N24zSkExdnZEU1JWREkyQTZ1eXN3ZFp1L1BVCkkwZXpZWFV0RVNnSk1IRmQycVVNMjNuNVJsSXJ3R0xuUXFISUh5VStWWHhsdnZsRnpNOVpEWllSTmU3QlJvYXgKQVlEdUI5STZXT3FYbkFvczFqRmxNUG5NbFpqdU5kSGxpT1BjTU1oNndLaTZzZFhpVStHYTJ2RUVLY01jSVUyRgpvU2djUWdMYTk0aEpacGk3ZnNMdm1OQUxoT045UHdNMGM1dVJVejV4T0dGMUtCbWRSeEgvbUNOS2JKYjFRQm1HCkkwYitEUEdaTktXTU0xMzhIQXdoV0tkNjVoVHdYOWl4V3ZHMkh4TG1WQzg0L1BHT0tWQW9FNkpsYWFHdTlQVmkKdjlOSjVaZlZrcXdCd0hKbzZXdk9xVlA3SVFjZmg3d0drWm89Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=",
"signerName": "kubernetes.io/kube-apiserver-client",
"expirationSeconds": 86400,
"usages": ["client auth"]
}
}))?;

let client = Client::try_default().await?;
let csr: Api<CertificateSigningRequest> = Api::all(client.clone());
assert!(csr.create(&PostParams::default(), &dummy_csr).await.is_ok());

// Patch the approval and approve the CSR
let approval_type = "ApprovedFake";
let csr_status: CertificateSigningRequestStatus = CertificateSigningRequestStatus {
certificate: None,
conditions: Some(vec![CertificateSigningRequestCondition {
type_: approval_type.to_string(),
last_update_time: None,
last_transition_time: None,
message: Some(format!("{} {}", approval_type, "by kube-rs client")),
reason: Some("kube-rsClient".to_string()),
status: "True".to_string(),
}]),
};
let csr_status_patch = Patch::Merge(serde_json::json!({ "status": csr_status }));
let _ = csr
.patch_approval(csr_name, &Default::default(), &csr_status_patch)
.await?;
let csr_after_approval = csr.get_approval(csr_name).await?;

assert_eq!(
csr_after_approval
.status
.as_ref()
.unwrap()
.conditions
.as_ref()
.unwrap()[0]
.type_,
approval_type.to_string()
);
csr.delete(csr_name, &DeleteParams::default()).await?;
Ok(())
}
}

0 comments on commit f076f61

Please sign in to comment.