cleanups and code fixes incl templ
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
146
server/handler/method_guards_test.go
Normal file
146
server/handler/method_guards_test.go
Normal file
@@ -0,0 +1,146 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"vctp/server/models"
|
||||
)
|
||||
|
||||
func TestMutatingHandlersRejectWrongMethod(t *testing.T) {
|
||||
h := &Handler{Logger: newTestLogger()}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
path string
|
||||
call func(*Handler, *httptest.ResponseRecorder, *http.Request)
|
||||
}{
|
||||
{
|
||||
name: "snapshot force hourly",
|
||||
path: "/api/snapshots/hourly/force",
|
||||
call: func(h *Handler, rr *httptest.ResponseRecorder, req *http.Request) {
|
||||
h.SnapshotForceHourly(rr, req)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "snapshot aggregate",
|
||||
path: "/api/snapshots/aggregate",
|
||||
call: func(h *Handler, rr *httptest.ResponseRecorder, req *http.Request) {
|
||||
h.SnapshotAggregateForce(rr, req)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "snapshot migrate",
|
||||
path: "/api/snapshots/migrate",
|
||||
call: func(h *Handler, rr *httptest.ResponseRecorder, req *http.Request) {
|
||||
h.SnapshotMigrate(rr, req)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "snapshot regenerate hourly",
|
||||
path: "/api/snapshots/regenerate-hourly-reports",
|
||||
call: func(h *Handler, rr *httptest.ResponseRecorder, req *http.Request) {
|
||||
h.SnapshotRegenerateHourlyReports(rr, req)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vm create event",
|
||||
path: "/api/event/vm/create",
|
||||
call: func(h *Handler, rr *httptest.ResponseRecorder, req *http.Request) {
|
||||
h.VmCreateEvent(rr, req)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vm modify event",
|
||||
path: "/api/event/vm/modify",
|
||||
call: func(h *Handler, rr *httptest.ResponseRecorder, req *http.Request) {
|
||||
h.VmModifyEvent(rr, req)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vm move event",
|
||||
path: "/api/event/vm/move",
|
||||
call: func(h *Handler, rr *httptest.ResponseRecorder, req *http.Request) {
|
||||
h.VmMoveEvent(rr, req)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vm delete event",
|
||||
path: "/api/event/vm/delete",
|
||||
call: func(h *Handler, rr *httptest.ResponseRecorder, req *http.Request) {
|
||||
h.VmDeleteEvent(rr, req)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vm import",
|
||||
path: "/api/import/vm",
|
||||
call: func(h *Handler, rr *httptest.ResponseRecorder, req *http.Request) {
|
||||
h.VmImport(rr, req)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vm update details",
|
||||
path: "/api/inventory/vm/update",
|
||||
call: func(h *Handler, rr *httptest.ResponseRecorder, req *http.Request) {
|
||||
h.VmUpdateDetails(rr, req)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vm cleanup",
|
||||
path: "/api/inventory/vm/delete",
|
||||
call: func(h *Handler, rr *httptest.ResponseRecorder, req *http.Request) {
|
||||
h.VmCleanup(rr, req)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "vcenter cleanup",
|
||||
path: "/api/cleanup/vcenter",
|
||||
call: func(h *Handler, rr *httptest.ResponseRecorder, req *http.Request) {
|
||||
h.VcCleanup(rr, req)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "update cleanup",
|
||||
path: "/api/cleanup/updates",
|
||||
call: func(h *Handler, rr *httptest.ResponseRecorder, req *http.Request) {
|
||||
h.UpdateCleanup(rr, req)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
req := httptest.NewRequest(http.MethodGet, tc.path, strings.NewReader("{}"))
|
||||
rr := httptest.NewRecorder()
|
||||
tc.call(h, rr, req)
|
||||
if rr.Code != http.StatusMethodNotAllowed {
|
||||
t.Fatalf("expected %d, got %d", http.StatusMethodNotAllowed, rr.Code)
|
||||
}
|
||||
if !strings.Contains(rr.Body.String(), "method not allowed") {
|
||||
t.Fatalf("expected method not allowed response, got: %s", rr.Body.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVcenterLoginFailuresAreHandled(t *testing.T) {
|
||||
h := &Handler{Logger: newTestLogger()}
|
||||
event := models.CloudEventReceived{}
|
||||
event.CloudEvent.Source = "https://invalid.local/sdk"
|
||||
|
||||
disk := h.calculateNewDiskSize(context.Background(), event)
|
||||
if disk != 0 {
|
||||
t.Fatalf("expected disk size 0 on login failure, got %f", disk)
|
||||
}
|
||||
|
||||
id, err := h.AddVmToInventory(event, context.Background(), 0)
|
||||
if err == nil {
|
||||
t.Fatal("expected error on login failure")
|
||||
}
|
||||
if id != 0 {
|
||||
t.Fatalf("expected id 0 on login failure, got %d", id)
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,9 @@ package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
@@ -10,6 +13,7 @@ const (
|
||||
defaultRequestTimeout = 2 * time.Minute
|
||||
reportRequestTimeout = 10 * time.Minute
|
||||
longRunningRequestTimeout = 2 * time.Hour
|
||||
defaultJSONBodyLimitBytes = 1 << 20 // 1 MiB
|
||||
)
|
||||
|
||||
func withRequestTimeout(r *http.Request, timeout time.Duration) (context.Context, context.CancelFunc) {
|
||||
@@ -22,3 +26,21 @@ func withRequestTimeout(r *http.Request, timeout time.Duration) (context.Context
|
||||
}
|
||||
return context.WithTimeout(base, timeout)
|
||||
}
|
||||
|
||||
func decodeJSONBody(w http.ResponseWriter, r *http.Request, dst any) error {
|
||||
if r == nil || r.Body == nil {
|
||||
return errors.New("request body is required")
|
||||
}
|
||||
decoder := json.NewDecoder(http.MaxBytesReader(w, r.Body, defaultJSONBodyLimitBytes))
|
||||
if err := decoder.Decode(dst); err != nil {
|
||||
return err
|
||||
}
|
||||
var trailing any
|
||||
if err := decoder.Decode(&trailing); err != io.EOF {
|
||||
if err == nil {
|
||||
return errors.New("request body must contain only one JSON object")
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -21,6 +21,11 @@ import (
|
||||
// @Failure 500 {object} models.ErrorResponse "Server error"
|
||||
// @Router /api/snapshots/aggregate [post]
|
||||
func (h *Handler) SnapshotAggregateForce(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
snapshotType := strings.ToLower(strings.TrimSpace(r.URL.Query().Get("type")))
|
||||
dateValue := strings.TrimSpace(r.URL.Query().Get("date"))
|
||||
granularity := strings.ToLower(strings.TrimSpace(r.URL.Query().Get("granularity")))
|
||||
|
||||
@@ -19,6 +19,11 @@ import (
|
||||
// @Failure 500 {object} models.ErrorResponse "Server error"
|
||||
// @Router /api/snapshots/hourly/force [post]
|
||||
func (h *Handler) SnapshotForceHourly(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
confirm := strings.TrimSpace(r.URL.Query().Get("confirm"))
|
||||
if strings.ToUpper(confirm) != "FORCE" {
|
||||
writeJSONError(w, http.StatusBadRequest, "confirm must be 'FORCE'")
|
||||
|
||||
@@ -15,6 +15,11 @@ import (
|
||||
// @Failure 500 {object} models.SnapshotMigrationResponse "Server error"
|
||||
// @Router /api/snapshots/migrate [post]
|
||||
func (h *Handler) SnapshotMigrate(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
ctx, cancel := withRequestTimeout(r, reportRequestTimeout)
|
||||
defer cancel()
|
||||
stats, err := report.MigrateSnapshotRegistry(ctx, h.Database)
|
||||
|
||||
@@ -19,6 +19,11 @@ import (
|
||||
// @Failure 500 {object} models.ErrorResponse "Server error"
|
||||
// @Router /api/snapshots/regenerate-hourly-reports [post]
|
||||
func (h *Handler) SnapshotRegenerateHourlyReports(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
ctx := r.Context()
|
||||
reportsDir := strings.TrimSpace(h.Settings.Values.Settings.ReportsDir)
|
||||
if reportsDir == "" {
|
||||
|
||||
@@ -15,6 +15,11 @@ import (
|
||||
// @Failure 500 {string} string "Server error"
|
||||
// @Router /api/cleanup/updates [delete]
|
||||
func (h *Handler) UpdateCleanup(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodDelete {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
if h.denyLegacyAPI(w, "/api/cleanup/updates") {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -18,6 +18,11 @@ import (
|
||||
// @Failure 400 {object} models.ErrorResponse "Invalid request"
|
||||
// @Router /api/cleanup/vcenter [delete]
|
||||
func (h *Handler) VcCleanup(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodDelete {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
if h.denyLegacyAPI(w, "/api/cleanup/vcenter") {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -20,6 +20,11 @@ import (
|
||||
// @Failure 400 {object} models.ErrorResponse "Invalid request"
|
||||
// @Router /api/inventory/vm/delete [delete]
|
||||
func (h *Handler) VmCleanup(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodDelete {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
if h.denyLegacyAPI(w, "/api/inventory/vm/delete") {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strconv"
|
||||
@@ -26,6 +25,11 @@ import (
|
||||
// @Failure 500 {object} models.ErrorResponse "Server error"
|
||||
// @Router /api/event/vm/create [post]
|
||||
func (h *Handler) VmCreateEvent(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
if h.denyLegacyAPI(w, "/api/event/vm/create") {
|
||||
return
|
||||
}
|
||||
@@ -39,18 +43,8 @@ func (h *Handler) VmCreateEvent(w http.ResponseWriter, r *http.Request) {
|
||||
//datacenter string
|
||||
)
|
||||
|
||||
reqBody, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
h.Logger.Error("Invalid data received", "error", err)
|
||||
writeJSONError(w, http.StatusInternalServerError, "Invalid data received")
|
||||
return
|
||||
} else {
|
||||
h.Logger.Debug("received input data", "length", len(reqBody))
|
||||
}
|
||||
|
||||
// Decode the JSON body into CloudEventReceived struct
|
||||
var event models.CloudEventReceived
|
||||
if err := json.Unmarshal(reqBody, &event); err != nil {
|
||||
if err := decodeJSONBody(w, r, &event); err != nil {
|
||||
h.Logger.Error("unable to decode json", "error", err)
|
||||
writeJSONError(w, http.StatusBadRequest, "Invalid JSON body")
|
||||
return
|
||||
|
||||
@@ -2,9 +2,7 @@ package handler
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
"vctp/db/queries"
|
||||
@@ -24,6 +22,11 @@ import (
|
||||
// @Failure 500 {object} models.ErrorResponse "Server error"
|
||||
// @Router /api/event/vm/delete [post]
|
||||
func (h *Handler) VmDeleteEvent(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
if h.denyLegacyAPI(w, "/api/event/vm/delete") {
|
||||
return
|
||||
}
|
||||
@@ -34,18 +37,8 @@ func (h *Handler) VmDeleteEvent(w http.ResponseWriter, r *http.Request) {
|
||||
deletedTimestamp int64
|
||||
)
|
||||
|
||||
reqBody, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
h.Logger.Error("Invalid data received", "error", err)
|
||||
writeJSONError(w, http.StatusInternalServerError, "Invalid data received")
|
||||
return
|
||||
} else {
|
||||
//h.Logger.Debug("received input data", "length", len(reqBody))
|
||||
}
|
||||
|
||||
// Decode the JSON body into CloudEventReceived struct
|
||||
var event models.CloudEventReceived
|
||||
if err := json.Unmarshal(reqBody, &event); err != nil {
|
||||
if err := decodeJSONBody(w, r, &event); err != nil {
|
||||
h.Logger.Error("unable to decode json", "error", err)
|
||||
prettyPrint(event)
|
||||
writeJSONError(w, http.StatusBadRequest, "Invalid JSON body")
|
||||
|
||||
@@ -2,10 +2,8 @@ package handler
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"vctp/db"
|
||||
@@ -25,26 +23,19 @@ import (
|
||||
// @Failure 500 {object} models.ErrorResponse "Server error"
|
||||
// @Router /api/import/vm [post]
|
||||
func (h *Handler) VmImport(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
if h.denyLegacyAPI(w, "/api/import/vm") {
|
||||
return
|
||||
}
|
||||
|
||||
// Read request body
|
||||
reqBody, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
h.Logger.Error("Invalid data received", "length", len(reqBody), "error", err)
|
||||
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Invalid data received: '%s'", err))
|
||||
return
|
||||
|
||||
} else {
|
||||
h.Logger.Debug("received input data", "length", len(reqBody))
|
||||
}
|
||||
|
||||
// Decode the JSON body into CloudEventReceived struct
|
||||
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)
|
||||
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Unable to decode json request body: '%s'", err))
|
||||
if err := decodeJSONBody(w, r, &inData); err != nil {
|
||||
h.Logger.Error("Unable to decode json request body", "error", err)
|
||||
writeJSONError(w, http.StatusBadRequest, fmt.Sprintf("Unable to decode json request body: '%s'", err))
|
||||
return
|
||||
} else {
|
||||
//h.Logger.Debug("successfully decoded JSON")
|
||||
@@ -66,7 +57,7 @@ func (h *Handler) VmImport(w http.ResponseWriter, r *http.Request) {
|
||||
VmId: sql.NullString{String: inData.VmId, Valid: inData.VmId != ""},
|
||||
DatacenterName: sql.NullString{String: inData.Datacenter, Valid: inData.Datacenter != ""},
|
||||
}
|
||||
_, err = h.Database.Queries().GetInventoryVmId(ctx, invParams)
|
||||
_, err := h.Database.Queries().GetInventoryVmId(ctx, invParams)
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strconv"
|
||||
@@ -32,6 +31,11 @@ import (
|
||||
// @Failure 500 {object} models.ErrorResponse "Server error"
|
||||
// @Router /api/event/vm/modify [post]
|
||||
func (h *Handler) VmModifyEvent(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
if h.denyLegacyAPI(w, "/api/event/vm/modify") {
|
||||
return
|
||||
}
|
||||
@@ -44,18 +48,10 @@ func (h *Handler) VmModifyEvent(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := withRequestTimeout(r, defaultRequestTimeout)
|
||||
defer cancel()
|
||||
|
||||
reqBody, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
h.Logger.Error("Invalid data received", "length", len(reqBody), "error", err)
|
||||
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Invalid data received: '%s'", err))
|
||||
return
|
||||
}
|
||||
|
||||
// Decode the JSON body into CloudEventReceived struct
|
||||
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)
|
||||
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Unable to decode json request body: '%s'", err))
|
||||
if err := decodeJSONBody(w, r, &event); err != nil {
|
||||
h.Logger.Error("Unable to decode json request body", "error", err)
|
||||
writeJSONError(w, http.StatusBadRequest, fmt.Sprintf("Unable to decode json request body: '%s'", err))
|
||||
return
|
||||
} else {
|
||||
//h.Logger.Debug("successfully decoded JSON")
|
||||
@@ -339,7 +335,15 @@ func (h *Handler) calculateNewDiskSize(ctx context.Context, event models.CloudEv
|
||||
var totalDiskBytes int64
|
||||
h.Logger.Debug("connecting to vcenter")
|
||||
vc := vcenter.New(h.Logger, h.VcCreds)
|
||||
vc.Login(event.CloudEvent.Source)
|
||||
if err := vc.Login(event.CloudEvent.Source); err != nil {
|
||||
h.Logger.Error("unable to connect to vcenter while calculating disk size", "source", event.CloudEvent.Source, "error", err)
|
||||
return 0
|
||||
}
|
||||
defer func() {
|
||||
logoutCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 5*time.Second)
|
||||
defer cancel()
|
||||
_ = vc.Logout(logoutCtx)
|
||||
}()
|
||||
|
||||
vmObject, err := vc.FindVMByIDWithDatacenter(event.CloudEvent.Data.VM.VM.Value, event.CloudEvent.Data.Datacenter.Datacenter.Value)
|
||||
|
||||
@@ -369,10 +373,6 @@ func (h *Handler) calculateNewDiskSize(ctx context.Context, event models.CloudEv
|
||||
}
|
||||
}
|
||||
|
||||
logoutCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 5*time.Second)
|
||||
defer cancel()
|
||||
_ = vc.Logout(logoutCtx)
|
||||
|
||||
h.Logger.Debug("Calculated new disk size", "value", diskSize)
|
||||
|
||||
return diskSize
|
||||
@@ -394,7 +394,15 @@ func (h *Handler) AddVmToInventory(evt models.CloudEventReceived, ctx context.Co
|
||||
)
|
||||
//c.Logger.Debug("connecting to vcenter")
|
||||
vc := vcenter.New(h.Logger, h.VcCreds)
|
||||
vc.Login(evt.CloudEvent.Source)
|
||||
if err := vc.Login(evt.CloudEvent.Source); err != nil {
|
||||
h.Logger.Error("unable to connect to vcenter", "source", evt.CloudEvent.Source, "error", err)
|
||||
return 0, err
|
||||
}
|
||||
defer func() {
|
||||
logoutCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 5*time.Second)
|
||||
defer cancel()
|
||||
_ = vc.Logout(logoutCtx)
|
||||
}()
|
||||
|
||||
//datacenter = evt.DatacenterName.String
|
||||
vmObject, err := vc.FindVMByIDWithDatacenter(evt.CloudEvent.Data.VM.VM.Value, evt.CloudEvent.Data.Datacenter.Datacenter.Value)
|
||||
@@ -410,7 +418,6 @@ func (h *Handler) AddVmToInventory(evt models.CloudEventReceived, ctx context.Co
|
||||
|
||||
if strings.HasPrefix(vmObject.Name, "vCLS-") {
|
||||
h.Logger.Info("Skipping internal vCLS VM", "vm_name", vmObject.Name)
|
||||
_ = vc.Logout(ctx)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
@@ -484,8 +491,6 @@ func (h *Handler) AddVmToInventory(evt models.CloudEventReceived, ctx context.Co
|
||||
poweredOn = "TRUE"
|
||||
}
|
||||
|
||||
_ = vc.Logout(ctx)
|
||||
|
||||
if foundVm {
|
||||
e := evt.CloudEvent
|
||||
h.Logger.Debug("Adding to Inventory table", "vm_name", e.Data.VM.Name, "vcpus", numVcpus, "ram", numRam, "dc", e.Data.Datacenter.Datacenter.Value)
|
||||
|
||||
@@ -2,10 +2,8 @@ package handler
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -26,6 +24,11 @@ import (
|
||||
// @Failure 500 {object} models.ErrorResponse "Server error"
|
||||
// @Router /api/event/vm/move [post]
|
||||
func (h *Handler) VmMoveEvent(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
if h.denyLegacyAPI(w, "/api/event/vm/move") {
|
||||
return
|
||||
}
|
||||
@@ -36,21 +39,10 @@ func (h *Handler) VmMoveEvent(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, cancel := withRequestTimeout(r, defaultRequestTimeout)
|
||||
defer cancel()
|
||||
|
||||
reqBody, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
h.Logger.Error("Invalid data received", "error", err)
|
||||
writeJSONError(w, http.StatusInternalServerError, "Invalid data received")
|
||||
return
|
||||
} else {
|
||||
//h.Logger.Debug("received input data", "length", len(reqBody))
|
||||
}
|
||||
|
||||
// Decode the JSON body into CloudEventReceived struct
|
||||
var event models.CloudEventReceived
|
||||
if err := json.Unmarshal(reqBody, &event); err != nil {
|
||||
if err := decodeJSONBody(w, r, &event); err != nil {
|
||||
h.Logger.Error("unable to unmarshal json", "error", err)
|
||||
prettyPrint(reqBody)
|
||||
writeJSONError(w, http.StatusInternalServerError, fmt.Sprintf("Unable to unmarshal JSON in request body: '%s'", err))
|
||||
writeJSONError(w, http.StatusBadRequest, fmt.Sprintf("Unable to unmarshal JSON in request body: '%s'", err))
|
||||
return
|
||||
} else {
|
||||
h.Logger.Debug("successfully decoded JSON")
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"net/http"
|
||||
"time"
|
||||
"vctp/db/queries"
|
||||
"vctp/internal/vcenter"
|
||||
)
|
||||
@@ -17,6 +19,11 @@ import (
|
||||
// @Failure 500 {object} models.ErrorResponse "Server error"
|
||||
// @Router /api/inventory/vm/update [post]
|
||||
func (h *Handler) VmUpdateDetails(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
writeJSONError(w, http.StatusMethodNotAllowed, "method not allowed")
|
||||
return
|
||||
}
|
||||
|
||||
if h.denyLegacyAPI(w, "/api/inventory/vm/update") {
|
||||
return
|
||||
}
|
||||
@@ -31,20 +38,42 @@ func (h *Handler) VmUpdateDetails(w http.ResponseWriter, r *http.Request) {
|
||||
defer cancel()
|
||||
|
||||
// reload settings in case vcenter list has changed
|
||||
h.Settings.ReadYMLSettings()
|
||||
if err := h.Settings.ReadYMLSettings(); err != nil {
|
||||
h.Logger.Error("unable to reload settings", "error", err)
|
||||
writeJSONError(w, http.StatusInternalServerError, "Unable to reload settings")
|
||||
return
|
||||
}
|
||||
|
||||
for _, url := range h.Settings.Values.Settings.VcenterAddresses {
|
||||
h.Logger.Debug("connecting to vcenter", "url", url)
|
||||
vc := vcenter.New(h.Logger, h.VcCreds)
|
||||
vc.Login(url)
|
||||
if err := vc.Login(url); err != nil {
|
||||
h.Logger.Error("unable to connect to vcenter", "url", url, "error", err)
|
||||
writeJSONError(w, http.StatusInternalServerError, "Unable to connect to vcenter")
|
||||
return
|
||||
}
|
||||
logout := func() {
|
||||
logoutCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 5*time.Second)
|
||||
defer cancel()
|
||||
if err := vc.Logout(logoutCtx); err != nil {
|
||||
h.Logger.Warn("vcenter logout failed", "url", url, "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Get list of VMs from vcenter
|
||||
vms, err := vc.GetAllVmReferences()
|
||||
if err != nil {
|
||||
logout()
|
||||
h.Logger.Error("Unable to query vcenter VM references", "url", url, "error", err)
|
||||
writeJSONError(w, http.StatusInternalServerError, "Unable to query vcenter VM references")
|
||||
return
|
||||
}
|
||||
|
||||
// Get list of VMs from inventory table
|
||||
h.Logger.Debug("Querying inventory table")
|
||||
results, err := h.Database.Queries().GetInventoryByVcenter(ctx, url)
|
||||
if err != nil {
|
||||
logout()
|
||||
h.Logger.Error("Unable to query inventory table", "error", err)
|
||||
writeJSONError(w, http.StatusInternalServerError, "Unable to query inventory table")
|
||||
return
|
||||
@@ -116,6 +145,7 @@ func (h *Handler) VmUpdateDetails(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
}
|
||||
logout()
|
||||
}
|
||||
|
||||
h.Logger.Debug("Processed vm update successfully")
|
||||
|
||||
Reference in New Issue
Block a user