-
Hi all, triedI tried the following code: func (r *SealedSecretRootKeyMonitorReconciler) SetupWithManager(mgr ctrl.Manager) error {
filterCR := predicate.Funcs{ // filter out delete events for the CR
DeleteFunc: func(e event.DeleteEvent) bool {
return false
},
}
filterSecrets := predicate.Funcs{ // filter out secrets that do not have my label key
UpdateFunc: func(e event.UpdateEvent) bool {
return labels.Set(e.ObjectOld.GetLabels()).Has("mylabelkey")
},
}
return ctrl.NewControllerManagedBy(mgr).
For(&v1alpha1.SealedSecretRootKeyMonitor{}, builder.WithPredicates(predicate.Or(predicate.GenerationChangedPredicate{}), filterCR)). // NOTE this is very important to avoid update reconciles on status change! https://groups.google.com/g/operator-framework/c/ouiOSoebALw/m/RjEeleEjAgAJ
For(&corev1.Secret{}, builder.WithPredicates(predicate.Or(predicate.GenerationChangedPredicate{}, predicate.AnnotationChangedPredicate{}), filterSecrets)).
Complete(r)
} result error Unexpected error:
<*errors.errorString | 0xc000446290>: {
s: "For(...) should only be called once, could not assign multiple objects for reconciliation",
}
For(...) should only be called once, could not assign multiple objects for reconciliation
occurred But I need several objects for reconciliation? Thanks in advance! |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments
-
Okay after some research I think I got the right track from https://book.kubebuilder.io/reference/watching-resources/externally-managed.html Changing the manager from For to Watch and additionally appending an owner to the secrets on CR reconcile should do the trick. return ctrl.NewControllerManagedBy(mgr).
For(&v1alpha1.SealedSecretRootKeyMonitor{}, builder.WithPredicates(predicate.Or(predicate.GenerationChangedPredicate{}), filterCR)). // NOTE this is very important to avoid update reconciles on status change! https://groups.google.com/g/operator-framework/c/ouiOSoebALw/m/RjEeleEjAgAJ
Watches(
&source.Kind{Type: &corev1.Secret{}},
&handler.EnqueueRequestForOwner{
OwnerType: &v1alpha1.SealedSecretRootKeyMonitor{},
IsController: false,
},
builder.WithPredicates(predicate.Or(predicate.GenerationChangedPredicate{}, predicate.AnnotationChangedPredicate{}), filterSecrets)).
Complete(r) Will test it and post back here |
Beta Was this translation helpful? Give feedback.
-
Found the solution and going to post it here for the future: Trigger operator custom resource reconcile by not owned kubernetes secret: How to setup the Managerfunc (r *SealedSecretRootKeyMonitorReconciler) SetupWithManager(mgr ctrl.Manager) error {
controller := &v1alpha1.SealedSecretRootKeyMonitor{}
// filter the CR events
filterCR := predicate.Funcs{
DeleteFunc: func(e event.DeleteEvent) bool {
return false
},
}
// mapping handler to map secret to cr
mappingHandler := handler.EnqueueRequestsFromMapFunc(r.reconcileCRViaSecret) // mapper function below
// filter the Secret Events
filterBitnamiRootSecrets := predicate.Funcs{
DeleteFunc: func(e event.DeleteEvent) bool {
return labels.Set(e.Object.GetLabels()).Has("sealedsecrets.bitnami.com/sealed-secrets-key")
},
UpdateFunc: func(e event.UpdateEvent) bool {
return labels.Set(e.ObjectOld.GetLabels()).Has("sealedsecrets.bitnami.com/sealed-secrets-key")
},
CreateFunc: func(e event.CreateEvent) bool {
if labels.Set(e.Object.GetLabels()).Has("sealed-secret-backup.unified-provisioning/fromBackup") {
return false
}
return labels.Set(e.Object.GetLabels()).Has("sealedsecrets.bitnami.com/sealed-secrets-key")
},
GenericFunc: func(e event.GenericEvent) bool {
return false
},
}
// create manager (set predicates on creation function to avoid global filtering
return ctrl.NewControllerManagedBy(mgr).
For(controller, builder.WithPredicates(predicate.GenerationChangedPredicate{}, filterCR)).
Watches(
&source.Kind{Type: &corev1.Secret{}},
mappingHandler,
builder.WithPredicates(predicate.GenerationChangedPredicate{}, filterBitnamiRootSecrets)).
Complete(r)
} How to map Secrets to trigger our CRs// use mapping function to trigger CR reconcile from Secret not owned by our Operator
func (r *SealedSecretRootKeyMonitorReconciler) reconcileCRViaSecret(secret client.Object) []reconcile.Request {
crList := &v1alpha1.SealedSecretRootKeyMonitorList{}
// labels we use to retrieve relevant CRs (in our case its static usually you would retrieve this info from a label from the secret that fires the event for example or another way similar)
crListOptions := []client.ListOption{
client.MatchingLabels(map[string]string{"app": "SealedSecretRootKeyMonitor"}),
}
err := r.List(context.TODO(), crList, crListOptions...)
if err != nil {
fmt.Println("error retrieving cr's ", reflect.TypeOf(crList), err)
return []reconcile.Request{}
}
// retrigger reconcile for all CRs we retrieved
requests := make([]reconcile.Request, len(crList.Items))
for i, item := range crList.Items {
requests[i] = reconcile.Request{
NamespacedName: types.NamespacedName{
Name: item.GetName(),
Namespace: item.GetNamespace(),
},
}
}
return requests
} |
Beta Was this translation helpful? Give feedback.
-
Closing since it is answered. |
Beta Was this translation helpful? Give feedback.
Found the solution and going to post it here for the future:
Trigger operator custom resource reconcile by not owned kubernetes secret:
How to setup the Manager