executor.go 2.4 KB

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