Skip to content

@W-24431985: Watch Events with an unstructured informer so events.k8s.io/v1 fields are not dropped - #292

Closed
venkatramreddykunta wants to merge 1 commit into
salesforce:masterfrom
venkatramreddykunta:bugfix/W-24431985-events-unstructured
Closed

venkatramreddykunta wants to merge 1 commit into
salesforce:masterfrom
venkatramreddykunta:bugfix/W-24431985-events-unstructured

Conversation

@venkatramreddykunta

Copy link
Copy Markdown
Collaborator

Problem

Some API servers serve Events on /api/v1/events with apiVersion: v1 but only the events.k8s.io/v1 field names (regarding, note, deprecatedCount, deprecatedFirstTimestamp, deprecatedLastTimestamp, deprecatedSource). One example is a read-only proxy that stores events.k8s.io/v1 Events.

Sloop watches Events with a typed corev1.Event informer. Decoding into corev1.Event silently drops every one of those fields. The Event is stored like this:

{"involvedObject": {}, "count": null, "firstTimestamp": null, "lastTimestamp": null, "message": null, "source": {}}

updateEventCountTable then skips it because the count is 0, and it has no involved object to attach to. The result is that the EventHeatMap shows no Events for any resource, and there is no error or log line.

Fix

  • Watch Events with a dynamic (unstructured) informer on {"", "v1", "events"}, so unknown fields are kept.
  • normalizeEvent copies the events.k8s.io/v1 values into the core/v1 fields only when those fields are missing:
    • regarding → involvedObject
    • note → message
    • deprecatedSource → source
    • reportingController → reportingComponent
    • deprecatedCount → count
    • deprecatedFirstTimestamp / deprecatedLastTimestamp → firstTimestamp / lastTimestamp
    • fallbacks: series.count, series.lastObservedTime, eventTime
  • Normal core/v1 Events (they already have involvedObject) are returned unchanged. The informer cache object is never modified; a copy is returned.
  • processUpdate uses meta.Accessor instead of a reflect lookup. The reflect lookup panicked when logging an excluded unstructured object.
  • makeRestConfig is shared by the typed client and the new MakeDynamicClient, so both use the same kubeconfig, context and QPS settings.

Tests

pkg/sloop/ingress/eventnormalize_test.go:

  • Test_typedEventDecodeDropsEventsV1Fields reproduces the bug: decoding into corev1.Event gives an empty involvedObject and a count of 0.
  • Test_normalizeEvent_* cover the events.k8s.io/v1 shape, an unchanged core/v1 Event, the input not being modified, series/eventTime, and a single eventTime.
  • Test_processUpdate_EventsV1Event and Test_processUpdate_ExcludedUnstructured: the second is the regression test for the reflect panic.
  • Test_bigPictureEventsV1Event runs end to end with a fake dynamic client and checks that the Event reaches the out channel in core/v1 shape.

Local checks: go vet ./..., go test -race ./..., go mod tidy (no diff), goimports (no new findings), go build ./pkg/sloop/main.go.

Manual before/after against a stub API server that serves events.k8s.io/v1 shaped Events: evidence in a comment below.

Compatibility

  • Stored Event payloads now include apiVersion and kind. The events.k8s.io/v1 fields are kept next to the copied core/v1 fields.
  • Events that were already stored with empty fields are not backfilled.
  • NewKubeWatcherSource takes an extra dynamic.Interface argument.
  • Clusters that serve normal core/v1 Events see no change in stored data.

….io/v1 fields are not dropped

Some API servers return Events on /api/v1 with only the events.k8s.io/v1
field names (regarding, note, deprecatedCount, deprecatedFirstTimestamp,
deprecatedLastTimestamp, deprecatedSource). The typed corev1.Event informer
decodes them with encoding/json, which silently drops those fields, so Sloop
stored the Event with "involvedObject":{}, no message, count 0 and null
timestamps. The event count table skips count 0, so the Event heatmap was
empty and the resource Events panel showed "No events found".

- Watch Events with a dynamic informer (GVR v1/events), built from the same
  rest config as the typed client (MakeDynamicClient).
- normalizeEvent copies regarding/note/deprecated* (and series/eventTime as a
  fallback) into the missing core/v1 fields. Core/v1 Events are unchanged.
- Use meta.Accessor when logging excluded objects; the reflect lookup of
  ObjectMeta panicked for unstructured objects (Events and CRDs).
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

package ingress

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)

// Sloop reads Events with the core/v1 field names (involvedObject, message, count, firstTimestamp,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

@venkatramreddykunta

Copy link
Copy Markdown
Collaborator Author

Closing this for now. The root cause is in the upstream API we point Sloop at: it serves Events in events.k8s.io/v1 shape on the core /api/v1/events endpoint, so fields like involvedObject, message and count came back empty. Sloop's core/v1 Event handling is correct for a standard kube-apiserver, so this isn't a Sloop bug.

We're fixing it on the API side instead, so every client gets core/v1 Events and not only Sloop. Thanks for the review. Happy to reopen if a Sloop-side change turns out to be useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant