diff --git a/backend/cmd/main.go b/backend/cmd/main.go index bb3df35..b4c4aa2 100644 --- a/backend/cmd/main.go +++ b/backend/cmd/main.go @@ -96,7 +96,8 @@ func main() { log.Printf("Warning: failed to initialize script interpreters table: %v", err) } scriptSvc := service.NewScriptServiceWithInterpreters(h.Repo, scriptRepo) - scriptHandlers := handlers.NewScriptHandlers(scriptSvc, cmdTracker) + scriptHandlers := handlers.NewScriptHandlers(scriptSvc, cmdTracker, + os.Getenv("WHEREAMI")) jobsHandlers := handlers.NewJobsHandlers(cmdTracker, scriptSvc, os.Getenv("WHEREAMI"), /* our address for redirects */ jobRepo, diff --git a/backend/internal/handlers/jobs.go b/backend/internal/handlers/jobs.go index 8a30c33..bc1f883 100644 --- a/backend/internal/handlers/jobs.go +++ b/backend/internal/handlers/jobs.go @@ -72,35 +72,49 @@ func (h *JobsHandlers) AddJob(c *gin.Context) { return } - agent, ok := h.tracker.GetAgent(in.AgentID) - if !ok { - c.Status(http.StatusNotFound) - c.Error(fmt.Errorf("agent not found")) - return - } - - command, err := resolveCommand(c, h.svc, in.InterpreterID, in.Command) + result, err := h.runCommand(c, in.AgentID, in.InterpreterID, in.Command, in.Stdin) if err != nil { c.Error(err) return } + c.JSON(http.StatusCreated, result) +} + +// runCommand resolves command, submits a job to the agent, and returns AddJobOut. +// Shared between jobs and scripts handlers. +func (h *JobsHandlers) runCommand( + c *gin.Context, + agentID string, + interpID int64, + command string, + stdin *string, +) (*AddJobOut, error) { + agent, ok := h.tracker.GetAgent(agentID) + if !ok { + return nil, fmt.Errorf("agent not found") + } + + cmd, err := resolveCommand(c, h.svc, interpID, command) + if err != nil { + return nil, err + } + jid, err := agent.AddJob(models.JobForInsert{ - Command: command, - Stdin: in.Stdin, + Command: cmd, + Stdin: stdin, }) if err != nil { - c.Error(err) - return + return nil, err } waitURL := fmt.Sprintf("%s/api/v1/jobs/%d/wait", h.whereami, jid) - c.JSON(http.StatusCreated, AddJobOut{ + return &AddJobOut{ ID: jid, - Command: command, + Command: cmd, WaitURL: waitURL, - }) + }, nil } // WaitJob waits for a submitted job to complete (long-poll). diff --git a/backend/internal/handlers/scripts.go b/backend/internal/handlers/scripts.go index 30299e5..3d8caea 100644 --- a/backend/internal/handlers/scripts.go +++ b/backend/internal/handlers/scripts.go @@ -13,12 +13,13 @@ import ( ) type ScriptHandlers struct { - svc *service.ScriptService - tracker *commander.ConnTracker + svc *service.ScriptService + tracker *commander.ConnTracker + whereami string } -func NewScriptHandlers(svc *service.ScriptService, tracker *commander.ConnTracker) ScriptHandlers { - return ScriptHandlers{svc: svc, tracker: tracker} +func NewScriptHandlers(svc *service.ScriptService, tracker *commander.ConnTracker, whereami string) ScriptHandlers { + return ScriptHandlers{svc: svc, tracker: tracker, whereami: whereami} } type RunScriptIn struct { @@ -28,73 +29,52 @@ type RunScriptIn struct { Stdin *string `json:"stdin"` } -type RunScriptOut struct { - ID int64 `json:"id"` - Command []string `json:"command"` - Stdin *string `json:"stdin"` - Stdout string `json:"stdout"` - Stderr string `json:"stderr"` - Status int32 `json:"status"` -} - -// RunScript executes a script on a target agent. +// RunScript submits a script as a job and returns a wait_url for the result. // @Summary Run a script on an agent // @Description Resolves interpreter argv[] and sends the full command to the agent // @Tags scripts // @Accept json // @Produce json // @Param body body RunScriptIn true "Script request" -// @Success 201 {object} RunScriptOut +// @Success 201 {object} AddJobOut // @Security Bearer // @Router /scripts/run [post] func (h *ScriptHandlers) RunScript(c *gin.Context) { - err := func() error { - var in RunScriptIn - if err := c.Bind(&in); err != nil { - return err - } + var in RunScriptIn + if err := c.Bind(&in); err != nil { + c.Error(err) + return + } - command, err := h.svc.ResolveCommand( - c.Request.Context(), - in.InterpreterID, - in.ScriptText, - ) - if err != nil { - return err - } + agent, ok := h.tracker.GetAgent(in.AgentID) + if !ok { + c.Status(http.StatusNotFound) + c.Error(fmt.Errorf("agent not found")) + return + } - agent, ok := h.tracker.GetAgent(in.AgentID) - if !ok { - c.Status(http.StatusNotFound) - return fmt.Errorf("agent not found") - } - - jid, err := agent.AddJob(models.JobForInsert{ - Command: command, - Stdin: in.Stdin, - }) - if err != nil { - return err - } - - job, err := agent.WaitJob(jid) - if err != nil { - return err - } - - c.JSON(http.StatusCreated, RunScriptOut{ - ID: job.ID, - Command: job.Command, - Stdin: job.Stdin, - Stdout: job.Stdout, - Stderr: job.Stderr, - Status: job.Status, - }) - return nil - }() + command, err := h.svc.ResolveCommand(c.Request.Context(), in.InterpreterID, in.ScriptText) if err != nil { c.Error(err) + return } + + jid, err := agent.AddJob(models.JobForInsert{ + Command: command, + Stdin: in.Stdin, + }) + if err != nil { + c.Error(err) + return + } + + waitURL := fmt.Sprintf("%s/api/v1/jobs/%d/wait", h.whereami, jid) + + c.JSON(http.StatusCreated, AddJobOut{ + ID: jid, + Command: command, + WaitURL: waitURL, + }) } // ListInterpreters returns all registered script interpreters. diff --git a/backend/internal/handlers/scripts_manage.go b/backend/internal/handlers/scripts_manage.go index 705a0dd..242d74d 100644 --- a/backend/internal/handlers/scripts_manage.go +++ b/backend/internal/handlers/scripts_manage.go @@ -254,7 +254,7 @@ func (sh *ScriptHandlersGroup) RunScriptByID(c *gin.Context) { return } - c.JSON(http.StatusCreated, RunScriptOut{ + c.JSON(http.StatusCreated, JobResult{ ID: job.ID, Command: job.Command, Stdin: job.Stdin,