executor.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package executor
  2. import (
  3. pb "github.com/jamesread/OliveTin/gen/grpc"
  4. acl "github.com/jamesread/OliveTin/internal/acl"
  5. config "github.com/jamesread/OliveTin/internal/config"
  6. log "github.com/sirupsen/logrus"
  7. "context"
  8. "errors"
  9. "os/exec"
  10. "time"
  11. )
  12. type InternalLogEntry struct {
  13. Datetime string
  14. Content string
  15. Stdout string
  16. Stderr string
  17. TimedOut bool
  18. ExitCode int32
  19. ActionTitle string
  20. }
  21. type Executor struct {
  22. Logs []InternalLogEntry
  23. }
  24. // ExecAction executes an action.
  25. func (e *Executor) ExecAction(cfg *config.Config, user *acl.User, actualAction *config.ActionButton) *pb.StartActionResponse {
  26. log.WithFields(log.Fields{
  27. "actionName": actualAction.Title,
  28. }).Infof("StartAction")
  29. res := execAction(cfg, actualAction)
  30. e.Logs = append(e.Logs, *res)
  31. return &pb.StartActionResponse{
  32. LogEntry: &pb.LogEntry{
  33. ActionTitle: actualAction.Title,
  34. TimedOut: res.TimedOut,
  35. Stderr: res.Stderr,
  36. Stdout: res.Stdout,
  37. ExitCode: res.ExitCode,
  38. },
  39. }
  40. }
  41. func execAction(cfg *config.Config, actualAction *config.ActionButton) *InternalLogEntry {
  42. res := &InternalLogEntry{
  43. Datetime: time.Now().Format("2006-01-02 15:04:05"),
  44. TimedOut: false,
  45. ActionTitle: actualAction.Title,
  46. }
  47. log.WithFields(log.Fields{
  48. "title": actualAction.Title,
  49. "timeout": actualAction.Timeout,
  50. }).Infof("Found action")
  51. ctx, cancel := context.WithTimeout(context.Background(), time.Duration(actualAction.Timeout)*time.Second)
  52. defer cancel()
  53. cmd := exec.CommandContext(ctx, "sh", "-c", actualAction.Shell)
  54. stdout, stderr := cmd.Output()
  55. res.ExitCode = int32(cmd.ProcessState.ExitCode())
  56. res.Stdout = string(stdout)
  57. if stderr == nil {
  58. res.Stderr = ""
  59. } else {
  60. res.Stderr = stderr.Error()
  61. }
  62. if ctx.Err() == context.DeadlineExceeded {
  63. res.TimedOut = true
  64. }
  65. log.WithFields(log.Fields{
  66. "stdout": res.Stdout,
  67. "stderr": res.Stderr,
  68. "timedOut": res.TimedOut,
  69. "exit": res.ExitCode,
  70. }).Infof("Finished command.")
  71. return res
  72. }
  73. func sanitizeAction(action *config.ActionButton) {
  74. if action.Timeout < 3 {
  75. action.Timeout = 3
  76. }
  77. }
  78. func FindAction(cfg *config.Config, actionTitle string) (*config.ActionButton, error) {
  79. for _, action := range cfg.ActionButtons {
  80. if action.Title == actionTitle {
  81. sanitizeAction(&action)
  82. return &action, nil
  83. }
  84. }
  85. return nil, errors.New("Action not found")
  86. }