Skip to content

Commit 7d3e749

Browse files
k-shaikhFiery-Fenix
authored andcommitted
[receiver/k8sclusterreceiver] Add missing attributes to entities in experimental entity feature (open-telemetry#39038)
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description Modified entity payloads to include additional attributes for the following entities. Some of which are mentioned here - Container - k8s.container.name - container.image.name - container.image.tag - k8s.pod.name - k8s.pod.uid - k8s.namespace.name - k8s.node.name Pod - k8s.namespace.name - k8s.pod.name Workload - k8s.namespace.name <!-- Issue number (e.g. open-telemetry#1234) or full URL to issue, if applicable. --> #### Link to tracking issue Partially Resolves: open-telemetry#38687 <!--Describe what testing was performed and which tests were added.--> #### Testing Updated unit tests to validate the desired attributes for the mentioned entities are included in the metadata for that entity <!--Describe the documentation added.--> #### Documentation None. <!--Please delete paragraphs that you did not use before submitting.-->
1 parent b9043cd commit 7d3e749

File tree

11 files changed

+169
-24
lines changed

11 files changed

+169
-24
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: k8sclusterreceiver
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Add missing attributes to entities in experimental entity feature
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: [39038]
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: [user]

receiver/k8sclusterreceiver/internal/constants/constants.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@ const (
1414
K8sKeyReplicationControllerUID = "k8s.replicationcontroller.uid"
1515
K8sKeyResourceQuotaUID = "k8s.resourcequota.uid"
1616
K8sKeyClusterResourceQuotaUID = "openshift.clusterquota.uid"
17+
K8sKeyPodUID = "k8s.pod.uid"
1718

1819
// Resource labels keys for Name.
1920
K8sKeyReplicationControllerName = "k8s.replicationcontroller.name"
2021
K8sKeyResourceQuotaName = "k8s.resourcequota.name"
2122
K8sKeyClusterResourceQuotaName = "openshift.clusterquota.name"
23+
K8sKeyNamespaceName = "k8s.namespace.name"
24+
K8sKeyPodName = "k8s.pod.name"
25+
K8sKeyNodeName = "k8s.node.name"
2226

2327
// Kubernetes resource kinds
2428
K8sKindCronJob = "CronJob"

receiver/k8sclusterreceiver/internal/container/containers.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313

1414
"github.com/open-telemetry/opentelemetry-collector-contrib/internal/common/docker"
1515
metadataPkg "github.com/open-telemetry/opentelemetry-collector-contrib/pkg/experimentalmetricmetadata"
16+
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/constants"
1617
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/metadata"
1718
imetadata "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/metadata"
1819
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/utils"
@@ -23,6 +24,9 @@ const (
2324
containerKeyStatus = "container.status"
2425
containerKeyStatusReason = "container.status.reason"
2526
containerCreationTimestamp = "container.creation_timestamp"
27+
containerName = "k8s.container.name"
28+
containerImageName = "container.image.name"
29+
containerImageTag = "container.image.tag"
2630

2731
// Values for container metadata
2832
containerStatusRunning = "running"
@@ -96,9 +100,23 @@ func RecordSpecMetrics(logger *zap.Logger, mb *imetadata.MetricsBuilder, c corev
96100
mb.EmitForResource(imetadata.WithResource(rb.Emit()))
97101
}
98102

99-
func GetMetadata(cs corev1.ContainerStatus) *metadata.KubernetesMetadata {
103+
func GetMetadata(pod *corev1.Pod, cs corev1.ContainerStatus, logger *zap.Logger) *metadata.KubernetesMetadata {
100104
mdata := map[string]string{}
101105

106+
imageStr := cs.Image
107+
image, err := docker.ParseImageName(cs.Image)
108+
if err != nil {
109+
docker.LogParseError(err, imageStr, logger)
110+
} else {
111+
mdata[containerImageName] = image.Repository
112+
mdata[containerImageTag] = image.Tag
113+
}
114+
mdata[containerName] = cs.Name
115+
mdata[constants.K8sKeyPodName] = pod.Name
116+
mdata[constants.K8sKeyPodUID] = string(pod.UID)
117+
mdata[constants.K8sKeyNamespaceName] = pod.Namespace
118+
mdata[constants.K8sKeyNodeName] = pod.Spec.NodeName
119+
102120
if cs.State.Running != nil {
103121
mdata[containerKeyStatus] = containerStatusRunning
104122
if !cs.State.Running.StartedAt.IsZero() {

receiver/k8sclusterreceiver/internal/container/containers_test.go

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,42 @@ import (
99

1010
"github.com/stretchr/testify/assert"
1111
"github.com/stretchr/testify/require"
12+
"go.uber.org/zap"
1213
corev1 "k8s.io/api/core/v1"
1314
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15+
"k8s.io/apimachinery/pkg/types"
16+
17+
"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/k8sclusterreceiver/internal/constants"
1418
)
1519

1620
func TestGetMetadata(t *testing.T) {
1721
refTime := v1.Now()
22+
pod := &corev1.Pod{
23+
ObjectMeta: v1.ObjectMeta{
24+
Name: "test-pod",
25+
Namespace: "test-namespace",
26+
UID: types.UID("test-pod-uid"),
27+
},
28+
Spec: corev1.PodSpec{
29+
NodeName: "test-node",
30+
},
31+
}
32+
1833
tests := []struct {
19-
name string
20-
containerState corev1.ContainerState
21-
expectedStatus string
22-
expectedReason string
23-
expectedStartedAt string
34+
name string
35+
containerState corev1.ContainerState
36+
expectedStatus string
37+
expectedReason string
38+
expectedStartedAt string
39+
containerName string
40+
containerID string
41+
containerImage string
42+
containerImageName string
43+
containerImageTag string
44+
podName string
45+
podUID string
46+
nodeName string
47+
namespaceName string
2448
}{
2549
{
2650
name: "Running container",
@@ -29,8 +53,17 @@ func TestGetMetadata(t *testing.T) {
2953
StartedAt: refTime,
3054
},
3155
},
32-
expectedStatus: containerStatusRunning,
33-
expectedStartedAt: refTime.Format(time.RFC3339),
56+
expectedStatus: containerStatusRunning,
57+
expectedStartedAt: refTime.Format(time.RFC3339),
58+
containerName: "my-test-container1",
59+
containerID: "f37ee861-f093-4cea-aa26-f39fff8b0998",
60+
containerImage: "docker/someimage1:v1.0",
61+
containerImageName: "docker/someimage1",
62+
containerImageTag: "v1.0",
63+
podName: pod.Name,
64+
podUID: string(pod.UID),
65+
namespaceName: "test-namespace",
66+
nodeName: "test-node",
3467
},
3568
{
3669
name: "Terminated container",
@@ -43,9 +76,18 @@ func TestGetMetadata(t *testing.T) {
4376
ExitCode: 0,
4477
},
4578
},
46-
expectedStatus: containerStatusTerminated,
47-
expectedReason: "Completed",
48-
expectedStartedAt: refTime.Format(time.RFC3339),
79+
expectedStatus: containerStatusTerminated,
80+
expectedReason: "Completed",
81+
expectedStartedAt: refTime.Format(time.RFC3339),
82+
containerName: "my-test-container2",
83+
containerID: "f37ee861-f093-4cea-aa26-f39fff8b0997",
84+
containerImage: "docker/someimage2:v1.1",
85+
containerImageName: "docker/someimage2",
86+
containerImageTag: "v1.1",
87+
podName: pod.Name,
88+
podUID: string(pod.UID),
89+
namespaceName: "test-namespace",
90+
nodeName: "test-node",
4991
},
5092
{
5193
name: "Waiting container",
@@ -54,17 +96,29 @@ func TestGetMetadata(t *testing.T) {
5496
Reason: "CrashLoopBackOff",
5597
},
5698
},
57-
expectedStatus: containerStatusWaiting,
58-
expectedReason: "CrashLoopBackOff",
99+
expectedStatus: containerStatusWaiting,
100+
expectedReason: "CrashLoopBackOff",
101+
containerName: "my-test-container3",
102+
containerID: "f37ee861-f093-4cea-aa26-f39fff8b0996",
103+
containerImage: "docker/someimage3:latest",
104+
containerImageName: "docker/someimage3",
105+
containerImageTag: "latest",
106+
podName: pod.Name,
107+
podUID: string(pod.UID),
108+
namespaceName: "test-namespace",
109+
nodeName: "test-node",
59110
},
60111
}
61-
112+
logger := zap.NewNop()
62113
for _, tt := range tests {
63114
t.Run(tt.name, func(t *testing.T) {
64115
cs := corev1.ContainerStatus{
65-
State: tt.containerState,
116+
State: tt.containerState,
117+
Name: tt.containerName,
118+
ContainerID: tt.containerID,
119+
Image: tt.containerImage,
66120
}
67-
md := GetMetadata(cs)
121+
md := GetMetadata(pod, cs, logger)
68122

69123
require.NotNil(t, md)
70124
assert.Equal(t, tt.expectedStatus, md.Metadata[containerKeyStatus])
@@ -75,6 +129,13 @@ func TestGetMetadata(t *testing.T) {
75129
assert.Contains(t, md.Metadata, containerCreationTimestamp)
76130
assert.Equal(t, tt.expectedStartedAt, md.Metadata[containerCreationTimestamp])
77131
}
132+
assert.Equal(t, tt.containerName, md.Metadata[containerName])
133+
assert.Equal(t, tt.containerImageName, md.Metadata[containerImageName])
134+
assert.Equal(t, tt.containerImageTag, md.Metadata[containerImageTag])
135+
assert.Equal(t, tt.podName, md.Metadata[constants.K8sKeyPodName])
136+
assert.Equal(t, tt.podUID, md.Metadata[constants.K8sKeyPodUID])
137+
assert.Equal(t, tt.namespaceName, md.Metadata[constants.K8sKeyNamespaceName])
138+
assert.Equal(t, tt.nodeName, md.Metadata[constants.K8sKeyNodeName])
78139
})
79140
}
80141
}

receiver/k8sclusterreceiver/internal/cronjob/cronjobs_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ func TestCronJobMetadata(t *testing.T) {
5959
"concurrency_policy": "concurrency_policy",
6060
"k8s.workload.kind": "CronJob",
6161
"k8s.workload.name": "test-cronjob-1",
62+
"k8s.namespace.name": "test-namespace",
6263
},
6364
},
6465
*actualMetadata["test-cronjob-1-uid"],

receiver/k8sclusterreceiver/internal/metadata/metadata.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ func GetGenericMetadata(om *v1.ObjectMeta, resourceType string) *KubernetesMetad
5555
metadata[constants.K8sKeyWorkLoadKind] = resourceType
5656
metadata[constants.K8sKeyWorkLoadName] = om.Name
5757
metadata[rType+".creation_timestamp"] = om.GetCreationTimestamp().Format(time.RFC3339)
58+
metadata[constants.K8sKeyNamespaceName] = om.Namespace
5859

5960
for _, or := range om.OwnerReferences {
6061
kind := strings.ToLower(or.Kind)

receiver/k8sclusterreceiver/internal/metadata/metadata_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ func Test_getGenericMetadata(t *testing.T) {
1919
om := &v1.ObjectMeta{
2020
Name: "test-name",
2121
UID: "test-uid",
22+
Namespace: "test-namespace",
2223
Generation: 0,
2324
CreationTimestamp: v1.NewTime(now),
2425
Labels: map[string]string{
@@ -46,6 +47,7 @@ func Test_getGenericMetadata(t *testing.T) {
4647
assert.Equal(t, map[string]string{
4748
"k8s.workload.name": "test-name",
4849
"k8s.workload.kind": "ResourceType",
50+
"k8s.namespace.name": "test-namespace",
4951
"resourcetype.creation_timestamp": now.Format(time.RFC3339),
5052
"k8s.owner-kind-1.name": "owner1",
5153
"k8s.owner-kind-1.uid": "owner1",

receiver/k8sclusterreceiver/internal/pod/pods.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ func GetMetadata(pod *corev1.Pod, mc *metadata.Store, logger *zap.Logger) map[ex
164164
meta = maps.MergeStringMaps(meta, collectPodReplicaSetProperties(pod, store, logger))
165165
}
166166

167+
meta[constants.K8sKeyNamespaceName] = pod.Namespace
168+
meta[constants.K8sKeyPodName] = pod.Name
169+
167170
podID := experimentalmetricmetadata.ResourceID(pod.UID)
168171
return metadata.MergeKubernetesMetadataMaps(map[experimentalmetricmetadata.ResourceID]*metadata.KubernetesMetadata{
169172
podID: {
@@ -172,7 +175,7 @@ func GetMetadata(pod *corev1.Pod, mc *metadata.Store, logger *zap.Logger) map[ex
172175
ResourceID: podID,
173176
Metadata: meta,
174177
},
175-
}, getPodContainerProperties(pod))
178+
}, getPodContainerProperties(pod, logger))
176179
}
177180

178181
// collectPodJobProperties checks if pod owner of type Job is cached. Check owners reference
@@ -249,10 +252,10 @@ func getWorkloadProperties(ref *v1.OwnerReference, labelKey string) map[string]s
249252
}
250253
}
251254

252-
func getPodContainerProperties(pod *corev1.Pod) map[experimentalmetricmetadata.ResourceID]*metadata.KubernetesMetadata {
255+
func getPodContainerProperties(pod *corev1.Pod, logger *zap.Logger) map[experimentalmetricmetadata.ResourceID]*metadata.KubernetesMetadata {
253256
km := map[experimentalmetricmetadata.ResourceID]*metadata.KubernetesMetadata{}
254257
for _, cs := range pod.Status.ContainerStatuses {
255-
md := container.GetMetadata(cs)
258+
md := container.GetMetadata(pod, cs, logger)
256259
km[md.ResourceID] = md
257260
}
258261
return km

receiver/k8sclusterreceiver/internal/pod/pods_test.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,10 @@ func testCaseForPodWorkload(to testCaseOptions) testCase {
235235

236236
func expectedKubernetesMetadata(to testCaseOptions) map[experimentalmetricmetadata.ResourceID]*metadata.KubernetesMetadata {
237237
podUIDLabel := "test-pod-0-uid"
238+
podNameLabel := "test-pod-0"
238239
kindLower := strings.ToLower(to.kind)
239240
kindObjName := fmt.Sprintf("test-%s-0", kindLower)
241+
namespaceLabel := "test-namespace"
240242
kindObjUID := fmt.Sprintf("test-%s-0-uid", kindLower)
241243
kindNameLabel := fmt.Sprintf("k8s.%s.name", kindLower)
242244
kindUIDLabel := fmt.Sprintf("k8s.%s.uid", kindLower)
@@ -247,9 +249,11 @@ func expectedKubernetesMetadata(to testCaseOptions) map[experimentalmetricmetada
247249
ResourceIDKey: "k8s.pod.uid",
248250
ResourceID: experimentalmetricmetadata.ResourceID(podUIDLabel),
249251
Metadata: map[string]string{
250-
kindNameLabel: kindObjName,
251-
kindUIDLabel: kindObjUID,
252-
"k8s.pod.phase": "Unknown", // Default value when phase is not set.
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,
253257
},
254258
},
255259
}
@@ -485,6 +489,8 @@ func TestTransform(t *testing.T) {
485489
func TestPodMetadata(t *testing.T) {
486490
tests := []struct {
487491
name string
492+
podName string
493+
namespace string
488494
statusPhase corev1.PodPhase
489495
statusReason string
490496
expectedMetadata map[string]string
@@ -494,6 +500,8 @@ func TestPodMetadata(t *testing.T) {
494500
statusPhase: corev1.PodFailed,
495501
statusReason: "Evicted",
496502
expectedMetadata: map[string]string{
503+
"k8s.pod.name": "test-pod-0",
504+
"k8s.namespace.name": "test-namespace",
497505
"k8s.pod.phase": "Failed",
498506
"k8s.pod.status_reason": "Evicted",
499507
"k8s.workload.kind": "Deployment",
@@ -509,6 +517,8 @@ func TestPodMetadata(t *testing.T) {
509517
statusPhase: corev1.PodRunning,
510518
statusReason: "",
511519
expectedMetadata: map[string]string{
520+
"k8s.pod.name": "test-pod-0",
521+
"k8s.namespace.name": "test-namespace",
512522
"k8s.pod.phase": "Running",
513523
"k8s.workload.kind": "Deployment",
514524
"k8s.workload.name": "test-deployment-0",

receiver/k8sclusterreceiver/internal/statefulset/statefulsets_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ func TestStatefulsetMetadata(t *testing.T) {
6666
Metadata: map[string]string{
6767
"k8s.workload.name": "test-statefulset-1",
6868
"k8s.workload.kind": "StatefulSet",
69+
"k8s.namespace.name": "test-namespace",
6970
"statefulset.creation_timestamp": "0001-01-01T00:00:00Z",
7071
"foo": "bar",
7172
"foo1": "",

0 commit comments

Comments
 (0)