github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/client/lib/resources/containment_linux.go (about) 1 //go:build linux 2 3 package resources 4 5 import ( 6 "fmt" 7 "os" 8 "path/filepath" 9 "sync" 10 11 "github.com/hashicorp/go-hclog" 12 "github.com/hashicorp/nomad/client/lib/cgutil" 13 "github.com/opencontainers/runc/libcontainer/cgroups" 14 "github.com/opencontainers/runc/libcontainer/cgroups/fs2" 15 "github.com/opencontainers/runc/libcontainer/configs" 16 ) 17 18 type containment struct { 19 lock sync.RWMutex 20 cgroup *configs.Cgroup 21 logger hclog.Logger 22 } 23 24 func Contain(logger hclog.Logger, cgroup *configs.Cgroup) *containment { 25 return &containment{ 26 cgroup: cgroup, 27 logger: logger.Named("containment"), 28 } 29 } 30 31 func (c *containment) Apply(pid int) error { 32 c.lock.Lock() 33 defer c.lock.Unlock() 34 35 c.logger.Trace("create containment for", "cgroup", c.cgroup, "pid", pid) 36 37 // for v2 use manager to create and enter the cgroup 38 if cgutil.UseV2 { 39 mgr, err := fs2.NewManager(c.cgroup, "") 40 if err != nil { 41 return fmt.Errorf("failed to create v2 cgroup manager for containment: %w", err) 42 } 43 44 // add the pid to the cgroup 45 if err = mgr.Apply(pid); err != nil { 46 return fmt.Errorf("failed to apply v2 cgroup containment: %w", err) 47 } 48 49 // in v2 it is important to set the device resource configuration 50 if err = mgr.Set(c.cgroup.Resources); err != nil { 51 return fmt.Errorf("failed to set v2 cgroup resources: %w", err) 52 } 53 54 return nil 55 } 56 57 // for v1 a random cgroup was created already; just enter it 58 if err := cgroups.EnterPid(map[string]string{"freezer": c.cgroup.Path}, pid); err != nil { 59 return fmt.Errorf("failed to add pid to v1 cgroup: %w", err) 60 } 61 62 return nil 63 } 64 65 func (c *containment) Cleanup() error { 66 c.lock.Lock() 67 defer c.lock.Unlock() 68 69 // the current pid is of the executor, who manages the task process cleanup 70 executorPID := os.Getpid() 71 c.logger.Trace("cleanup on", "cgroup", c.cgroup, "executor_pid", executorPID) 72 73 // destroy the task processes 74 destroyer := cgutil.NewGroupKiller(c.logger, executorPID) 75 return destroyer.KillGroup(c.cgroup) 76 } 77 78 func (c *containment) GetPIDs() PIDs { 79 c.lock.Lock() 80 defer c.lock.Unlock() 81 82 m := make(PIDs) 83 if c.cgroup == nil { 84 return m 85 } 86 87 // get the cgroup path under containment 88 var path string 89 if cgutil.UseV2 { 90 path = filepath.Join(cgutil.CgroupRoot, c.cgroup.Path) 91 } else { 92 path = c.cgroup.Path 93 } 94 95 // find the pids in the cgroup under containment 96 pids, err := cgroups.GetAllPids(path) 97 if err != nil { 98 c.logger.Debug("failed to get pids", "cgroup", c.cgroup, "error", err) 99 return m 100 } 101 102 for _, pid := range pids { 103 m[pid] = NewPID(pid) 104 } 105 106 return m 107 }