mod service_user; use core::fmt; use std::sync::Arc; use k8s_openapi::NamespaceResourceScope; use kube::runtime::controller::Action; use kube::runtime::finalizer; use kube::{Api, Resource, ResourceExt}; use serde::Serialize; use serde::de::DeserializeOwned; use tracing::{debug, instrument}; pub use self::service_user::ServiceUser; use crate::context::Context; use crate::lldap; #[derive(thiserror::Error, Debug)] pub enum Error { #[error("Failed to commit: {0}")] Commit(#[from] kube::api::entry::CommitError), #[error("Kube api error: {0}")] Kube(#[from] kube::Error), #[error("LLDAP error: {0}")] Lldap(#[from] lldap::Error), #[error("Finalizer error: {0}")] Finalizer(#[source] Box>), #[error("MissingObjectKey: {0}")] MissingObjectKey(&'static str), } impl From> for Error { fn from(error: finalizer::Error) -> Self { Self::Finalizer(Box::new(error)) } } type Result = std::result::Result; trait Reconcile { async fn reconcile(self: Arc, ctx: Arc) -> Result; async fn cleanup(self: Arc, ctx: Arc) -> Result; } #[instrument(skip(obj, ctx))] pub async fn reconcile(obj: Arc, ctx: Arc) -> Result where T: Resource + ResourceExt + Clone + Serialize + DeserializeOwned + fmt::Debug + Reconcile, ::DynamicType: Default, { debug!(name = obj.name_any(), "Reconcile"); let namespace = obj.namespace().expect("Resource is namespace scoped"); let service_users = Api::::namespaced(ctx.client.clone(), &namespace); Ok( finalizer(&service_users, &ctx.controller_name, obj, |event| async { match event { finalizer::Event::Apply(obj) => obj.reconcile(ctx.clone()).await, finalizer::Event::Cleanup(obj) => obj.cleanup(ctx.clone()).await, } }) .await?, ) }