[ci skip] more suggested improvements

This commit is contained in:
2026-02-06 15:35:18 +11:00
parent dfbaacb6f3
commit 0e3cf5aae9
24 changed files with 452 additions and 356 deletions

View File

@@ -3,7 +3,6 @@ package handler
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"net/http"
"strings"
@@ -186,20 +185,18 @@ LIMIT %d
}
response := models.DailyCreationDiagnosticsResponse{
Status: "OK",
Date: parsed.Format("2006-01-02"),
Table: tableName,
TotalRows: totalRows,
MissingCreationCount: missingTotal,
MissingCreationPct: missingPct,
AvgIsPresentLtOneCount: avgIsPresentLtOne,
MissingCreationPartialCount: missingPartialCount,
MissingByVcenter: byVcenter,
Samples: samples,
Status: "OK",
Date: parsed.Format("2006-01-02"),
Table: tableName,
TotalRows: totalRows,
MissingCreationCount: missingTotal,
MissingCreationPct: missingPct,
AvgIsPresentLtOneCount: avgIsPresentLtOne,
MissingCreationPartialCount: missingPartialCount,
MissingByVcenter: byVcenter,
Samples: samples,
MissingCreationPartialSamples: partialSamples,
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(response)
writeJSON(w, http.StatusOK, response)
}

View File

@@ -57,9 +57,7 @@ func (h *Handler) EncryptData(w http.ResponseWriter, r *http.Request) {
}
h.Logger.Debug("encrypted plaintext payload", "input_length", len(plaintext))
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_ = json.NewEncoder(w).Encode(map[string]string{
writeJSON(w, http.StatusOK, map[string]string{
"status": "OK",
"message": cipherText,
"prefixed": encryptedValuePrefixV1 + cipherText,

View File

@@ -0,0 +1,135 @@
package handler
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"vctp/internal/secrets"
)
func newEncryptTestHandler() (*Handler, *secrets.Secrets) {
logger := newTestLogger()
key := []byte("0123456789abcdef0123456789abcdef")
secret := secrets.New(logger, key)
return &Handler{
Logger: logger,
Secret: secret,
}, secret
}
func decodeResponse(t *testing.T, rr *httptest.ResponseRecorder) map[string]string {
t.Helper()
var resp map[string]string
if err := json.Unmarshal(rr.Body.Bytes(), &resp); err != nil {
t.Fatalf("failed to decode response body %q: %v", rr.Body.String(), err)
}
return resp
}
func TestEncryptDataRejectsWrongMethod(t *testing.T) {
h, _ := newEncryptTestHandler()
req := httptest.NewRequest(http.MethodGet, "/api/encrypt", nil)
rr := httptest.NewRecorder()
h.EncryptData(rr, req)
if rr.Code != http.StatusMethodNotAllowed {
t.Fatalf("expected %d, got %d", http.StatusMethodNotAllowed, rr.Code)
}
resp := decodeResponse(t, rr)
if resp["status"] != "ERROR" {
t.Fatalf("expected status ERROR, got %#v", resp)
}
}
func TestEncryptDataRejectsInvalidJSON(t *testing.T) {
h, _ := newEncryptTestHandler()
req := httptest.NewRequest(http.MethodPost, "/api/encrypt", strings.NewReader("{"))
rr := httptest.NewRecorder()
h.EncryptData(rr, req)
if rr.Code != http.StatusBadRequest {
t.Fatalf("expected %d, got %d", http.StatusBadRequest, rr.Code)
}
resp := decodeResponse(t, rr)
if resp["status"] != "ERROR" {
t.Fatalf("expected status ERROR, got %#v", resp)
}
}
func TestEncryptDataAcceptsPlaintextField(t *testing.T) {
h, secret := newEncryptTestHandler()
req := httptest.NewRequest(http.MethodPost, "/api/encrypt", strings.NewReader(`{"plaintext":"super-secret"}`))
rr := httptest.NewRecorder()
h.EncryptData(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("expected %d, got %d", http.StatusOK, rr.Code)
}
resp := decodeResponse(t, rr)
if resp["status"] != "OK" {
t.Fatalf("expected status OK, got %#v", resp)
}
if resp["ciphertext"] == "" || resp["prefixed"] == "" {
t.Fatalf("expected ciphertext+prefixed fields, got %#v", resp)
}
if !strings.HasPrefix(resp["prefixed"], encryptedValuePrefixV1) {
t.Fatalf("expected prefixed value with %q, got %q", encryptedValuePrefixV1, resp["prefixed"])
}
if !strings.EqualFold(resp["message"], resp["ciphertext"]) {
t.Fatalf("expected message to mirror ciphertext, got %#v", resp)
}
plain, err := secret.Decrypt(resp["ciphertext"])
if err != nil {
t.Fatalf("unable to decrypt ciphertext response: %v", err)
}
if string(plain) != "super-secret" {
t.Fatalf("unexpected decrypted value %q", string(plain))
}
}
func TestEncryptDataAcceptsLegacyValueField(t *testing.T) {
h, secret := newEncryptTestHandler()
body := bytes.NewBufferString(`{"value":"legacy-input"}`)
req := httptest.NewRequest(http.MethodPost, "/api/encrypt", body)
rr := httptest.NewRecorder()
h.EncryptData(rr, req)
if rr.Code != http.StatusOK {
t.Fatalf("expected %d, got %d", http.StatusOK, rr.Code)
}
resp := decodeResponse(t, rr)
cipherText := resp["ciphertext"]
if cipherText == "" {
t.Fatalf("expected ciphertext in response, got %#v", resp)
}
plain, err := secret.Decrypt(cipherText)
if err != nil {
t.Fatalf("unable to decrypt ciphertext response: %v", err)
}
if string(plain) != "legacy-input" {
t.Fatalf("unexpected decrypted value %q", string(plain))
}
}
func TestEncryptDataRejectsMissingPayloadValue(t *testing.T) {
h, _ := newEncryptTestHandler()
req := httptest.NewRequest(http.MethodPost, "/api/encrypt", strings.NewReader(`{}`))
rr := httptest.NewRecorder()
h.EncryptData(rr, req)
if rr.Code != http.StatusBadRequest {
t.Fatalf("expected %d, got %d", http.StatusBadRequest, rr.Code)
}
resp := decodeResponse(t, rr)
if resp["status"] != "ERROR" {
t.Fatalf("expected status ERROR, got %#v", resp)
}
}

View File

@@ -0,0 +1,63 @@
package handler
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
)
func TestDenyLegacyAPIDisabledByDefault(t *testing.T) {
t.Setenv(legacyAPIEnvVar, "")
h := &Handler{Logger: newTestLogger()}
rr := httptest.NewRecorder()
denied := h.denyLegacyAPI(rr, "/api/event/vm/create")
if !denied {
t.Fatal("expected legacy API to be denied by default")
}
if rr.Code != http.StatusGone {
t.Fatalf("expected %d, got %d", http.StatusGone, rr.Code)
}
if !strings.Contains(rr.Body.String(), "deprecated") {
t.Fatalf("unexpected response body: %s", rr.Body.String())
}
}
func TestDenyLegacyAPIEnabledViaEnv(t *testing.T) {
t.Setenv(legacyAPIEnvVar, "1")
h := &Handler{Logger: newTestLogger()}
rr := httptest.NewRecorder()
denied := h.denyLegacyAPI(rr, "/api/event/vm/create")
if denied {
t.Fatal("expected legacy API to be allowed when env var is set")
}
if rr.Body.Len() != 0 {
t.Fatalf("expected no response body write, got: %s", rr.Body.String())
}
}
func TestVmCreateEventHonorsLegacyGate(t *testing.T) {
h := &Handler{Logger: newTestLogger()}
t.Run("disabled", func(t *testing.T) {
t.Setenv(legacyAPIEnvVar, "")
req := httptest.NewRequest(http.MethodPost, "/api/event/vm/create", strings.NewReader("{invalid"))
rr := httptest.NewRecorder()
h.VmCreateEvent(rr, req)
if rr.Code != http.StatusGone {
t.Fatalf("expected %d, got %d", http.StatusGone, rr.Code)
}
})
t.Run("enabled", func(t *testing.T) {
t.Setenv(legacyAPIEnvVar, "1")
req := httptest.NewRequest(http.MethodPost, "/api/event/vm/create", strings.NewReader("{invalid"))
rr := httptest.NewRecorder()
h.VmCreateEvent(rr, req)
if rr.Code != http.StatusBadRequest {
t.Fatalf("expected %d when gate is open, got %d", http.StatusBadRequest, rr.Code)
}
})
}

View File

@@ -2,7 +2,6 @@ package handler
import (
"context"
"encoding/json"
"fmt"
"net/http"
"vctp/internal/report"
@@ -24,12 +23,7 @@ func (h *Handler) InventoryReportDownload(w http.ResponseWriter, r *http.Request
reportData, err := report.CreateInventoryReport(h.Logger, h.Database, ctx)
if err != nil {
h.Logger.Error("Failed to create report", "error", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Unable to create xlsx report: '%s'", err),
})
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Unable to create xlsx report: '%s'", err))
return
}
@@ -58,12 +52,7 @@ func (h *Handler) UpdateReportDownload(w http.ResponseWriter, r *http.Request) {
reportData, err := report.CreateUpdatesReport(h.Logger, h.Database, ctx)
if err != nil {
h.Logger.Error("Failed to create report", "error", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Unable to create xlsx report: '%s'", err),
})
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Unable to create xlsx report: '%s'", err))
return
}

View File

@@ -0,0 +1,41 @@
package handler
import (
"encoding/json"
"net/http"
"vctp/server/models"
)
func writeJSON(w http.ResponseWriter, statusCode int, payload any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(statusCode)
_ = json.NewEncoder(w).Encode(payload)
}
func writeJSONStatus(w http.ResponseWriter, statusCode int, status string) {
writeJSON(w, statusCode, models.StatusResponse{
Status: status,
})
}
func writeJSONStatusMessage(w http.ResponseWriter, statusCode int, status, message string) {
writeJSON(w, statusCode, models.StatusMessageResponse{
Status: status,
Message: message,
})
}
func writeJSONOK(w http.ResponseWriter) {
writeJSONStatus(w, http.StatusOK, "OK")
}
func writeJSONOKMessage(w http.ResponseWriter, message string) {
writeJSONStatusMessage(w, http.StatusOK, "OK", message)
}
func writeJSONError(w http.ResponseWriter, statusCode int, message string) {
writeJSON(w, statusCode, models.ErrorResponse{
Status: "ERROR",
Message: message,
})
}

View File

@@ -2,13 +2,11 @@ package handler
import (
"context"
"encoding/json"
"net/http"
"strings"
"time"
"vctp/internal/settings"
"vctp/internal/tasks"
"vctp/server/models"
)
// SnapshotAggregateForce forces regeneration of a daily or monthly summary table.
@@ -102,18 +100,5 @@ func (h *Handler) SnapshotAggregateForce(w http.ResponseWriter, r *http.Request)
"granularity", granularity,
"duration", time.Since(startedAt),
)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{
"status": "OK",
})
}
func writeJSONError(w http.ResponseWriter, status int, message string) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(models.ErrorResponse{
Status: "ERROR",
Message: message,
})
writeJSONOK(w)
}

View File

@@ -2,7 +2,6 @@ package handler
import (
"context"
"encoding/json"
"net/http"
"strings"
"time"
@@ -44,8 +43,5 @@ func (h *Handler) SnapshotForceHourly(w http.ResponseWriter, r *http.Request) {
}
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",
})
writeJSONOK(w)
}

View File

@@ -2,9 +2,9 @@ package handler
import (
"context"
"encoding/json"
"net/http"
"vctp/internal/report"
"vctp/server/models"
)
// SnapshotMigrate rebuilds the snapshot registry and normalizes hourly table names.
@@ -19,20 +19,28 @@ func (h *Handler) SnapshotMigrate(w http.ResponseWriter, r *http.Request) {
ctx := context.Background()
stats, err := report.MigrateSnapshotRegistry(ctx, h.Database)
if err != nil {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]interface{}{
"status": "ERROR",
"error": err.Error(),
"stats": stats,
writeJSON(w, http.StatusInternalServerError, models.SnapshotMigrationResponse{
Status: "ERROR",
Error: err.Error(),
Stats: models.SnapshotMigrationStats{
HourlyRenamed: stats.HourlyRenamed,
HourlyRegistered: stats.HourlyRegistered,
DailyRegistered: stats.DailyRegistered,
MonthlyRegistered: stats.MonthlyRegistered,
Errors: stats.Errors,
},
})
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]interface{}{
"status": "OK",
"stats": stats,
writeJSON(w, http.StatusOK, models.SnapshotMigrationResponse{
Status: "OK",
Stats: models.SnapshotMigrationStats{
HourlyRenamed: stats.HourlyRenamed,
HourlyRegistered: stats.HourlyRegistered,
DailyRegistered: stats.DailyRegistered,
MonthlyRegistered: stats.MonthlyRegistered,
Errors: stats.Errors,
},
})
}

View File

@@ -1,13 +1,13 @@
package handler
import (
"encoding/json"
"net/http"
"os"
"path/filepath"
"strings"
"time"
"vctp/internal/report"
"vctp/server/models"
)
// SnapshotRegenerateHourlyReports regenerates missing hourly snapshot XLSX reports on disk.
@@ -54,15 +54,14 @@ func (h *Handler) SnapshotRegenerateHourlyReports(w http.ResponseWriter, r *http
regenerated++
}
resp := map[string]interface{}{
"status": "OK",
"total": len(records),
"regenerated": regenerated,
"skipped": skipped,
"errors": errors,
"reports_dir": reportsDir,
"snapshotType": "hourly",
resp := models.SnapshotRegenerateReportsResponse{
Status: "OK",
Total: len(records),
Regenerated: regenerated,
Skipped: skipped,
Errors: errors,
ReportsDir: reportsDir,
SnapshotType: "hourly",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(resp)
writeJSON(w, http.StatusOK, resp)
}

View File

@@ -2,7 +2,6 @@ package handler
import (
"context"
"encoding/json"
"fmt"
"net/http"
"strconv"
@@ -10,6 +9,7 @@ import (
"time"
"vctp/db"
"vctp/internal/report"
"vctp/server/models"
)
// SnapshotRepair scans existing daily summaries and backfills missing SnapshotTime and lifecycle fields.
@@ -21,20 +21,18 @@ import (
// @Router /api/snapshots/repair [post]
func (h *Handler) SnapshotRepair(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
writeJSONError(w, http.StatusMethodNotAllowed, "method not allowed")
return
}
h.Logger.Info("snapshot repair started", "scope", "daily")
repaired, failed := h.repairDailySummaries(r.Context(), time.Now())
h.Logger.Info("snapshot repair finished", "daily_repaired", repaired, "daily_failed", failed)
resp := map[string]string{
"status": "ok",
"repaired": strconv.Itoa(repaired),
"failed": strconv.Itoa(failed),
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(resp)
writeJSON(w, http.StatusOK, models.SnapshotRepairResponse{
Status: "OK",
Repaired: strconv.Itoa(repaired),
Failed: strconv.Itoa(failed),
})
}
func (h *Handler) repairDailySummaries(ctx context.Context, now time.Time) (repaired int, failed int) {
@@ -42,8 +40,8 @@ func (h *Handler) repairDailySummaries(ctx context.Context, now time.Time) (repa
dailyRecs, err := report.SnapshotRecordsWithFallback(ctx, h.Database, "daily", "inventory_daily_summary_", "20060102", time.Time{}, now)
if err != nil {
h.Logger.Warn("failed to list daily summaries", "error", err)
return 0, 1
h.Logger.Warn("failed to list daily summaries", "error", err)
return 0, 1
}
for _, rec := range dailyRecs {
@@ -53,27 +51,27 @@ func (h *Handler) repairDailySummaries(ctx context.Context, now time.Time) (repa
if err := db.EnsureSummaryTable(ctx, dbConn, rec.TableName); err != nil {
h.Logger.Warn("ensure summary table failed", "table", rec.TableName, "error", err)
failed++
continue
}
failed++
continue
}
hourlyRecs, err := report.SnapshotRecordsWithFallback(ctx, h.Database, "hourly", "inventory_hourly_", "epoch", dayStart, dayEnd)
if err != nil || len(hourlyRecs) == 0 {
h.Logger.Warn("no hourly snapshots for repair window", "table", rec.TableName, "error", err)
failed++
continue
}
hourlyRecs, err := report.SnapshotRecordsWithFallback(ctx, h.Database, "hourly", "inventory_hourly_", "epoch", dayStart, dayEnd)
if err != nil || len(hourlyRecs) == 0 {
h.Logger.Warn("no hourly snapshots for repair window", "table", rec.TableName, "error", err)
failed++
continue
}
cols := []string{
`"InventoryId"`, `"Name"`, `"Vcenter"`, `"VmId"`, `"EventKey"`, `"CloudId"`, `"CreationTime"`,
`"DeletionTime"`, `"ResourcePool"`, `"Datacenter"`, `"Cluster"`, `"Folder"`,
`"ProvisionedDisk"`, `"VcpuCount"`, `"RamGB"`, `"IsTemplate"`, `"PoweredOn"`,
`"SrmPlaceholder"`, `"VmUuid"`, `"SnapshotTime"`,
}
union, err := buildUnionFromRecords(hourlyRecs, cols, `COALESCE(CAST("IsTemplate" AS TEXT), '') NOT IN ('TRUE','true','1')`)
if err != nil {
h.Logger.Warn("failed to build union for repair", "table", rec.TableName, "error", err)
failed++
cols := []string{
`"InventoryId"`, `"Name"`, `"Vcenter"`, `"VmId"`, `"EventKey"`, `"CloudId"`, `"CreationTime"`,
`"DeletionTime"`, `"ResourcePool"`, `"Datacenter"`, `"Cluster"`, `"Folder"`,
`"ProvisionedDisk"`, `"VcpuCount"`, `"RamGB"`, `"IsTemplate"`, `"PoweredOn"`,
`"SrmPlaceholder"`, `"VmUuid"`, `"SnapshotTime"`,
}
union, err := buildUnionFromRecords(hourlyRecs, cols, `COALESCE(CAST("IsTemplate" AS TEXT), '') NOT IN ('TRUE','true','1')`)
if err != nil {
h.Logger.Warn("failed to build union for repair", "table", rec.TableName, "error", err)
failed++
continue
}
@@ -106,7 +104,7 @@ func (h *Handler) repairDailySummaries(ctx context.Context, now time.Time) (repa
// @Router /api/snapshots/repair/all [post]
func (h *Handler) SnapshotRepairSuite(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
writeJSONError(w, http.StatusMethodNotAllowed, "method not allowed")
return
}
@@ -135,15 +133,13 @@ func (h *Handler) SnapshotRepairSuite(w http.ResponseWriter, r *http.Request) {
h.Logger.Info("repair suite step", "step", "monthly_refine")
monthlyRefined, monthlyFailed := h.refineMonthlyFromDaily(ctx, time.Now())
resp := map[string]string{
"status": "ok",
"daily_repaired": strconv.Itoa(dailyRepaired),
"daily_failed": strconv.Itoa(dailyFailed),
"monthly_refined": strconv.Itoa(monthlyRefined),
"monthly_failed": strconv.Itoa(monthlyFailed),
}
w.Header().Set("Content-Type", "application/json")
_ = json.NewEncoder(w).Encode(resp)
writeJSON(w, http.StatusOK, models.SnapshotRepairSuiteResponse{
Status: "OK",
DailyRepaired: strconv.Itoa(dailyRepaired),
DailyFailed: strconv.Itoa(dailyFailed),
MonthlyRefined: strconv.Itoa(monthlyRefined),
MonthlyFailed: strconv.Itoa(monthlyFailed),
})
}
func (h *Handler) refineMonthlyFromDaily(ctx context.Context, now time.Time) (refined int, failed int) {
@@ -178,11 +174,11 @@ func (h *Handler) refineMonthlyFromDaily(ctx context.Context, now time.Time) (re
continue
}
union, err := buildUnionFromRecords(recs, cols, `COALESCE(CAST("IsTemplate" AS TEXT), '') NOT IN ('TRUE','true','1')`)
if err != nil {
h.Logger.Warn("failed to build union for monthly refine", "table", summaryTable, "error", err)
failed++
continue
union, err := buildUnionFromRecords(recs, cols, `COALESCE(CAST("IsTemplate" AS TEXT), '') NOT IN ('TRUE','true','1')`)
if err != nil {
h.Logger.Warn("failed to build union for monthly refine", "table", summaryTable, "error", err)
failed++
continue
}
if err := db.RefineCreationDeletionFromUnion(ctx, dbConn, summaryTable, union); err != nil {

View File

@@ -2,7 +2,6 @@ package handler
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
@@ -62,24 +61,14 @@ func (h *Handler) SnapshotReportDownload(w http.ResponseWriter, r *http.Request)
ctx := context.Background()
tableName := r.URL.Query().Get("table")
if tableName == "" {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": "Missing table parameter",
})
writeJSONError(w, http.StatusBadRequest, "Missing table parameter")
return
}
reportData, err := report.CreateTableReport(h.Logger, h.Database, ctx, tableName)
if err != nil {
h.Logger.Error("Failed to create snapshot report", "error", err, "table", tableName)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Unable to create snapshot report: '%s'", err),
})
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Unable to create snapshot report: '%s'", err))
return
}

View File

@@ -0,0 +1,10 @@
package handler
import (
"io"
"log/slog"
)
func newTestLogger() *slog.Logger {
return slog.New(slog.NewTextHandler(io.Discard, nil))
}

View File

@@ -43,12 +43,9 @@ func (h *Handler) UpdateCleanup(w http.ResponseWriter, r *http.Request) {
if err != nil {
h.Logger.Error("Error received cleaning updates table", "error", err)
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "Delete Request unsuccessful %s\n", err)
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Delete Request unsuccessful %s", err))
} else {
h.Logger.Debug("Processed update cleanup successfully")
w.WriteHeader(http.StatusOK)
// TODO - return some JSON
fmt.Fprintf(w, "Processed update cleanup successfully")
writeJSONOKMessage(w, "Processed update cleanup successfully")
}
}

View File

@@ -3,7 +3,6 @@ package handler
import (
"context"
"database/sql"
"encoding/json"
"errors"
"fmt"
"net/http"
@@ -35,21 +34,11 @@ func (h *Handler) VcCleanup(w http.ResponseWriter, r *http.Request) {
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
h.Logger.Error("No VMs found for vcenter", "url", vcUrl)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("No match to vcenter details specified. vc_url: '%s'", vcUrl),
})
writeJSONError(w, http.StatusBadRequest, fmt.Sprintf("No match to vcenter details specified. vc_url: '%s'", vcUrl))
return
} else {
h.Logger.Error("Error checking for vcenter to cleanup", "error", err, "url", vcUrl)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Error checking for vcenter to cleanup. error: '%s'", err),
})
writeJSONError(w, http.StatusBadRequest, fmt.Sprintf("Error checking for vcenter to cleanup. error: '%s'", err))
return
}
} else {
@@ -57,33 +46,18 @@ func (h *Handler) VcCleanup(w http.ResponseWriter, r *http.Request) {
err = h.Database.Queries().InventoryCleanupVcenter(ctx, vcUrl)
if err != nil {
h.Logger.Error("Error cleaning up VMs from Inventory table", "error", err, "url", vcUrl)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Error cleaning up VMs from Inventory table. error: '%s'", err),
})
writeJSONError(w, http.StatusBadRequest, fmt.Sprintf("Error cleaning up VMs from Inventory table. error: '%s'", err))
return
} else {
// Successful cleanup
h.Logger.Debug("VMs successfully removed from inventory for vcenter", "url", vcUrl)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{
"status": "OK",
"message": fmt.Sprintf("Removed VMs from Inventory table for vcenter '%s'", vcUrl),
})
writeJSONOKMessage(w, fmt.Sprintf("Removed VMs from Inventory table for vcenter '%s'", vcUrl))
return
}
}
} else {
h.Logger.Error("Parameters not correctly specified", "url", vcUrl)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Parameters not correctly specified. vc_url: '%s'", vcUrl),
})
writeJSONError(w, http.StatusBadRequest, fmt.Sprintf("Parameters not correctly specified. vc_url: '%s'", vcUrl))
return
}
}

View File

@@ -3,7 +3,6 @@ package handler
import (
"context"
"database/sql"
"encoding/json"
"errors"
"fmt"
"net/http"
@@ -38,21 +37,11 @@ func (h *Handler) VmCleanup(w http.ResponseWriter, r *http.Request) {
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
h.Logger.Error("No VM found matching parameters", "vm_id", vmId, "datacenter_name", datacenterName)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("No match to VM details specified. vm_id: '%s', datacenter_name: '%s'", vmId, datacenterName),
})
writeJSONError(w, http.StatusBadRequest, fmt.Sprintf("No match to VM details specified. vm_id: '%s', datacenter_name: '%s'", vmId, datacenterName))
return
} else {
h.Logger.Error("Error checking for VM to cleanup", "error", err, "vm_id", vmId, "datacenter_name", datacenterName)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Error checking for VM to cleanup. error: '%s'", err),
})
writeJSONError(w, http.StatusBadRequest, fmt.Sprintf("Error checking for VM to cleanup. error: '%s'", err))
return
}
} else {
@@ -68,33 +57,18 @@ func (h *Handler) VmCleanup(w http.ResponseWriter, r *http.Request) {
err = h.Database.Queries().InventoryCleanup(ctx, params)
if err != nil {
h.Logger.Error("Error cleaning up VM from Inventory table", "error", err, "vm_id", vmId, "datacenter_name", datacenterName)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Error cleaning up VM from Inventory table. error: '%s'", err),
})
writeJSONError(w, http.StatusBadRequest, fmt.Sprintf("Error cleaning up VM from Inventory table. error: '%s'", err))
return
} else {
// Successful cleanup
h.Logger.Debug("VM successfully removed from inventory", "vm_name", vm.Name, "iid", vm.Iid, "vm_id", vmId, "datacenter_name", datacenterName)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{
"status": "OK",
"message": fmt.Sprintf("VM '%s' removed from Inventory table", vm.Name),
})
writeJSONOKMessage(w, fmt.Sprintf("VM '%s' removed from Inventory table", vm.Name))
return
}
}
} else {
h.Logger.Error("Parameters not correctly specified", "vm_id", vmId, "datacenter_name", datacenterName)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Parameters not correctly specified. vm_id: '%s', datacenter_name: '%s'", vmId, datacenterName),
})
writeJSONError(w, http.StatusBadRequest, fmt.Sprintf("Parameters not correctly specified. vm_id: '%s', datacenter_name: '%s'", vmId, datacenterName))
return
}
}

View File

@@ -20,11 +20,11 @@ import (
// @Tags events
// @Deprecated
// @Accept json
// @Produce text/plain
// @Produce json
// @Param event body models.CloudEventReceived true "CloudEvent payload"
// @Success 200 {string} string "Create event processed"
// @Failure 400 {string} string "Invalid request"
// @Failure 500 {string} string "Server error"
// @Success 200 {object} models.StatusMessageResponse "Create event processed"
// @Failure 400 {object} models.ErrorResponse "Invalid request"
// @Failure 500 {object} models.ErrorResponse "Server error"
// @Router /api/event/vm/create [post]
func (h *Handler) VmCreateEvent(w http.ResponseWriter, r *http.Request) {
if h.denyLegacyAPI(w, "/api/event/vm/create") {
@@ -41,8 +41,7 @@ func (h *Handler) VmCreateEvent(w http.ResponseWriter, r *http.Request) {
reqBody, err := io.ReadAll(r.Body)
if err != nil {
h.Logger.Error("Invalid data received", "error", err)
fmt.Fprintf(w, "Invalid data received")
w.WriteHeader(http.StatusInternalServerError)
writeJSONError(w, http.StatusInternalServerError, "Invalid data received")
return
} else {
h.Logger.Debug("received input data", "length", len(reqBody))
@@ -52,7 +51,7 @@ func (h *Handler) VmCreateEvent(w http.ResponseWriter, r *http.Request) {
var event models.CloudEventReceived
if err := json.Unmarshal(reqBody, &event); err != nil {
h.Logger.Error("unable to decode json", "error", err)
http.Error(w, "Invalid JSON body", http.StatusBadRequest)
writeJSONError(w, http.StatusBadRequest, "Invalid JSON body")
return
} else {
h.Logger.Debug("successfully decoded JSON")
@@ -100,16 +99,13 @@ func (h *Handler) VmCreateEvent(w http.ResponseWriter, r *http.Request) {
result, err := h.Database.Queries().CreateEvent(context.Background(), params)
if err != nil {
h.Logger.Error("unable to perform database insert", "error", err)
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "Error : %v\n", err)
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Error: %v", err))
return
} else {
h.Logger.Debug("created database record", "insert_result", result)
}
//h.Logger.Debug("received create request", "body", string(reqBody))
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Create Request : %v\n", result)
writeJSONOKMessage(w, fmt.Sprintf("Create request processed: %v", result))
}
// prettyPrint comes from https://gist.github.com/sfate/9d45f6c5405dc4c9bf63bf95fe6d1a7c

View File

@@ -18,11 +18,11 @@ import (
// @Tags events
// @Deprecated
// @Accept json
// @Produce text/plain
// @Produce json
// @Param event body models.CloudEventReceived true "CloudEvent payload"
// @Success 200 {string} string "Delete event processed"
// @Failure 400 {string} string "Invalid request"
// @Failure 500 {string} string "Server error"
// @Success 200 {object} models.StatusMessageResponse "Delete event processed"
// @Failure 400 {object} models.ErrorResponse "Invalid request"
// @Failure 500 {object} models.ErrorResponse "Server error"
// @Router /api/event/vm/delete [post]
func (h *Handler) VmDeleteEvent(w http.ResponseWriter, r *http.Request) {
if h.denyLegacyAPI(w, "/api/event/vm/delete") {
@@ -36,8 +36,7 @@ func (h *Handler) VmDeleteEvent(w http.ResponseWriter, r *http.Request) {
reqBody, err := io.ReadAll(r.Body)
if err != nil {
h.Logger.Error("Invalid data received", "error", err)
fmt.Fprintf(w, "Invalid data received")
w.WriteHeader(http.StatusInternalServerError)
writeJSONError(w, http.StatusInternalServerError, "Invalid data received")
return
} else {
//h.Logger.Debug("received input data", "length", len(reqBody))
@@ -48,7 +47,7 @@ func (h *Handler) VmDeleteEvent(w http.ResponseWriter, r *http.Request) {
if err := json.Unmarshal(reqBody, &event); err != nil {
h.Logger.Error("unable to decode json", "error", err)
prettyPrint(event)
http.Error(w, "Invalid JSON body", http.StatusBadRequest)
writeJSONError(w, http.StatusBadRequest, "Invalid JSON body")
return
} else {
h.Logger.Debug("successfully decoded deletion type cloud event", "vm_id", event.CloudEvent.Data.VM.VM.Value)
@@ -76,13 +75,10 @@ func (h *Handler) VmDeleteEvent(w http.ResponseWriter, r *http.Request) {
if err != nil {
h.Logger.Error("Error received marking VM as deleted", "error", err)
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "Delete Request unsuccessful %s\n", err)
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Delete Request unsuccessful %s", err))
} else {
h.Logger.Debug("Processed VM Deletion event successfully")
w.WriteHeader(http.StatusOK)
// TODO - return some JSON
fmt.Fprintf(w, "Processed VM Deletion event successfully")
writeJSONOKMessage(w, "Processed VM Deletion event successfully")
}
//h.Logger.Debug("received delete request", "body", string(reqBody))

View File

@@ -29,12 +29,7 @@ func (h *Handler) VmImport(w http.ResponseWriter, r *http.Request) {
reqBody, err := io.ReadAll(r.Body)
if err != nil {
h.Logger.Error("Invalid data received", "length", len(reqBody), "error", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Invalid data received: '%s'", err),
})
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Invalid data received: '%s'", err))
return
} else {
@@ -45,12 +40,7 @@ func (h *Handler) VmImport(w http.ResponseWriter, r *http.Request) {
var inData models.ImportReceived
if err := json.Unmarshal(reqBody, &inData); err != nil {
h.Logger.Error("Unable to decode json request body", "length", len(reqBody), "error", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Unable to decode json request body: '%s'", err),
})
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Unable to decode json request body: '%s'", err))
return
} else {
//h.Logger.Debug("successfully decoded JSON")
@@ -59,12 +49,7 @@ func (h *Handler) VmImport(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(inData.Name, "vCLS-") {
h.Logger.Info("Skipping internal vCLS VM import", "vm_name", inData.Name)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{
"status": "OK",
"message": fmt.Sprintf("Skipped internal VM '%s'", inData.Name),
})
writeJSONOKMessage(w, fmt.Sprintf("Skipped internal VM '%s'", inData.Name))
return
}
@@ -103,10 +88,5 @@ func (h *Handler) VmImport(w http.ResponseWriter, r *http.Request) {
h.Logger.Info("not adding vm to inventory table since record alraedy exists", "vm_id", inData.VmId, "datacenter_name", inData.Datacenter)
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{
"status": "OK",
"message": fmt.Sprintf("Successfully processed import request for VM '%s'", inData.Name),
})
writeJSONOKMessage(w, fmt.Sprintf("Successfully processed import request for VM '%s'", inData.Name))
}

View File

@@ -46,12 +46,7 @@ func (h *Handler) VmModifyEvent(w http.ResponseWriter, r *http.Request) {
reqBody, err := io.ReadAll(r.Body)
if err != nil {
h.Logger.Error("Invalid data received", "length", len(reqBody), "error", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Invalid data received: '%s'", err),
})
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Invalid data received: '%s'", err))
return
}
@@ -59,12 +54,7 @@ func (h *Handler) VmModifyEvent(w http.ResponseWriter, r *http.Request) {
var event models.CloudEventReceived
if err := json.Unmarshal(reqBody, &event); err != nil {
h.Logger.Error("Unable to decode json request body", "length", len(reqBody), "error", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Unable to decode json request body: '%s'", err),
})
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Unable to decode json request body: '%s'", err))
return
} else {
//h.Logger.Debug("successfully decoded JSON")
@@ -74,12 +64,7 @@ func (h *Handler) VmModifyEvent(w http.ResponseWriter, r *http.Request) {
if event.CloudEvent.Data.ConfigChanges == nil {
h.Logger.Warn("Received event contains no config change")
prettyPrint(event)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusAccepted)
json.NewEncoder(w).Encode(map[string]string{
"status": "OK",
"message": "Received update event successfully but no config changes were found",
})
writeJSONStatusMessage(w, http.StatusAccepted, "OK", "Received update event successfully but no config changes were found")
return
} else {
h.Logger.Info("Received event contains config change info", "source", event.CloudEvent.Source,
@@ -239,13 +224,8 @@ func (h *Handler) VmModifyEvent(w http.ResponseWriter, r *http.Request) {
iid, err2 := h.AddVmToInventory(event, ctx, unixTimestamp)
if err2 != nil {
h.Logger.Error("Received error adding VM to inventory", "error", err2)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Valid request but experienced error adding vm id '%s' in datacenter name '%s' to inventory table : %s",
event.CloudEvent.Data.VM.VM.Value, event.CloudEvent.Data.Datacenter.Name, err2),
})
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Valid request but experienced error adding vm id '%s' in datacenter name '%s' to inventory table : %s",
event.CloudEvent.Data.VM.VM.Value, event.CloudEvent.Data.Datacenter.Name, err2))
return
}
@@ -253,24 +233,14 @@ func (h *Handler) VmModifyEvent(w http.ResponseWriter, r *http.Request) {
params.InventoryId = sql.NullInt64{Int64: iid, Valid: iid > 0}
} else {
h.Logger.Error("Received zero for inventory id when adding VM to inventory")
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Valid request but received zero result when adding vm id '%s' in datacenter name '%s' to inventory table",
event.CloudEvent.Data.VM.VM.Value, event.CloudEvent.Data.Datacenter.Name),
})
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Valid request but received zero result when adding vm id '%s' in datacenter name '%s' to inventory table",
event.CloudEvent.Data.VM.VM.Value, event.CloudEvent.Data.Datacenter.Name))
return
}
} else {
h.Logger.Error("unable to find existing inventory record for this VM", "error", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Valid request but could not locate vm id '%s' and datacenter name '%s' within inventory table : %s",
event.CloudEvent.Data.VM.VM.Value, event.CloudEvent.Data.Datacenter.Name, err),
})
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Valid request but could not locate vm id '%s' and datacenter name '%s' within inventory table : %s",
event.CloudEvent.Data.VM.VM.Value, event.CloudEvent.Data.Datacenter.Name, err))
return
}
@@ -282,11 +252,7 @@ func (h *Handler) VmModifyEvent(w http.ResponseWriter, r *http.Request) {
if params.UpdateType == "diskChange" && invResult.ProvisionedDisk.Float64 == params.NewProvisionedDisk.Float64 {
h.Logger.Info("VM update type was for disk size but current size of VM matches inventory record, no need for update record",
"vm_name", invResult.Name, "db_value", invResult.ProvisionedDisk.Float64, "new_value", params.NewProvisionedDisk.Float64)
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{
"status": "OK",
"message": "Successfully processed vm modify event",
})
writeJSONOKMessage(w, "Successfully processed vm modify event")
return
}
@@ -303,23 +269,17 @@ func (h *Handler) VmModifyEvent(w http.ResponseWriter, r *http.Request) {
result, err := h.Database.Queries().CreateUpdate(ctx, params)
if err != nil {
h.Logger.Error("unable to perform database insert", "error", err)
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "Error : %v\n", err)
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Error : %v", err))
return
} else {
h.Logger.Debug("created database record", "insert_result", result)
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(map[string]string{
"status": "OK",
"message": "Successfully processed vm modify event",
})
writeJSONOKMessage(w, "Successfully processed vm modify event")
return
}
} else {
h.Logger.Debug("Didn't find any configuration changes of interest", "id", event.CloudEvent.ID,
"vm", event.CloudEvent.Data.VM.Name, "config_changes", configChanges)
w.WriteHeader(http.StatusAccepted)
fmt.Fprintf(w, "Processed update event but no config changes were of interest\n")
writeJSONStatusMessage(w, http.StatusAccepted, "OK", "Processed update event but no config changes were of interest")
//prettyPrint(event.CloudEvent.Data.ConfigSpec)
}
}

View File

@@ -39,8 +39,7 @@ func (h *Handler) VmMoveEvent(w http.ResponseWriter, r *http.Request) {
reqBody, err := io.ReadAll(r.Body)
if err != nil {
h.Logger.Error("Invalid data received", "error", err)
fmt.Fprintf(w, "Invalid data received")
w.WriteHeader(http.StatusInternalServerError)
writeJSONError(w, http.StatusInternalServerError, "Invalid data received")
return
} else {
//h.Logger.Debug("received input data", "length", len(reqBody))
@@ -51,12 +50,7 @@ func (h *Handler) VmMoveEvent(w http.ResponseWriter, r *http.Request) {
if err := json.Unmarshal(reqBody, &event); err != nil {
h.Logger.Error("unable to unmarshal json", "error", err)
prettyPrint(reqBody)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Unable to unmarshal JSON in request body: '%s'", err),
})
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Unable to unmarshal JSON in request body: '%s'", err))
return
} else {
h.Logger.Debug("successfully decoded JSON")
@@ -66,12 +60,7 @@ func (h *Handler) VmMoveEvent(w http.ResponseWriter, r *http.Request) {
if event.CloudEvent.Data.OldParent == nil || event.CloudEvent.Data.NewParent == nil {
h.Logger.Error("No resource pool data found in cloud event")
prettyPrint(event)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": "CloudEvent missing resource pool data",
})
writeJSONError(w, http.StatusBadRequest, "CloudEvent missing resource pool data")
return
}
@@ -92,13 +81,8 @@ func (h *Handler) VmMoveEvent(w http.ResponseWriter, r *http.Request) {
iid, err2 := h.AddVmToInventory(event, ctx, unixTimestamp)
if err2 != nil {
h.Logger.Error("Received error adding VM to inventory", "error", err2)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Valid request but experienced error adding vm id '%s' in datacenter name '%s' to inventory table : %s",
event.CloudEvent.Data.VM.VM.Value, event.CloudEvent.Data.Datacenter.Name, err2),
})
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Valid request but experienced error adding vm id '%s' in datacenter name '%s' to inventory table : %s",
event.CloudEvent.Data.VM.VM.Value, event.CloudEvent.Data.Datacenter.Name, err2))
return
}
@@ -106,13 +90,8 @@ func (h *Handler) VmMoveEvent(w http.ResponseWriter, r *http.Request) {
params.InventoryId = sql.NullInt64{Int64: iid, Valid: iid > 0}
} else {
h.Logger.Error("Received zero for inventory id when adding VM to inventory")
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Valid request but received zero result when adding vm id '%s' in datacenter name '%s' to inventory table",
event.CloudEvent.Data.VM.VM.Value, event.CloudEvent.Data.Datacenter.Name),
})
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Valid request but received zero result when adding vm id '%s' in datacenter name '%s' to inventory table",
event.CloudEvent.Data.VM.VM.Value, event.CloudEvent.Data.Datacenter.Name))
return
}
}
@@ -142,22 +121,12 @@ func (h *Handler) VmMoveEvent(w http.ResponseWriter, r *http.Request) {
result, err := h.Database.Queries().CreateUpdate(ctx, params)
if err != nil {
h.Logger.Error("unable to perform database insert", "error", err)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"status": "ERROR",
"message": fmt.Sprintf("Unable to insert move event into database: '%s'", err),
})
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Unable to insert move event into database: '%s'", err))
return
} else {
h.Logger.Debug("created database record", "insert_result", result)
w.WriteHeader(http.StatusOK)
//fmt.Fprintf(w, "Processed update event: %v\n", result)
json.NewEncoder(w).Encode(map[string]string{
"status": "OK",
"message": "Successfully processed move event",
})
writeJSONOKMessage(w, "Successfully processed move event")
return
}
}

View File

@@ -3,7 +3,6 @@ package handler
import (
"context"
"database/sql"
"fmt"
"net/http"
"vctp/db/queries"
"vctp/internal/vcenter"
@@ -13,9 +12,9 @@ import (
// @Summary Refresh VM details
// @Description Queries vCenter and updates inventory records with missing details.
// @Tags inventory
// @Produce text/plain
// @Success 200 {string} string "Update completed"
// @Failure 500 {string} string "Server error"
// @Produce json
// @Success 200 {object} models.StatusMessageResponse "Update completed"
// @Failure 500 {object} models.ErrorResponse "Server error"
// @Router /api/inventory/vm/update [post]
func (h *Handler) VmUpdateDetails(w http.ResponseWriter, r *http.Request) {
var matchFound bool
@@ -42,8 +41,8 @@ func (h *Handler) VmUpdateDetails(w http.ResponseWriter, r *http.Request) {
results, err := h.Database.Queries().GetInventoryByVcenter(ctx, url)
if err != nil {
h.Logger.Error("Unable to query inventory table", "error", err)
w.WriteHeader(http.StatusInternalServerError)
fmt.Fprintf(w, "Unable to query inventory table %s\n", err)
writeJSONError(w, http.StatusInternalServerError, "Unable to query inventory table")
return
}
if len(results) == 0 {
@@ -115,7 +114,5 @@ func (h *Handler) VmUpdateDetails(w http.ResponseWriter, r *http.Request) {
}
h.Logger.Debug("Processed vm update successfully")
w.WriteHeader(http.StatusOK)
// TODO - return some JSON
fmt.Fprintf(w, "Processed vm update successfully")
writeJSONOKMessage(w, "Processed vm update successfully")
}