cgroup_test.go 3.9 KB

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