2 Commits

Author SHA1 Message Date
zero@thinky b88245e7d9 feat(backend/jobs): add agent_id parameter
ci-agent / build (push) Failing after 5m27s
2026-04-05 04:17:55 +03:00
zero@thinky fd01eecfcc feat!(backend): unify script run and ad-hoc job run 2026-04-05 04:17:43 +03:00
6 changed files with 41 additions and 88 deletions
+8 -28
View File
@@ -1059,6 +1059,12 @@ const docTemplate = `{
"description": "Time period (e.g. 1h, 24h, 7d)",
"name": "period",
"in": "query"
},
{
"type": "string",
"description": "Filter by agent ID",
"name": "agent_id",
"in": "query"
}
],
"responses": {
@@ -1684,7 +1690,7 @@ const docTemplate = `{
"201": {
"description": "Created",
"schema": {
"$ref": "#/definitions/internal_handlers.RunScriptOut"
"$ref": "#/definitions/internal_handlers.JobResult"
}
},
"400": {
@@ -2118,7 +2124,7 @@ const docTemplate = `{
"201": {
"description": "Created",
"schema": {
"$ref": "#/definitions/internal_handlers.RunScriptOut"
"$ref": "#/definitions/internal_handlers.AddJobOut"
}
}
}
@@ -2904,32 +2910,6 @@ const docTemplate = `{
}
}
},
"internal_handlers.RunScriptOut": {
"type": "object",
"properties": {
"command": {
"type": "array",
"items": {
"type": "string"
}
},
"id": {
"type": "integer"
},
"status": {
"type": "integer"
},
"stderr": {
"type": "string"
},
"stdin": {
"type": "string"
},
"stdout": {
"type": "string"
}
}
},
"internal_handlers.RunStoredScriptIn": {
"type": "object",
"required": [
+8 -28
View File
@@ -1048,6 +1048,12 @@
"description": "Time period (e.g. 1h, 24h, 7d)",
"name": "period",
"in": "query"
},
{
"type": "string",
"description": "Filter by agent ID",
"name": "agent_id",
"in": "query"
}
],
"responses": {
@@ -1673,7 +1679,7 @@
"201": {
"description": "Created",
"schema": {
"$ref": "#/definitions/internal_handlers.RunScriptOut"
"$ref": "#/definitions/internal_handlers.JobResult"
}
},
"400": {
@@ -2107,7 +2113,7 @@
"201": {
"description": "Created",
"schema": {
"$ref": "#/definitions/internal_handlers.RunScriptOut"
"$ref": "#/definitions/internal_handlers.AddJobOut"
}
}
}
@@ -2893,32 +2899,6 @@
}
}
},
"internal_handlers.RunScriptOut": {
"type": "object",
"properties": {
"command": {
"type": "array",
"items": {
"type": "string"
}
},
"id": {
"type": "integer"
},
"status": {
"type": "integer"
},
"stderr": {
"type": "string"
},
"stdin": {
"type": "string"
},
"stdout": {
"type": "string"
}
}
},
"internal_handlers.RunStoredScriptIn": {
"type": "object",
"required": [
+6 -19
View File
@@ -504,23 +504,6 @@ definitions:
- interpreter_id
- script_text
type: object
internal_handlers.RunScriptOut:
properties:
command:
items:
type: string
type: array
id:
type: integer
status:
type: integer
stderr:
type: string
stdin:
type: string
stdout:
type: string
type: object
internal_handlers.RunStoredScriptIn:
properties:
stdin:
@@ -1246,6 +1229,10 @@ paths:
in: query
name: period
type: string
- description: Filter by agent ID
in: query
name: agent_id
type: string
produces:
- application/json
responses:
@@ -1608,7 +1595,7 @@ paths:
"201":
description: Created
schema:
$ref: '#/definitions/internal_handlers.RunScriptOut'
$ref: '#/definitions/internal_handlers.JobResult'
"400":
description: Bad Request
schema:
@@ -1882,7 +1869,7 @@ paths:
"201":
description: Created
schema:
$ref: '#/definitions/internal_handlers.RunScriptOut'
$ref: '#/definitions/internal_handlers.AddJobOut'
security:
- Bearer: []
summary: Run a script on an agent
+3 -1
View File
@@ -230,6 +230,7 @@ type JobMetricsOut struct {
// @Tags jobs
// @Produce json
// @Param period query string false "Time period (e.g. 1h, 24h, 7d)" default(24h)
// @Param agent_id query string false "Filter by agent ID"
// @Success 200 {object} JobMetricsOut
// @Failure 400 {object} map[string]string
// @Security Bearer
@@ -242,8 +243,9 @@ func (h *JobsHandlers) GetJobMetrics(c *gin.Context) {
return
}
agentID := c.Query("agent_id")
since := time.Now().Add(-period)
metrics, err := h.jobRepo.GetJobMetrics(c.Request.Context(), since)
metrics, err := h.jobRepo.GetJobMetrics(c.Request.Context(), since, agentID)
if err != nil {
c.Error(err)
return
+1 -1
View File
@@ -198,7 +198,7 @@ func (sh *ScriptHandlersGroup) DeleteScript(c *gin.Context) {
// @Produce json
// @Param id path int true "Script ID"
// @Param body body RunStoredScriptIn true "Agent token and optional stdin"
// @Success 201 {object} RunScriptOut
// @Success 201 {object} JobResult
// @Failure 400 {object} map[string]string
// @Failure 404 {object} map[string]string
// @Failure 500 {object} map[string]string
+15 -11
View File
@@ -113,18 +113,22 @@ type JobMetrics struct {
}
// GetJobMetrics returns job success metrics for jobs updated since the given time.
// A successful job has status == 0, failed has status != 0, pending has status == 0 with empty stdout/stderr.
func (r *JobRepository) GetJobMetrics(ctx context.Context, since time.Time) (JobMetrics, error) {
// If agentID is non-empty, results are filtered to that agent only.
func (r *JobRepository) GetJobMetrics(ctx context.Context, since time.Time, agentID string) (JobMetrics, error) {
var m JobMetrics
err := r.DB.QueryRowContext(ctx,
`SELECT
COUNT(*),
SUM(CASE WHEN status = 0 AND (stdout != '' OR stderr != '') THEN 1 ELSE 0 END),
SUM(CASE WHEN status != 0 THEN 1 ELSE 0 END),
SUM(CASE WHEN status = 0 AND stdout = '' AND stderr = '' THEN 1 ELSE 0 END)
FROM jobs WHERE updated_at >= ?`,
since,
).Scan(&m.Total, &m.Success, &m.Failed, &m.Pending)
query := `SELECT
COUNT(*),
SUM(CASE WHEN status = 0 AND (stdout != '' OR stderr != '') THEN 1 ELSE 0 END),
SUM(CASE WHEN status != 0 THEN 1 ELSE 0 END),
SUM(CASE WHEN status = 0 AND stdout = '' AND stderr = '' THEN 1 ELSE 0 END)
FROM jobs WHERE updated_at >= ?`
args := []any{since}
if agentID != "" {
query += " AND agent_id = ?"
args = append(args, agentID)
}
err := r.DB.QueryRowContext(ctx, query, args...).Scan(&m.Total, &m.Success, &m.Failed, &m.Pending)
if err != nil {
return JobMetrics{}, err
}