Skip to content

Commit 1b82715

Browse files
authored
[processor/k8sattributes]: fix pod_association for container.id (#40841)
<!--Ex. Fixing a bug - Describe the bug and how this fixes the issue. Ex. Adding a feature - Explain what this achieves.--> #### Description When setting pod_association to container.id it can not match at the moment, as it will look up pod.Attributes and fail to match. Update getIdentifiersFromAssoc() to generate PodIdentifier also from pod.Containers.ByID. This then also covers the case, where a single k8s.pod.UID covers multiple container.ids. <!-- Issue number (e.g. #1234) or full URL to issue, if applicable. --> #### Link to tracking issue Fixes #40745 <!--Describe what testing was performed and which tests were added.--> #### Testing <!--Describe the documentation added.--> #### Documentation <!--Please delete paragraphs that you did not use before submitting.--> --------- Signed-off-by: Florian Lehner <[email protected]>
1 parent c995625 commit 1b82715

File tree

3 files changed

+204
-3
lines changed

3 files changed

+204
-3
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: bug_fix
5+
6+
# The name of the component, or a single word describing the area of concern, (e.g. filelogreceiver)
7+
component: k8sattributesprocessor
8+
9+
# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`).
10+
note: Make sure getIdentifiersFromAssoc() can handle container.id
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: [40745]
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]

processor/k8sattributesprocessor/internal/kube/client.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88
"errors"
99
"fmt"
10+
"maps"
1011
"regexp"
1112
"strings"
1213
"sync"
@@ -980,6 +981,7 @@ func getPodReplicaSetUID(pod *api_v1.Pod) string {
980981
func (c *WatchClient) getIdentifiersFromAssoc(pod *Pod) []PodIdentifier {
981982
var ids []PodIdentifier
982983
for _, assoc := range c.Associations {
984+
retID4containerID := -1
983985
ret := PodIdentifier{}
984986
skip := false
985987
for i, source := range assoc.Sources {
@@ -1013,13 +1015,17 @@ func (c *WatchClient) getIdentifiersFromAssoc(pod *Pod) []PodIdentifier {
10131015
// k8s.pod.ip is set by passthrough mode
10141016
case K8sIPLabelName:
10151017
attr = pod.Address
1018+
case string(conventions.ContainerIDKey):
1019+
// At this point just an empty attr is added and we remember the position.
1020+
// Later this position in PodIdentifier will be filled with the actual
1021+
// value for container.ID.
1022+
retID4containerID = i
10161023
default:
10171024
if v, ok := pod.Attributes[source.Name]; ok {
10181025
attr = v
10191026
}
10201027
}
1021-
1022-
if attr == "" {
1028+
if attr == "" && retID4containerID == -1 {
10231029
skip = true
10241030
break
10251031
}
@@ -1028,7 +1034,21 @@ func (c *WatchClient) getIdentifiersFromAssoc(pod *Pod) []PodIdentifier {
10281034
}
10291035

10301036
if !skip {
1031-
ids = append(ids, ret)
1037+
if retID4containerID != -1 {
1038+
// As there can be multiple container.IDs per pod,
1039+
// one PodIdentifier is added per container.ID.
1040+
cIDs := maps.Keys(pod.Containers.ByID)
1041+
for cID := range cIDs {
1042+
retCpy := ret
1043+
retCpy[retID4containerID] = PodIdentifierAttributeFromSource(AssociationSource{
1044+
From: ResourceSource,
1045+
Name: string(conventions.ContainerIDKey),
1046+
}, cID)
1047+
ids = append(ids, retCpy)
1048+
}
1049+
} else {
1050+
ids = append(ids, ret)
1051+
}
10321052
}
10331053
}
10341054

@@ -1043,6 +1063,7 @@ func (c *WatchClient) getIdentifiersFromAssoc(pod *Pod) []PodIdentifier {
10431063
ids = append(ids, PodIdentifier{
10441064
PodIdentifierAttributeFromConnection(pod.Address),
10451065
})
1066+
10461067
// k8s.pod.ip is set by passthrough mode
10471068
ids = append(ids, PodIdentifier{
10481069
PodIdentifierAttributeFromResourceAttribute(K8sIPLabelName, pod.Address),

processor/k8sattributesprocessor/internal/kube/client_test.go

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/stretchr/testify/assert"
1313
"github.com/stretchr/testify/require"
1414
"go.opentelemetry.io/collector/component/componenttest"
15+
conventions "go.opentelemetry.io/otel/semconv/v1.6.1"
1516
"go.uber.org/zap"
1617
"go.uber.org/zap/zapcore"
1718
"go.uber.org/zap/zaptest/observer"
@@ -2376,3 +2377,155 @@ func Test_parseServiceVersionFromImage(t *testing.T) {
23762377
})
23772378
}
23782379
}
2380+
2381+
func TestGetIdentifiersFromAssoc(t *testing.T) {
2382+
tests := map[string]struct {
2383+
associations []Association
2384+
pod *Pod
2385+
expected []PodIdentifier
2386+
}{
2387+
"K8SPodUID": {
2388+
associations: []Association{
2389+
{
2390+
Sources: []AssociationSource{
2391+
{
2392+
From: ResourceSource,
2393+
Name: string(conventions.K8SPodUIDKey),
2394+
},
2395+
},
2396+
},
2397+
},
2398+
pod: &Pod{
2399+
PodUID: "myK8sPodUID",
2400+
},
2401+
expected: []PodIdentifier{
2402+
{
2403+
PodIdentifierAttribute{Source: AssociationSource{From: "resource_attribute", Name: "k8s.pod.uid"}, Value: "myK8sPodUID"},
2404+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2405+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2406+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2407+
},
2408+
{
2409+
PodIdentifierAttribute{Source: AssociationSource{From: "resource_attribute", Name: "k8s.pod.uid"}, Value: "myK8sPodUID"},
2410+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2411+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2412+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2413+
},
2414+
},
2415+
},
2416+
"ContainerID": {
2417+
associations: []Association{
2418+
{
2419+
Sources: []AssociationSource{
2420+
{
2421+
From: ResourceSource,
2422+
Name: string(conventions.ContainerIDKey),
2423+
},
2424+
},
2425+
},
2426+
},
2427+
pod: &Pod{
2428+
PodUID: "myK8sPodUID",
2429+
Containers: PodContainers{
2430+
ByID: map[string]*Container{
2431+
"id1": {
2432+
Name: "id1",
2433+
},
2434+
"id2": {
2435+
Name: "id2",
2436+
},
2437+
},
2438+
},
2439+
},
2440+
expected: []PodIdentifier{
2441+
{
2442+
PodIdentifierAttribute{Source: AssociationSource{From: "resource_attribute", Name: "container.id"}, Value: "id1"},
2443+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2444+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2445+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2446+
},
2447+
{
2448+
PodIdentifierAttribute{Source: AssociationSource{From: "resource_attribute", Name: "container.id"}, Value: "id2"},
2449+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2450+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2451+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2452+
},
2453+
{
2454+
PodIdentifierAttribute{Source: AssociationSource{From: "resource_attribute", Name: "k8s.pod.uid"}, Value: "myK8sPodUID"},
2455+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2456+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2457+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2458+
},
2459+
},
2460+
},
2461+
"multiple associations": {
2462+
associations: []Association{
2463+
{
2464+
Sources: []AssociationSource{
2465+
{
2466+
From: ResourceSource,
2467+
Name: string(conventions.ContainerIDKey),
2468+
},
2469+
{
2470+
From: ConnectionSource,
2471+
},
2472+
},
2473+
},
2474+
},
2475+
pod: &Pod{
2476+
PodUID: "myK8sPodUID",
2477+
Address: "localhost",
2478+
Containers: PodContainers{
2479+
ByID: map[string]*Container{
2480+
"id1": {
2481+
Name: "id1",
2482+
},
2483+
"id2": {
2484+
Name: "id2",
2485+
},
2486+
},
2487+
},
2488+
},
2489+
expected: []PodIdentifier{
2490+
{
2491+
PodIdentifierAttribute{Source: AssociationSource{From: "resource_attribute", Name: "container.id"}, Value: "id1"},
2492+
PodIdentifierAttribute{Source: AssociationSource{From: "connection", Name: ""}, Value: "localhost"},
2493+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2494+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2495+
},
2496+
{
2497+
PodIdentifierAttribute{Source: AssociationSource{From: "resource_attribute", Name: "container.id"}, Value: "id2"},
2498+
PodIdentifierAttribute{Source: AssociationSource{From: "connection", Name: ""}, Value: "localhost"},
2499+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2500+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2501+
},
2502+
{
2503+
PodIdentifierAttribute{Source: AssociationSource{From: "resource_attribute", Name: "k8s.pod.uid"}, Value: "myK8sPodUID"},
2504+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2505+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2506+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2507+
},
2508+
{
2509+
PodIdentifierAttribute{Source: AssociationSource{From: "connection", Name: ""}, Value: "localhost"},
2510+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2511+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2512+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2513+
},
2514+
{
2515+
PodIdentifierAttribute{Source: AssociationSource{From: "resource_attribute", Name: "k8s.pod.ip"}, Value: "localhost"},
2516+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2517+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2518+
PodIdentifierAttribute{Source: AssociationSource{From: "", Name: ""}, Value: ""},
2519+
},
2520+
},
2521+
},
2522+
}
2523+
for name, tc := range tests {
2524+
t.Run(name, func(t *testing.T) {
2525+
wc, _ := newTestClient(t)
2526+
wc.Associations = tc.associations
2527+
actual := wc.getIdentifiersFromAssoc(tc.pod)
2528+
assert.ElementsMatch(t, tc.expected, actual)
2529+
})
2530+
}
2531+
}

0 commit comments

Comments
 (0)