Added finalizer with empty cleanup

This commit is contained in:
Dreaded_X 2025-03-18 01:13:27 +01:00
parent c63c26137d
commit 87a4749471
Signed by: Dreaded_X
GPG Key ID: FA5F485356B0D2D4
2 changed files with 61 additions and 7 deletions

View File

@ -9,7 +9,7 @@ use kube::{
use lldap_controller::{
context::Context,
lldap::LldapConfig,
resources::{self, ServiceUser},
resources::{self, reconcile, ServiceUser},
};
use tracing::{debug, info, warn};
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry};
@ -44,7 +44,7 @@ async fn main() -> anyhow::Result<()> {
Controller::new(service_users.clone(), Default::default())
.owns(secrets, Default::default())
.shutdown_on_signal()
.run(ServiceUser::reconcile, error_policy, Arc::new(data))
.run(reconcile, error_policy, Arc::new(data))
.for_each(|res| async move {
match res {
Ok(obj) => debug!("reconciled {:?}", obj.0.name),

View File

@ -1,16 +1,21 @@
use core::fmt;
use std::collections::BTreeMap;
use std::str::from_utf8;
use std::sync::Arc;
use std::time::Duration;
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use k8s_openapi::api::core::v1::Secret;
use k8s_openapi::apimachinery::pkg::apis::meta::v1::OwnerReference;
use k8s_openapi::NamespaceResourceScope;
use kube::api::{ObjectMeta, Patch, PatchParams, PostParams};
use kube::runtime::controller::Action;
use kube::{Api, CustomResource, Resource};
use kube::runtime::finalizer;
use kube::{Api, CustomResource, Resource, ResourceExt};
use passwords::PasswordGenerator;
use schemars::JsonSchema;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use serde_json::json;
use tracing::{debug, instrument, trace};
@ -26,10 +31,18 @@ pub enum Error {
Kube(#[from] kube::Error),
#[error("LLDAP error: {0}")]
Lldap(#[from] lldap::Error),
#[error("Finalizer error: {0}")]
Finalizer(#[source] Box<finalizer::Error<Self>>),
#[error("MissingObjectKey: {0}")]
MissingObjectKey(&'static str),
}
impl From<finalizer::Error<Self>> for Error {
fn from(error: finalizer::Error<Self>) -> Self {
Self::Finalizer(Box::new(error))
}
}
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(CustomResource, Deserialize, Serialize, Clone, Debug, JsonSchema)]
@ -84,9 +97,44 @@ fn new_secret(username: &str, oref: OwnerReference) -> Secret {
}
}
impl ServiceUser {
#[instrument(skip(self, ctx))]
pub async fn reconcile(self: Arc<Self>, ctx: Arc<Context>) -> Result<Action> {
#[async_trait]
trait Reconcile {
async fn reconcile(self: Arc<Self>, ctx: Arc<Context>) -> Result<Action>;
async fn cleanup(self: Arc<Self>, ctx: Arc<Context>) -> Result<Action>;
}
#[instrument(skip(obj, ctx))]
pub async fn reconcile<T>(obj: Arc<T>, ctx: Arc<Context>) -> Result<Action>
where
T: Resource<Scope = NamespaceResourceScope>
+ ResourceExt
+ Clone
+ Serialize
+ DeserializeOwned
+ fmt::Debug
+ Reconcile,
<T as Resource>::DynamicType: Default,
{
debug!(name = obj.name_any(), "Reconcile");
let namespace = obj.namespace().expect("Resource is namespace scoped");
let service_users = Api::<T>::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?,
)
}
#[async_trait]
impl Reconcile for ServiceUser {
async fn reconcile(self: Arc<Self>, ctx: Arc<Context>) -> Result<Action> {
let name = self
.metadata
.name
@ -101,7 +149,7 @@ impl ServiceUser {
.controller_owner_ref(&())
.expect("Field should populated by apiserver");
debug!(name, "reconcile request");
debug!(name, "Apply");
let secret_name = format!("{name}-lldap-credentials");
let username = format!("{name}.{namespace}");
@ -172,6 +220,12 @@ impl ServiceUser {
Ok(Action::requeue(Duration::from_secs(3600)))
}
async fn cleanup(self: Arc<Self>, _ctx: Arc<Context>) -> Result<Action> {
debug!(name = self.name_any(), "Cleanup");
Ok(Action::await_change())
}
}
#[cfg(test)]