You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
3.2 KiB
134 lines
3.2 KiB
package limit |
|
|
|
import ( |
|
"errors" |
|
"os" |
|
"fmt" |
|
"io/ioutil" |
|
"strconv" |
|
) |
|
|
|
var ( |
|
LimitConfNil = errors.New("Config of resource limit is nil") |
|
LimitConfError = errors.New("LimitConfError") |
|
CgroupPathNotExist = errors.New("Cgroup Path Not Exist") |
|
MemCgroupPathNotExist = errors.New("Mem subgroup Not Exist") |
|
CpuCgroupPathNotExist = errors.New("Cpu subgroup Not Exist") |
|
) |
|
|
|
type LimitConf struct { |
|
AppName string |
|
CgroupPath string |
|
LimitMemMB int |
|
LimitMemEnabled bool |
|
LimitCpuCore int |
|
LimitCpuEnabled bool |
|
} |
|
|
|
type Limit struct { |
|
c *LimitConf |
|
} |
|
|
|
// LimitRes init Limit |
|
func LimitRes(c *LimitConf) (l *Limit, err error) { |
|
if c == nil { |
|
return nil, LimitConfError |
|
} |
|
l = new(Limit) |
|
l.c = c |
|
|
|
if c.AppName == "" { |
|
return nil, fmt.Errorf("AppName can't be nil") |
|
} |
|
|
|
if err = pathExists(l.c.CgroupPath, false); err != nil { |
|
return nil, CgroupPathNotExist |
|
} |
|
if l.c.LimitMemEnabled { |
|
if l.c.LimitCpuCore <= 0 { |
|
return nil, fmt.Errorf("LimitCpuCore must be greater than 0") |
|
} |
|
if err = l.limitMem(); err != nil { |
|
return nil, err |
|
} |
|
} |
|
if l.c.LimitCpuEnabled { |
|
if l.c.LimitMemMB <= 0 { |
|
return nil, fmt.Errorf("LimitMemMB must be greater than 0") |
|
} |
|
if err = l.limitCpu(); err != nil { |
|
return nil, err |
|
} |
|
} |
|
return |
|
} |
|
|
|
// limitMem limit memory by memory.limit_in_bytes |
|
func (l *Limit) limitMem() (err error) { |
|
if err = pathExists(fmt.Sprintf("%s/memory", l.c.CgroupPath), false); err != nil { |
|
return MemCgroupPathNotExist |
|
} |
|
|
|
memPath := fmt.Sprintf("%s/memory/%s/", l.c.CgroupPath, l.c.AppName) |
|
if err = pathExists(memPath, true); err != nil { |
|
return err |
|
} |
|
// cgroup.procs |
|
pidPath := memPath + "cgroup.procs" |
|
if err = pathExists(pidPath, false); err != nil { |
|
return err |
|
} |
|
if err = ioutil.WriteFile(pidPath, []byte(strconv.Itoa(os.Getegid())), 0644); err != nil { |
|
return err |
|
} |
|
// memory.limit_in_bytes |
|
limitPath := memPath + "memory.limit_in_bytes" |
|
if err = pathExists(limitPath, false); err != nil { |
|
return err |
|
} |
|
if err = ioutil.WriteFile(limitPath, []byte(fmt.Sprintf("%sM", strconv.Itoa(l.c.LimitMemMB))), 0644); err != nil { |
|
return err |
|
} |
|
return |
|
} |
|
|
|
// limitCpu limit cpu by cpu.cfs_quota_us and cpu.cfs_period_us |
|
func (l *Limit) limitCpu() (err error) { |
|
if err = pathExists(fmt.Sprintf("%s/cpu,cpuacct", l.c.CgroupPath), false); err != nil { |
|
return CpuCgroupPathNotExist |
|
} |
|
|
|
cpuPath := fmt.Sprintf("%s/cpu,cpuacct/%s/", l.c.CgroupPath, l.c.AppName) |
|
if err = pathExists(cpuPath, true); err != nil { |
|
return err |
|
} |
|
// cpu.cfs_quota_us |
|
quotaPath := cpuPath + "cpu.cfs_quota_us" |
|
if err = pathExists(quotaPath, false); err != nil { |
|
return err |
|
} |
|
if err = ioutil.WriteFile(quotaPath, []byte(strconv.Itoa(10000)), 0644); err != nil { |
|
return err |
|
} |
|
// cpu.cfs_period_us |
|
periodPath := cpuPath + "cpu.cfs_period_us" |
|
if err = pathExists(periodPath, false); err != nil { |
|
return err |
|
} |
|
if err = ioutil.WriteFile(periodPath, []byte(fmt.Sprintf("%s", strconv.Itoa(10000*l.c.LimitCpuCore))), 0644); err != nil { |
|
return err |
|
} |
|
return |
|
} |
|
|
|
// pathExists check if path exist |
|
func pathExists(path string, create bool) (err error) { |
|
if _, err = os.Stat(path); err == nil { |
|
return |
|
} |
|
|
|
if os.IsNotExist(err) && create == true { |
|
return os.MkdirAll(path, os.ModePerm) |
|
} |
|
return |
|
}
|
|
|