Skip to content

Commit dc1a471

Browse files
committed
fix(container): fix container ID detection using deepest cgroup path match
If multiple container IDs are found within a single cgroup path, the changed function prioritizes the one appearing furthest to the right or "deepest" in the path string. e.g. for a pod created in kind cluster, the cgroup path for the process running in pod is typically like below: 0::/system.slice/docker-fd9d0ea06257a9780827cbc7fd92e3812a54fca26d63e191b73610d5d48b9cbd.scope/kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-besteffort.slice/kubelet-kubepods-besteffort-podeab5a334_93fe_48a8_b139_9e8079c1f163.slice/cri-containerd-99f3a16ea25b7724cb56a4f0c0df1113ad9474fbf5545bead97fd5c7f61c13f4.scope the first container (docker) refers to the kind node the second container (cri-containerd) refers to the container running as part of the pod this commit will return the second container id Signed-off-by: Vimal Kumar <[email protected]>
1 parent bb1413d commit dc1a471

File tree

2 files changed

+59
-4
lines changed

2 files changed

+59
-4
lines changed

internal/resource/container.go

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"fmt"
88
"path/filepath"
99
"regexp"
10+
"sort"
1011
"strings"
1112
)
1213

@@ -78,17 +79,65 @@ func containerInfoFromProc(proc procInfo) (*Container, error) {
7879
return c, nil
7980
}
8081

81-
// containerInfoFromCgroupPaths looks for container IDs in cgroup paths
82+
// matchResult stores information about a successful regex match.
83+
type matchResult struct {
84+
Runtime ContainerRuntime
85+
ID string
86+
StartIdx int // The starting index of the match in the original string
87+
MatchLen int // The length of the overall matched string
88+
}
89+
90+
// containerInfoFromCgroupPaths iterates through cgroup paths, finds all possible matches,
91+
// and selects the "deepest" match (i.e., the one that starts latest in the string).
8292
func containerInfoFromCgroupPaths(paths []string) (ContainerRuntime, string) {
93+
var bestMatch *matchResult
94+
8395
for _, path := range paths {
96+
var currentPathMatches []matchResult
97+
98+
// Find all matches for the current path
8499
for pattern, runtime := range containerPatterns {
85-
if matches := pattern.FindStringSubmatch(path); len(matches) > 1 {
86-
return runtime, matches[1]
100+
// FindAllStringSubmatchIndex returns all successive matches of the expression,
101+
// returning the start and end indices of the match and its subexpressions.
102+
matches := pattern.FindAllStringSubmatchIndex(path, -1)
103+
if len(matches) > 0 {
104+
for _, match := range matches {
105+
// match[0] is start index of overall match, match[1] is end index of overall match
106+
// match[2] is start index of first capturing group, match[3] is end index of first capturing group
107+
if len(match) >= 4 { // Ensure there's a capturing group
108+
id := path[match[2]:match[3]]
109+
currentPathMatches = append(currentPathMatches, matchResult{
110+
Runtime: runtime,
111+
ID: id,
112+
StartIdx: match[0],
113+
MatchLen: match[1] - match[0],
114+
})
115+
}
116+
}
87117
}
88118
}
119+
120+
// If multiple matches are found for the current path, pick the "deepest" one.
121+
// "Deepest" is defined as the match with the highest starting index.
122+
if len(currentPathMatches) > 0 {
123+
sort.Slice(currentPathMatches, func(i, j int) bool {
124+
// Sort by StartIdx in descending order to get the deepest match first.
125+
return currentPathMatches[i].StartIdx > currentPathMatches[j].StartIdx
126+
})
127+
128+
// The first element after sorting will be the deepest match for this path.
129+
// Compare it with the overall bestMatch found so far across all paths.
130+
if bestMatch == nil || currentPathMatches[0].StartIdx > bestMatch.StartIdx {
131+
bestMatch = &currentPathMatches[0]
132+
}
133+
}
134+
}
135+
136+
if bestMatch != nil {
137+
return bestMatch.Runtime, bestMatch.ID
89138
}
90139

91-
return UnknownRuntime, ""
140+
return UnknownRuntime, "" // No match found
92141
}
93142

94143
// containerNameFromEnv extracts container metadata from environment variables

internal/resource/container_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ func TestContainerInfoFromCgroups(t *testing.T) {
6464
"/docker-ce82d94d69e1fbbc7feeb66930c69e9b96d9f151f594773e5d0e342741d15437",
6565
},
6666
expected: expect{id: "ce82d94d69e1fbbc7feeb66930c69e9b96d9f151f594773e5d0e342741d15437", runtime: DockerRuntime},
67+
}, {
68+
name: "Nested containers in same cgroup path (in kind cluster)",
69+
cgroups: []string{
70+
"0::/system.slice/docker-fd9d0ea06257a9780827cbc7fd92e3812a54fca26d63e191b73610d5d48b9cbd.scope/kubelet.slice/kubelet-kubepods.slice/kubelet-kubepods-besteffort.slice/kubelet-kubepods-besteffort-podeab5a334_93fe_48a8_b139_9e8079c1f163.slice/cri-containerd-99f3a16ea25b7724cb56a4f0c0df1113ad9474fbf5545bead97fd5c7f61c13f4.scope",
71+
},
72+
expected: expect{id: "99f3a16ea25b7724cb56a4f0c0df1113ad9474fbf5545bead97fd5c7f61c13f4", runtime: ContainerDRuntime},
6773
}}
6874

6975
for _, tc := range tt {

0 commit comments

Comments
 (0)