use futures::{
future::try_join_all,
stream::{self, StreamExt},
};
use k8s_openapi::apimachinery::pkg::apis::meta::v1::APIResource;
use kube::Client;
pub struct DiscoverClient {
client: Client,
}
impl DiscoverClient {
pub fn new(client: Client) -> Self {
Self { client }
}
pub async fn list_api_resources(&self) -> anyhow::Result<Vec<APIResource>> {
Ok(self
.list_api_groups_resources()
.await?
.into_iter()
.chain(self.list_core_api_resources().await?)
.filter(|resource| !resource.name.contains("/"))
.collect())
}
pub async fn list_api_groups_resources(&self) -> anyhow::Result<Vec<APIResource>> {
let groups = self.client.list_api_groups().await?.groups;
let resources = stream::iter(groups)
.flat_map(|group| stream::iter(group.versions))
.then(|version| async move {
let mut resources = self
.client
.list_api_group_resources(&version.group_version)
.await?;
for resource in &mut resources.resources {
if let Some((group, version)) = version.group_version.split_once('/') {
resource.group = Some(group.to_string());
resource.version = Some(version.to_string());
}
}
Ok::<_, anyhow::Error>(resources)
})
.flat_map(|api_resource_list| {
stream::iter(api_resource_list.unwrap_or_default().resources)
})
.collect::<Vec<_>>()
.await;
Ok(resources)
}
pub async fn list_core_api_resources(&self) -> anyhow::Result<Vec<APIResource>> {
let versions = self.client.list_core_api_versions().await?.versions;
Ok(try_join_all(versions.into_iter().map(|version| async move {
let mut resources = self.client.list_core_api_resources(&version).await?;
for resource in &mut resources.resources {
resource.group = Some("core".to_string());
resource.version = Some(version.clone());
}
Ok::<_, anyhow::Error>(resources)
}))
.await?
.into_iter()
.flat_map(|api_resource_list| api_resource_list.resources)
.collect())
}
}