add endpoint to manually trigger inventory collection
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-01-15 16:37:58 +11:00
parent e5e5be37a3
commit 2ea0f937c5
6 changed files with 204 additions and 2 deletions

View File

@@ -3,7 +3,6 @@ package vcenter
import ( import (
"context" "context"
"fmt" "fmt"
"log"
"log/slog" "log/slog"
"net/url" "net/url"
"path" "path"
@@ -58,10 +57,19 @@ func New(logger *slog.Logger, creds *VcenterLogin) *Vcenter {
} }
func (v *Vcenter) Login(vUrl string) error { func (v *Vcenter) Login(vUrl string) error {
if v == nil {
return fmt.Errorf("vcenter is nil")
}
if strings.TrimSpace(vUrl) == "" {
return fmt.Errorf("vcenter URL is empty")
}
if v.credentials == nil {
return fmt.Errorf("vcenter credentials are nil")
}
// Connect to vCenter // Connect to vCenter
u, err := soap.ParseURL(vUrl) u, err := soap.ParseURL(vUrl)
if err != nil { if err != nil {
log.Fatalf("Error parsing vCenter URL: %s", err) return fmt.Errorf("error parsing vCenter URL: %w", err)
} }
v.Vurl = vUrl v.Vurl = vUrl

View File

@@ -0,0 +1,51 @@
package handler
import (
"context"
"encoding/json"
"net/http"
"strings"
"time"
"vctp/internal/tasks"
)
// SnapshotForceHourly triggers an on-demand hourly snapshot run.
// @Summary Trigger hourly snapshot (manual)
// @Description Manually trigger an hourly snapshot for all configured vCenters. Requires confirmation text to avoid accidental execution.
// @Tags snapshots
// @Accept json
// @Produce json
// @Param confirm query string true "Confirmation text; must be 'FORCE'"
// @Success 200 {object} map[string]string "Snapshot started"
// @Failure 400 {object} map[string]string "Invalid request"
// @Failure 500 {object} map[string]string "Server error"
// @Router /api/snapshots/hourly/force [post]
func (h *Handler) SnapshotForceHourly(w http.ResponseWriter, r *http.Request) {
confirm := strings.TrimSpace(r.URL.Query().Get("confirm"))
if strings.ToUpper(confirm) != "FORCE" {
writeJSONError(w, http.StatusBadRequest, "confirm must be 'FORCE'")
return
}
ctx := context.Background()
ct := &tasks.CronTask{
Logger: h.Logger,
Database: h.Database,
Settings: h.Settings,
VcCreds: h.VcCreds,
}
started := time.Now()
h.Logger.Info("Manual hourly snapshot requested")
if err := ct.RunVcenterSnapshotHourly(ctx, h.Logger.With("manual", true)); err != nil {
h.Logger.Error("Manual hourly snapshot failed", "error", err)
writeJSONError(w, http.StatusInternalServerError, err.Error())
return
}
h.Logger.Info("Manual hourly snapshot completed", "duration", time.Since(started))
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]string{
"status": "OK",
})
}

View File

@@ -647,6 +647,59 @@ const docTemplate = `{
} }
} }
}, },
"/api/snapshots/hourly/force": {
"post": {
"description": "Manually trigger an hourly snapshot for all configured vCenters. Requires confirmation text to avoid accidental execution.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"snapshots"
],
"summary": "Trigger hourly snapshot (manual)",
"parameters": [
{
"type": "string",
"description": "Confirmation text; must be 'FORCE'",
"name": "confirm",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "Snapshot started",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"400": {
"description": "Invalid request",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"500": {
"description": "Server error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/api/snapshots/migrate": { "/api/snapshots/migrate": {
"post": { "post": {
"description": "Rebuilds the snapshot registry from existing tables and renames hourly tables to epoch-based names.", "description": "Rebuilds the snapshot registry from existing tables and renames hourly tables to epoch-based names.",

View File

@@ -636,6 +636,59 @@
} }
} }
}, },
"/api/snapshots/hourly/force": {
"post": {
"description": "Manually trigger an hourly snapshot for all configured vCenters. Requires confirmation text to avoid accidental execution.",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"snapshots"
],
"summary": "Trigger hourly snapshot (manual)",
"parameters": [
{
"type": "string",
"description": "Confirmation text; must be 'FORCE'",
"name": "confirm",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "Snapshot started",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"400": {
"description": "Invalid request",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"500": {
"description": "Server error",
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
}
},
"/api/snapshots/migrate": { "/api/snapshots/migrate": {
"post": { "post": {
"description": "Rebuilds the snapshot registry from existing tables and renames hourly tables to epoch-based names.", "description": "Rebuilds the snapshot registry from existing tables and renames hourly tables to epoch-based names.",

View File

@@ -580,6 +580,42 @@ paths:
summary: Force snapshot aggregation summary: Force snapshot aggregation
tags: tags:
- snapshots - snapshots
/api/snapshots/hourly/force:
post:
consumes:
- application/json
description: Manually trigger an hourly snapshot for all configured vCenters.
Requires confirmation text to avoid accidental execution.
parameters:
- description: Confirmation text; must be 'FORCE'
in: query
name: confirm
required: true
type: string
produces:
- application/json
responses:
"200":
description: Snapshot started
schema:
additionalProperties:
type: string
type: object
"400":
description: Invalid request
schema:
additionalProperties:
type: string
type: object
"500":
description: Server error
schema:
additionalProperties:
type: string
type: object
summary: Trigger hourly snapshot (manual)
tags:
- snapshots
/api/snapshots/migrate: /api/snapshots/migrate:
post: post:
description: Rebuilds the snapshot registry from existing tables and renames description: Rebuilds the snapshot registry from existing tables and renames

View File

@@ -63,6 +63,7 @@ func New(logger *slog.Logger, database db.Database, buildTime string, sha1ver st
mux.HandleFunc("/api/report/updates", h.UpdateReportDownload) mux.HandleFunc("/api/report/updates", h.UpdateReportDownload)
mux.HandleFunc("/api/report/snapshot", h.SnapshotReportDownload) mux.HandleFunc("/api/report/snapshot", h.SnapshotReportDownload)
mux.HandleFunc("/api/snapshots/aggregate", h.SnapshotAggregateForce) mux.HandleFunc("/api/snapshots/aggregate", h.SnapshotAggregateForce)
mux.HandleFunc("/api/snapshots/hourly/force", h.SnapshotForceHourly)
mux.HandleFunc("/api/snapshots/migrate", h.SnapshotMigrate) mux.HandleFunc("/api/snapshots/migrate", h.SnapshotMigrate)
mux.HandleFunc("/api/snapshots/regenerate-hourly-reports", h.SnapshotRegenerateHourlyReports) mux.HandleFunc("/api/snapshots/regenerate-hourly-reports", h.SnapshotRegenerateHourlyReports)
mux.HandleFunc("/metrics", h.Metrics) mux.HandleFunc("/metrics", h.Metrics)