use crate::{gvk::GroupVersionKind, resource::Resource};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
pub struct ApiResource {
pub group: String,
pub version: String,
pub api_version: String,
pub kind: String,
pub plural: String,
}
impl ApiResource {
pub fn erase<K: Resource>(dt: &K::DynamicType) -> Self {
ApiResource {
group: K::group(dt).to_string(),
version: K::version(dt).to_string(),
api_version: K::api_version(dt).to_string(),
kind: K::kind(dt).to_string(),
plural: K::plural(dt).to_string(),
}
}
pub fn from_gvk_with_plural(gvk: &GroupVersionKind, plural: &str) -> Self {
ApiResource {
api_version: gvk.api_version(),
group: gvk.group.clone(),
version: gvk.version.clone(),
kind: gvk.kind.clone(),
plural: plural.to_string(),
}
}
pub fn from_gvk(gvk: &GroupVersionKind) -> Self {
ApiResource::from_gvk_with_plural(gvk, &to_plural(&gvk.kind.to_ascii_lowercase()))
}
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
pub enum Scope {
Cluster,
Namespaced,
}
pub mod verbs {
pub const CREATE: &str = "create";
pub const GET: &str = "get";
pub const LIST: &str = "list";
pub const WATCH: &str = "watch";
pub const DELETE: &str = "delete";
pub const DELETE_COLLECTION: &str = "deletecollection";
pub const UPDATE: &str = "update";
pub const PATCH: &str = "patch";
}
#[derive(Debug, Clone)]
pub struct ApiCapabilities {
pub scope: Scope,
pub subresources: Vec<(ApiResource, ApiCapabilities)>,
pub operations: Vec<String>,
}
impl ApiCapabilities {
pub fn supports_operation(&self, operation: &str) -> bool {
self.operations.iter().any(|op| op == operation)
}
}
fn to_plural(word: &str) -> String {
if word == "endpoints" || word == "endpointslices" {
return word.to_owned();
} else if word == "nodemetrics" {
return "nodes".to_owned();
} else if word == "podmetrics" {
return "pods".to_owned();
}
if word.ends_with('s')
|| word.ends_with('x')
|| word.ends_with('z')
|| word.ends_with("ch")
|| word.ends_with("sh")
{
return format!("{word}es");
}
if word.ends_with('y') {
if let Some(c) = word.chars().nth(word.len() - 2) {
if !matches!(c, 'a' | 'e' | 'i' | 'o' | 'u') {
let mut chars = word.chars();
chars.next_back();
return format!("{}ies", chars.as_str());
}
}
}
format!("{word}s")
}
#[test]
fn test_to_plural_native() {
#[rustfmt::skip]
let native_kinds = vec![
("APIService", "apiservices"),
("Binding", "bindings"),
("CertificateSigningRequest", "certificatesigningrequests"),
("ClusterRole", "clusterroles"), ("ClusterRoleBinding", "clusterrolebindings"),
("ComponentStatus", "componentstatuses"),
("ConfigMap", "configmaps"),
("ControllerRevision", "controllerrevisions"),
("CronJob", "cronjobs"),
("CSIDriver", "csidrivers"), ("CSINode", "csinodes"), ("CSIStorageCapacity", "csistoragecapacities"),
("CustomResourceDefinition", "customresourcedefinitions"),
("DaemonSet", "daemonsets"),
("Deployment", "deployments"),
("Endpoints", "endpoints"), ("EndpointSlice", "endpointslices"),
("Event", "events"),
("FlowSchema", "flowschemas"),
("HorizontalPodAutoscaler", "horizontalpodautoscalers"),
("Ingress", "ingresses"), ("IngressClass", "ingressclasses"),
("Job", "jobs"),
("Lease", "leases"),
("LimitRange", "limitranges"),
("LocalSubjectAccessReview", "localsubjectaccessreviews"),
("MutatingWebhookConfiguration", "mutatingwebhookconfigurations"),
("Namespace", "namespaces"),
("NetworkPolicy", "networkpolicies"),
("Node", "nodes"),
("PersistentVolumeClaim", "persistentvolumeclaims"),
("PersistentVolume", "persistentvolumes"),
("PodDisruptionBudget", "poddisruptionbudgets"),
("Pod", "pods"),
("PodSecurityPolicy", "podsecuritypolicies"),
("PodTemplate", "podtemplates"),
("PriorityClass", "priorityclasses"),
("PriorityLevelConfiguration", "prioritylevelconfigurations"),
("ReplicaSet", "replicasets"),
("ReplicationController", "replicationcontrollers"),
("ResourceQuota", "resourcequotas"),
("Role", "roles"), ("RoleBinding", "rolebindings"),
("RuntimeClass", "runtimeclasses"),
("Secret", "secrets"),
("SelfSubjectAccessReview", "selfsubjectaccessreviews"),
("SelfSubjectRulesReview", "selfsubjectrulesreviews"),
("ServiceAccount", "serviceaccounts"),
("Service", "services"),
("StatefulSet", "statefulsets"),
("StorageClass", "storageclasses"), ("StorageVersion", "storageversions"),
("SubjectAccessReview", "subjectaccessreviews"),
("TokenReview", "tokenreviews"),
("ValidatingWebhookConfiguration", "validatingwebhookconfigurations"),
("VolumeAttachment", "volumeattachments"),
];
for (kind, plural) in native_kinds {
assert_eq!(to_plural(&kind.to_ascii_lowercase()), plural);
}
}