7be99f8e91
- agent+proto+backend: transfer service status - agent: fix returning empty message on nonzero exit status - backend: refactor collector+commander and handlers dependent on them: implement agent accounting via grpc stats handler
219 lines
5.4 KiB
Go
219 lines
5.4 KiB
Go
package handlers
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/grpcsrv/commander"
|
|
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/models"
|
|
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/repository"
|
|
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/service"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type ScriptHandlers struct {
|
|
svc *service.ScriptService
|
|
tracker *commander.ConnTracker
|
|
}
|
|
|
|
func NewScriptHandlers(svc *service.ScriptService, tracker *commander.ConnTracker) ScriptHandlers {
|
|
return ScriptHandlers{svc: svc, tracker: tracker}
|
|
}
|
|
|
|
type RunScriptIn struct {
|
|
AgentID string `json:"agent_id" binding:"required"`
|
|
InterpreterID int64 `json:"interpreter_id" binding:"required"`
|
|
ScriptText string `json:"script_text" binding:"required"`
|
|
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.
|
|
// @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
|
|
// @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
|
|
}
|
|
|
|
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)
|
|
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
|
|
}()
|
|
if err != nil {
|
|
c.Error(err)
|
|
}
|
|
}
|
|
|
|
// ListInterpreters returns all registered script interpreters.
|
|
// @Summary List interpreters
|
|
// @Description Returns all script interpreters available in the system
|
|
// @Tags scripts
|
|
// @Produce json
|
|
// @Success 200 {array} repository.ScriptInterpreter
|
|
// @Security Bearer
|
|
// @Router /scripts/interpreters [get]
|
|
func (h *ScriptHandlers) ListInterpreters(c *gin.Context) {
|
|
interpreters, err := h.svc.List(c.Request.Context())
|
|
if err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, interpreters)
|
|
}
|
|
|
|
// CreateInterpreter registers a new script interpreter.
|
|
// @Summary Create interpreter
|
|
// @Description Registers a new script interpreter with name, label, and argv
|
|
// @Tags scripts
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param body body repository.ScriptInterpreterCreate true "Interpreter definition"
|
|
// @Success 201 {object} repository.ScriptInterpreter
|
|
// @Security Bearer
|
|
// @Router /scripts/interpreters [post]
|
|
func (h *ScriptHandlers) CreateInterpreter(c *gin.Context) {
|
|
var in repository.ScriptInterpreterCreate
|
|
if err := c.BindJSON(&in); err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
|
|
si, err := h.svc.Create(c.Request.Context(), in)
|
|
if err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
c.JSON(http.StatusCreated, si)
|
|
}
|
|
|
|
// GetInterpreter returns a single interpreter by ID.
|
|
// @Summary Get interpreter
|
|
// @Description Returns a script interpreter by ID
|
|
// @Tags scripts
|
|
// @Produce json
|
|
// @Param id path int true "Interpreter ID"
|
|
// @Success 200 {object} repository.ScriptInterpreter
|
|
// @Security Bearer
|
|
// @Router /scripts/interpreters/:id [get]
|
|
func (h *ScriptHandlers) GetInterpreter(c *gin.Context) {
|
|
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
|
|
si, err := h.svc.GetByID(c.Request.Context(), id)
|
|
if err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, si)
|
|
}
|
|
|
|
// UpdateInterpreter updates an interpreter.
|
|
// @Summary Update interpreter
|
|
// @Description Updates fields of a script interpreter
|
|
// @Tags scripts
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param id path int true "Interpreter ID"
|
|
// @Param body body repository.ScriptInterpreterUpdate true "Interpreter fields"
|
|
// @Success 200 {object} repository.ScriptInterpreter
|
|
// @Security Bearer
|
|
// @Router /scripts/interpreters/:id [put]
|
|
func (h *ScriptHandlers) UpdateInterpreter(c *gin.Context) {
|
|
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
|
|
var in repository.ScriptInterpreterUpdate
|
|
if err := c.BindJSON(&in); err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
|
|
si, err := h.svc.Update(c.Request.Context(), id, in)
|
|
if err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, si)
|
|
}
|
|
|
|
// DeleteInterpreter removes an interpreter.
|
|
// @Summary Delete interpreter
|
|
// @Description Removes a script interpreter by ID
|
|
// @Tags scripts
|
|
// @Param id path int true "Interpreter ID"
|
|
// @Success 204
|
|
// @Security Bearer
|
|
// @Router /scripts/interpreters/:id [delete]
|
|
func (h *ScriptHandlers) DeleteInterpreter(c *gin.Context) {
|
|
id, err := strconv.ParseInt(c.Param("id"), 10, 64)
|
|
if err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
|
|
if err := h.svc.Delete(c.Request.Context(), id); err != nil {
|
|
c.Error(err)
|
|
return
|
|
}
|
|
c.Status(http.StatusNoContent)
|
|
}
|