Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CONTINT-3554] Fix build on linux and do not send cgroup node inode if in host cgroup namespace #2453

Merged
merged 5 commits into from
Dec 20, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
44 changes: 33 additions & 11 deletions internal/container.go → internal/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016 Datadog, Inc.

//go:build linux

package internal

import (
Expand All @@ -20,20 +22,20 @@ const (
// cgroupPath is the path to the cgroup file where we can find the container id if one exists.
cgroupPath = "/proc/self/cgroup"

// cgroupV2Key is the key used to store the cgroup v2 identify the cgroupv2 mount point in the cgroupMounts map.
cgroupV2Key = "cgroupv2"

// cgroupV1BaseController is the base controller used to identify the cgroup v1 mount point in the cgroupMounts map.
cgroupV1BaseController = "memory"

// defaultCgroupMountPath is the path to the cgroup mount point.
defaultCgroupMountPath = "/sys/fs/cgroup"
)

const (
uuidSource = "[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}|[0-9a-f]{8}(?:-[0-9a-f]{4}){4}$"
containerSource = "[0-9a-f]{64}"
taskSource = "[0-9a-f]{32}-\\d+"

// From https://github.com/torvalds/linux/blob/5859a2b1991101d6b978f3feb5325dad39421f29/include/linux/proc_ns.h#L41-L49
// Currently, host namespace inode number are hardcoded, which can be used to detect
// if we're running in host namespace or not (does not work when running in DinD)
hostCgroupNamespaceInode = 0xEFFFFFFB
)

var (
Expand All @@ -47,9 +49,8 @@ var (
containerID string

// entityID is the entityID to use for the container. It is the `cid-<containerID>` if the container id available,
// otherwise the cgroup v2 node inode prefixed with `in-` or an empty string on cgroup v1 or incompatible OS.
// It is retrieved by finding cgroup2 mounts in /proc/mounts, finding the cgroup v2 node path in /proc/self/cgroup and
// calling stat on mountPath+nodePath to get the inode.
// otherwise the cgroup node controller's inode prefixed with `in-` or an empty string on incompatible OS.
// We use the memory controller on cgroupv1 and the root cgroup on cgroupv2.
entityID string
)

Expand Down Expand Up @@ -145,16 +146,37 @@ func inodeForPath(path string) string {
return fmt.Sprintf("in-%d", stats.Ino)
}

// readEntityID attempts to return the cgroup v2 node inode or empty on failure.
// readEntityID attempts to return the cgroup node inode or empty on failure.
func readEntityID(mountPath, cgroupPath string) string {
// First try to emit the containerID if available. It will be retrieved if the container is
// running in the host cgroup namespace, independently of the cgroup version.
if containerID != "" {
return "cid-" + containerID
}
// Rely on the inode if we're not running in the host cgroup namespace.
if isHostCgroupNamespace() {
return ""
}
return getCgroupInode(mountPath, cgroupPath)
}

// EntityID attempts to return the container ID or the cgroup v2 node inode if the container ID is not available.
// The cid is prefixed with `cid-` and the inode with `in-`.
// EntityID attempts to return the container ID or the cgroup node controller's inode if the container ID
// is not available. The cid is prefixed with `cid-` and the inode with `in-`.
func EntityID() string {
return entityID
}

// isHostCgroupNamespace checks if the agent is running in the host cgroup namespace.
func isHostCgroupNamespace() bool {
fi, err := os.Stat("/proc/self/ns/cgroup")
if err != nil {
return false
}

stat, ok := fi.Sys().(*syscall.Stat_t)
if ok {
return stat.Ino == hostCgroupNamespaceInode
}

return false
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016 Datadog, Inc.

//go:build test && linux
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test build tag isn't defined, so these tests won't run. I think you just want the linux tag.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I just removed it !

I also asked a review to my team members. They should have the knowledge necessary. Normally I am just aligning on what is done in dogstatsd DataDog/datadog-go#291


package internal

import (
Expand Down
19 changes: 19 additions & 0 deletions internal/container_stub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Unless explicitly stated otherwise all files in this repository are licensed
// under the Apache License Version 2.0.
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2016 Datadog, Inc.

//go:build !linux

package internal

// ContainerID attempts to return the container ID from /proc/self/cgroup or empty on failure.
func ContainerID() string {
return ""
}

// EntityID attempts to return the container ID or the cgroup v2 node inode if the container ID is not available.
// The cid is prefixed with `cid-` and the inode with `in-`.
func EntityID() string {
return ""
}