2
0

runner.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package worker
  2. import (
  3. "errors"
  4. "os"
  5. "os/exec"
  6. "strings"
  7. "syscall"
  8. "time"
  9. "golang.org/x/sys/unix"
  10. )
  11. // runner is to run os commands giving command line, env and log file
  12. // it's an alternative to python-sh or go-sh
  13. var errProcessNotStarted = errors.New("Process Not Started")
  14. type cmdJob struct {
  15. cmd *exec.Cmd
  16. workingDir string
  17. env map[string]string
  18. logFile *os.File
  19. finished chan empty
  20. provider mirrorProvider
  21. }
  22. func newCmdJob(provider mirrorProvider, cmdAndArgs []string, workingDir string, env map[string]string) *cmdJob {
  23. var cmd *exec.Cmd
  24. if provider.Cgroup() != nil {
  25. c := "cgexec"
  26. args := []string{"-g", provider.Cgroup().Cgroup()}
  27. args = append(args, cmdAndArgs...)
  28. cmd = exec.Command(c, args...)
  29. } else {
  30. if len(cmdAndArgs) == 1 {
  31. cmd = exec.Command(cmdAndArgs[0])
  32. } else if len(cmdAndArgs) > 1 {
  33. c := cmdAndArgs[0]
  34. args := cmdAndArgs[1:]
  35. cmd = exec.Command(c, args...)
  36. } else if len(cmdAndArgs) == 0 {
  37. panic("Command length should be at least 1!")
  38. }
  39. }
  40. logger.Debugf("Executing command %s at %s", cmdAndArgs[0], workingDir)
  41. if _, err := os.Stat(workingDir); os.IsNotExist(err) {
  42. logger.Debugf("Making dir %s", workingDir)
  43. if err = os.MkdirAll(workingDir, 0755); err != nil {
  44. logger.Errorf("Error making dir %s", workingDir)
  45. }
  46. }
  47. cmd.Dir = workingDir
  48. cmd.Env = newEnviron(env, true)
  49. return &cmdJob{
  50. cmd: cmd,
  51. workingDir: workingDir,
  52. env: env,
  53. }
  54. }
  55. func (c *cmdJob) Start() error {
  56. c.finished = make(chan empty, 1)
  57. return c.cmd.Start()
  58. }
  59. func (c *cmdJob) Wait() error {
  60. err := c.cmd.Wait()
  61. close(c.finished)
  62. return err
  63. }
  64. func (c *cmdJob) SetLogFile(logFile *os.File) {
  65. c.cmd.Stdout = logFile
  66. c.cmd.Stderr = logFile
  67. }
  68. func (c *cmdJob) Terminate() error {
  69. if c.cmd == nil || c.cmd.Process == nil {
  70. return errProcessNotStarted
  71. }
  72. err := unix.Kill(c.cmd.Process.Pid, syscall.SIGTERM)
  73. if err != nil {
  74. return err
  75. }
  76. select {
  77. case <-time.After(2 * time.Second):
  78. unix.Kill(c.cmd.Process.Pid, syscall.SIGKILL)
  79. return errors.New("SIGTERM failed to kill the job")
  80. case <-c.finished:
  81. return nil
  82. }
  83. }
  84. // Copied from go-sh
  85. func newEnviron(env map[string]string, inherit bool) []string { //map[string]string {
  86. environ := make([]string, 0, len(env))
  87. if inherit {
  88. for _, line := range os.Environ() {
  89. // if os environment and env collapses,
  90. // omit the os one
  91. k := strings.Split(line, "=")[0]
  92. if _, ok := env[k]; ok {
  93. continue
  94. }
  95. environ = append(environ, line)
  96. }
  97. }
  98. for k, v := range env {
  99. environ = append(environ, k+"="+v)
  100. }
  101. return environ
  102. }