1

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)?

David Maze
  • 130,717
  • 29
  • 175
  • 215
Victor Kim
  • 1,647
  • 2
  • 16
  • 33

1 Answers1

0

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.

Operator watches objects which are created by it based on the scope value defined in its CRD. If the scope is defined as "Cluster" then it will watch all the namespaces. If the scope is defined as "Namespaced" then it will watch object only in a particular namespace. Please refer CRD documentation for more details

# either Namespaced or Cluster
  scope: Namespaced

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

For above requirement its taken cared by kubernetes controller for ex: pod getting creating automatically for daemonset or deployment if its desired state is not matching.

Nataraj Medayhal
  • 980
  • 1
  • 2
  • 12