cgroup_test.go 3.8 KB

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