Files
Ronak Nathani f48d5bf9ba Add owner references to EnhancedEvent, consolidate calls to apiserver, make cache size configurable and add metrics for reads (#144)
* Adds ownerReferences to the exported events

This commit uses the same approach as labels and annotations and adds ownerReferences to the EnhancedEvent struct.
The flow is as follows:
* use an LRU cache to store the ownerReferences with object UID as the key
* if the object doesn't exist in cache, look up using dynamic client and store it in cache
* if the object exists in cache, return the value from cache

* Reduce the number of GetObject calls by using a single cache to store all labels, annotations and ownerReferences

Currently, every time there's an event, the events exporter runs GetObject for metadata like labels and annotations
independently. This results in the same object being looked up multiple times for different pieces of the metadata.
These number of calls grow as we want to look up additional information about the object like ownerReferences.
So, in this change, a struct called `ObjectMetadata` is created to capture all the pieces of information that need to be added
to the EnhancedEvent. And every time there's an event, the object is fetched from the kube-apiserver if it's not in the cache already
and all pieces of metadata require only 1 call. The metadata is cached so repeated events about the same object don't
result in more calls.

Additionally, UID + ResourceVersion is used the cacheKey so if the object changes, it's looked up again.

One more change here is introduction of a `deleted` field in the `EnhancedEvent.InvolvedObject` to capture whether the object
is deleted. This helps receivers identify whether a resource is deleted and create rules for it when needed.

Tests are added for these updates and the mock functions are moved to the test files.

* Make the cache size configurable

* Add metrics for number of reads served from cache and kube-apiserver respectively

* Add `deleted` field to the involvedObject in EnhancedEvent to identify whether the resource is being deleted
2023-11-18 01:00:27 +03:00

75 lines
2.2 KiB
Go

package kube
import (
"encoding/json"
"strings"
"time"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
type EnhancedEvent struct {
corev1.Event `json:",inline"`
ClusterName string `json:"clusterName"`
InvolvedObject EnhancedObjectReference `json:"involvedObject"`
}
// DeDot replaces all dots in the labels and annotations with underscores. This is required for example in the
// elasticsearch sink. The dynamic mapping generation interprets dots in JSON keys as as path in a onject.
// For reference see this logstash filter: https://www.elastic.co/guide/en/logstash/current/plugins-filters-de_dot.html
func (e EnhancedEvent) DeDot() EnhancedEvent {
c := e
c.Labels = dedotMap(e.Labels)
c.Annotations = dedotMap(e.Annotations)
c.InvolvedObject.Labels = dedotMap(e.InvolvedObject.Labels)
c.InvolvedObject.Annotations = dedotMap(e.InvolvedObject.Annotations)
return c
}
func dedotMap(in map[string]string) map[string]string {
if len(in) == 0 {
return in
}
ret := make(map[string]string, len(in))
for key, value := range in {
nKey := strings.ReplaceAll(key, ".", "_")
ret[nKey] = value
}
return ret
}
type EnhancedObjectReference struct {
corev1.ObjectReference `json:",inline"`
Labels map[string]string `json:"labels,omitempty"`
Annotations map[string]string `json:"annotations,omitempty"`
OwnerReferences []metav1.OwnerReference `json:"ownerReferences,omitempty"`
Deleted bool `json:"deleted"`
}
// ToJSON does not return an error because we are %99 confident it is JSON serializable.
// TODO(makin) Is it a bad practice? It's open to discussion.
func (e *EnhancedEvent) ToJSON() []byte {
b, _ := json.Marshal(e)
return b
}
func (e *EnhancedEvent) GetTimestampMs() int64 {
timestamp := e.FirstTimestamp.Time
if timestamp.IsZero() {
timestamp = e.EventTime.Time
}
return timestamp.UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond))
}
func (e *EnhancedEvent) GetTimestampISO8601() string {
timestamp := e.FirstTimestamp.Time
if timestamp.IsZero() {
timestamp = e.EventTime.Time
}
layout := "2006-01-02T15:04:05.000Z"
return timestamp.Format(layout)
}