// Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 //go:build linux package proclib import ( "time" "github.com/hashicorp/go-hclog" "github.com/hashicorp/nomad/client/lib/cgroupslib" "oss.indeed.com/go/libtime/decay" ) // LinuxWranglerCG1 is an implementation of ProcessWrangler that leverages // cgroups v1 on older Linux systems. // // e.g. Ubuntu 20.04 / RHEL 8 and previous versions. type LinuxWranglerCG1 struct { task Task log hclog.Logger cg cgroupslib.Lifecycle } func newCG1(c *Configs) (create, error) { logger := c.Logger.Named("cg1") err := cgroupslib.Init(logger, c.UsableCores.String()) if err != nil { return nil, err } return func(task Task) ProcessWrangler { return &LinuxWranglerCG1{ task: task, log: logger, cg: cgroupslib.Factory(task.AllocID, task.Task, task.Cores), } }, nil } func (w *LinuxWranglerCG1) Initialize() error { w.log.Trace("initialize cgroups", "task", w.task) return w.cg.Setup() } func (w *LinuxWranglerCG1) Kill() error { w.log.Trace("force kill processes in cgroup", "task", w.task) return w.cg.Kill() } func (w *LinuxWranglerCG1) Cleanup() error { w.log.Trace("remove cgroups", "task", w.task) // need to give the kernel an opportunity to cleanup procs; which could // take some time while the procs wake from being thawed only to find they // have been issued a kill signal and need to be reaped rm := func() (bool, error) { err := w.cg.Teardown() if err != nil { return true, err } return false, nil } go func() { if err := decay.Backoff(rm, decay.BackoffOptions{ MaxSleepTime: 30 * time.Second, InitialGapSize: 1 * time.Second, }); err != nil { w.log.Debug("failed to cleanup cgroups", "alloc", w.task.AllocID, "task", w.task.Task, "error", err) } }() return nil }