mirror of
https://github.com/tuna/tunasync.git
synced 2025-04-20 11:42:43 +00:00
[WIP] cgroupv2: support start with cgroupv2
This commit is contained in:
parent
28d160a7f0
commit
0f05c69c36
@ -3,6 +3,7 @@ package worker
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -25,38 +26,47 @@ type cgroupHook struct {
|
|||||||
cgMgrV2 *cgv2.Manager
|
cgMgrV2 *cgv2.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type execCmd string
|
||||||
|
|
||||||
|
const (
|
||||||
|
cmdCont execCmd = "cont"
|
||||||
|
cmdAbrt execCmd = "abrt"
|
||||||
|
)
|
||||||
|
|
||||||
func init () {
|
func init () {
|
||||||
reexec.Register("tunasync-exec", waitExec)
|
reexec.Register("tunasync-exec", waitExec)
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitExec () {
|
func waitExec () {
|
||||||
binary, lookErr := exec.LookPath(os.Args[1])
|
binary, err := exec.LookPath(os.Args[1])
|
||||||
if lookErr != nil {
|
if err != nil {
|
||||||
panic(lookErr)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
pipe := os.NewFile(3, "pipe")
|
pipe := os.NewFile(3, "pipe")
|
||||||
if pipe != nil {
|
if pipe != nil {
|
||||||
for {
|
if _, err := pipe.Stat(); err == nil {
|
||||||
tmpBytes := make([]byte, 1)
|
cmdBytes, err := ioutil.ReadAll(pipe)
|
||||||
nRead, err := pipe.Read(tmpBytes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
panic(err)
|
||||||
}
|
}
|
||||||
if nRead == 0 {
|
if err := pipe.Close(); err != nil {
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
cmd := execCmd(string(cmdBytes))
|
||||||
|
switch cmd {
|
||||||
|
case cmdAbrt:
|
||||||
|
fallthrough
|
||||||
|
default:
|
||||||
|
panic("Exited on request")
|
||||||
|
case cmdCont:
|
||||||
}
|
}
|
||||||
err := pipe.Close()
|
|
||||||
if err != nil {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
args := os.Args[1:]
|
args := os.Args[1:]
|
||||||
env := os.Environ()
|
env := os.Environ()
|
||||||
execErr := syscall.Exec(binary, args, env)
|
if err := syscall.Exec(binary, args, env); err != nil {
|
||||||
if execErr != nil {
|
panic(err)
|
||||||
panic(execErr)
|
|
||||||
}
|
}
|
||||||
panic("Exec failed.")
|
panic("Exec failed.")
|
||||||
}
|
}
|
||||||
@ -241,6 +251,7 @@ func newCgroupHook(p mirrorProvider, cfg cgroupConfig, memLimit MemBytes) *cgrou
|
|||||||
provider: p,
|
provider: p,
|
||||||
},
|
},
|
||||||
cgCfg: cfg,
|
cgCfg: cfg,
|
||||||
|
memLimit: memLimit,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,7 +266,7 @@ func (c *cgroupHook) preExec() error {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
subMgr, err := c.cgMgrV2.NewChild(c.provider.Name(), resSet)
|
subMgr, err := c.cgCfg.cgMgrV2.NewChild(c.provider.Name(), resSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("Failed to create cgroup for task %s: %s", c.provider.Name(), err.Error())
|
logger.Errorf("Failed to create cgroup for task %s: %s", c.provider.Name(), err.Error())
|
||||||
return err
|
return err
|
||||||
@ -263,15 +274,15 @@ func (c *cgroupHook) preExec() error {
|
|||||||
c.cgMgrV2 = subMgr
|
c.cgMgrV2 = subMgr
|
||||||
} else {
|
} else {
|
||||||
logger.Debugf("Creating v1 cgroup for task %s", c.provider.Name())
|
logger.Debugf("Creating v1 cgroup for task %s", c.provider.Name())
|
||||||
var resSet *contspecs.LinuxResources
|
var resSet contspecs.LinuxResources
|
||||||
if c.memLimit != 0 {
|
if c.memLimit != 0 {
|
||||||
resSet = &contspecs.LinuxResources {
|
resSet = contspecs.LinuxResources {
|
||||||
Memory: &contspecs.LinuxMemory{
|
Memory: &contspecs.LinuxMemory{
|
||||||
Limit: func(i int64) *int64 { return &i }(c.memLimit.Value()),
|
Limit: func(i int64) *int64 { return &i }(c.memLimit.Value()),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
subMgr, err := c.cgMgrV1.New(c.provider.Name(), resSet)
|
subMgr, err := c.cgCfg.cgMgrV1.New(c.provider.Name(), &resSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Errorf("Failed to create cgroup for task %s: %s", c.provider.Name(), err.Error())
|
logger.Errorf("Failed to create cgroup for task %s: %s", c.provider.Name(), err.Error())
|
||||||
return err
|
return err
|
||||||
|
@ -10,10 +10,15 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
cgv1 "github.com/containerd/cgroups"
|
cgv1 "github.com/containerd/cgroups"
|
||||||
units "github.com/docker/go-units"
|
units "github.com/docker/go-units"
|
||||||
|
"github.com/moby/moby/pkg/reexec"
|
||||||
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
reexec.Init()
|
||||||
|
}
|
||||||
|
|
||||||
func TestCgroup(t *testing.T) {
|
func TestCgroup(t *testing.T) {
|
||||||
Convey("Cgroup Should Work", t, func(ctx C) {
|
Convey("Cgroup Should Work", t, func(ctx C) {
|
||||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||||
@ -77,14 +82,15 @@ sleep 30
|
|||||||
cgcf := cgroupConfig{BasePath: "/sys/fs/cgroup", Group: "tunasync", Subsystem: "cpu"}
|
cgcf := cgroupConfig{BasePath: "/sys/fs/cgroup", Group: "tunasync", Subsystem: "cpu"}
|
||||||
err = initCgroup(&cgcf)
|
err = initCgroup(&cgcf)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
if cgcf.isUnified {
|
||||||
|
So(cgcf.cgMgrV2, ShouldNotBeNil)
|
||||||
|
} else {
|
||||||
|
So(cgcf.cgMgrV1, ShouldNotBeNil)
|
||||||
|
}
|
||||||
cg := newCgroupHook(provider, cgcf, 0)
|
cg := newCgroupHook(provider, cgcf, 0)
|
||||||
provider.AddHook(cg)
|
provider.AddHook(cg)
|
||||||
|
|
||||||
err = cg.preExec()
|
err = cg.preExec()
|
||||||
if err != nil {
|
|
||||||
logger.Errorf("Failed to create cgroup")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
@ -140,15 +146,21 @@ sleep 30
|
|||||||
cgcf := cgroupConfig{BasePath: "/sys/fs/cgroup", Group: "tunasync", Subsystem: "cpu"}
|
cgcf := cgroupConfig{BasePath: "/sys/fs/cgroup", Group: "tunasync", Subsystem: "cpu"}
|
||||||
err = initCgroup(&cgcf)
|
err = initCgroup(&cgcf)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
if cgcf.isUnified {
|
||||||
|
So(cgcf.cgMgrV2, ShouldNotBeNil)
|
||||||
|
} else {
|
||||||
|
So(cgcf.cgMgrV1, ShouldNotBeNil)
|
||||||
|
}
|
||||||
cg := newCgroupHook(provider, cgcf, 512 * units.MiB)
|
cg := newCgroupHook(provider, cgcf, 512 * units.MiB)
|
||||||
provider.AddHook(cg)
|
provider.AddHook(cg)
|
||||||
|
|
||||||
err = cg.preExec()
|
err = cg.preExec()
|
||||||
if err != nil {
|
So(err, ShouldBeNil)
|
||||||
logger.Errorf("Failed to create cgroup")
|
if cgcf.isUnified {
|
||||||
return
|
memoLimit, err := ioutil.ReadFile(filepath.Join(cgcf.BasePath, cgcf.Group, provider.Name(), "memory.max"))
|
||||||
}
|
So(err, ShouldBeNil)
|
||||||
So(cg.cgMgrV1, ShouldNotBeNil)
|
So(strings.Trim(string(memoLimit), "\n"), ShouldEqual, strconv.Itoa(512*1024*1024))
|
||||||
|
} else {
|
||||||
for _, subsys := range(cg.cgMgrV1.Subsystems()) {
|
for _, subsys := range(cg.cgMgrV1.Subsystems()) {
|
||||||
if subsys.Name() == cgv1.Memory {
|
if subsys.Name() == cgv1.Memory {
|
||||||
memoLimit, err := ioutil.ReadFile(filepath.Join(cgcf.BasePath, "memory", cgcf.Group, provider.Name(), "memory.limit_in_bytes"))
|
memoLimit, err := ioutil.ReadFile(filepath.Join(cgcf.BasePath, "memory", cgcf.Group, provider.Name(), "memory.limit_in_bytes"))
|
||||||
@ -156,6 +168,7 @@ sleep 30
|
|||||||
So(strings.Trim(string(memoLimit), "\n"), ShouldEqual, strconv.Itoa(512*1024*1024))
|
So(strings.Trim(string(memoLimit), "\n"), ShouldEqual, strconv.Itoa(512*1024*1024))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
cg.postExec()
|
cg.postExec()
|
||||||
So(cg.cgMgrV1, ShouldBeNil)
|
So(cg.cgMgrV1, ShouldBeNil)
|
||||||
})
|
})
|
||||||
|
@ -12,6 +12,8 @@ import (
|
|||||||
|
|
||||||
"github.com/codeskyblue/go-sh"
|
"github.com/codeskyblue/go-sh"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
"github.com/moby/moby/pkg/reexec"
|
||||||
|
cgv1 "github.com/containerd/cgroups"
|
||||||
)
|
)
|
||||||
|
|
||||||
// runner is to run os commands giving command line, env and log file
|
// runner is to run os commands giving command line, env and log file
|
||||||
@ -70,11 +72,7 @@ func newCmdJob(provider mirrorProvider, cmdAndArgs []string, workingDir string,
|
|||||||
cmd = exec.Command(c, args...)
|
cmd = exec.Command(c, args...)
|
||||||
|
|
||||||
} else if provider.Cgroup() != nil {
|
} else if provider.Cgroup() != nil {
|
||||||
//c := "cgexec"
|
cmd = reexec.Command(append([]string{"tunasync-exec"}, cmdAndArgs...)...)
|
||||||
//args := []string{"-g", provider.Cgroup().Cgroup()}
|
|
||||||
//args = append(args, cmdAndArgs...)
|
|
||||||
//cmd = exec.Command(c, args...)
|
|
||||||
cmd = exec.Command(cmdAndArgs[0], cmdAndArgs[1:]...)
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if len(cmdAndArgs) == 1 {
|
if len(cmdAndArgs) == 1 {
|
||||||
@ -109,9 +107,59 @@ func newCmdJob(provider mirrorProvider, cmdAndArgs []string, workingDir string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *cmdJob) Start() error {
|
func (c *cmdJob) Start() error {
|
||||||
|
cg := c.provider.Cgroup()
|
||||||
|
var (
|
||||||
|
pipeR *os.File
|
||||||
|
pipeW *os.File
|
||||||
|
)
|
||||||
|
if cg != nil {
|
||||||
|
logger.Debugf("Preparing cgroup sync pipes for job %s", c.provider.Name())
|
||||||
|
var err error
|
||||||
|
pipeR, pipeW, err = os.Pipe();
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.cmd.ExtraFiles = []*os.File{pipeR}
|
||||||
|
defer pipeR.Close()
|
||||||
|
defer pipeW.Close()
|
||||||
|
}
|
||||||
|
|
||||||
logger.Debugf("Command start: %v", c.cmd.Args)
|
logger.Debugf("Command start: %v", c.cmd.Args)
|
||||||
c.finished = make(chan empty, 1)
|
c.finished = make(chan empty, 1)
|
||||||
return c.cmd.Start()
|
|
||||||
|
if err := c.cmd.Start(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if cg != nil {
|
||||||
|
if err := pipeR.Close(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if c.cmd == nil || c.cmd.Process == nil {
|
||||||
|
return errProcessNotStarted
|
||||||
|
}
|
||||||
|
pid := c.cmd.Process.Pid
|
||||||
|
if cg.cgCfg.isUnified {
|
||||||
|
if err := cg.cgMgrV2.AddProc(uint64(pid)); err != nil{
|
||||||
|
if errors.Is(err, syscall.ESRCH) {
|
||||||
|
logger.Infof("Write pid %d to cgroup failed: process vanished, ignoring")
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := cg.cgMgrV1.Add(cgv1.Process{Pid: pid}); err != nil{
|
||||||
|
if errors.Is(err, syscall.ESRCH) {
|
||||||
|
logger.Infof("Write pid %d to cgroup failed: process vanished, ignoring")
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := pipeW.WriteString(string(cmdCont)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *cmdJob) Wait() error {
|
func (c *cmdJob) Wait() error {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user