pub use k8s_openapi::apimachinery::pkg::apis::meta::v1::ObjectMeta;
use k8s_openapi::{api::core::v1::ObjectReference, apimachinery::pkg::apis::meta::v1::OwnerReference};
use std::{borrow::Cow, collections::BTreeMap};
pub trait Resource {
type DynamicType: Send + Sync + 'static;
fn kind(dt: &Self::DynamicType) -> Cow<'_, str>;
fn group(dt: &Self::DynamicType) -> Cow<'_, str>;
fn version(dt: &Self::DynamicType) -> Cow<'_, str>;
fn api_version(dt: &Self::DynamicType) -> Cow<'_, str> {
let group = Self::group(dt);
if group.is_empty() {
return Self::version(dt);
}
let mut group = group.into_owned();
group.push('/');
group.push_str(&Self::version(dt));
group.into()
}
fn plural(dt: &Self::DynamicType) -> Cow<'_, str>;
fn url_path(dt: &Self::DynamicType, namespace: Option<&str>) -> String {
let n = if let Some(ns) = namespace {
format!("namespaces/{}/", ns)
} else {
"".into()
};
let group = Self::group(dt);
let api_version = Self::api_version(dt);
let plural = Self::plural(dt);
format!(
"/{group}/{api_version}/{namespaces}{plural}",
group = if group.is_empty() { "api" } else { "apis" },
api_version = api_version,
namespaces = n,
plural = plural
)
}
fn meta(&self) -> &ObjectMeta;
fn meta_mut(&mut self) -> &mut ObjectMeta;
fn object_ref(&self, dt: &Self::DynamicType) -> ObjectReference {
let meta = self.meta();
ObjectReference {
name: meta.name.clone(),
namespace: meta.namespace.clone(),
uid: meta.uid.clone(),
api_version: Some(Self::api_version(dt).to_string()),
kind: Some(Self::kind(dt).to_string()),
..Default::default()
}
}
}
impl<K> Resource for K
where
K: k8s_openapi::Metadata<Ty = ObjectMeta>,
{
type DynamicType = ();
fn kind(_: &()) -> Cow<'_, str> {
K::KIND.into()
}
fn group(_: &()) -> Cow<'_, str> {
K::GROUP.into()
}
fn version(_: &()) -> Cow<'_, str> {
K::VERSION.into()
}
fn api_version(_: &()) -> Cow<'_, str> {
K::API_VERSION.into()
}
fn plural(_: &()) -> Cow<'_, str> {
K::URL_PATH_SEGMENT.into()
}
fn meta(&self) -> &ObjectMeta {
self.metadata()
}
fn meta_mut(&mut self) -> &mut ObjectMeta {
self.metadata_mut()
}
}
pub trait ResourceExt: Resource {
fn name(&self) -> String;
fn namespace(&self) -> Option<String>;
fn resource_version(&self) -> Option<String>;
fn uid(&self) -> Option<String>;
fn labels(&self) -> &BTreeMap<String, String>;
fn labels_mut(&mut self) -> &mut BTreeMap<String, String>;
fn annotations(&self) -> &BTreeMap<String, String>;
fn annotations_mut(&mut self) -> &mut BTreeMap<String, String>;
fn owner_references(&self) -> &[OwnerReference];
fn owner_references_mut(&mut self) -> &mut Vec<OwnerReference>;
fn finalizers(&self) -> &[String];
fn finalizers_mut(&mut self) -> &mut Vec<String>;
}
use once_cell::sync::Lazy;
static EMPTY_MAP: Lazy<BTreeMap<String, String>> = Lazy::new(BTreeMap::new);
impl<K: Resource> ResourceExt for K {
fn name(&self) -> String {
self.meta().name.clone().expect(".metadata.name missing")
}
fn namespace(&self) -> Option<String> {
self.meta().namespace.clone()
}
fn resource_version(&self) -> Option<String> {
self.meta().resource_version.clone()
}
fn uid(&self) -> Option<String> {
self.meta().uid.clone()
}
fn labels(&self) -> &BTreeMap<String, String> {
self.meta().labels.as_ref().unwrap_or_else(|| &*EMPTY_MAP)
}
fn labels_mut(&mut self) -> &mut BTreeMap<String, String> {
self.meta_mut().labels.get_or_insert_with(BTreeMap::new)
}
fn annotations(&self) -> &BTreeMap<String, String> {
self.meta().annotations.as_ref().unwrap_or_else(|| &*EMPTY_MAP)
}
fn annotations_mut(&mut self) -> &mut BTreeMap<String, String> {
self.meta_mut().annotations.get_or_insert_with(BTreeMap::new)
}
fn owner_references(&self) -> &[OwnerReference] {
self.meta().owner_references.as_deref().unwrap_or_default()
}
fn owner_references_mut(&mut self) -> &mut Vec<OwnerReference> {
self.meta_mut().owner_references.get_or_insert_with(Vec::new)
}
fn finalizers(&self) -> &[String] {
self.meta().finalizers.as_deref().unwrap_or_default()
}
fn finalizers_mut(&mut self) -> &mut Vec<String> {
self.meta_mut().finalizers.get_or_insert_with(Vec::new)
}
}