diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f310bc2655..80731b0eadc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm These additions are replacements for the `Instrument` and `InstrumentKind` types from `go.opentelemetry.io/otel/sdk/metric/view`. (#3459) - The `Stream` type is added to `go.opentelemetry.io/otel/sdk/metric` to define a metric data stream a view will produce. (#3459) - The `AssertHasAttributes` allows instrument authors to test that datapoints returned have appropriate attributes. (#3487) +- Both `"go.opentelemetry.io/otel/sdk/resource".WithContainer` and `"go.opentelemetry.io/otel/sdk/resource".WithContainerID` now support the cgoupv2 files. (#3508) ### Changed @@ -79,6 +80,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Handle partial success responses in `go.opentelemetry.io/otel/exporters/otlp/otlpmetric` exporters. (#3162, #3440) - Prevent duplicate Prometheus description, unit, and type. (#3469) - Prevents panic when using incorrect `attribute.Value.As[Type]Slice()`. (#3489) +- Both `"go.opentelemetry.io/otel/sdk/resource".WithContainer` and `"go.opentelemetry.io/otel/sdk/resource".WithContainerID` now return the correct container ID on the Podman. (#3508) ### Removed diff --git a/sdk/resource/container.go b/sdk/resource/container.go index 7a897e96977..fd9a31fd620 100644 --- a/sdk/resource/container.go +++ b/sdk/resource/container.go @@ -20,7 +20,6 @@ import ( "errors" "io" "os" - "regexp" semconv "go.opentelemetry.io/otel/semconv/v1.12.0" ) @@ -28,16 +27,15 @@ import ( type containerIDProvider func() (string, error) var ( - containerID containerIDProvider = getContainerIDFromCGroup - cgroupContainerIDRe = regexp.MustCompile(`^.*/(?:.*-)?([0-9a-f]+)(?:\.|\s*$)`) + containerID containerIDProvider = getContainerIDFromCGroup + cgroupV1ContainerIDProvider containerIDProvider = getContainerIDFromCGroupV1 + cgroupV2ContainerIDProvider containerIDProvider = getContainerIDFromCGroupV2 ) type cgroupContainerIDDetector struct{} -const cgroupPath = "/proc/self/cgroup" - -// Detect returns a *Resource that describes the id of the container. -// If no container id found, an empty resource will be returned. +// Detect returns a *Resource that describes the ID of the container. +// If no container ID found, an empty resource will be returned. func (cgroupContainerIDDetector) Detect(ctx context.Context) (*Resource, error) { containerID, err := containerID() if err != nil { @@ -60,9 +58,27 @@ var ( osOpen = defaultOSOpen ) -// getContainerIDFromCGroup returns the id of the container from the cgroup file. -// If no container id found, an empty string will be returned. +// getContainerIDFromCGroup returns the ID of the container from the cgroup file. +// If cgroup v1 container ID provider fails, then fall back to cgroup v2 container ID provider. +// If no container ID found, an empty string will be returned. func getContainerIDFromCGroup() (string, error) { + containerID, err := cgroupV1ContainerIDProvider() + if err != nil { + return "", err + } + + if containerID == "" { + // Fallback to cgroup v2 + containerID, err = cgroupV2ContainerIDProvider() + if err != nil { + return "", err + } + } + + return containerID, nil +} + +func getContainerIDFromCGroupFile(cgroupPath string, extractor func(string) string) (string, error) { if _, err := osStat(cgroupPath); errors.Is(err, os.ErrNotExist) { // File does not exist, skip return "", nil @@ -74,27 +90,18 @@ func getContainerIDFromCGroup() (string, error) { } defer file.Close() - return getContainerIDFromReader(file), nil + return getContainerIDFromReader(file, extractor), nil } -// getContainerIDFromReader returns the id of the container from reader. -func getContainerIDFromReader(reader io.Reader) string { +// getContainerIDFromReader returns the ID of the container from reader. +func getContainerIDFromReader(reader io.Reader, extractor func(string) string) string { scanner := bufio.NewScanner(reader) for scanner.Scan() { line := scanner.Text() - if id := getContainerIDFromLine(line); id != "" { + if id := extractor(line); id != "" { return id } } return "" } - -// getContainerIDFromLine returns the id of the container from one string line. -func getContainerIDFromLine(line string) string { - matches := cgroupContainerIDRe.FindStringSubmatch(line) - if len(matches) <= 1 { - return "" - } - return matches[1] -} diff --git a/sdk/resource/container_id_cgroup_v1.go b/sdk/resource/container_id_cgroup_v1.go new file mode 100644 index 00000000000..c7da6285c25 --- /dev/null +++ b/sdk/resource/container_id_cgroup_v1.go @@ -0,0 +1,42 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package resource // import "go.opentelemetry.io/otel/sdk/resource" + +import ( + "regexp" + "strings" +) + +const cgroupV1Path = "/proc/self/cgroup" + +var cgroupV1ContainerIDRe = regexp.MustCompile(`^.*/(?:.*-)?([\w+-]+)(?:\.|\s*$)`) + +func getContainerIDFromCGroupV1() (string, error) { + return getContainerIDFromCGroupFile(cgroupV1Path, getContainerIDFromCgroupV1Line) +} + +// getContainerIDFromCgroupV1Line returns the ID of the container from one string line. +func getContainerIDFromCgroupV1Line(line string) string { + // Only match line contains "cpuset" + if !strings.Contains(line, "cpuset") { + return "" + } + + matches := cgroupV1ContainerIDRe.FindStringSubmatch(line) + if len(matches) <= 1 { + return "" + } + return matches[1] +} diff --git a/sdk/resource/container_id_cgroup_v1_test.go b/sdk/resource/container_id_cgroup_v1_test.go new file mode 100644 index 00000000000..786f20956d4 --- /dev/null +++ b/sdk/resource/container_id_cgroup_v1_test.go @@ -0,0 +1,83 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package resource // import "go.opentelemetry.io/otel/sdk/resource" + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetContainerIDFromCgroupV1Line(t *testing.T) { + testCases := []struct { + name string + line string + expectedContainerID string + }{ + { + name: "with suffix", + line: "13:cpuset:/podruntime/docker/kubepods/ac679f8a8319c8cf7d38e1adf263bc08d23.aaaa", + expectedContainerID: "ac679f8a8319c8cf7d38e1adf263bc08d23", + }, + { + name: "with prefix and suffix", + line: "13:cpuset:/podruntime/docker/kubepods/crio-dc679f8a8319c8cf7d38e1adf263bc08d23.stuff", + expectedContainerID: "dc679f8a8319c8cf7d38e1adf263bc08d23", + }, + { + name: "no prefix and suffix", + line: "13:cpuset:/pod/d86d75589bf6cc254f3e2cc29debdf85dde404998aa128997a819ff991827356", + expectedContainerID: "d86d75589bf6cc254f3e2cc29debdf85dde404998aa128997a819ff991827356", + }, + { + name: "with space", + line: " 13:cpuset:/pod/d86d75589bf6cc254f3e2cc29debdf85dde404998aa128997a819ff991827356 ", + expectedContainerID: "d86d75589bf6cc254f3e2cc29debdf85dde404998aa128997a819ff991827356", + }, + { + name: "invalid hex string", + line: "13:name=systemd:/podruntime/docker/kubepods/ac679f8a8319c8cf7d38e1adf263bc08d23zzzz", + }, + { + name: "no container id - 1", + line: "pids: /", + }, + { + name: "no container id - 2", + line: "pids: ", + }, + { + name: "minikube containerd cgroup", + line: "11:cpuset:/kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236", + expectedContainerID: "58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236", + }, + { + name: "minikube docker cgroup", + line: "5:cpuset:/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod350bff31_89d4_429e_b653_86d8167bc60e.slice/docker-3a5881f09ab409d7ac174b59f20d003b28b76da368257eb1e3d23648920a742b.scope", + expectedContainerID: "3a5881f09ab409d7ac174b59f20d003b28b76da368257eb1e3d23648920a742b", + }, + { + name: "podman cgroup", + line: "14:name=systemd:/user.slice/user-1000.slice/user@1000.service/app.slice/podman.service", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + containerID := getContainerIDFromCgroupV1Line(tc.line) + assert.Equal(t, tc.expectedContainerID, containerID) + }) + } +} diff --git a/sdk/resource/container_id_cgroup_v2.go b/sdk/resource/container_id_cgroup_v2.go new file mode 100644 index 00000000000..44166acd09b --- /dev/null +++ b/sdk/resource/container_id_cgroup_v2.go @@ -0,0 +1,42 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package resource // import "go.opentelemetry.io/otel/sdk/resource" + +import ( + "regexp" + "strings" +) + +const cgroupV2Path = "/proc/self/mountinfo" + +var cgroupV2ContainerIDRe = regexp.MustCompile(`^.*/.+/([\w+-.]{64})/.*$`) + +func getContainerIDFromCGroupV2() (string, error) { + return getContainerIDFromCGroupFile(cgroupV2Path, getContainerIDFromCgroupV2Line) +} + +// getContainerIDFromCgroupV2Line returns the ID of the container from one string line. +func getContainerIDFromCgroupV2Line(line string) string { + // Only match line contains "cpuset" + if !strings.Contains(line, "hostname") { + return "" + } + + matches := cgroupV2ContainerIDRe.FindStringSubmatch(line) + if len(matches) <= 1 { + return "" + } + return matches[1] +} diff --git a/sdk/resource/container_id_cgroup_v2_test.go b/sdk/resource/container_id_cgroup_v2_test.go new file mode 100644 index 00000000000..8da98f3dad8 --- /dev/null +++ b/sdk/resource/container_id_cgroup_v2_test.go @@ -0,0 +1,74 @@ +// Copyright The OpenTelemetry Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package resource // import "go.opentelemetry.io/otel/sdk/resource" + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestGetContainerIDFromCgroupV2Line(t *testing.T) { + testCases := []struct { + name string + line string + expectedContainerID string + }{ + { + name: "empty - 1", + line: "456 375 0:143 / / rw,relatime master:175 - overlay overlay rw,lowerdir=/var/lib/docker/overlay2/l/37L57D2IM7MEWLVE2Q2ECNDT67:/var/lib/docker/overlay2/l/46FCA2JFPCSNFGAR5TSYLLNHLK,upperdir=/var/lib/docker/overlay2/4e82c300793d703c19bdf887bfdad8b0354edda884ea27a8a2df89ab292719a4/diff,workdir=/var/lib/docker/overlay2/4e82c300793d703c19bdf887bfdad8b0354edda884ea27a8a2df89ab292719a4/work", + }, + { + name: "empty - 2", + line: "457 456 0:146 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw", + }, + { + name: "empty - 3", + line: "383 457 0:147 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755", + }, + { + name: "hostname", + line: "473 456 254:1 /docker/containers/dc64b5743252dbaef6e30521c34d6bbd1620c8ce65bdb7bf9e7143b61bb5b183/hostname /etc/hostname rw,relatime - ext4 /dev/vda1 rw", + expectedContainerID: "dc64b5743252dbaef6e30521c34d6bbd1620c8ce65bdb7bf9e7143b61bb5b183", + }, + { + name: "minikube containerd mountinfo", + line: "1537 1517 8:1 /var/lib/containerd/io.containerd.grpc.v1.cri/sandboxes/fb5916a02feca96bdeecd8e062df9e5e51d6617c8214b5e1f3ff9320f4402ae6/hostname /etc/hostname rw,relatime - ext4 /dev/sda1 rw", + expectedContainerID: "fb5916a02feca96bdeecd8e062df9e5e51d6617c8214b5e1f3ff9320f4402ae6", + }, + { + name: "minikube docker mountinfo", + line: "2327 2307 8:1 /var/lib/docker/containers/a1551a1d7e1881d6c18d2c9ec462cab6ad3666825f0adb2098e9d5b198fd7e19/hostname /etc/hostname rw,relatime - ext4 /dev/sda1 rw", + expectedContainerID: "a1551a1d7e1881d6c18d2c9ec462cab6ad3666825f0adb2098e9d5b198fd7e19", + }, + { + name: "minikube docker mountinfo 2", + line: "929 920 254:1 /docker/volumes/minikube/_data/lib/docker/containers/0eaa6718003210b6520f7e82d14b4c8d4743057a958a503626240f8d1900bc33/hostname /etc/hostname rw,relatime - ext4 /dev/vda1 rw", + expectedContainerID: "0eaa6718003210b6520f7e82d14b4c8d4743057a958a503626240f8d1900bc33", + }, + { + name: "podman mountinfo", + line: "1096 1088 0:104 /containers/overlay-containers/1a2de27e7157106568f7e081e42a8c14858c02bd9df30d6e352b298178b46809/userdata/hostname /etc/hostname rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=813800k,nr_inodes=203450,mode=700,uid=1000,gid=1000", + expectedContainerID: "1a2de27e7157106568f7e081e42a8c14858c02bd9df30d6e352b298178b46809", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + containerID := getContainerIDFromCgroupV2Line(tc.line) + assert.Equal(t, tc.expectedContainerID, containerID) + }) + } +} diff --git a/sdk/resource/container_test.go b/sdk/resource/container_test.go index b09160da872..016fb399bf8 100644 --- a/sdk/resource/container_test.go +++ b/sdk/resource/container_test.go @@ -36,54 +36,6 @@ func setContainerProviders( containerID = idProvider } -func TestGetContainerIDFromLine(t *testing.T) { - testCases := []struct { - name string - line string - expectedContainerID string - }{ - { - name: "with suffix", - line: "13:name=systemd:/podruntime/docker/kubepods/ac679f8a8319c8cf7d38e1adf263bc08d23.aaaa", - expectedContainerID: "ac679f8a8319c8cf7d38e1adf263bc08d23", - }, - { - name: "with prefix and suffix", - line: "13:name=systemd:/podruntime/docker/kubepods/crio-dc679f8a8319c8cf7d38e1adf263bc08d23.stuff", - expectedContainerID: "dc679f8a8319c8cf7d38e1adf263bc08d23", - }, - { - name: "no prefix and suffix", - line: "13:name=systemd:/pod/d86d75589bf6cc254f3e2cc29debdf85dde404998aa128997a819ff991827356", - expectedContainerID: "d86d75589bf6cc254f3e2cc29debdf85dde404998aa128997a819ff991827356", - }, - { - name: "with space", - line: " 13:name=systemd:/pod/d86d75589bf6cc254f3e2cc29debdf85dde404998aa128997a819ff991827356 ", - expectedContainerID: "d86d75589bf6cc254f3e2cc29debdf85dde404998aa128997a819ff991827356", - }, - { - name: "invalid hex string", - line: "13:name=systemd:/podruntime/docker/kubepods/ac679f8a8319c8cf7d38e1adf263bc08d23zzzz", - }, - { - name: "no container id - 1", - line: "pids: /", - }, - { - name: "no container id - 2", - line: "pids: ", - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - containerID := getContainerIDFromLine(tc.line) - assert.Equal(t, tc.expectedContainerID, containerID) - }) - } -} - func TestGetContainerIDFromReader(t *testing.T) { testCases := []struct { name string @@ -93,8 +45,8 @@ func TestGetContainerIDFromReader(t *testing.T) { { name: "multiple lines", reader: strings.NewReader(`// -1:name=systemd:/podruntime/docker/kubepods/docker-dc579f8a8319c8cf7d38e1adf263bc08d23 -1:name=systemd:/podruntime/docker/kubepods/docker-dc579f8a8319c8cf7d38e1adf263bc08d24 +1:cpuset:/podruntime/docker/kubepods/docker-dc579f8a8319c8cf7d38e1adf263bc08d23 +1:cpuset:/podruntime/docker/kubepods/docker-dc579f8a8319c8cf7d38e1adf263bc08d24 `), expectedContainerID: "dc579f8a8319c8cf7d38e1adf263bc08d23", }, @@ -109,7 +61,7 @@ func TestGetContainerIDFromReader(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - containerID := getContainerIDFromReader(tc.reader) + containerID := getContainerIDFromReader(tc.reader, getContainerIDFromCgroupV1Line) assert.Equal(t, tc.expectedContainerID, containerID) }) } @@ -122,16 +74,19 @@ func TestGetContainerIDFromCGroup(t *testing.T) { }) testCases := []struct { - name string - cgroupFileNotExist bool - openFileError error - content string - expectedContainerID string - expectedError bool + name string + cgroupV1FileNotExist bool + cgroupV2FileNotExist bool + openFileError error + cgroupV1FileContent string + cgroupV2FileContent string + expectedContainerID string + expectedError bool }{ { - name: "the cgroup file does not exist", - cgroupFileNotExist: true, + name: "the cgroup file does not exist", + cgroupV1FileNotExist: true, + cgroupV2FileNotExist: true, }, { name: "error when opening cgroup file", @@ -139,16 +94,128 @@ func TestGetContainerIDFromCGroup(t *testing.T) { expectedError: true, }, { - name: "cgroup file", - content: "1:name=systemd:/podruntime/docker/kubepods/docker-dc579f8a8319c8cf7d38e1adf263bc08d23", + name: "cgroup file v1", + cgroupV1FileContent: "1:cpuset:/podruntime/docker/kubepods/docker-dc579f8a8319c8cf7d38e1adf263bc08d23", expectedContainerID: "dc579f8a8319c8cf7d38e1adf263bc08d23", }, + { + name: "cgroup file v2", + cgroupV2FileContent: "474 456 254:1 /docker/containers/dc64b5743252dbaef6e30521c34d6bbd1620c8ce65bdb7bf9e7143b61bb5b183/hostname /etc/hosts rw,relatime - ext4 /dev/vda1 rw", + expectedContainerID: "dc64b5743252dbaef6e30521c34d6bbd1620c8ce65bdb7bf9e7143b61bb5b183", + }, + { + name: "both way fail", + cgroupV1FileContent: " ", + cgroupV2FileContent: " ", + }, + { + name: "minikube containerd", + cgroupV1FileContent: `11:cpuset:/kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 +10:hugetlb:/kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 +9:pids:/kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 +8:memory:/kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 +7:net_cls,net_prio:/kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 +6:perf_event:/kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 +5:blkio:/kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 +4:devices:/kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 +3:freezer:/kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 +2:cpu,cpuacct:/kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 +1:name=systemd:/kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236`, + cgroupV2FileContent: `1517 1428 0:208 / / rw,relatime master:510 - overlay overlay rw,lowerdir=/mnt/sda1/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/34/fs,upperdir=/mnt/sda1/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/35/fs,workdir=/mnt/sda1/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/35/work +1518 1517 0:210 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +1519 1517 0:211 / /dev rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +1520 1519 0:212 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +1521 1519 0:198 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +1522 1517 0:203 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs ro +1523 1522 0:213 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,mode=755 +1524 1523 0:24 /kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 /sys/fs/cgroup/systemd ro,nosuid,nodev,noexec,relatime master:8 - cgroup cgroup rw,xattr,release_agent=/usr/lib/systemd/systemd-cgroups-agent,name=systemd +1525 1523 0:26 /kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 /sys/fs/cgroup/cpu,cpuacct ro,nosuid,nodev,noexec,relatime master:11 - cgroup cgroup rw,cpu,cpuacct +1526 1523 0:27 /kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 /sys/fs/cgroup/freezer ro,nosuid,nodev,noexec,relatime master:12 - cgroup cgroup rw,freezer +1527 1523 0:28 /kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 /sys/fs/cgroup/devices ro,nosuid,nodev,noexec,relatime master:13 - cgroup cgroup rw,devices +1528 1523 0:29 /kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 /sys/fs/cgroup/blkio ro,nosuid,nodev,noexec,relatime master:14 - cgroup cgroup rw,blkio +1529 1523 0:30 /kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 /sys/fs/cgroup/perf_event ro,nosuid,nodev,noexec,relatime master:15 - cgroup cgroup rw,perf_event +1530 1523 0:31 /kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 /sys/fs/cgroup/net_cls,net_prio ro,nosuid,nodev,noexec,relatime master:16 - cgroup cgroup rw,net_cls,net_prio +1531 1523 0:32 /kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 /sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime master:17 - cgroup cgroup rw,memory +1532 1523 0:33 /kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 /sys/fs/cgroup/pids ro,nosuid,nodev,noexec,relatime master:18 - cgroup cgroup rw,pids +1533 1523 0:34 /kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 /sys/fs/cgroup/hugetlb ro,nosuid,nodev,noexec,relatime master:19 - cgroup cgroup rw,hugetlb +1534 1523 0:35 /kubepods/besteffort/pod28478e30-384f-41e5-9d85-eae249ae8506/58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236 /sys/fs/cgroup/cpuset ro,nosuid,nodev,noexec,relatime master:20 - cgroup cgroup rw,cpuset +1535 1517 8:1 /var/lib/kubelet/pods/28478e30-384f-41e5-9d85-eae249ae8506/etc-hosts /etc/hosts rw,relatime - ext4 /dev/sda1 rw +1536 1519 8:1 /var/lib/kubelet/pods/28478e30-384f-41e5-9d85-eae249ae8506/containers/alpine/e3d5dec7 /dev/termination-log rw,relatime - ext4 /dev/sda1 rw +1537 1517 8:1 /var/lib/containerd/io.containerd.grpc.v1.cri/sandboxes/fb5916a02feca96bdeecd8e062df9e5e51d6617c8214b5e1f3ff9320f4402ae6/hostname /etc/hostname rw,relatime - ext4 /dev/sda1 rw +1538 1517 8:1 /var/lib/containerd/io.containerd.grpc.v1.cri/sandboxes/fb5916a02feca96bdeecd8e062df9e5e51d6617c8214b5e1f3ff9320f4402ae6/resolv.conf /etc/resolv.conf rw,relatime - ext4 /dev/sda1 rw +1539 1519 0:195 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=65536k +1540 1517 0:194 / /run/secrets/kubernetes.io/serviceaccount ro,relatime - tmpfs tmpfs rw,size=5925720k +1429 1519 0:212 /0 /dev/console rw,nosuid,noexec,relatime - devpts devpts rw,gid=5,mode=620,ptmxmode=666 +1430 1518 0:210 /asound /proc/asound ro,nosuid,nodev,noexec,relatime - proc proc rw +1431 1518 0:210 /bus /proc/bus ro,nosuid,nodev,noexec,relatime - proc proc rw +1432 1518 0:210 /fs /proc/fs ro,nosuid,nodev,noexec,relatime - proc proc rw +1433 1518 0:210 /irq /proc/irq ro,nosuid,nodev,noexec,relatime - proc proc rw +1434 1518 0:210 /sys /proc/sys ro,nosuid,nodev,noexec,relatime - proc proc rw +1435 1518 0:210 /sysrq-trigger /proc/sysrq-trigger ro,nosuid,nodev,noexec,relatime - proc proc rw +1436 1518 0:214 / /proc/acpi ro,relatime - tmpfs tmpfs ro +1437 1518 0:211 /null /proc/kcore rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +1438 1518 0:211 /null /proc/keys rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +1439 1518 0:211 /null /proc/timer_list rw,nosuid - tmpfs tmpfs rw,size=65536k,mode=755 +1440 1518 0:215 / /proc/scsi ro,relatime - tmpfs tmpfs ro +1441 1522 0:216 / /sys/firmware ro,relatime - tmpfs tmpfs ro`, + expectedContainerID: "58a77afcbf0b16959d526758f6696677c862517acc97a562dc5c5b09afbf5236", + }, + { + name: "minikube docker cgroup", + cgroupV1FileContent: `11:blkio:/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod350bff31_89d4_429e_b653_86d8167bc60e.slice/docker-3a5881f09ab409d7ac174b59f20d003b28b76da368257eb1e3d23648920a742b.scope +10:perf_event:/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod350bff31_89d4_429e_b653_86d8167bc60e.slice/docker-3a5881f09ab409d7ac174b59f20d003b28b76da368257eb1e3d23648920a742b.scope +9:pids:/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod350bff31_89d4_429e_b653_86d8167bc60e.slice/docker-3a5881f09ab409d7ac174b59f20d003b28b76da368257eb1e3d23648920a742b.scope +8:memory:/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod350bff31_89d4_429e_b653_86d8167bc60e.slice/docker-3a5881f09ab409d7ac174b59f20d003b28b76da368257eb1e3d23648920a742b.scope +7:cpu,cpuacct:/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod350bff31_89d4_429e_b653_86d8167bc60e.slice/docker-3a5881f09ab409d7ac174b59f20d003b28b76da368257eb1e3d23648920a742b.scope +6:net_cls,net_prio:/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod350bff31_89d4_429e_b653_86d8167bc60e.slice/docker-3a5881f09ab409d7ac174b59f20d003b28b76da368257eb1e3d23648920a742b.scope +5:cpuset:/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod350bff31_89d4_429e_b653_86d8167bc60e.slice/docker-3a5881f09ab409d7ac174b59f20d003b28b76da368257eb1e3d23648920a742b.scope +4:devices:/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod350bff31_89d4_429e_b653_86d8167bc60e.slice/docker-3a5881f09ab409d7ac174b59f20d003b28b76da368257eb1e3d23648920a742b.scope +3:hugetlb:/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod350bff31_89d4_429e_b653_86d8167bc60e.slice/docker-3a5881f09ab409d7ac174b59f20d003b28b76da368257eb1e3d23648920a742b.scope +2:freezer:/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod350bff31_89d4_429e_b653_86d8167bc60e.slice/docker-3a5881f09ab409d7ac174b59f20d003b28b76da368257eb1e3d23648920a742b.scope +1:name=systemd:/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod350bff31_89d4_429e_b653_86d8167bc60e.slice/docker-3a5881f09ab409d7ac174b59f20d003b28b76da368257eb1e3d23648920a742b.scope`, + expectedContainerID: "3a5881f09ab409d7ac174b59f20d003b28b76da368257eb1e3d23648920a742b", + }, + { + name: "podman cgroup", + cgroupV1FileContent: `14:name=systemd:/user.slice/user-1000.slice/user@1000.service/app.slice/podman.service +13:rdma:/ +12:pids:/user.slice/user-1000.slice/user@1000.service +11:hugetlb:/ +10:net_prio:/ +9:perf_event:/ +8:net_cls:/ +7:freezer:/ +6:devices:/user.slice +5:blkio:/user.slice +4:cpuacct:/ +3:cpu:/user.slice +2:cpuset:/ +1:memory:/user.slice/user-1000.slice/user@1000.service +0::/user.slice/user-1000.slice/user@1000.service/app.slice/podman.service`, + cgroupV2FileContent: `1088 875 0:118 / / rw,noatime - fuse.fuse-overlayfs fuse-overlayfs rw,user_id=0,group_id=0,default_permissions,allow_other +1089 1088 0:121 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw +1090 1088 0:122 / /dev rw,nosuid,noexec - tmpfs tmpfs rw,size=65536k,mode=755,uid=1000,gid=1000 +1091 1088 0:123 / /sys ro,nosuid,nodev,noexec,relatime - sysfs sysfs rw +1092 1090 0:124 / /dev/pts rw,nosuid,noexec,relatime - devpts devpts rw,gid=100004,mode=620,ptmxmode=666 +1093 1090 0:120 / /dev/mqueue rw,nosuid,nodev,noexec,relatime - mqueue mqueue rw +1094 1088 0:104 /containers/overlay-containers/1a2de27e7157106568f7e081e42a8c14858c02bd9df30d6e352b298178b46809/userdata/hosts /etc/hosts rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=813800k,nr_inodes=203450,mode=700,uid=1000,gid=1000 +1095 1090 0:117 / /dev/shm rw,nosuid,nodev,noexec,relatime - tmpfs shm rw,size=64000k,uid=1000,gid=1000 +1096 1088 0:104 /containers/overlay-containers/1a2de27e7157106568f7e081e42a8c14858c02bd9df30d6e352b298178b46809/userdata/hostname /etc/hostname rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=813800k,nr_inodes=203450,mode=700,uid=1000,gid=1000 +1097 1088 0:104 /containers/overlay-containers/1a2de27e7157106568f7e081e42a8c14858c02bd9df30d6e352b298178b46809/userdata/.containerenv /run/.containerenv rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=813800k,nr_inodes=203450,mode=700,uid=1000,gid=1000 +1098 1088 0:104 /containers/overlay-containers/1a2de27e7157106568f7e081e42a8c14858c02bd9df30d6e352b298178b46809/userdata/run/secrets /run/secrets rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=813800k,nr_inodes=203450,mode=700,uid=1000,gid=1000 +1099 1088 0:104 /containers/overlay-containers/1a2de27e7157106568f7e081e42a8c14858c02bd9df30d6e352b298178b46809/userdata/resolv.conf /etc/resolv.conf rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=813800k,nr_inodes=203450,mode=700,uid=1000,gid=1000 +1100 1091 0:125 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime - tmpfs cgroup rw,size=1024k,uid=1000,gid=1000`, + expectedContainerID: "1a2de27e7157106568f7e081e42a8c14858c02bd9df30d6e352b298178b46809", + }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { osStat = func(name string) (os.FileInfo, error) { - if tc.cgroupFileNotExist { + if tc.cgroupV1FileNotExist && name == cgroupV1Path { + return nil, os.ErrNotExist + } + if tc.cgroupV2FileNotExist && name == cgroupV2Path { return nil, os.ErrNotExist } return nil, nil @@ -158,7 +225,10 @@ func TestGetContainerIDFromCGroup(t *testing.T) { if tc.openFileError != nil { return nil, tc.openFileError } - return io.NopCloser(strings.NewReader(tc.content)), nil + if name == cgroupV1Path { + return io.NopCloser(strings.NewReader(tc.cgroupV1FileContent)), nil + } + return io.NopCloser(strings.NewReader(tc.cgroupV2FileContent)), nil } containerID, err := getContainerIDFromCGroup()