Added finalizer with empty cleanup
This commit is contained in:
parent
c63c26137d
commit
87a4749471
|
@ -9,7 +9,7 @@ use kube::{
|
||||||
use lldap_controller::{
|
use lldap_controller::{
|
||||||
context::Context,
|
context::Context,
|
||||||
lldap::LldapConfig,
|
lldap::LldapConfig,
|
||||||
resources::{self, ServiceUser},
|
resources::{self, reconcile, ServiceUser},
|
||||||
};
|
};
|
||||||
use tracing::{debug, info, warn};
|
use tracing::{debug, info, warn};
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry};
|
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())
|
Controller::new(service_users.clone(), Default::default())
|
||||||
.owns(secrets, Default::default())
|
.owns(secrets, Default::default())
|
||||||
.shutdown_on_signal()
|
.shutdown_on_signal()
|
||||||
.run(ServiceUser::reconcile, error_policy, Arc::new(data))
|
.run(reconcile, error_policy, Arc::new(data))
|
||||||
.for_each(|res| async move {
|
.for_each(|res| async move {
|
||||||
match res {
|
match res {
|
||||||
Ok(obj) => debug!("reconciled {:?}", obj.0.name),
|
Ok(obj) => debug!("reconciled {:?}", obj.0.name),
|
||||||
|
|
|
@ -1,16 +1,21 @@
|
||||||
|
use core::fmt;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::str::from_utf8;
|
use std::str::from_utf8;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use k8s_openapi::api::core::v1::Secret;
|
use k8s_openapi::api::core::v1::Secret;
|
||||||
use k8s_openapi::apimachinery::pkg::apis::meta::v1::OwnerReference;
|
use k8s_openapi::apimachinery::pkg::apis::meta::v1::OwnerReference;
|
||||||
|
use k8s_openapi::NamespaceResourceScope;
|
||||||
use kube::api::{ObjectMeta, Patch, PatchParams, PostParams};
|
use kube::api::{ObjectMeta, Patch, PatchParams, PostParams};
|
||||||
use kube::runtime::controller::Action;
|
use kube::runtime::controller::Action;
|
||||||
use kube::{Api, CustomResource, Resource};
|
use kube::runtime::finalizer;
|
||||||
|
use kube::{Api, CustomResource, Resource, ResourceExt};
|
||||||
use passwords::PasswordGenerator;
|
use passwords::PasswordGenerator;
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use tracing::{debug, instrument, trace};
|
use tracing::{debug, instrument, trace};
|
||||||
|
@ -26,10 +31,18 @@ pub enum Error {
|
||||||
Kube(#[from] kube::Error),
|
Kube(#[from] kube::Error),
|
||||||
#[error("LLDAP error: {0}")]
|
#[error("LLDAP error: {0}")]
|
||||||
Lldap(#[from] lldap::Error),
|
Lldap(#[from] lldap::Error),
|
||||||
|
#[error("Finalizer error: {0}")]
|
||||||
|
Finalizer(#[source] Box<finalizer::Error<Self>>),
|
||||||
#[error("MissingObjectKey: {0}")]
|
#[error("MissingObjectKey: {0}")]
|
||||||
MissingObjectKey(&'static str),
|
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>;
|
pub type Result<T, E = Error> = std::result::Result<T, E>;
|
||||||
|
|
||||||
#[derive(CustomResource, Deserialize, Serialize, Clone, Debug, JsonSchema)]
|
#[derive(CustomResource, Deserialize, Serialize, Clone, Debug, JsonSchema)]
|
||||||
|
@ -84,9 +97,44 @@ fn new_secret(username: &str, oref: OwnerReference) -> Secret {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServiceUser {
|
#[async_trait]
|
||||||
#[instrument(skip(self, ctx))]
|
trait Reconcile {
|
||||||
pub async fn reconcile(self: Arc<Self>, ctx: Arc<Context>) -> Result<Action> {
|
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
|
let name = self
|
||||||
.metadata
|
.metadata
|
||||||
.name
|
.name
|
||||||
|
@ -101,7 +149,7 @@ impl ServiceUser {
|
||||||
.controller_owner_ref(&())
|
.controller_owner_ref(&())
|
||||||
.expect("Field should populated by apiserver");
|
.expect("Field should populated by apiserver");
|
||||||
|
|
||||||
debug!(name, "reconcile request");
|
debug!(name, "Apply");
|
||||||
|
|
||||||
let secret_name = format!("{name}-lldap-credentials");
|
let secret_name = format!("{name}-lldap-credentials");
|
||||||
let username = format!("{name}.{namespace}");
|
let username = format!("{name}.{namespace}");
|
||||||
|
@ -172,6 +220,12 @@ impl ServiceUser {
|
||||||
|
|
||||||
Ok(Action::requeue(Duration::from_secs(3600)))
|
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)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user