initial
This commit is contained in:
61
server/handler/encryptData.go
Normal file
61
server/handler/encryptData.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (h *Handler) EncryptData(w http.ResponseWriter, r *http.Request) {
|
||||
//ctx := context.Background()
|
||||
var cipherText string
|
||||
|
||||
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)
|
||||
return
|
||||
} else {
|
||||
h.Logger.Debug("received input data", "length", len(reqBody))
|
||||
}
|
||||
|
||||
// get the json input
|
||||
var input map[string]string
|
||||
if err := json.Unmarshal(reqBody, &input); 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),
|
||||
})
|
||||
return
|
||||
} else {
|
||||
h.Logger.Debug("successfully decoded JSON")
|
||||
//prettyPrint(input)
|
||||
}
|
||||
|
||||
//cipher, err := h.Secret.Encrypt()
|
||||
for k := range input {
|
||||
//h.Logger.Debug("foo", "key", k, "value", input[k])
|
||||
cipherText, err = h.Secret.Encrypt([]byte(input[k]))
|
||||
if err != nil {
|
||||
h.Logger.Error("Unable to encrypt", "error", err)
|
||||
} else {
|
||||
h.Logger.Debug("Encrypted plaintext", "length", len(input[k]), "ciphertext", cipherText)
|
||||
w.WriteHeader(http.StatusOK)
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "OK",
|
||||
"message": cipherText,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// return the result
|
||||
|
||||
}
|
33
server/handler/handler.go
Normal file
33
server/handler/handler.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"wnzl-snow/db"
|
||||
"wnzl-snow/internal/secrets"
|
||||
"wnzl-snow/internal/settings"
|
||||
|
||||
"github.com/a-h/templ"
|
||||
)
|
||||
|
||||
// Handler handles requests.
|
||||
type Handler struct {
|
||||
Logger *slog.Logger
|
||||
Database db.Database
|
||||
BuildTime string
|
||||
SHA1Ver string
|
||||
GoVersion string
|
||||
//VcCreds *vcenter.VcenterLogin
|
||||
Secret *secrets.Secrets
|
||||
Settings *settings.Settings
|
||||
}
|
||||
|
||||
func (h *Handler) html(ctx context.Context, w http.ResponseWriter, status int, t templ.Component) {
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
w.WriteHeader(status)
|
||||
|
||||
if err := t.Render(ctx, w); err != nil {
|
||||
h.Logger.Error("Failed to render component", "error", err)
|
||||
}
|
||||
}
|
62
server/handler/home.go
Normal file
62
server/handler/home.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"time"
|
||||
"wnzl-snow/components/views"
|
||||
)
|
||||
|
||||
// Home handles the home page.
|
||||
func (h *Handler) Home(w http.ResponseWriter, r *http.Request) {
|
||||
//h.html(r.Context(), w, http.StatusOK, core.HTML("Example Site", home.Home()))
|
||||
|
||||
// Render the template
|
||||
/*
|
||||
err := home.Home(h.BuildTime, h.SHA1Ver, h.GoVersion).Render(r.Context(), w)
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to render template", http.StatusInternalServerError)
|
||||
}
|
||||
*/
|
||||
|
||||
info := views.BuildInfo{
|
||||
BuildTime: h.BuildTime,
|
||||
SHA1Ver: h.SHA1Ver,
|
||||
GoVersion: h.GoVersion,
|
||||
}
|
||||
|
||||
err := views.Index(info).Render(r.Context(), w)
|
||||
if err != nil {
|
||||
http.Error(w, "Failed to render template", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
// prettyPrint comes from https://gist.github.com/sfate/9d45f6c5405dc4c9bf63bf95fe6d1a7c
|
||||
func prettyPrint(args ...interface{}) {
|
||||
var caller string
|
||||
|
||||
timeNow := time.Now().Format("01-02-2006 15:04:05")
|
||||
prefix := fmt.Sprintf("[%s] %s -- ", "PrettyPrint", timeNow)
|
||||
_, fileName, fileLine, ok := runtime.Caller(1)
|
||||
|
||||
if ok {
|
||||
caller = fmt.Sprintf("%s:%d", fileName, fileLine)
|
||||
} else {
|
||||
caller = ""
|
||||
}
|
||||
|
||||
fmt.Printf("\n%s%s\n", prefix, caller)
|
||||
|
||||
if len(args) == 2 {
|
||||
label := args[0]
|
||||
value := args[1]
|
||||
|
||||
s, _ := json.MarshalIndent(value, "", "\t")
|
||||
fmt.Printf("%s%s: %s\n", prefix, label, string(s))
|
||||
} else {
|
||||
s, _ := json.MarshalIndent(args, "", "\t")
|
||||
fmt.Printf("%s%s\n", prefix, string(s))
|
||||
}
|
||||
}
|
22
server/handler/newSnow.go
Normal file
22
server/handler/newSnow.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// NewSnow receives data from the DMSP Snow New() function
|
||||
func (h *Handler) NewSnow(w http.ResponseWriter, r *http.Request) {
|
||||
var ()
|
||||
|
||||
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)
|
||||
return
|
||||
} else {
|
||||
h.Logger.Debug("received input data", "length", len(reqBody))
|
||||
}
|
||||
}
|
61
server/handler/reportDownload.go
Normal file
61
server/handler/reportDownload.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"wnzl-snow/internal/report"
|
||||
)
|
||||
|
||||
func (h *Handler) InventoryReportDownload(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Generate the XLSX report
|
||||
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),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Set HTTP headers to indicate file download
|
||||
w.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="inventory_report.xlsx"`)
|
||||
w.Header().Set("File-Name", "inventory_report.xlsx")
|
||||
|
||||
// Write the XLSX file to the HTTP response
|
||||
w.Write(reportData)
|
||||
}
|
||||
|
||||
func (h *Handler) UpdateReportDownload(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Generate the XLSX report
|
||||
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),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Set HTTP headers to indicate file download
|
||||
w.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
||||
w.Header().Set("Content-Disposition", `attachment; filename="updates_report.xlsx"`)
|
||||
w.Header().Set("File-Name", "updates_report.xlsx")
|
||||
|
||||
// Write the XLSX file to the HTTP response
|
||||
w.Write(reportData)
|
||||
}
|
42
server/handler/updateCleanup.go
Normal file
42
server/handler/updateCleanup.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// VmUpdate receives the CloudEvent for a VM modification or move
|
||||
func (h *Handler) UpdateCleanup(w http.ResponseWriter, r *http.Request) {
|
||||
/*
|
||||
// Get the current time
|
||||
now := time.Now()
|
||||
// Get the start of the current day (midnight today)
|
||||
midnightToday := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||
// Convert to Unix time
|
||||
unixTime := midnightToday.Unix()
|
||||
|
||||
// create the database parameters
|
||||
params := queries.CleanupUpdatesParams{
|
||||
UpdateType: "diskchange",
|
||||
UpdateTime: sql.NullInt64{Int64: unixTime, Valid: unixTime > 0},
|
||||
}
|
||||
|
||||
h.Logger.Debug("database params", "params", params)
|
||||
err := h.Database.Queries().CleanupUpdates(context.Background(), params)
|
||||
*/
|
||||
|
||||
//err := h.Database.Queries().InventoryCleanupTemplates(context.Background())
|
||||
err := h.Database.Queries().CleanupUpdatesNullVm(context.Background())
|
||||
|
||||
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)
|
||||
} else {
|
||||
h.Logger.Debug("Processed update cleanup successfully")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
// TODO - return some JSON
|
||||
fmt.Fprintf(w, "Processed update cleanup successfully")
|
||||
}
|
||||
}
|
18
server/middleware/cache.go
Normal file
18
server/middleware/cache.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"wnzl-snow/version"
|
||||
)
|
||||
|
||||
// CacheMiddleware sets the Cache-Control header based on the version.
|
||||
func CacheMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if version.Value == "dev" {
|
||||
w.Header().Set("Cache-Control", "no-cache")
|
||||
} else {
|
||||
w.Header().Set("Cache-Control", "public, max-age=31536000")
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
35
server/middleware/logging.go
Normal file
35
server/middleware/logging.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// LoggingMiddleware represents a logging middleware.
|
||||
type LoggingMiddleware struct {
|
||||
logger *slog.Logger
|
||||
handler http.Handler
|
||||
}
|
||||
|
||||
// NewLoggingMiddleware creates a new logging middleware with the given logger and handler.
|
||||
func NewLoggingMiddleware(logger *slog.Logger, handler http.Handler) *LoggingMiddleware {
|
||||
return &LoggingMiddleware{
|
||||
logger: logger,
|
||||
handler: handler,
|
||||
}
|
||||
}
|
||||
|
||||
// ServeHTTP logs the request and calls the next handler.
|
||||
func (l *LoggingMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
l.handler.ServeHTTP(w, r)
|
||||
|
||||
l.logger.Debug(
|
||||
"Request recieved",
|
||||
slog.String("method", r.Method),
|
||||
slog.String("path", r.URL.Path),
|
||||
slog.String("remote", r.RemoteAddr),
|
||||
slog.Duration("duration", time.Since(start)),
|
||||
)
|
||||
}
|
22
server/middleware/middleware.go
Normal file
22
server/middleware/middleware.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package middleware
|
||||
|
||||
import "net/http"
|
||||
|
||||
type Handler func(http.Handler) http.Handler
|
||||
|
||||
func Chain(handlers ...Handler) Handler {
|
||||
if len(handlers) == 0 {
|
||||
return defaultHandler
|
||||
}
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
for i := len(handlers) - 1; i >= 0; i-- {
|
||||
next = handlers[i](next)
|
||||
}
|
||||
return next
|
||||
}
|
||||
}
|
||||
|
||||
func defaultHandler(next http.Handler) http.Handler {
|
||||
return next
|
||||
}
|
292
server/models/models.go
Normal file
292
server/models/models.go
Normal file
@@ -0,0 +1,292 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type IncidentResponse struct {
|
||||
ImportSet string `json:"import_set"`
|
||||
StagingTable string `json:"staging_table"`
|
||||
Result []struct {
|
||||
TransformMap string `json:"transform_map"`
|
||||
Table string `json:"table"`
|
||||
DisplayName string `json:"display_name"`
|
||||
DisplayValue string `json:"display_value"`
|
||||
RecordLink string `json:"record_link"`
|
||||
Status string `json:"status"`
|
||||
SysID string `json:"sys_id"`
|
||||
}
|
||||
}
|
||||
|
||||
type Incident struct {
|
||||
IncidentNumber string `json:"incident_number,omitempty"` // The incident number in ServiceNow. If blank, creates a new incident, if populated with a valid value it updates that record.
|
||||
Description string `json:"description,omitempty"`
|
||||
ShortDescription string `json:"short_description,omitempty"`
|
||||
// 1 = Critical , 2 = High, 3 = Medium, 4 = Low
|
||||
Urgency string `json:"urgency,omitempty"` // integer value, 1-4
|
||||
// 1 = Critical , 2 = High, 3 = Medium, 4 = Low
|
||||
Impact string `json:"impact,omitempty"` // integer value, 1-4
|
||||
// State: 1 = New ; 2 = In Progress ; 3 = On Hold ; 6 = Resolved ; 7 = Closed ; 8 = Cancelled
|
||||
State string `json:"state,omitempty"` // integer value, 1-6 (6 is resolved)
|
||||
// Associated DeviceID (UUID from CPDB)
|
||||
ExternalID string `json:"external_id,omitempty"` // CPDB UUID for the configuration item
|
||||
WorkNotes string `json:"work_notes,omitempty"` // Additional notes
|
||||
AssignmentGroup string `json:"assignment_group,omitempty"`
|
||||
AssignedTo string `json:"assigned_to,omitempty"`
|
||||
// Cat/SubCategory to populate the Incident appropriately
|
||||
Category string `json:"category,omitempty"`
|
||||
SubCategory string `json:"subcategory,omitempty"`
|
||||
}
|
||||
|
||||
type CloudEventReceived struct {
|
||||
CloudEvent struct {
|
||||
ID string `json:"id"`
|
||||
Specversion string `json:"specversion"`
|
||||
Source string `json:"source"`
|
||||
Type string `json:"type"`
|
||||
Time string `json:"time"` // Modified from time.Time
|
||||
Data struct {
|
||||
ChainID int `json:"ChainId"`
|
||||
ChangeTag string `json:"ChangeTag"`
|
||||
ComputeResource struct {
|
||||
ComputeResource struct {
|
||||
Type string `json:"Type"`
|
||||
Value string `json:"Value"`
|
||||
} `json:"ComputeResource"`
|
||||
Name string `json:"Name"`
|
||||
} `json:"ComputeResource"`
|
||||
CreatedTime string `json:"CreatedTime"` // Modified from time.Time
|
||||
Datacenter struct {
|
||||
Datacenter struct {
|
||||
Type string `json:"Type"`
|
||||
Value string `json:"Value"`
|
||||
} `json:"Datacenter"`
|
||||
Name string `json:"Name"`
|
||||
} `json:"Datacenter"`
|
||||
Ds interface{} `json:"Ds"`
|
||||
Dvs interface{} `json:"Dvs"`
|
||||
FullFormattedMessage string `json:"FullFormattedMessage"`
|
||||
Host struct {
|
||||
Host struct {
|
||||
Type string `json:"Type"`
|
||||
Value string `json:"Value"`
|
||||
} `json:"Host"`
|
||||
Name string `json:"Name"`
|
||||
} `json:"Host"`
|
||||
Key int `json:"Key"`
|
||||
Net interface{} `json:"Net"`
|
||||
NewParent *CloudEventResourcePool `json:"NewParent"`
|
||||
OldParent *CloudEventResourcePool `json:"OldParent"`
|
||||
SrcTemplate *CloudEventVm `json:"SrcTemplate"`
|
||||
Template bool `json:"Template"`
|
||||
UserName string `json:"UserName"`
|
||||
VM struct {
|
||||
Name string `json:"Name"`
|
||||
VM struct {
|
||||
Type string `json:"Type"`
|
||||
Value string `json:"Value"`
|
||||
} `json:"Vm"`
|
||||
} `json:"Vm"`
|
||||
ConfigSpec *json.RawMessage `json:"configSpec"`
|
||||
ConfigChanges *ConfigChangesReceived `json:"configChanges"` // Modified to separate struct
|
||||
} `json:"data"`
|
||||
} `json:"cloudEvent"`
|
||||
}
|
||||
|
||||
type CloudEventResourcePool struct {
|
||||
Name string `json:"Name"`
|
||||
ResourcePool struct {
|
||||
Type string `json:"Type"`
|
||||
Value string `json:"Value"`
|
||||
} `json:"ResourcePool"`
|
||||
}
|
||||
|
||||
type CloudEventVm struct {
|
||||
Name string `json:"Name"`
|
||||
VM struct {
|
||||
Type string `json:"Type"`
|
||||
Value string `json:"Value"`
|
||||
} `json:"Vm"`
|
||||
}
|
||||
|
||||
type ImportReceived struct {
|
||||
Name string `json:"Name"`
|
||||
Vcenter string `json:"Vcenter"`
|
||||
VmId string `json:"VmId"`
|
||||
InitialRam int `json:"InitialRam"`
|
||||
PowerState int `json:"PowerState"`
|
||||
CreationTime int `json:"CreationTime"`
|
||||
InitialVcpus int `json:"InitialVcpus"`
|
||||
ProvisionedDisk float64 `json:"ProvisionedDisk"`
|
||||
Folder string `json:"Folder"`
|
||||
ResourcePool string `json:"ResourcePool"`
|
||||
Datacenter string `json:"Datacenter"`
|
||||
Cluster string `json:"Cluster"`
|
||||
}
|
||||
|
||||
type ConfigChangesReceived struct {
|
||||
Modified string `json:"modified"`
|
||||
}
|
||||
|
||||
// This probably needs more fields added so not in use yet
|
||||
type ConfigSpec struct {
|
||||
AlternateGuestName string `json:"AlternateGuestName"`
|
||||
Annotation string `json:"Annotation"`
|
||||
BootOptions any `json:"BootOptions"`
|
||||
ChangeTrackingEnabled any `json:"ChangeTrackingEnabled"`
|
||||
ChangeVersion string `json:"ChangeVersion"`
|
||||
ConsolePreferences any `json:"ConsolePreferences"`
|
||||
CPUAffinity any `json:"CpuAffinity"`
|
||||
CPUAllocation any `json:"CpuAllocation"`
|
||||
CPUFeatureMask any `json:"CpuFeatureMask"`
|
||||
CPUHotAddEnabled any `json:"CpuHotAddEnabled"`
|
||||
CPUHotRemoveEnabled any `json:"CpuHotRemoveEnabled"`
|
||||
CreateDate string `json:"CreateDate"` // Modified from time.Time
|
||||
Crypto any `json:"Crypto"`
|
||||
DeviceChange []struct {
|
||||
Backing any `json:"Backing"`
|
||||
Device struct {
|
||||
Backing *BackingSpec `json:"Backing,omitempty"`
|
||||
CapacityInBytes int `json:"CapacityInBytes"`
|
||||
CapacityInKB int `json:"CapacityInKB"`
|
||||
Connectable struct {
|
||||
AllowGuestControl bool `json:"AllowGuestControl"`
|
||||
Connected bool `json:"Connected"`
|
||||
MigrateConnect string `json:"MigrateConnect"`
|
||||
StartConnected bool `json:"StartConnected"`
|
||||
Status string `json:"Status"`
|
||||
} `json:"Connectable"`
|
||||
ControllerKey int `json:"ControllerKey"`
|
||||
DeviceInfo struct {
|
||||
Label string `json:"Label"`
|
||||
Summary string `json:"Summary"`
|
||||
} `json:"DeviceInfo"`
|
||||
ExternalID string `json:"ExternalId"`
|
||||
MacAddress string `json:"MacAddress"`
|
||||
ResourceAllocation struct {
|
||||
Limit int `json:"Limit"`
|
||||
Reservation int `json:"Reservation"`
|
||||
Share struct {
|
||||
Level string `json:"Level"`
|
||||
Shares int `json:"Shares"`
|
||||
} `json:"Share"`
|
||||
} `json:"ResourceAllocation"`
|
||||
SlotInfo any `json:"SlotInfo"`
|
||||
UnitNumber int `json:"UnitNumber"`
|
||||
UptCompatibilityEnabled bool `json:"UptCompatibilityEnabled"`
|
||||
WakeOnLanEnabled bool `json:"WakeOnLanEnabled"`
|
||||
DiskObjectID string `json:"DiskObjectId"`
|
||||
Iofilter any `json:"Iofilter"`
|
||||
Key int `json:"Key"`
|
||||
NativeUnmanagedLinkedClone any `json:"NativeUnmanagedLinkedClone"`
|
||||
Shares any `json:"Shares"`
|
||||
StorageIOAllocation struct {
|
||||
Limit int `json:"Limit"`
|
||||
Reservation any `json:"Reservation"`
|
||||
Shares struct {
|
||||
Level string `json:"Level"`
|
||||
Shares int `json:"Shares"`
|
||||
} `json:"Shares"`
|
||||
} `json:"StorageIOAllocation"`
|
||||
VDiskID any `json:"VDiskId"`
|
||||
VFlashCacheConfigInfo any `json:"VFlashCacheConfigInfo"`
|
||||
} `json:"Device,omitempty"`
|
||||
FileOperation string `json:"FileOperation"`
|
||||
Operation string `json:"Operation"`
|
||||
Profile []struct {
|
||||
ProfileData struct {
|
||||
ExtensionKey string `json:"ExtensionKey"`
|
||||
ObjectData string `json:"ObjectData"` // Modified from time.Time
|
||||
} `json:"ProfileData"`
|
||||
ProfileID string `json:"ProfileId"`
|
||||
ProfileParams any `json:"ProfileParams"`
|
||||
ReplicationSpec any `json:"ReplicationSpec"`
|
||||
} `json:"Profile"`
|
||||
} `json:"DeviceChange"`
|
||||
ExtraConfig any `json:"ExtraConfig"`
|
||||
Files struct {
|
||||
FtMetadataDirectory string `json:"FtMetadataDirectory"`
|
||||
LogDirectory string `json:"LogDirectory"`
|
||||
SnapshotDirectory string `json:"SnapshotDirectory"`
|
||||
SuspendDirectory string `json:"SuspendDirectory"`
|
||||
VMPathName string `json:"VmPathName"`
|
||||
} `json:"Files"`
|
||||
Firmware string `json:"Firmware"`
|
||||
Flags any `json:"Flags"`
|
||||
FtInfo any `json:"FtInfo"`
|
||||
GuestAutoLockEnabled any `json:"GuestAutoLockEnabled"`
|
||||
GuestID string `json:"GuestId"`
|
||||
GuestMonitoringModeInfo any `json:"GuestMonitoringModeInfo"`
|
||||
InstanceUUID string `json:"InstanceUuid"`
|
||||
LatencySensitivity any `json:"LatencySensitivity"`
|
||||
LocationID string `json:"LocationId"`
|
||||
ManagedBy any `json:"ManagedBy"`
|
||||
MaxMksConnections int `json:"MaxMksConnections"`
|
||||
MemoryAffinity any `json:"MemoryAffinity"`
|
||||
MemoryAllocation any `json:"MemoryAllocation"`
|
||||
MemoryHotAddEnabled any `json:"MemoryHotAddEnabled"`
|
||||
MemoryMB int `json:"MemoryMB"`
|
||||
MemoryReservationLockedToMax any `json:"MemoryReservationLockedToMax"`
|
||||
MessageBusTunnelEnabled any `json:"MessageBusTunnelEnabled"`
|
||||
MigrateEncryption string `json:"MigrateEncryption"`
|
||||
Name string `json:"Name"`
|
||||
NestedHVEnabled any `json:"NestedHVEnabled"`
|
||||
NetworkShaper any `json:"NetworkShaper"`
|
||||
NpivDesiredNodeWwns int `json:"NpivDesiredNodeWwns"`
|
||||
NpivDesiredPortWwns int `json:"NpivDesiredPortWwns"`
|
||||
NpivNodeWorldWideName any `json:"NpivNodeWorldWideName"`
|
||||
NpivOnNonRdmDisks any `json:"NpivOnNonRdmDisks"`
|
||||
NpivPortWorldWideName any `json:"NpivPortWorldWideName"`
|
||||
NpivTemporaryDisabled any `json:"NpivTemporaryDisabled"`
|
||||
NpivWorldWideNameOp string `json:"NpivWorldWideNameOp"`
|
||||
NpivWorldWideNameType string `json:"NpivWorldWideNameType"`
|
||||
NumCPUs int `json:"NumCPUs"`
|
||||
NumCoresPerSocket int `json:"NumCoresPerSocket"`
|
||||
PowerOpInfo any `json:"PowerOpInfo"`
|
||||
RepConfig any `json:"RepConfig"`
|
||||
ScheduledHardwareUpgradeInfo any `json:"ScheduledHardwareUpgradeInfo"`
|
||||
SevEnabled any `json:"SevEnabled"`
|
||||
SgxInfo any `json:"SgxInfo"`
|
||||
SwapPlacement string `json:"SwapPlacement"`
|
||||
Tools any `json:"Tools"`
|
||||
UUID string `json:"Uuid"`
|
||||
VAppConfig any `json:"VAppConfig"`
|
||||
VAppConfigRemoved any `json:"VAppConfigRemoved"`
|
||||
VAssertsEnabled any `json:"VAssertsEnabled"`
|
||||
VPMCEnabled any `json:"VPMCEnabled"`
|
||||
VcpuConfig any `json:"VcpuConfig"`
|
||||
Version string `json:"Version"`
|
||||
VirtualICH7MPresent any `json:"VirtualICH7MPresent"`
|
||||
VirtualSMCPresent any `json:"VirtualSMCPresent"`
|
||||
VMProfile any `json:"VmProfile"`
|
||||
}
|
||||
|
||||
type BackingSpec struct {
|
||||
Port struct {
|
||||
ConnectionCookie int `json:"ConnectionCookie"`
|
||||
PortKey string `json:"PortKey"`
|
||||
PortgroupKey string `json:"PortgroupKey"`
|
||||
SwitchUUID string `json:"SwitchUuid"`
|
||||
} `json:"Port"`
|
||||
BackingObjectID string `json:"BackingObjectId"`
|
||||
ChangeID string `json:"ChangeId"`
|
||||
ContentID string `json:"ContentId"`
|
||||
Datastore struct {
|
||||
Type string `json:"Type"`
|
||||
Value string `json:"Value"`
|
||||
} `json:"Datastore"`
|
||||
DeltaDiskFormat string `json:"DeltaDiskFormat"`
|
||||
DeltaDiskFormatVariant string `json:"DeltaDiskFormatVariant"`
|
||||
DeltaGrainSize int `json:"DeltaGrainSize"`
|
||||
DigestEnabled any `json:"DigestEnabled"`
|
||||
DiskMode string `json:"DiskMode"`
|
||||
EagerlyScrub bool `json:"EagerlyScrub"`
|
||||
FileName string `json:"FileName"`
|
||||
KeyID any `json:"KeyId"`
|
||||
Parent any `json:"Parent"`
|
||||
Sharing string `json:"Sharing"`
|
||||
Split any `json:"Split"`
|
||||
ThinProvisioned bool `json:"ThinProvisioned"`
|
||||
UUID string `json:"Uuid"`
|
||||
WriteThrough any `json:"WriteThrough"`
|
||||
}
|
62
server/router/router.go
Normal file
62
server/router/router.go
Normal file
@@ -0,0 +1,62 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
"wnzl-snow/db"
|
||||
"wnzl-snow/dist"
|
||||
"wnzl-snow/internal/settings"
|
||||
"wnzl-snow/server/handler"
|
||||
"wnzl-snow/server/middleware"
|
||||
)
|
||||
|
||||
func New(logger *slog.Logger, database db.Database, buildTime string, sha1ver string, goVersion string, settings *settings.Settings) http.Handler {
|
||||
h := &handler.Handler{
|
||||
Logger: logger,
|
||||
Database: database,
|
||||
BuildTime: buildTime,
|
||||
SHA1Ver: sha1ver,
|
||||
GoVersion: goVersion,
|
||||
//VcCreds: creds,
|
||||
//Secret: secret,
|
||||
Settings: settings,
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
|
||||
mux.Handle("/assets/", middleware.CacheMiddleware(http.FileServer(http.FS(dist.AssetsDir))))
|
||||
mux.HandleFunc("/", h.Home)
|
||||
|
||||
mux.HandleFunc("/api/now/import/x_dusa2_itom_inc_imp", h.NewSnow)
|
||||
|
||||
// mux.HandleFunc("/api/event/vm/create", h.VmCreateEvent)
|
||||
// mux.HandleFunc("/api/event/vm/modify", h.VmModifyEvent)
|
||||
// mux.HandleFunc("/api/event/vm/move", h.VmMoveEvent)
|
||||
// mux.HandleFunc("/api/event/vm/delete", h.VmDeleteEvent)
|
||||
// mux.HandleFunc("/api/import/vm", h.VmImport)
|
||||
// // Use this when we need to manually remove a VM from the database to clean up
|
||||
// mux.HandleFunc("/api/inventory/vm/delete", h.VmCleanup)
|
||||
|
||||
// // add missing data to VMs
|
||||
// //mux.HandleFunc("/api/inventory/vm/update", h.VmUpdateDetails)
|
||||
|
||||
// // temporary endpoint
|
||||
// mux.HandleFunc("/api/cleanup/updates", h.UpdateCleanup)
|
||||
// //mux.HandleFunc("/api/cleanup/vcenter", h.VcCleanup)
|
||||
|
||||
// mux.HandleFunc("/api/report/inventory", h.InventoryReportDownload)
|
||||
// mux.HandleFunc("/api/report/updates", h.UpdateReportDownload)
|
||||
|
||||
// // endpoint for encrypting vcenter credential
|
||||
// mux.HandleFunc("/api/encrypt", h.EncryptData)
|
||||
|
||||
// Register pprof handlers
|
||||
mux.HandleFunc("/debug/pprof/", pprof.Index)
|
||||
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
|
||||
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
|
||||
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
|
||||
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
|
||||
|
||||
return middleware.NewLoggingMiddleware(logger, mux)
|
||||
}
|
179
server/server.go
Normal file
179
server/server.go
Normal file
@@ -0,0 +1,179 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/go-co-op/gocron/v2"
|
||||
)
|
||||
|
||||
// Server represents an HTTP server.
|
||||
type Server struct {
|
||||
srv *http.Server
|
||||
logger *slog.Logger
|
||||
cron gocron.Scheduler
|
||||
cancel context.CancelFunc
|
||||
disableTls bool
|
||||
tlsCertFilename string
|
||||
tlsKeyFilename string
|
||||
encryptionKey string
|
||||
}
|
||||
|
||||
// New creates a new server with the given logger, address and options.
|
||||
func New(logger *slog.Logger, cron gocron.Scheduler, addr string, opts ...Option) *Server {
|
||||
|
||||
// Set some options for TLS
|
||||
tlsConfig := &tls.Config{
|
||||
MinVersion: tls.VersionTLS12,
|
||||
CurvePreferences: []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
|
||||
PreferServerCipherSuites: true,
|
||||
InsecureSkipVerify: true,
|
||||
CipherSuites: []uint16{
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
},
|
||||
}
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: addr,
|
||||
//WriteTimeout: 120 * time.Second,
|
||||
WriteTimeout: 0,
|
||||
ReadTimeout: 30 * time.Second,
|
||||
TLSConfig: tlsConfig,
|
||||
TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
|
||||
}
|
||||
|
||||
// Set the initial server values
|
||||
server := &Server{
|
||||
srv: srv,
|
||||
logger: logger,
|
||||
cron: cron,
|
||||
//cancel: cancel,
|
||||
}
|
||||
|
||||
// Apply any options
|
||||
for _, opt := range opts {
|
||||
opt(server)
|
||||
}
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
// Option represents a server option.
|
||||
type Option func(*Server)
|
||||
|
||||
// WithWriteTimeout sets the write timeout.
|
||||
func WithWriteTimeout(timeout time.Duration) Option {
|
||||
return func(s *Server) {
|
||||
s.srv.WriteTimeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
// WithReadTimeout sets the read timeout.
|
||||
func WithReadTimeout(timeout time.Duration) Option {
|
||||
return func(s *Server) {
|
||||
s.srv.ReadTimeout = timeout
|
||||
}
|
||||
}
|
||||
|
||||
// WithRouter sets the handler.
|
||||
func WithRouter(handler http.Handler) Option {
|
||||
return func(s *Server) {
|
||||
s.srv.Handler = handler
|
||||
}
|
||||
}
|
||||
|
||||
// SetKey sets the encryption key we use when generating secrets
|
||||
func SetKey(key string) Option {
|
||||
return func(s *Server) {
|
||||
s.encryptionKey = key
|
||||
}
|
||||
}
|
||||
|
||||
// SetTls sets the disable tls value
|
||||
func SetTls(disableTls bool) Option {
|
||||
return func(s *Server) {
|
||||
s.disableTls = disableTls
|
||||
}
|
||||
}
|
||||
|
||||
// SetCertificate sets the path to the certificate used for TLS, in PEM format
|
||||
func SetCertificate(tlsCertFilename string) Option {
|
||||
return func(s *Server) {
|
||||
//fmt.Printf("Setting tlsCertFilename to '%s'\n", tlsCertFilename)
|
||||
s.tlsCertFilename = tlsCertFilename
|
||||
}
|
||||
}
|
||||
|
||||
// SetPrivateKey sets the path to the private key used for TLS, in PEM format
|
||||
func SetPrivateKey(tlsKeyFilename string) Option {
|
||||
return func(s *Server) {
|
||||
s.tlsKeyFilename = tlsKeyFilename
|
||||
}
|
||||
}
|
||||
|
||||
// StartAndWait starts the server and waits for a signal to shut down.
|
||||
func (s *Server) StartAndWait() {
|
||||
s.Start()
|
||||
s.GracefulShutdown()
|
||||
}
|
||||
|
||||
// Start starts the server.
|
||||
func (s *Server) Start() {
|
||||
|
||||
go func() {
|
||||
if s.disableTls {
|
||||
s.logger.Info("starting server", "port", s.srv.Addr)
|
||||
if err := s.srv.ListenAndServe(); err != nil {
|
||||
s.logger.Error("failed to start server", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
s.logger.Info("starting TLS server", "port", s.srv.Addr, "cert", s.tlsCertFilename, "key", s.tlsKeyFilename)
|
||||
if err := s.srv.ListenAndServeTLS(s.tlsCertFilename, s.tlsKeyFilename); err != nil && err != http.ErrServerClosed {
|
||||
s.logger.Error("failed to start server", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// GracefulShutdown shuts down the server gracefully.
|
||||
func (s *Server) GracefulShutdown() {
|
||||
c := make(chan os.Signal, 1)
|
||||
// We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C)
|
||||
// SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught.
|
||||
signal.Notify(c, os.Interrupt)
|
||||
|
||||
// Block until we receive our signal.
|
||||
<-c
|
||||
|
||||
// Create a deadline to wait for.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
// Doesn't block if no connections, but will otherwise wait
|
||||
// until the timeout deadline.
|
||||
_ = s.srv.Shutdown(ctx)
|
||||
|
||||
s.logger.Info("runing cron shutdown")
|
||||
err := s.cron.Shutdown()
|
||||
if err != nil {
|
||||
s.logger.Error("error shutting cron", "error", err)
|
||||
}
|
||||
|
||||
s.logger.Info("runing cancel")
|
||||
s.cancel()
|
||||
|
||||
// Optionally, you could run srv.Shutdown in a goroutine and block on
|
||||
// <-ctx.Done() if your application should wait for other services
|
||||
// to finalize based on context cancellation.
|
||||
s.logger.Info("shutting down")
|
||||
//os.Exit(0)
|
||||
}
|
Reference in New Issue
Block a user