@@ -20,6 +20,7 @@ import (
2020 "context"
2121 "fmt"
2222 "sync"
23+ "time"
2324
2425 "github.com/go-logr/logr"
2526 corev1 "k8s.io/api/core/v1"
@@ -33,7 +34,6 @@ import (
3334 "k8s.io/client-go/restmapper"
3435 "k8s.io/client-go/tools/cache"
3536 "k8s.io/client-go/util/retry"
36- "sigs.k8s.io/cluster-api/util"
3737 "sigs.k8s.io/controller-runtime/pkg/client"
3838
3939 configv1beta1 "github.com/projectsveltos/addon-controller/api/v1beta1"
@@ -75,8 +75,11 @@ type manager struct {
7575 // Those resources' values will be used to instantiate templates contained in referenced
7676 requestorForTemplateResourceRefs map [schema.GroupVersionKind ]* libsveltosset.Set
7777
78- // key: resource being watched, value: list of ClusterSummary interested in this resource
78+ // key: resource being watched, value: list of ClusterSummary interested in ALL changes (including status)
7979 templateResourceRefsWatched map [corev1.ObjectReference ]* libsveltosset.Set
80+
81+ // key: resource being watched, value: list of ClusterSummary interested ONLY in spec/metadata changes
82+ templateResourceRefsWatchedIgnoreStatus map [corev1.ObjectReference ]* libsveltosset.Set
8083}
8184
8285// initializeManager initializes a manager implementing the Watchers
@@ -95,6 +98,7 @@ func initializeManager(l logr.Logger, config *rest.Config, c client.Client) {
9598 managerInstance .mgmtResourcesWatchedKustomizeRef = make (map [corev1.ObjectReference ]* libsveltosset.Set )
9699 managerInstance .mgmtResourcesWatchedPolicyRef = make (map [corev1.ObjectReference ]* libsveltosset.Set )
97100 managerInstance .templateResourceRefsWatched = make (map [corev1.ObjectReference ]* libsveltosset.Set )
101+ managerInstance .templateResourceRefsWatchedIgnoreStatus = make (map [corev1.ObjectReference ]* libsveltosset.Set )
98102 }
99103 }
100104}
@@ -140,7 +144,8 @@ func (m *manager) startWatcherForMgmtResource(ctx context.Context, gvk schema.Gr
140144
141145// startWatcherForTemplateResourceRef starts a watcher if one does not exist already
142146// ClusterSummary is listed as one of the consumer for this watcher.
143- // ClusterSummary will only receive updates when the specific resource itself changes, not when other resources of the same type change.
147+ // ClusterSummary will only receive updates when the specific resource itself changes,
148+ // not when other resources of the same type change.
144149func (m * manager ) startWatcherForTemplateResourceRef (ctx context.Context , gvk schema.GroupVersionKind ,
145150 ref * configv1beta1.TemplateResourceRef , clusterSummary * configv1beta1.ClusterSummary ) error {
146151
@@ -184,12 +189,29 @@ func (m *manager) startWatcherForTemplateResourceRef(ctx context.Context, gvk sc
184189
185190 m .requestorForTemplateResourceRefs [gvk ].Insert (consumer )
186191
187- if _ , ok := m .templateResourceRefsWatched [resource ]; ! ok {
188- s := & libsveltosset.Set {}
189- m .templateResourceRefsWatched [resource ] = s
190- }
192+ if ref .IgnoreStatusChanges {
193+ // Ensure it's NOT in the "All Changes" bucket
194+ if m .templateResourceRefsWatched [resource ] != nil {
195+ m .templateResourceRefsWatched [resource ].Erase (consumer )
196+ }
197+
198+ // Add to "Ignore Status" bucket
199+ if _ , ok := m .templateResourceRefsWatchedIgnoreStatus [resource ]; ! ok {
200+ m .templateResourceRefsWatchedIgnoreStatus [resource ] = & libsveltosset.Set {}
201+ }
202+ m .templateResourceRefsWatchedIgnoreStatus [resource ].Insert (consumer )
203+ } else {
204+ // Ensure it's NOT in the "Ignore Status" bucket
205+ if m .templateResourceRefsWatchedIgnoreStatus [resource ] != nil {
206+ m .templateResourceRefsWatchedIgnoreStatus [resource ].Erase (consumer )
207+ }
191208
192- m .templateResourceRefsWatched [resource ].Insert (consumer )
209+ // Add to "All Changes" bucket
210+ if _ , ok := m .templateResourceRefsWatched [resource ]; ! ok {
211+ m .templateResourceRefsWatched [resource ] = & libsveltosset.Set {}
212+ }
213+ m .templateResourceRefsWatched [resource ].Insert (consumer )
214+ }
193215
194216 return nil
195217}
@@ -314,14 +336,25 @@ func (m *manager) stopStaleWatchForTemplateResourceRef(ctx context.Context,
314336 }
315337 }
316338
317- for resource := range m .templateResourceRefsWatched {
339+ // Clean up the "All Changes" bucket
340+ for resource , set := range m .templateResourceRefsWatched {
318341 if _ , ok := currentResources [resource ]; ! ok {
319- m . templateResourceRefsWatched [ resource ] .Erase (consumer )
320- if m . templateResourceRefsWatched [ resource ] .Len () == 0 {
342+ set .Erase (consumer )
343+ if set .Len () == 0 {
321344 delete (m .templateResourceRefsWatched , resource )
322345 }
323346 }
324347 }
348+
349+ // Clean up the "Ignore Status" bucket
350+ for resource , set := range m .templateResourceRefsWatchedIgnoreStatus {
351+ if _ , ok := currentResources [resource ]; ! ok {
352+ set .Erase (consumer )
353+ if set .Len () == 0 {
354+ delete (m .templateResourceRefsWatchedIgnoreStatus , resource )
355+ }
356+ }
357+ }
325358}
326359
327360func (m * manager ) startWatcher (ctx context.Context , gvk * schema.GroupVersionKind ) error {
@@ -389,13 +422,13 @@ func (m *manager) runInformer(stopCh <-chan struct{}, s cache.SharedIndexInforme
389422
390423 handlers := cache.ResourceEventHandlerFuncs {
391424 AddFunc : func (obj interface {}) {
392- m .react (obj .(client.Object ), logger )
425+ m .react (nil , obj .(client.Object ), logger )
393426 },
394427 DeleteFunc : func (obj interface {}) {
395- m .react (obj .(client.Object ), logger )
428+ m .react (nil , obj .(client.Object ), logger )
396429 },
397430 UpdateFunc : func (oldObj , newObj interface {}) {
398- m .react (newObj .(client.Object ), logger )
431+ m .react (oldObj .(client. Object ), newObj .(client.Object ), logger )
399432 },
400433 }
401434 _ , err := s .AddEventHandler (handlers )
@@ -406,15 +439,15 @@ func (m *manager) runInformer(stopCh <-chan struct{}, s cache.SharedIndexInforme
406439}
407440
408441// react gets called when an instance of passed in gvk has been modified.
409- func (m * manager ) react (obj client.Object , logger logr.Logger ) {
442+ func (m * manager ) react (oldObj , newObj client.Object , logger logr.Logger ) {
410443 m .watchMu .RLock ()
411444 defer m .watchMu .RUnlock ()
412445
413446 ref := corev1.ObjectReference {
414- Kind : obj .GetObjectKind ().GroupVersionKind ().Kind ,
415- APIVersion : obj .GetObjectKind ().GroupVersionKind ().GroupVersion ().String (),
416- Namespace : obj .GetNamespace (),
417- Name : obj .GetName (),
447+ Kind : newObj .GetObjectKind ().GroupVersionKind ().Kind ,
448+ APIVersion : newObj .GetObjectKind ().GroupVersionKind ().GroupVersion ().String (),
449+ Namespace : newObj .GetNamespace (),
450+ Name : newObj .GetName (),
418451 }
419452
420453 logger = logger .WithValues ("resource" , fmt .Sprintf ("%s/%s" , ref .Namespace , ref .Name ))
@@ -432,10 +465,23 @@ func (m *manager) react(obj client.Object, logger logr.Logger) {
432465 }
433466
434467 // finds all ClusterSummary objects that want to be informed about updates to this specific resource.
435- // It takes into account registrations made through TemplateResourceRefs
468+ // It takes into account registrations made through TemplateResourceRefs.
469+ // Consumers interested in ALL changes
436470 if v , ok := m .templateResourceRefsWatched [ref ]; ok {
437471 m .notify (v , logger )
438472 }
473+
474+ // finds all ClusterSummary objects that want to be informed about updates to this specific resource.
475+ // It takes into account registrations made through TemplateResourceRefs.
476+ // Consumers ignoring Status changes
477+ if v , ok := m .templateResourceRefsWatchedIgnoreStatus [ref ]; ok {
478+ // - Or the Generation has increased (Spec/Metadata change)
479+ if oldObj == nil || oldObj .GetGeneration () != newObj .GetGeneration () {
480+ m .notify (v , logger )
481+ } else {
482+ logger .V (logs .LogDebug ).Info ("skipping notification: only status changed" )
483+ }
484+ }
439485}
440486
441487func (m * manager ) notify (consumers * libsveltosset.Set , logger logr.Logger ) {
@@ -460,12 +506,12 @@ func (m *manager) notifyConsumer(consumer *corev1.ObjectReference) {
460506
461507 m .log .V (logs .LogInfo ).Info (fmt .Sprintf ("requeuing ClusterSummary %s/%s" ,
462508 currentRequestor .Namespace , currentRequestor .Name ))
463- // reset hash
464- for i := range currentRequestor .Status .FeatureSummaries {
465- const length = 20
466- currentRequestor .Status .FeatureSummaries [i ].Hash = []byte (util .RandomString (length ))
509+ // reset annotation. This will cause a new reconciliation to happen
510+ if currentRequestor .Annotations == nil {
511+ currentRequestor .Annotations = map [string ]string {}
467512 }
468- return m .Status ().Update (context .TODO (), currentRequestor )
513+ currentRequestor .Annotations [retriggerAnnotation ] = time .Now ().UTC ().Format (time .RFC3339Nano )
514+ return m .Update (context .TODO (), currentRequestor )
469515 })
470516 if err != nil {
471517 // TODO: if this fails, there is no way to reconcile the ClusterSummary
0 commit comments