Skip to content

Commit 0c03e0c

Browse files
committed
config: add ignored fields
Specify fields to skip sending object update. Will be applied to all objects. If after removal of these fields from k8s object all remaining fields will be equal, handler won't trigger sending update. Removing array elements is not supported. For example, ```yaml ignorefields: status: metadata: resourceVersion: managedFields: ``` will remove ".status", ".metadata.resourceVersion" and ".metadata.managedFields" from k8s object before comparing old & new k8s objects.
1 parent a97d5dd commit 0c03e0c

File tree

2 files changed

+72
-27
lines changed

2 files changed

+72
-27
lines changed

config/config.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,19 @@ type Config struct {
9494
// For watching specific namespace, leave it empty for watching all.
9595
// this config is ignored when watching namespaces
9696
Namespace string `json:"namespace,omitempty"`
97+
98+
// Specify fields to skip sending object update. Will be applied to all objects.
99+
// If after removal of these fields from k8s object all remaining fields will be equal,
100+
// handler won't trigger sending update. Removing array elements is not supported.
101+
// For example,
102+
// ignorefields:
103+
// status:
104+
// metadata:
105+
// resourceVersion:
106+
// managedFields:
107+
// will remove ".status", ".metadata.resourceVersion" and ".metadata.managedFields"
108+
// from k8s object before comparing old & new k8s objects.
109+
IgnoredFields map[string]interface{} `json:"ignoredfields,omitempty"`
97110
}
98111

99112
// Slack contains slack configuration

pkg/controller/controller.go

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
131131
cache.Indexers{},
132132
)
133133

134-
allCoreEventsController := newResourceController(kubeClient, eventHandler, allCoreEventsInformer, objName(api_v1.Event{}), V1, kubewatchEventsMetrics)
134+
allCoreEventsController := newResourceController(kubeClient, eventHandler, allCoreEventsInformer, objName(api_v1.Event{}), V1, kubewatchEventsMetrics, conf.IgnoredFields)
135135
stopAllCoreEventsCh := make(chan struct{})
136136
defer close(stopAllCoreEventsCh)
137137

@@ -155,7 +155,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
155155
cache.Indexers{},
156156
)
157157

158-
allEventsController := newResourceController(kubeClient, eventHandler, allEventsInformer, objName(events_v1.Event{}), EVENTS_V1, kubewatchEventsMetrics)
158+
allEventsController := newResourceController(kubeClient, eventHandler, allEventsInformer, objName(events_v1.Event{}), EVENTS_V1, kubewatchEventsMetrics, conf.IgnoredFields)
159159
stopAllEventsCh := make(chan struct{})
160160
defer close(stopAllEventsCh)
161161

@@ -177,7 +177,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
177177
cache.Indexers{},
178178
)
179179

180-
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.Pod{}), V1, kubewatchEventsMetrics)
180+
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.Pod{}), V1, kubewatchEventsMetrics, conf.IgnoredFields)
181181
stopCh := make(chan struct{})
182182
defer close(stopCh)
183183

@@ -199,7 +199,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
199199
cache.Indexers{},
200200
)
201201

202-
c := newResourceController(kubeClient, eventHandler, informer, objName(autoscaling_v1.HorizontalPodAutoscaler{}), AUTOSCALING_V1, kubewatchEventsMetrics)
202+
c := newResourceController(kubeClient, eventHandler, informer, objName(autoscaling_v1.HorizontalPodAutoscaler{}), AUTOSCALING_V1, kubewatchEventsMetrics, conf.IgnoredFields)
203203
stopCh := make(chan struct{})
204204
defer close(stopCh)
205205

@@ -222,7 +222,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
222222
cache.Indexers{},
223223
)
224224

225-
c := newResourceController(kubeClient, eventHandler, informer, objName(apps_v1.DaemonSet{}), APPS_V1, kubewatchEventsMetrics)
225+
c := newResourceController(kubeClient, eventHandler, informer, objName(apps_v1.DaemonSet{}), APPS_V1, kubewatchEventsMetrics, conf.IgnoredFields)
226226
stopCh := make(chan struct{})
227227
defer close(stopCh)
228228

@@ -244,7 +244,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
244244
cache.Indexers{},
245245
)
246246

247-
c := newResourceController(kubeClient, eventHandler, informer, objName(apps_v1.StatefulSet{}), APPS_V1, kubewatchEventsMetrics)
247+
c := newResourceController(kubeClient, eventHandler, informer, objName(apps_v1.StatefulSet{}), APPS_V1, kubewatchEventsMetrics, conf.IgnoredFields)
248248
stopCh := make(chan struct{})
249249
defer close(stopCh)
250250

@@ -266,7 +266,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
266266
cache.Indexers{},
267267
)
268268

269-
c := newResourceController(kubeClient, eventHandler, informer, objName(apps_v1.ReplicaSet{}), APPS_V1, kubewatchEventsMetrics)
269+
c := newResourceController(kubeClient, eventHandler, informer, objName(apps_v1.ReplicaSet{}), APPS_V1, kubewatchEventsMetrics, conf.IgnoredFields)
270270
stopCh := make(chan struct{})
271271
defer close(stopCh)
272272

@@ -288,7 +288,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
288288
cache.Indexers{},
289289
)
290290

291-
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.Service{}), V1, kubewatchEventsMetrics)
291+
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.Service{}), V1, kubewatchEventsMetrics, conf.IgnoredFields)
292292
stopCh := make(chan struct{})
293293
defer close(stopCh)
294294

@@ -310,7 +310,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
310310
cache.Indexers{},
311311
)
312312

313-
c := newResourceController(kubeClient, eventHandler, informer, objName(apps_v1.Deployment{}), APPS_V1, kubewatchEventsMetrics)
313+
c := newResourceController(kubeClient, eventHandler, informer, objName(apps_v1.Deployment{}), APPS_V1, kubewatchEventsMetrics, conf.IgnoredFields)
314314
stopCh := make(chan struct{})
315315
defer close(stopCh)
316316

@@ -332,7 +332,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
332332
cache.Indexers{},
333333
)
334334

335-
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.Namespace{}), V1, kubewatchEventsMetrics)
335+
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.Namespace{}), V1, kubewatchEventsMetrics, conf.IgnoredFields)
336336
stopCh := make(chan struct{})
337337
defer close(stopCh)
338338

@@ -354,7 +354,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
354354
cache.Indexers{},
355355
)
356356

357-
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.ReplicationController{}), V1, kubewatchEventsMetrics)
357+
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.ReplicationController{}), V1, kubewatchEventsMetrics, conf.IgnoredFields)
358358
stopCh := make(chan struct{})
359359
defer close(stopCh)
360360

@@ -376,7 +376,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
376376
cache.Indexers{},
377377
)
378378

379-
c := newResourceController(kubeClient, eventHandler, informer, objName(batch_v1.Job{}), BATCH_V1, kubewatchEventsMetrics)
379+
c := newResourceController(kubeClient, eventHandler, informer, objName(batch_v1.Job{}), BATCH_V1, kubewatchEventsMetrics, conf.IgnoredFields)
380380
stopCh := make(chan struct{})
381381
defer close(stopCh)
382382

@@ -398,7 +398,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
398398
cache.Indexers{},
399399
)
400400

401-
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.Node{}), V1, kubewatchEventsMetrics)
401+
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.Node{}), V1, kubewatchEventsMetrics, conf.IgnoredFields)
402402
stopCh := make(chan struct{})
403403
defer close(stopCh)
404404

@@ -420,7 +420,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
420420
cache.Indexers{},
421421
)
422422

423-
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.ServiceAccount{}), V1, kubewatchEventsMetrics)
423+
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.ServiceAccount{}), V1, kubewatchEventsMetrics, conf.IgnoredFields)
424424
stopCh := make(chan struct{})
425425
defer close(stopCh)
426426

@@ -442,7 +442,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
442442
cache.Indexers{},
443443
)
444444

445-
c := newResourceController(kubeClient, eventHandler, informer, objName(rbac_v1.ClusterRole{}), RBAC_V1, kubewatchEventsMetrics)
445+
c := newResourceController(kubeClient, eventHandler, informer, objName(rbac_v1.ClusterRole{}), RBAC_V1, kubewatchEventsMetrics, conf.IgnoredFields)
446446
stopCh := make(chan struct{})
447447
defer close(stopCh)
448448

@@ -464,7 +464,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
464464
cache.Indexers{},
465465
)
466466

467-
c := newResourceController(kubeClient, eventHandler, informer, objName(rbac_v1.ClusterRoleBinding{}), RBAC_V1, kubewatchEventsMetrics)
467+
c := newResourceController(kubeClient, eventHandler, informer, objName(rbac_v1.ClusterRoleBinding{}), RBAC_V1, kubewatchEventsMetrics, conf.IgnoredFields)
468468
stopCh := make(chan struct{})
469469
defer close(stopCh)
470470

@@ -486,7 +486,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
486486
cache.Indexers{},
487487
)
488488

489-
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.PersistentVolume{}), V1, kubewatchEventsMetrics)
489+
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.PersistentVolume{}), V1, kubewatchEventsMetrics, conf.IgnoredFields)
490490
stopCh := make(chan struct{})
491491
defer close(stopCh)
492492

@@ -508,7 +508,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
508508
cache.Indexers{},
509509
)
510510

511-
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.Secret{}), V1, kubewatchEventsMetrics)
511+
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.Secret{}), V1, kubewatchEventsMetrics, conf.IgnoredFields)
512512
stopCh := make(chan struct{})
513513
defer close(stopCh)
514514

@@ -530,7 +530,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
530530
cache.Indexers{},
531531
)
532532

533-
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.ConfigMap{}), V1, kubewatchEventsMetrics)
533+
c := newResourceController(kubeClient, eventHandler, informer, objName(api_v1.ConfigMap{}), V1, kubewatchEventsMetrics, conf.IgnoredFields)
534534
stopCh := make(chan struct{})
535535
defer close(stopCh)
536536

@@ -552,7 +552,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
552552
cache.Indexers{},
553553
)
554554

555-
c := newResourceController(kubeClient, eventHandler, informer, objName(networking_v1.Ingress{}), NETWORKING_V1, kubewatchEventsMetrics)
555+
c := newResourceController(kubeClient, eventHandler, informer, objName(networking_v1.Ingress{}), NETWORKING_V1, kubewatchEventsMetrics, conf.IgnoredFields)
556556
stopCh := make(chan struct{})
557557
defer close(stopCh)
558558

@@ -583,7 +583,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
583583
cache.Indexers{},
584584
)
585585

586-
c := newResourceController(kubeClient, eventHandler, informer, crd.Resource, fmt.Sprintf("%s/%s", crd.Group, crd.Version), kubewatchEventsMetrics)
586+
c := newResourceController(kubeClient, eventHandler, informer, crd.Resource, fmt.Sprintf("%s/%s", crd.Group, crd.Version), kubewatchEventsMetrics, conf.IgnoredFields)
587587
stopCh := make(chan struct{})
588588
defer close(stopCh)
589589

@@ -596,7 +596,7 @@ func Start(conf *config.Config, eventHandler handlers.Handler) {
596596
<-sigterm
597597
}
598598

599-
func newResourceController(client kubernetes.Interface, eventHandler handlers.Handler, informer cache.SharedIndexInformer, resourceType string, apiVersion string, kubewatchEventsMetrics *prometheus.CounterVec) *Controller {
599+
func newResourceController(client kubernetes.Interface, eventHandler handlers.Handler, informer cache.SharedIndexInformer, resourceType string, apiVersion string, kubewatchEventsMetrics *prometheus.CounterVec, ignoredFields map[string]interface{}) *Controller {
600600
queue := workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter())
601601
var newEvent Event
602602
var err error
@@ -620,20 +620,34 @@ func newResourceController(client kubernetes.Interface, eventHandler handlers.Ha
620620
kubewatchEventsMetrics.WithLabelValues(resourceType, "create").Inc()
621621
},
622622
UpdateFunc: func(old, new interface{}) {
623-
var ok bool
623+
var okOld, okNew bool
624624
newEvent.namespace = "" // namespace retrived in processItem incase namespace value is empty
625625
newEvent.key, err = cache.MetaNamespaceKeyFunc(old)
626626
newEvent.eventType = "update"
627627
newEvent.resourceType = resourceType
628628
newEvent.apiVersion = apiVersion
629-
newEvent.obj, ok = new.(runtime.Object)
630-
if !ok {
629+
newEvent.obj, okNew = new.(runtime.Object)
630+
if !okNew {
631631
logrus.WithField("pkg", "kubewatch-"+resourceType).Errorf("cannot convert to runtime.Object for update on %v", new)
632632
}
633-
newEvent.oldObj, ok = old.(runtime.Object)
634-
if !ok {
633+
newEvent.oldObj, okOld = old.(runtime.Object)
634+
if !okOld {
635635
logrus.WithField("pkg", "kubewatch-"+resourceType).Errorf("cannot convert old to runtime.Object for update on %v", old)
636636
}
637+
if okOld && okNew && len(ignoredFields) > 0 {
638+
oldUnstructured, okOld := newEvent.oldObj.DeepCopyObject().(runtime.Unstructured)
639+
newUnstructured, okNew := newEvent.obj.DeepCopyObject().(runtime.Unstructured)
640+
if okOld && okNew {
641+
oldContent := oldUnstructured.UnstructuredContent()
642+
newContent := newUnstructured.UnstructuredContent()
643+
recursiveDelete(oldContent, ignoredFields)
644+
recursiveDelete(newContent, ignoredFields)
645+
if reflect.DeepEqual(oldContent, newContent) {
646+
logrus.WithField("pkg", "kubewatch-"+resourceType).Infof("Ignoring update to %v: %s", resourceType, newEvent.key)
647+
return
648+
}
649+
}
650+
}
637651
logrus.WithField("pkg", "kubewatch-"+resourceType).Infof("Processing update to %v: %s", resourceType, newEvent.key)
638652
if err == nil {
639653
queue.Add(newEvent)
@@ -670,6 +684,24 @@ func newResourceController(client kubernetes.Interface, eventHandler handlers.Ha
670684
}
671685
}
672686

687+
// recursiveDelete recursively removes key from object
688+
// value of key should be either nil or nested map[string]interface{}
689+
// value of object to delete from should be nested map[string]interface{}
690+
func recursiveDelete(object map[string]interface{}, key map[string]interface{}) {
691+
for k, v := range key {
692+
if v == nil {
693+
delete(object, k)
694+
continue
695+
}
696+
if recursiveKey, ok := v.(map[string]interface{}); ok {
697+
if recursiveObj, ok := object[k].(map[string]interface{}); ok {
698+
recursiveDelete(recursiveObj, recursiveKey)
699+
}
700+
}
701+
}
702+
return
703+
}
704+
673705
// Run starts the kubewatch controller
674706
func (c *Controller) Run(stopCh <-chan struct{}) {
675707
defer utilruntime.HandleCrash()

0 commit comments

Comments
 (0)