mirror of
https://github.com/kubernetes/kubectl.git
synced 2026-04-15 22:00:02 -04:00
fix: include node events with null involvedObject.uid in describe output
kubectl describe node omits events where involvedObject.uid is unset/null. This happens with kubelet-emitted node status events on some clusters (e.g. EKS). NodeDescriber.Describe() searched for events using two UIDs: 1. The node's real UID (for controller events) 2. The node name as UID (for kubelet events using name workaround) Neither matched events where involvedObject.uid is null/empty. Add a third search with empty UID (matching by kind+name only) and deduplicate the merged results to avoid showing duplicates. Ref: kubernetes/kubectl/issues/1838 Signed-off-by: vigneshakaviki <kumarvignesh295@gmail.com>
This commit is contained in:
parent
8144b746a4
commit
e976d59fe7
2 changed files with 96 additions and 2 deletions
|
|
@ -3467,14 +3467,35 @@ func (d *NodeDescriber) Describe(namespace, name string, describerSettings Descr
|
|||
// there are two UIDs for host events:
|
||||
// controller use node.uid
|
||||
// kubelet use node.name
|
||||
// some kubelet events have involvedObject.uid unset (null)
|
||||
// TODO: Uniform use of UID
|
||||
events, _ = searchEvents(d.CoreV1(), ref, describerSettings.ChunkSize)
|
||||
|
||||
ref.UID = types.UID(ref.Name)
|
||||
eventsInvName, _ := searchEvents(d.CoreV1(), ref, describerSettings.ChunkSize)
|
||||
|
||||
// Merge the results of two queries
|
||||
events.Items = append(events.Items, eventsInvName.Items...)
|
||||
// Search for events with no UID set (involvedObject.uid is null),
|
||||
// which can happen with kubelet-emitted node events.
|
||||
ref.UID = ""
|
||||
eventsNoUID, _ := searchEvents(d.CoreV1(), ref, describerSettings.ChunkSize)
|
||||
|
||||
// Merge and deduplicate the results of the three queries
|
||||
seen := make(map[types.UID]bool, len(events.Items))
|
||||
for _, e := range events.Items {
|
||||
seen[e.UID] = true
|
||||
}
|
||||
for _, e := range eventsInvName.Items {
|
||||
if !seen[e.UID] {
|
||||
events.Items = append(events.Items, e)
|
||||
seen[e.UID] = true
|
||||
}
|
||||
}
|
||||
for _, e := range eventsNoUID.Items {
|
||||
if !seen[e.UID] {
|
||||
events.Items = append(events.Items, e)
|
||||
seen[e.UID] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6447,6 +6447,79 @@ func TestDescribeNode(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestDescribeNodeEventsWithNullUID(t *testing.T) {
|
||||
node := &corev1.Node{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-node",
|
||||
UID: "real-node-uid",
|
||||
},
|
||||
}
|
||||
fake := fake.NewClientset(
|
||||
node,
|
||||
&coordinationv1.Lease{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test-node",
|
||||
Namespace: corev1.NamespaceNodeLease,
|
||||
},
|
||||
},
|
||||
&corev1.EventList{
|
||||
Items: []corev1.Event{
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "event-with-uid",
|
||||
Namespace: "default",
|
||||
UID: "evt-1",
|
||||
},
|
||||
InvolvedObject: corev1.ObjectReference{
|
||||
Kind: "Node",
|
||||
Name: "test-node",
|
||||
UID: "test-node",
|
||||
},
|
||||
Message: "Node test-node status is now: NodeHasSufficientMemory",
|
||||
FirstTimestamp: metav1.NewTime(time.Date(2024, time.January, 15, 0, 0, 0, 0, time.UTC)),
|
||||
LastTimestamp: metav1.NewTime(time.Date(2024, time.January, 15, 0, 0, 0, 0, time.UTC)),
|
||||
Count: 1,
|
||||
Type: corev1.EventTypeNormal,
|
||||
},
|
||||
{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "event-null-uid",
|
||||
Namespace: "default",
|
||||
UID: "evt-2",
|
||||
},
|
||||
InvolvedObject: corev1.ObjectReference{
|
||||
Kind: "Node",
|
||||
Name: "test-node",
|
||||
// UID intentionally omitted (empty/null) —
|
||||
// kubelet-emitted events on some clusters
|
||||
},
|
||||
Message: "Node test-node status is now: NodeHasInsufficientMemory",
|
||||
FirstTimestamp: metav1.NewTime(time.Date(2024, time.January, 15, 0, 0, 0, 0, time.UTC)),
|
||||
LastTimestamp: metav1.NewTime(time.Date(2024, time.January, 15, 0, 0, 0, 0, time.UTC)),
|
||||
Count: 1,
|
||||
Type: corev1.EventTypeWarning,
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
c := &describeClient{T: t, Namespace: "", Interface: fake}
|
||||
d := NodeDescriber{c}
|
||||
out, err := d.Describe("", "test-node", DescriberSettings{ShowEvents: true})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// Event with UID should always appear
|
||||
if !strings.Contains(out, "NodeHasSufficientMemory") {
|
||||
t.Errorf("expected event with UID to appear in output, got:\n%s", out)
|
||||
}
|
||||
|
||||
// Event with null/empty UID should also appear
|
||||
if !strings.Contains(out, "NodeHasInsufficientMemory") {
|
||||
t.Errorf("expected event with null UID to appear in output, got:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDescribeNodeWithSidecar(t *testing.T) {
|
||||
holderIdentity := "holder"
|
||||
nodeCapacity := mergeResourceLists(
|
||||
|
|
|
|||
Loading…
Reference in a new issue