Skip to main content

rws_k8s/k8s/
mod.rs

1//! Kubernetes integration and an operator framework (`k8s` feature,
2//! 18.35.0), on [kube-rs](https://kube.rs):
3//!
4//! | Module | What |
5//! |---|---|
6//! | [`client`] | A client: in a pod its service account, else `KUBECONFIG` / `~/.kube/config` |
7//! | [`leader`] | [`LeaderElector`](leader::LeaderElector): one replica does the work, over a `Lease` |
8//! | [`config`] | ConfigMaps and Secrets watched live; `k8s://` secret references |
9//! | [`discovery`] | A Service's ready endpoints (EndpointSlices) as a `BackendPool` |
10//! | [`controller`] | Controllers: watch, reconcile, requeue, finalizers, status |
11//! | [`webhook`] | Admission (validating, mutating) and conversion webhooks, with their TLS certificate |
12//! | [`manifests`] | CRDs from Rust types, RBAC, webhook configurations, as YAML-compatible JSON |
13//! | [`testing`] | Tests against a real API server: a throwaway namespace per test |
14//!
15//! `kube`, `k8s_openapi` and `schemars` are re-exported for the types they
16//! define (`kube::CustomResource`, `k8s_openapi::api::core::v1::Pod`, …).
17
18pub use k8s_openapi;
19pub use kube;
20#[cfg(feature = "k8s")]
21pub use schemars;
22
23pub mod client;
24pub mod leader;
25#[cfg(feature = "k8s")]
26pub mod config;
27#[cfg(feature = "k8s")]
28pub mod controller;
29#[cfg(feature = "k8s")]
30pub mod discovery;
31#[cfg(feature = "k8s")]
32pub mod manifests;
33#[cfg(feature = "k8s")]
34pub mod testing;
35#[cfg(feature = "k8s")]
36pub mod webhook;
37
38/// One error type for the module: kube's errors and our own messages.
39#[derive(Debug)]
40pub enum Error {
41    Kube(kube::Error),
42    Other(String),
43}
44
45impl std::fmt::Display for Error {
46    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47        match self {
48            Error::Kube(e) => write!(f, "{e}"),
49            Error::Other(e) => f.write_str(e),
50        }
51    }
52}
53
54impl std::error::Error for Error {}
55
56impl From<kube::Error> for Error {
57    fn from(e: kube::Error) -> Self {
58        Error::Kube(e)
59    }
60}
61
62impl From<String> for Error {
63    fn from(e: String) -> Self {
64        Error::Other(e)
65    }
66}
67
68impl From<&str> for Error {
69    fn from(e: &str) -> Self {
70        Error::Other(e.to_string())
71    }
72}
73
74pub type Result<T, E = Error> = std::result::Result<T, E>;
75
76/// An `Api` for a kind whatever its scope: namespaced kinds in a namespace
77/// (or across all), cluster-wide kinds everywhere. Implemented for
78/// k8s-openapi's two scope types.
79pub trait Scope {
80    fn api<K: kube::Resource<Scope = Self, DynamicType = ()>>(client: kube::Client, namespace: Option<&str>) -> kube::Api<K>;
81}
82
83impl Scope for k8s_openapi::NamespaceResourceScope {
84    fn api<K: kube::Resource<Scope = Self, DynamicType = ()>>(client: kube::Client, namespace: Option<&str>) -> kube::Api<K> {
85        match namespace {
86            Some(ns) => kube::Api::namespaced(client, ns),
87            None => kube::Api::all(client),
88        }
89    }
90}
91
92impl Scope for k8s_openapi::ClusterResourceScope {
93    fn api<K: kube::Resource<Scope = Self, DynamicType = ()>>(client: kube::Client, _namespace: Option<&str>) -> kube::Api<K> {
94        kube::Api::all(client)
95    }
96}
97
98/// The `Api` for `obj`'s kind, in its namespace when it has one.
99pub fn api_for<K>(client: &kube::Client, obj: &K) -> kube::Api<K>
100where
101    K: kube::Resource<DynamicType = ()>,
102    K::Scope: Scope,
103{
104    <K::Scope as Scope>::api::<K>(client.clone(), obj.meta().namespace.as_deref())
105}