Skip to content

Commit 19fd427

Browse files
odubajDTChrsMark
andauthored
[receiver/k8scluster] Add node name to pod metadata (#38669)
Fixes #37454 --------- Signed-off-by: odubajDT <[email protected]> Co-authored-by: Christos Markou <[email protected]>
1 parent 570f062 commit 19fd427

File tree

6 files changed

+84
-42
lines changed

6 files changed

+84
-42
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Use this changelog template to create an entry for release notes.
2+
3+
# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix'
4+
change_type: enhancement
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: receiver/k8scluster
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: "Add node name to pod metadata"
11+
12+
# Mandatory: One or more tracking issues related to the change. You can use the PR number here if no issue exists.
13+
issues: [37454]
14+
15+
# (Optional) One or more lines of additional information to render under the primary note.
16+
# These lines will be padded with 2 spaces and then inserted directly into the document.
17+
# Use pipe (|) for multiline entries.
18+
subtext:
19+
20+
# If your change doesn't affect end users or the exported elements of any package,
21+
# you should instead start your pull request title with [chore] or use the "Skip Changelog" label.
22+
# Optional: The change log or logs in which this entry should be included.
23+
# e.g. '[user]' or '[user, api]'
24+
# Include 'user' if the change is relevant to end users.
25+
# Include 'api' if there is a change to a library API.
26+
# Default: '[user]'
27+
change_logs: []

receiver/k8sclusterreceiver/internal/pod/pods.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ func GetMetadata(pod *corev1.Pod, mc *metadata.Store, logger *zap.Logger) map[ex
139139
meta[podStatusReason] = reason
140140
}
141141

142+
meta[conventions.AttributeK8SNodeName] = pod.Spec.NodeName
143+
142144
for _, or := range pod.OwnerReferences {
143145
kind := strings.ToLower(or.Kind)
144146
meta[metadata.GetOTelNameFromKind(kind)] = or.Name

receiver/k8sclusterreceiver/internal/pod/pods_test.go

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/stretchr/testify/require"
1515
"go.opentelemetry.io/collector/pdata/pcommon"
1616
"go.opentelemetry.io/collector/receiver/receivertest"
17+
conventions "go.opentelemetry.io/collector/semconv/v1.6.1"
1718
"go.uber.org/zap"
1819
"go.uber.org/zap/zapcore"
1920
"go.uber.org/zap/zaptest/observer"
@@ -249,11 +250,12 @@ func expectedKubernetesMetadata(to testCaseOptions) map[experimentalmetricmetada
249250
ResourceIDKey: "k8s.pod.uid",
250251
ResourceID: experimentalmetricmetadata.ResourceID(podUIDLabel),
251252
Metadata: map[string]string{
252-
kindNameLabel: kindObjName,
253-
kindUIDLabel: kindObjUID,
254-
"k8s.pod.phase": "Unknown", // Default value when phase is not set.
255-
"k8s.namespace.name": namespaceLabel,
256-
"k8s.pod.name": podNameLabel,
253+
kindNameLabel: kindObjName,
254+
kindUIDLabel: kindObjUID,
255+
conventions.AttributeK8SNodeName: "test-node",
256+
"k8s.pod.name": podNameLabel,
257+
"k8s.pod.phase": "Unknown", // Default value when phase is not set.
258+
"k8s.namespace.name": namespaceLabel,
257259
},
258260
},
259261
}
@@ -348,7 +350,7 @@ func podWithOwnerReference(kind string) *corev1.Pod {
348350
Name: fmt.Sprintf("test-%s-0", kindLower),
349351
UID: types.UID(fmt.Sprintf("test-%s-0-uid", kindLower)),
350352
},
351-
}, testutils.NewPodWithContainer("0", &corev1.PodSpec{}, &corev1.PodStatus{}),
353+
}, testutils.NewPodWithContainer("0", &corev1.PodSpec{NodeName: "test-node"}, &corev1.PodStatus{}),
352354
).(*corev1.Pod)
353355
}
354356

@@ -500,32 +502,34 @@ func TestPodMetadata(t *testing.T) {
500502
statusPhase: corev1.PodFailed,
501503
statusReason: "Evicted",
502504
expectedMetadata: map[string]string{
503-
"k8s.pod.name": "test-pod-0",
504-
"k8s.namespace.name": "test-namespace",
505-
"k8s.pod.phase": "Failed",
506-
"k8s.pod.status_reason": "Evicted",
507-
"k8s.workload.kind": "Deployment",
508-
"k8s.workload.name": "test-deployment-0",
509-
"k8s.replicaset.name": "test-replicaset-0",
510-
"k8s.replicaset.uid": "test-replicaset-0-uid",
511-
"k8s.deployment.name": "test-deployment-0",
512-
"k8s.deployment.uid": "test-deployment-0-uid",
505+
"k8s.pod.name": "test-pod-0",
506+
"k8s.namespace.name": "test-namespace",
507+
"k8s.pod.phase": "Failed",
508+
"k8s.pod.status_reason": "Evicted",
509+
"k8s.workload.kind": "Deployment",
510+
"k8s.workload.name": "test-deployment-0",
511+
"k8s.replicaset.name": "test-replicaset-0",
512+
"k8s.replicaset.uid": "test-replicaset-0-uid",
513+
"k8s.deployment.name": "test-deployment-0",
514+
"k8s.deployment.uid": "test-deployment-0-uid",
515+
conventions.AttributeK8SNodeName: "test-node",
513516
},
514517
},
515518
{
516519
name: "Pod without status reason",
517520
statusPhase: corev1.PodRunning,
518521
statusReason: "",
519522
expectedMetadata: map[string]string{
520-
"k8s.pod.name": "test-pod-0",
521-
"k8s.namespace.name": "test-namespace",
522-
"k8s.pod.phase": "Running",
523-
"k8s.workload.kind": "Deployment",
524-
"k8s.workload.name": "test-deployment-0",
525-
"k8s.replicaset.name": "test-replicaset-0",
526-
"k8s.replicaset.uid": "test-replicaset-0-uid",
527-
"k8s.deployment.name": "test-deployment-0",
528-
"k8s.deployment.uid": "test-deployment-0-uid",
523+
"k8s.pod.name": "test-pod-0",
524+
"k8s.namespace.name": "test-namespace",
525+
"k8s.pod.phase": "Running",
526+
"k8s.workload.kind": "Deployment",
527+
"k8s.workload.name": "test-deployment-0",
528+
"k8s.replicaset.name": "test-replicaset-0",
529+
"k8s.replicaset.uid": "test-replicaset-0-uid",
530+
"k8s.deployment.name": "test-deployment-0",
531+
"k8s.deployment.uid": "test-deployment-0-uid",
532+
conventions.AttributeK8SNodeName: "test-node",
529533
},
530534
},
531535
}

receiver/k8sclusterreceiver/mock_resources_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ func createPods(t *testing.T, client *fake.Clientset, numPods int) []*corev1.Pod
2929
Name: strconv.Itoa(i),
3030
Namespace: "test",
3131
},
32+
Spec: corev1.PodSpec{
33+
NodeName: "test-node",
34+
},
3235
}
3336

3437
createdPod, err := client.CoreV1().Pods(p.Namespace).Create(context.Background(), p, v1.CreateOptions{})

receiver/k8sclusterreceiver/receiver_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,9 @@ func getUpdatedPod(pod *corev1.Pod) any {
301301
"key": "value",
302302
},
303303
},
304+
Spec: corev1.PodSpec{
305+
NodeName: "test-node",
306+
},
304307
}
305308
}
306309

receiver/k8sclusterreceiver/watcher_test.go

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"go.opentelemetry.io/collector/component"
1313
"go.opentelemetry.io/collector/consumer/consumertest"
1414
"go.opentelemetry.io/collector/receiver/receivertest"
15+
conventions "go.opentelemetry.io/collector/semconv/v1.6.1"
1516
"go.uber.org/zap"
1617
"go.uber.org/zap/zapcore"
1718
"go.uber.org/zap/zaptest/observer"
@@ -270,7 +271,7 @@ func TestSyncMetadataAndEmitEntityEvents(t *testing.T) {
270271
"otel.entity.interval": int64(7200000), // 2h in milliseconds
271272
"otel.entity.type": "k8s.pod",
272273
"otel.entity.id": map[string]any{"k8s.pod.uid": "pod0"},
273-
"otel.entity.attributes": map[string]any{"pod.creation_timestamp": "0001-01-01T00:00:00Z", "k8s.pod.phase": "Unknown", "k8s.namespace.name": "test", "k8s.pod.name": "0"},
274+
"otel.entity.attributes": map[string]any{"pod.creation_timestamp": "0001-01-01T00:00:00Z", "k8s.pod.phase": "Unknown", "k8s.namespace.name": "test", "k8s.pod.name": "0", conventions.AttributeK8SNodeName: "test-node"},
274275
}
275276
assert.Equal(t, expected, lr.Attributes().AsRaw())
276277
assert.WithinRange(t, lr.Timestamp().AsTime(), step1, step2)
@@ -324,7 +325,7 @@ func TestObjMetadata(t *testing.T) {
324325
EntityType: "k8s.pod",
325326
ResourceIDKey: "k8s.pod.uid",
326327
ResourceID: "test-pod-0-uid",
327-
Metadata: allPodMetadata(map[string]string{"k8s.pod.phase": "Succeeded", "k8s.pod.name": "test-pod-0", "k8s.namespace.name": "test-namespace"}),
328+
Metadata: allPodMetadata(map[string]string{"k8s.pod.phase": "Succeeded", "k8s.pod.name": "test-pod-0", "k8s.namespace.name": "test-namespace", conventions.AttributeK8SNodeName: "test-node"}),
328329
},
329330
experimentalmetricmetadata.ResourceID("container-id"): {
330331
EntityType: "container",
@@ -353,21 +354,22 @@ func TestObjMetadata(t *testing.T) {
353354
Name: "test-statefulset-0",
354355
UID: "test-statefulset-0-uid",
355356
},
356-
}, testutils.NewPodWithContainer("0", &corev1.PodSpec{}, &corev1.PodStatus{Phase: corev1.PodFailed, Reason: "Evicted"})),
357+
}, testutils.NewPodWithContainer("0", &corev1.PodSpec{NodeName: "test-node"}, &corev1.PodStatus{Phase: corev1.PodFailed, Reason: "Evicted"})),
357358
want: map[experimentalmetricmetadata.ResourceID]*metadata.KubernetesMetadata{
358359
experimentalmetricmetadata.ResourceID("test-pod-0-uid"): {
359360
EntityType: "k8s.pod",
360361
ResourceIDKey: "k8s.pod.uid",
361362
ResourceID: "test-pod-0-uid",
362363
Metadata: allPodMetadata(map[string]string{
363-
"k8s.workload.kind": "StatefulSet",
364-
"k8s.workload.name": "test-statefulset-0",
365-
"k8s.statefulset.name": "test-statefulset-0",
366-
"k8s.statefulset.uid": "test-statefulset-0-uid",
367-
"k8s.pod.phase": "Failed",
368-
"k8s.pod.status_reason": "Evicted",
369-
"k8s.pod.name": "test-pod-0",
370-
"k8s.namespace.name": "test-namespace",
364+
"k8s.workload.kind": "StatefulSet",
365+
"k8s.workload.name": "test-statefulset-0",
366+
"k8s.statefulset.name": "test-statefulset-0",
367+
"k8s.statefulset.uid": "test-statefulset-0-uid",
368+
"k8s.pod.phase": "Failed",
369+
"k8s.pod.status_reason": "Evicted",
370+
"k8s.pod.name": "test-pod-0",
371+
"k8s.namespace.name": "test-namespace",
372+
conventions.AttributeK8SNodeName: "test-node",
371373
}),
372374
},
373375
},
@@ -396,19 +398,20 @@ func TestObjMetadata(t *testing.T) {
396398
}(),
397399
resource: podWithAdditionalLabels(
398400
map[string]string{"k8s-app": "my-app"},
399-
testutils.NewPodWithContainer("0", &corev1.PodSpec{}, &corev1.PodStatus{Phase: corev1.PodRunning}),
401+
testutils.NewPodWithContainer("0", &corev1.PodSpec{NodeName: "test-node"}, &corev1.PodStatus{Phase: corev1.PodRunning}),
400402
),
401403
want: map[experimentalmetricmetadata.ResourceID]*metadata.KubernetesMetadata{
402404
experimentalmetricmetadata.ResourceID("test-pod-0-uid"): {
403405
EntityType: "k8s.pod",
404406
ResourceIDKey: "k8s.pod.uid",
405407
ResourceID: "test-pod-0-uid",
406408
Metadata: allPodMetadata(map[string]string{
407-
"k8s.service.test-service": "",
408-
"k8s-app": "my-app",
409-
"k8s.pod.phase": "Running",
410-
"k8s.namespace.name": "test-namespace",
411-
"k8s.pod.name": "test-pod-0",
409+
"k8s.service.test-service": "",
410+
"k8s-app": "my-app",
411+
"k8s.pod.phase": "Running",
412+
"k8s.namespace.name": "test-namespace",
413+
"k8s.pod.name": "test-pod-0",
414+
conventions.AttributeK8SNodeName: "test-node",
412415
}),
413416
},
414417
},

0 commit comments

Comments
 (0)