cgroup_test.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. package worker
  2. import (
  3. "io/ioutil"
  4. "os"
  5. "path/filepath"
  6. "strconv"
  7. "strings"
  8. "testing"
  9. "time"
  10. cgv1 "github.com/containerd/cgroups"
  11. units "github.com/docker/go-units"
  12. "github.com/moby/moby/pkg/reexec"
  13. . "github.com/smartystreets/goconvey/convey"
  14. )
  15. func init() {
  16. reexec.Init()
  17. }
  18. func TestCgroup(t *testing.T) {
  19. Convey("Cgroup Should Work", t, func(ctx C) {
  20. tmpDir, err := ioutil.TempDir("", "tunasync")
  21. defer os.RemoveAll(tmpDir)
  22. So(err, ShouldBeNil)
  23. cmdScript := filepath.Join(tmpDir, "cmd.sh")
  24. daemonScript := filepath.Join(tmpDir, "daemon.sh")
  25. tmpFile := filepath.Join(tmpDir, "log_file")
  26. bgPidfile := filepath.Join(tmpDir, "bg.pid")
  27. c := cmdConfig{
  28. name: "tuna-cgroup",
  29. upstreamURL: "http://mirrors.tuna.moe/",
  30. command: cmdScript + " " + daemonScript,
  31. workingDir: tmpDir,
  32. logDir: tmpDir,
  33. logFile: tmpFile,
  34. interval: 600 * time.Second,
  35. env: map[string]string{
  36. "BG_PIDFILE": bgPidfile,
  37. },
  38. }
  39. cmdScriptContent := `#!/bin/bash
  40. redirect-std() {
  41. [[ -t 0 ]] && exec </dev/null
  42. [[ -t 1 ]] && exec >/dev/null
  43. [[ -t 2 ]] && exec 2>/dev/null
  44. }
  45. # close all non-std* fds
  46. close-fds() {
  47. eval exec {3..255}\>\&-
  48. }
  49. # full daemonization of external command with setsid
  50. daemonize() {
  51. (
  52. redirect-std
  53. cd /
  54. close-fds
  55. exec setsid "$@"
  56. ) &
  57. }
  58. echo $$
  59. daemonize $@
  60. sleep 5
  61. `
  62. daemonScriptContent := `#!/bin/bash
  63. echo $$ > $BG_PIDFILE
  64. sleep 30
  65. `
  66. err = ioutil.WriteFile(cmdScript, []byte(cmdScriptContent), 0755)
  67. So(err, ShouldBeNil)
  68. err = ioutil.WriteFile(daemonScript, []byte(daemonScriptContent), 0755)
  69. So(err, ShouldBeNil)
  70. provider, err := newCmdProvider(c)
  71. So(err, ShouldBeNil)
  72. cgcf := cgroupConfig{BasePath: "/sys/fs/cgroup", Group: "tunasync", Subsystem: "cpu"}
  73. err = initCgroup(&cgcf)
  74. So(err, ShouldBeNil)
  75. if cgcf.isUnified {
  76. So(cgcf.cgMgrV2, ShouldNotBeNil)
  77. } else {
  78. So(cgcf.cgMgrV1, ShouldNotBeNil)
  79. }
  80. cg := newCgroupHook(provider, cgcf, 0)
  81. provider.AddHook(cg)
  82. err = cg.preExec()
  83. So(err, ShouldBeNil)
  84. go func() {
  85. err := provider.Run(make(chan empty, 1))
  86. ctx.So(err, ShouldNotBeNil)
  87. }()
  88. time.Sleep(1 * time.Second)
  89. // Deamon should be started
  90. daemonPidBytes, err := ioutil.ReadFile(bgPidfile)
  91. So(err, ShouldBeNil)
  92. daemonPid := strings.Trim(string(daemonPidBytes), " \n")
  93. logger.Debug("daemon pid: %s", daemonPid)
  94. procDir := filepath.Join("/proc", daemonPid)
  95. _, err = os.Stat(procDir)
  96. So(err, ShouldBeNil)
  97. err = provider.Terminate()
  98. So(err, ShouldBeNil)
  99. // Deamon won't be killed
  100. _, err = os.Stat(procDir)
  101. So(err, ShouldBeNil)
  102. // Deamon can be killed by cgroup killer
  103. cg.postExec()
  104. _, err = os.Stat(procDir)
  105. So(os.IsNotExist(err), ShouldBeTrue)
  106. })
  107. Convey("Rsync Memory Should Be Limited", t, func() {
  108. tmpDir, err := ioutil.TempDir("", "tunasync")
  109. defer os.RemoveAll(tmpDir)
  110. So(err, ShouldBeNil)
  111. scriptFile := filepath.Join(tmpDir, "myrsync")
  112. tmpFile := filepath.Join(tmpDir, "log_file")
  113. c := rsyncConfig{
  114. name: "tuna-cgroup",
  115. upstreamURL: "rsync://rsync.tuna.moe/tuna/",
  116. rsyncCmd: scriptFile,
  117. workingDir: tmpDir,
  118. logDir: tmpDir,
  119. logFile: tmpFile,
  120. useIPv6: true,
  121. interval: 600 * time.Second,
  122. }
  123. provider, err := newRsyncProvider(c)
  124. So(err, ShouldBeNil)
  125. cgcf := cgroupConfig{BasePath: "/sys/fs/cgroup", Group: "tunasync", Subsystem: "cpu"}
  126. err = initCgroup(&cgcf)
  127. So(err, ShouldBeNil)
  128. if cgcf.isUnified {
  129. So(cgcf.cgMgrV2, ShouldNotBeNil)
  130. } else {
  131. So(cgcf.cgMgrV1, ShouldNotBeNil)
  132. }
  133. cg := newCgroupHook(provider, cgcf, 512 * units.MiB)
  134. provider.AddHook(cg)
  135. err = cg.preExec()
  136. So(err, ShouldBeNil)
  137. if cgcf.isUnified {
  138. memoLimit, err := ioutil.ReadFile(filepath.Join(cgcf.BasePath, cgcf.Group, provider.Name(), "memory.max"))
  139. So(err, ShouldBeNil)
  140. So(strings.Trim(string(memoLimit), "\n"), ShouldEqual, strconv.Itoa(512*1024*1024))
  141. } else {
  142. for _, subsys := range(cg.cgMgrV1.Subsystems()) {
  143. if subsys.Name() == cgv1.Memory {
  144. memoLimit, err := ioutil.ReadFile(filepath.Join(cgcf.BasePath, "memory", cgcf.Group, provider.Name(), "memory.limit_in_bytes"))
  145. So(err, ShouldBeNil)
  146. So(strings.Trim(string(memoLimit), "\n"), ShouldEqual, strconv.Itoa(512*1024*1024))
  147. }
  148. }
  149. }
  150. cg.postExec()
  151. So(cg.cgMgrV1, ShouldBeNil)
  152. })
  153. }