I have an operator that creates a number of daemonsets which in turn create pods. Lets say operator -> daemonset1 -> pod1_1, operator -> daemonset2 -> {pod2_1,pod2_2}). Now I want to catch whenever one of daemonset2 pods (lets say pod2_1) changes (e.g. creating a new one instead of old one). I read through available docs, including about externally managed resource but I'm having hard times to understand how do I implement this use case. I don’t want to 'watch' all the daemonsets or pods, just pods owned by one particular daemonset in the same namespace with the operator.
The declaration Watches(&source.Kind{Type: &appsv1.DaemonSet{}}
doesn’t quite fit as it watches all pods across all namespaces (please correct me if I’m wrong). Owns(&appsv1.DaemonSet{})
also filters by the type, but not by a particular daemonset instance.
I also tried EnqueueRequestsFromMapFunc
(see golang code snippet below) as suggested in this answer, but it does call the Reconcile for other pods that I don’t need to (see the output below).
func (r *MyTest1Reconciler) SetupWithManager(mgr ctrl.Manager) error {
log.Info("MapFunc ", "a.GetNamespace():", a.GetNamespace(), "a.GetName(): ", a.GetName())
mapFn := handler.MapFunc(
func(a client.Object) []reconcile.Request {
return []reconcile.Request{
{NamespacedName: types.NamespacedName{
Name: a.GetName(),
Namespace: "test",
}},
}
})
p := predicate.Funcs{
//trying to filter out
CreateFunc: func(e event.CreateEvent) bool {
namespace := e.Object.GetNamespace()
name := e.Object.GetName()
ok := ((namespace == "test") && (strings.Contains(name, "pod2")))
return ok
},
}
mgr.GetFieldIndexer().IndexField()
return ctrl.NewControllerManagedBy(mgr).
For(&mytest1v1.MyTest1{}).
Watches(&source.Kind{Type: &appsv1.DaemonSet{}},
handler.EnqueueRequestsFromMapFunc(mapFn),
builder.WithPredicates(p)).
Complete(r)
}
Added debugging logging in the Reconcile to check what objects are in the pod: log.Info("Reconcile: ", "Namespace:", req.Namespace, "Name: ", req.Name)
And found a bunch of requests from alien pods even though the ‘test’ namespace is a new one and ‘kubectl get pods’ lists only those pods that I’ve created:
2022-09-12T02:43:59.735-0700 INFO controller_xcrypt Reconcile: {"Namespace:": "openshift-cluster-csi-drivers", "Name: ": "aws-ebs-csi-driver-node"}
2022-09-12T02:43:59.779-0700 INFO controller_xcrypt MapFunc {"a.GetNamespace():": "openshift-cluster-node-tuning-operator", "a.GetName(): ": "tuned"}
2022-09-12T02:43:59.779-0700 INFO controller_xcrypt MapFunc {"a.GetNamespace():": "openshift-cluster-node-tuning-operator", "a.GetName(): ": "tuned"}
2022-09-12T02:43:59.779-0700 INFO controller_xcrypt Reconcile: {"Namespace:": "openshift-cluster-node-tuning-operator", "Name: ": "tuned"}
2022-09-12T02:43:59.779-0700 INFO controller_xcrypt Reconcile: {"Namespace:": "openshift-cluster-node-tuning-operator", "Name: ": "tuned"}
2022-09-12T02:43:59.884-0700 INFO controller_xcrypt Reconcile: {"Namespace:": "openshift-monitoring", "Name: ": "node-exporter"}
2022-09-12T02:43:59.885-0700 INFO controller_xcrypt Reconcile: {"Namespace:": "openshift-monitoring", "Name: ": "node-exporter"}
2022-09-12T02:43:59.931-0700 INFO controller_xcrypt MapFunc {"a.GetNamespace():": "openshift-image-registry", "a.GetName(): ": "node-ca"}
2022-09-12T02:43:59.931-0700 INFO controller_xcrypt MapFunc {"a.GetNamespace():": "openshift-image-registry", "a.GetName(): ": "node-ca"}
2022-09-12T02:43:59.931-0700 INFO controller_xcrypt Reconcile: {"Namespace:": "openshift-image-registry", "Name: ": "node-ca"}
2022-09-12T02:43:59.931-0700 INFO controller_xcrypt MapFunc {"a.GetNamespace():": "openshift-multus", "a.GetName(): ": "network-metrics-daemon"}
2022-09-12T02:43:59.931-0700 INFO controller_xcrypt MapFunc {"a.GetNamespace():": "openshift-multus", "a.GetName(): ": "network-metrics-daemon"}
2022-09-12T02:43:59.931-0700 INFO controller_xcrypt Reconcile: {"Namespace:": "openshift-multus", "Name: ": "network-metrics-daemon"}
2022-09-12T02:43:59.935-0700 INFO controller_xcrypt MapFunc {"a.GetNamespace():": "openshift-dns", "a.GetName(): ": "node-resolver"}
2022-09-12T02:43:59.935-0700 INFO controller_xcrypt MapFunc {"a.GetNamespace():": "openshift-dns", "a.GetName(): ": "node-resolver"}
i.e. I receive a whole bunch of irrelevant to my case Reconcile requests even from other namespaces. Not sure why each reconcile is called twice BTW.
Most of examples (e.g. this one) that I've come across include narrowing by resource type (e.g. corev1.Pod{}), but not by a particular instance of that type. This question looks similar, but it's not the same as in my case the watched resource is not arbitrary. And the EnqueueRequestsFromMapFunc suggestion doesn't quite work for my use case (see above).
Is there a good way to watch from a k8s operator for a particular instance of resource that is not directly owned by the controller, but owned through a subresource, such as daemonset (watch for pods, that were created by a particular daemonset, that was created by the controller)?