mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-19 02:28:59 +00:00
Remove redundant inventory definition route
This commit is contained in:
parent
58112a6876
commit
445c2d49ef
13 changed files with 10 additions and 189 deletions
|
|
@ -177,7 +177,7 @@ with that export, but `internal/api/reporting_inventory_handlers.go` and
|
|||
`internal/api/router_routes_licensing.go` remain API-owned reporting transport,
|
||||
not lifecycle-owned inventory or install behavior.
|
||||
That adjacent reporting transport now also includes a reporting catalog route
|
||||
plus a VM inventory definition route that own panel copy, performance report
|
||||
whose nested VM inventory definition owns panel copy, performance report
|
||||
options, export title, column schema, and filename prefixes. Lifecycle-
|
||||
adjacent install and fleet surfaces may read those facts, but they must not
|
||||
redefine reporting or inventory schema locally.
|
||||
|
|
|
|||
|
|
@ -226,11 +226,11 @@ first-class surface separate from historical metrics reports.
|
|||
`internal/api/reporting_inventory_handlers.go`,
|
||||
`internal/api/router_routes_licensing.go`, and the settings reporting shell now
|
||||
own `/api/admin/reports/catalog` as the canonical operator-facing reporting
|
||||
catalog plus `/api/admin/reports/inventory/vms/definition` and
|
||||
`/api/admin/reports/inventory/vms/export` as the stable VM inventory sub-
|
||||
contract. The catalog endpoint owns the reporting panel title, description,
|
||||
locked-shell teaser copy, historical performance report options, and nested VM inventory definition,
|
||||
while the export endpoint remains the spreadsheet-shaped CSV transport. That
|
||||
catalog plus `/api/admin/reports/inventory/vms/export` as the stable VM
|
||||
inventory sub-contract. The catalog endpoint owns the reporting panel title,
|
||||
description, locked-shell teaser copy, historical performance report options,
|
||||
and nested VM inventory definition, while the export endpoint remains the
|
||||
spreadsheet-shaped CSV transport. That
|
||||
export is intentionally not comment-prefixed like the legacy metrics CSV, and
|
||||
it now carries Proxmox pool membership from the canonical unified VM runtime
|
||||
model instead of inferring or reconstructing that field locally inside the
|
||||
|
|
|
|||
|
|
@ -223,10 +223,10 @@ state VM facts, but `internal/api/reporting_inventory_handlers.go` and
|
|||
`internal/api/router_routes_licensing.go` remain API/reporting transport
|
||||
ownership rather than storage/recovery contract ownership.
|
||||
That adjacent reporting transport now also includes a reporting catalog route
|
||||
plus a VM inventory definition route that own panel copy, stable column
|
||||
schema, and filename prefix. Storage and recovery flows may read those facts
|
||||
when they need fleet context, but they must not fork their own reporting or
|
||||
inventory column contract.
|
||||
whose nested VM inventory definition owns panel copy, stable column schema,
|
||||
and filename prefix. Storage and recovery flows may read those facts when they
|
||||
need fleet context, but they must not fork their own reporting or inventory
|
||||
column contract.
|
||||
That catalog route is intentionally metadata-readable without the
|
||||
`advanced_reporting` feature gate so locked admin reporting shells can stay on
|
||||
the same API-owned definition before upsell; storage- and recovery-adjacent
|
||||
|
|
|
|||
|
|
@ -50,7 +50,6 @@ func TestReportingEndpointsRequireSettingsReadScope(t *testing.T) {
|
|||
"/api/admin/reports/catalog",
|
||||
"/api/admin/reports/generate",
|
||||
"/api/admin/reports/generate-multi",
|
||||
"/api/admin/reports/inventory/vms/definition",
|
||||
"/api/admin/reports/inventory/vms/export",
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -551,94 +551,6 @@ func TestContract_PerformanceReportTransportUsesCatalogDefaultRange(t *testing.T
|
|||
}
|
||||
}
|
||||
|
||||
func TestContract_VMInventoryExportDefinitionJSONSnapshot(t *testing.T) {
|
||||
handler := NewReportingHandlers(nil, nil)
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/admin/reports/inventory/vms/definition", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
|
||||
handler.HandleGetVMInventoryDefinition(rec, req)
|
||||
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200, got %d body=%s", rec.Code, rec.Body.String())
|
||||
}
|
||||
if got := rec.Header().Get("Content-Type"); got != "application/json" {
|
||||
t.Fatalf("expected json content type, got %q", got)
|
||||
}
|
||||
|
||||
const want = `{
|
||||
"id":"vm_inventory",
|
||||
"title":"VM Inventory Export",
|
||||
"description":"Export the current fleet-wide VM inventory as CSV using the canonical runtime model. Includes VM identity, placement, CPU, memory allocation, disk allocation, and disk usage columns.",
|
||||
"format":"csv",
|
||||
"exportEndpoint":"/api/admin/reports/inventory/vms/export",
|
||||
"filenamePrefix":"vm-inventory",
|
||||
"columns":[
|
||||
{
|
||||
"key":"resource_id",
|
||||
"label":"Resource ID",
|
||||
"description":"Canonical Pulse resource ID for the VM."
|
||||
},
|
||||
{
|
||||
"key":"instance",
|
||||
"label":"Instance",
|
||||
"description":"Configured Proxmox instance or cluster name."
|
||||
},
|
||||
{
|
||||
"key":"node",
|
||||
"label":"Node",
|
||||
"description":"Proxmox node currently hosting the VM."
|
||||
},
|
||||
{
|
||||
"key":"pool",
|
||||
"label":"Pool",
|
||||
"description":"Canonical Proxmox pool membership when the platform reports one."
|
||||
},
|
||||
{
|
||||
"key":"vmid",
|
||||
"label":"VMID",
|
||||
"description":"Numeric Proxmox VM identifier."
|
||||
},
|
||||
{
|
||||
"key":"vm_name",
|
||||
"label":"VM Name",
|
||||
"description":"Current VM display name from the runtime model."
|
||||
},
|
||||
{
|
||||
"key":"status",
|
||||
"label":"Status",
|
||||
"description":"Canonical runtime status for the VM."
|
||||
},
|
||||
{
|
||||
"key":"cpu_cores",
|
||||
"label":"CPU Cores",
|
||||
"description":"Allocated virtual CPU core count."
|
||||
},
|
||||
{
|
||||
"key":"memory_allocated_bytes",
|
||||
"label":"Memory Allocated Bytes",
|
||||
"description":"Configured memory allocation in bytes."
|
||||
},
|
||||
{
|
||||
"key":"disk_allocated_bytes",
|
||||
"label":"Disk Allocated Bytes",
|
||||
"description":"Total allocated disk capacity in bytes across the VM."
|
||||
},
|
||||
{
|
||||
"key":"disk_used_bytes",
|
||||
"label":"Disk Used Bytes",
|
||||
"description":"Current used disk bytes from the canonical runtime disk view."
|
||||
},
|
||||
{
|
||||
"key":"disk_status_reason",
|
||||
"label":"Disk Status Reason",
|
||||
"description":"Reason disk usage is partial or unavailable when the runtime cannot provide a full guest view."
|
||||
}
|
||||
]
|
||||
}`
|
||||
|
||||
assertJSONSnapshot(t, rec.Body.Bytes(), want)
|
||||
}
|
||||
|
||||
func TestContract_HostedTenantAISettingsFallbackJSONSnapshot(t *testing.T) {
|
||||
t.Setenv("PULSE_HOSTED_MODE", "true")
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import (
|
|||
type testReportingAdminEndpoints struct {
|
||||
catalogCalls int
|
||||
generateCalls int
|
||||
definitionCalls int
|
||||
exportInventoryCalls int
|
||||
}
|
||||
|
||||
|
|
@ -25,10 +24,6 @@ func (t *testReportingAdminEndpoints) HandleGenerateReport(http.ResponseWriter,
|
|||
|
||||
func (t *testReportingAdminEndpoints) HandleGenerateMultiReport(http.ResponseWriter, *http.Request) {}
|
||||
|
||||
func (t *testReportingAdminEndpoints) HandleGetVMInventoryDefinition(http.ResponseWriter, *http.Request) {
|
||||
t.definitionCalls++
|
||||
}
|
||||
|
||||
func (t *testReportingAdminEndpoints) HandleExportVMInventory(http.ResponseWriter, *http.Request) {
|
||||
t.exportInventoryCalls++
|
||||
}
|
||||
|
|
@ -105,19 +100,3 @@ func TestResolveReportingAdminEndpoints_UsesDefaultCatalogHandler(t *testing.T)
|
|||
t.Fatalf("expected default reporting catalog handler call, got %d", defaults.catalogCalls)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveReportingAdminEndpoints_UsesDefaultInventoryDefinitionHandler(t *testing.T) {
|
||||
SetReportingAdminEndpointsBinder(nil)
|
||||
t.Cleanup(func() {
|
||||
SetReportingAdminEndpointsBinder(nil)
|
||||
})
|
||||
|
||||
defaults := &testReportingAdminEndpoints{}
|
||||
resolved := resolveReportingAdminEndpoints(defaults, extensions.ReportingAdminRuntime{})
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/admin/reports/inventory/vms/definition", nil)
|
||||
rec := httptest.NewRecorder()
|
||||
resolved.HandleGetVMInventoryDefinition(rec, req)
|
||||
if defaults.definitionCalls != 1 {
|
||||
t.Fatalf("expected default VM inventory definition handler call, got %d", defaults.definitionCalls)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ func TestReportingEndpointsRequireAuthInAPIMode(t *testing.T) {
|
|||
{method: http.MethodGet, path: "/api/admin/reports/catalog", body: ""},
|
||||
{method: http.MethodGet, path: "/api/admin/reports/generate", body: ""},
|
||||
{method: http.MethodPost, path: "/api/admin/reports/generate-multi", body: `{}`},
|
||||
{method: http.MethodGet, path: "/api/admin/reports/inventory/vms/definition", body: ""},
|
||||
{method: http.MethodGet, path: "/api/admin/reports/inventory/vms/export", body: ""},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -307,44 +307,6 @@ func TestReportingHandlers_GetReportingCatalog_ReturnsCanonicalDefinition(t *tes
|
|||
}
|
||||
}
|
||||
|
||||
func TestReportingHandlers_GetVMInventoryDefinition_MethodNotAllowed(t *testing.T) {
|
||||
handler := NewReportingHandlers(nil, nil)
|
||||
req := httptest.NewRequest(http.MethodPost, "/api/admin/reports/inventory/vms/definition", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
handler.HandleGetVMInventoryDefinition(rr, req)
|
||||
|
||||
if rr.Code != http.StatusMethodNotAllowed {
|
||||
t.Fatalf("expected status %d, got %d", http.StatusMethodNotAllowed, rr.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReportingHandlers_GetVMInventoryDefinition_ReturnsCanonicalDefinition(t *testing.T) {
|
||||
handler := NewReportingHandlers(nil, nil)
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/admin/reports/inventory/vms/definition", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
handler.HandleGetVMInventoryDefinition(rr, req)
|
||||
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected status %d, got %d body=%s", http.StatusOK, rr.Code, rr.Body.String())
|
||||
}
|
||||
if contentType := rr.Header().Get("Content-Type"); !strings.Contains(contentType, "application/json") {
|
||||
t.Fatalf("expected JSON content type, got %q", contentType)
|
||||
}
|
||||
|
||||
var payload reporting.VMInventoryExportDefinition
|
||||
if err := json.NewDecoder(rr.Body).Decode(&payload); err != nil {
|
||||
t.Fatalf("decode definition payload: %v", err)
|
||||
}
|
||||
if payload.ID != "vm_inventory" || payload.Format != reporting.FormatCSV {
|
||||
t.Fatalf("unexpected VM inventory definition payload: %+v", payload)
|
||||
}
|
||||
if len(payload.Columns) == 0 || payload.Columns[3].Label != "Pool" {
|
||||
t.Fatalf("expected canonical Pool column in definition payload, got %+v", payload.Columns)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReportingHandlers_ExportVMInventory_InvalidFormat(t *testing.T) {
|
||||
handler := NewReportingHandlers(nil, nil)
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/admin/reports/inventory/vms/export?format=pdf", nil)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
|
@ -10,18 +9,6 @@ import (
|
|||
"github.com/rcourtman/pulse-go-rewrite/pkg/reporting"
|
||||
)
|
||||
|
||||
// HandleGetVMInventoryDefinition returns the canonical operator-facing
|
||||
// definition for the VM inventory export surface.
|
||||
func (h *ReportingHandlers) HandleGetVMInventoryDefinition(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_ = json.NewEncoder(w).Encode(reporting.DescribeVMInventoryExport())
|
||||
}
|
||||
|
||||
// HandleExportVMInventory exports the current VM inventory as spreadsheet-friendly CSV.
|
||||
func (h *ReportingHandlers) HandleExportVMInventory(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
|
|
|
|||
|
|
@ -450,7 +450,6 @@ var allRouteAllowlist = []string{
|
|||
"/api/admin/reports/generate",
|
||||
"/api/admin/reports/generate-multi",
|
||||
"/api/admin/reports/catalog",
|
||||
"/api/admin/reports/inventory/vms/definition",
|
||||
"/api/admin/reports/inventory/vms/export",
|
||||
"/api/admin/webhooks/audit",
|
||||
"/api/security/change-password",
|
||||
|
|
|
|||
|
|
@ -195,12 +195,6 @@ func (r *Router) registerOrgLicenseRoutesGroup(orgHandlers *OrgHandlers, rbacHan
|
|||
}
|
||||
RequireLicenseFeature(r.licenseHandlers, featureAdvancedReportingValue, RequireScope(config.ScopeSettingsRead, reportingAdminEndpoints.HandleGenerateMultiReport))(w, req)
|
||||
}))
|
||||
r.mux.HandleFunc("/api/admin/reports/inventory/vms/definition", RequirePermission(r.config, r.authorizer, auth.ActionRead, auth.ResourceNodes, func(w http.ResponseWriter, req *http.Request) {
|
||||
if !ensureAdminSession(r.config, w, req) {
|
||||
return
|
||||
}
|
||||
RequireLicenseFeature(r.licenseHandlers, featureAdvancedReportingValue, RequireScope(config.ScopeSettingsRead, reportingAdminEndpoints.HandleGetVMInventoryDefinition))(w, req)
|
||||
}))
|
||||
r.mux.HandleFunc("/api/admin/reports/inventory/vms/export", RequirePermission(r.config, r.authorizer, auth.ActionRead, auth.ResourceNodes, func(w http.ResponseWriter, req *http.Request) {
|
||||
if !ensureAdminSession(r.config, w, req) {
|
||||
return
|
||||
|
|
@ -329,14 +323,6 @@ func (a reportingAdminEndpointAdapter) HandleGenerateMultiReport(w http.Response
|
|||
a.handlers.HandleGenerateMultiReport(w, req)
|
||||
}
|
||||
|
||||
func (a reportingAdminEndpointAdapter) HandleGetVMInventoryDefinition(w http.ResponseWriter, req *http.Request) {
|
||||
if a.handlers == nil {
|
||||
writeErrorResponse(w, http.StatusNotImplemented, "reporting_unavailable", "Reporting is not available", nil)
|
||||
return
|
||||
}
|
||||
a.handlers.HandleGetVMInventoryDefinition(w, req)
|
||||
}
|
||||
|
||||
func (a reportingAdminEndpointAdapter) HandleExportVMInventory(w http.ResponseWriter, req *http.Request) {
|
||||
if a.handlers == nil {
|
||||
writeErrorResponse(w, http.StatusNotImplemented, "reporting_unavailable", "Reporting is not available", nil)
|
||||
|
|
|
|||
|
|
@ -2917,7 +2917,6 @@ func TestReportingExecutionEndpointsRequireLicenseFeature(t *testing.T) {
|
|||
paths := []string{
|
||||
"/api/admin/reports/generate",
|
||||
"/api/admin/reports/generate-multi",
|
||||
"/api/admin/reports/inventory/vms/definition",
|
||||
"/api/admin/reports/inventory/vms/export",
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ type ReportingAdminEndpoints interface {
|
|||
HandleGetReportingCatalog(http.ResponseWriter, *http.Request)
|
||||
HandleGenerateReport(http.ResponseWriter, *http.Request)
|
||||
HandleGenerateMultiReport(http.ResponseWriter, *http.Request)
|
||||
HandleGetVMInventoryDefinition(http.ResponseWriter, *http.Request)
|
||||
HandleExportVMInventory(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue