Files
nomad/client/lib/cgutil/cpuset_manager.go
Seth Hoenig 13bd08b15b client: refactor cpuset manager initialization
This PR refactors the code path in Client startup for setting up the cpuset
cgroup manager (non-linux systems not affected).

Before, there was a logic bug where we would try to read the cpuset.cpus.effective
cgroup interface file before ensuring nomad's parent cgroup existed. Therefor that
file would not exist, and the list of useable cpus would be empty. Tasks started
thereafter would not have a value set for their cpuset.cpus.

The refactoring fixes some less than ideal coding style. Instead we now bootstrap
each cpuset manager type (v1/v2) within its own constructor. If something goes
awry during bootstrap (e.g. cgroups not enabled), the constructor returns the
noop implementation and logs a warning.

Fixes #14229
2022-08-25 11:18:43 -05:00

86 lines
2.4 KiB
Go

package cgutil
import (
"context"
"fmt"
"path/filepath"
"strings"
"github.com/hashicorp/nomad/lib/cpuset"
"github.com/hashicorp/nomad/nomad/structs"
)
const (
// CgroupRoot is hard-coded in the cgroups specification.
// It only applies to linux but helpers have references to it in driver(s).
CgroupRoot = "/sys/fs/cgroup"
)
// CpusetManager is used to setup cpuset cgroups for each task.
type CpusetManager interface {
// Init should be called before the client starts running allocations. This
// is where the cpuset manager should start doing background operations.
Init()
// AddAlloc adds an allocation to the manager
AddAlloc(alloc *structs.Allocation)
// RemoveAlloc removes an alloc by ID from the manager
RemoveAlloc(allocID string)
// CgroupPathFor returns a callback for getting the cgroup path and any error that may have occurred during
// cgroup initialization. The callback will block if the cgroup has not been created
CgroupPathFor(allocID, taskName string) CgroupPathGetter
}
type NoopCpusetManager struct{}
func (n NoopCpusetManager) Init() {
}
func (n NoopCpusetManager) AddAlloc(alloc *structs.Allocation) {
}
func (n NoopCpusetManager) RemoveAlloc(allocID string) {
}
func (n NoopCpusetManager) CgroupPathFor(allocID, task string) CgroupPathGetter {
return func(context.Context) (string, error) { return "", nil }
}
// CgroupPathGetter is a function which returns the cgroup path and any error which
// occurred during cgroup initialization.
//
// It should block until the cgroup has been created or an error is reported.
type CgroupPathGetter func(context.Context) (path string, err error)
type TaskCgroupInfo struct {
CgroupPath string
RelativeCgroupPath string
Cpuset cpuset.CPUSet
Error error
}
// identity is the "<allocID>.<taskName>" string that uniquely identifies an
// individual instance of a task within the flat cgroup namespace
type identity string
func makeID(allocID, task string) identity {
return identity(fmt.Sprintf("%s.%s", allocID, task))
}
func makeScope(id identity) string {
return string(id) + ".scope"
}
// SplitPath determines the parent and cgroup from p.
// p must contain at least 2 elements (parent + cgroup).
//
// Handles the cgroup root if present.
func SplitPath(p string) (string, string) {
p = strings.TrimPrefix(p, CgroupRoot)
p = strings.Trim(p, "/")
parts := strings.Split(p, "/")
return parts[0], "/" + filepath.Join(parts[1:]...)
}