github.com/mirantis/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/pkg/utils/cgroups/controllers.go (about) 1 /* 2 Copyright 2018 Mirantis 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package cgroups 18 19 import ( 20 "fmt" 21 "io" 22 "path/filepath" 23 "strings" 24 25 "github.com/Mirantis/virtlet/pkg/fs" 26 "github.com/Mirantis/virtlet/pkg/utils" 27 ) 28 29 const ( 30 cgroupfs = "/sys/fs/cgroup" 31 ) 32 33 // Controller represents a named controller for a process 34 type Controller struct { 35 fsys fs.FileSystem 36 name string 37 path string 38 } 39 40 // Manager provides an interface to operate on linux cgroups 41 type Manager interface { 42 // GetProcessControllers returns the mapping between controller types and 43 // their paths inside cgroup fs for the specified PID. 44 GetProcessControllers() (map[string]string, error) 45 // GetProcessController returns a named resource Controller for the specified PID. 46 GetProcessController(controllerName string) (*Controller, error) 47 // MoveProcess move the process to the path under a cgroup controller 48 MoveProcess(controller, path string) error 49 } 50 51 // RealManager provides an implementation of Manager which is 52 // using default linux system paths to access info about cgroups for processes. 53 type RealManager struct { 54 fsys fs.FileSystem 55 pid string 56 } 57 58 var _ Manager = &RealManager{} 59 60 // NewManager returns an instance of RealManager 61 func NewManager(pid interface{}, fsys fs.FileSystem) Manager { 62 if fsys == nil { 63 fsys = fs.RealFileSystem 64 } 65 return &RealManager{fsys: fsys, pid: utils.Stringify(pid)} 66 } 67 68 // GetProcessControllers is an implementation of GetProcessControllers method 69 // of Manager interface. 70 func (c *RealManager) GetProcessControllers() (map[string]string, error) { 71 fr, err := c.fsys.GetDelimitedReader(filepath.Join("/proc", c.pid, "cgroup")) 72 if err != nil { 73 return nil, err 74 } 75 defer fr.Close() 76 77 ctrls := make(map[string]string) 78 79 for { 80 line, err := fr.ReadString('\n') 81 if err != nil { 82 if err != io.EOF { 83 return nil, err 84 } 85 } 86 87 // strip eol 88 line = strings.Trim(line, "\n") 89 if line == "" { 90 break 91 } 92 93 // split entries like: 94 // "6:memory:/user.slice/user-xxx.slice/session-xx.scope" 95 parts := strings.SplitN(line, ":", 3) 96 97 name := parts[1] 98 if strings.HasPrefix(name, "name=") { 99 // Handle named cgroup hierarchies like name=systemd 100 // The corresponding directory tree will be /sys/fs/cgroup/systemd 101 name = name[5:] 102 } 103 104 // use second part as controller name and third as its path 105 ctrls[name] = parts[2] 106 107 if err == io.EOF { 108 break 109 } 110 } 111 112 return ctrls, nil 113 } 114 115 // GetProcessController is an implementation of GetProcessController method 116 // of Manager interface. 117 func (c *RealManager) GetProcessController(controllerName string) (*Controller, error) { 118 controllers, err := c.GetProcessControllers() 119 if err != nil { 120 return nil, err 121 } 122 123 controllerPath, ok := controllers[controllerName] 124 if !ok { 125 return nil, fmt.Errorf("controller %q for process %v not found", controllerName, c.pid) 126 } 127 128 return &Controller{ 129 fsys: c.fsys, 130 name: controllerName, 131 path: controllerPath, 132 }, nil 133 } 134 135 // MoveProcess implements MoveProcess method of Manager 136 func (c *RealManager) MoveProcess(controller, path string) error { 137 return c.fsys.WriteFile( 138 filepath.Join(cgroupfs, controller, path, "cgroup.procs"), 139 []byte(utils.Stringify(c.pid)), 140 0644, 141 ) 142 } 143 144 // Set sets the value of a controller setting 145 func (c *Controller) Set(name string, value interface{}) error { 146 return c.fsys.WriteFile( 147 filepath.Join(cgroupfs, c.name, c.path, c.name+"."+name), 148 []byte(utils.Stringify(value)), 149 0644, 150 ) 151 }