database insert is working
Some checks failed
CI / Lint (push) Waiting to run
CI / Test (push) Waiting to run
CI / End-to-End (push) Waiting to run
CI / Publish Docker (push) Blocked by required conditions
continuous-integration/drone/push Build is failing

This commit is contained in:
2024-09-12 15:03:24 +10:00
parent 0d2f983eb3
commit 6b285e55b8
9 changed files with 165 additions and 28 deletions

View File

@@ -1,8 +1,10 @@
package db
import (
"database/sql"
"embed"
"log/slog"
"reflect"
"vctp/db/queries"
"github.com/jmoiron/sqlx"
@@ -66,3 +68,33 @@ func Migrate(db Database) error {
return nil
}
// ConvertToSQLParams is a utility function that generically converts a struct to a corresponding sqlc-generated struct
func ConvertToSQLParams(input interface{}, output interface{}) {
inputVal := reflect.ValueOf(input).Elem()
outputVal := reflect.ValueOf(output).Elem()
for i := 0; i < outputVal.NumField(); i++ {
outputField := outputVal.Field(i)
inputField := inputVal.FieldByName(outputVal.Type().Field(i).Name)
if !inputField.IsValid() || !outputField.CanSet() {
continue
}
switch outputField.Type() {
case reflect.TypeOf(sql.NullString{}):
if inputField.Kind() == reflect.Ptr && inputField.IsNil() {
outputField.Set(reflect.ValueOf(sql.NullString{Valid: false}))
} else {
outputField.Set(reflect.ValueOf(sql.NullString{String: inputField.String(), Valid: true}))
}
case reflect.TypeOf(sql.NullInt64{}):
if inputField.Int() == 0 {
outputField.Set(reflect.ValueOf(sql.NullInt64{Valid: false}))
} else {
outputField.Set(reflect.ValueOf(sql.NullInt64{Int64: inputField.Int(), Valid: true}))
}
}
}
}

View File

@@ -2,13 +2,13 @@
-- +goose StatementBegin
CREATE TABLE IF NOT EXISTS "Inventory" (
"Iid" INTEGER UNIQUE,
"Name" TEXT,
"Vcenter" TEXT,
"Name" TEXT NOT NULL,
"Vcenter" TEXT NOT NULL,
"VmId" TEXT,
"EventKey" TEXT,
"EventId" TEXT,
"CreationTime" TEXT,
"DeletionTime" TEXT,
"CreationTime" INTEGER,
"DeletionTime" INTEGER,
"ResourcePool" TEXT,
"VmType" TEXT,
"Datacenter" TEXT,
@@ -23,8 +23,8 @@ CREATE TABLE IF NOT EXISTS "Inventory" (
CREATE TABLE IF NOT EXISTS "Updates" (
"Uid" INTEGER UNIQUE,
"InventoryId" INTEGER,
"UpdateTime" TEXT,
"UpdateType" TEXT,
"UpdateTime" INTEGER,
"UpdateType" TEXT NOT NULL,
"NewVcpus" INTEGER,
"NewRam" INTEGER,
"NewResourcePool" TEXT

View File

@@ -10,13 +10,13 @@ import (
type Inventory struct {
Iid sql.NullInt64
Name sql.NullString
Vcenter sql.NullString
Name string
Vcenter string
VmId sql.NullString
EventKey sql.NullString
EventId sql.NullString
CreationTime sql.NullString
DeletionTime sql.NullString
CreationTime sql.NullInt64
DeletionTime sql.NullInt64
ResourcePool sql.NullString
VmType sql.NullString
Datacenter sql.NullString
@@ -31,8 +31,8 @@ type Inventory struct {
type Updates struct {
Uid sql.NullInt64
InventoryId sql.NullInt64
UpdateTime sql.NullString
UpdateType sql.NullString
UpdateTime sql.NullInt64
UpdateType string
NewVcpus sql.NullInt64
NewRam sql.NullInt64
NewResourcePool sql.NullString

View File

@@ -20,12 +20,12 @@ RETURNING Iid, Name, Vcenter, VmId, EventKey, EventId, CreationTime, DeletionTim
`
type CreateInventoryParams struct {
Name sql.NullString
Vcenter sql.NullString
Name string
Vcenter string
VmId sql.NullString
EventKey sql.NullString
EventId sql.NullString
CreationTime sql.NullString
CreationTime sql.NullInt64
ResourcePool sql.NullString
VmType sql.NullString
Datacenter sql.NullString
@@ -83,7 +83,7 @@ SELECT Iid, Name, Vcenter, VmId, EventKey, EventId, CreationTime, DeletionTime,
WHERE "Name" = ? LIMIT 1
`
func (q *Queries) GetInventoryByName(ctx context.Context, name sql.NullString) (Inventory, error) {
func (q *Queries) GetInventoryByName(ctx context.Context, name string) (Inventory, error) {
row := q.db.QueryRowContext(ctx, getInventoryByName, name)
var i Inventory
err := row.Scan(

View File

@@ -10,11 +10,11 @@ func New(level Level, output Output) *slog.Logger {
var h slog.Handler
switch output {
case OutputJson:
h = slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: level.ToSlog()})
h = slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: level.ToSlog(), AddSource: true})
case OutputText:
h = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: level.ToSlog()})
h = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: level.ToSlog(), AddSource: true})
default:
h = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: level.ToSlog()})
h = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: level.ToSlog(), AddSource: true})
}
return slog.New(h)
}

View File

@@ -40,13 +40,6 @@ func main() {
}
defer database.Close()
/*
if err = db.Migrate(database); err != nil && !errors.Is(err, migrate.ErrNoChange) {
logger.Error("failed to migrate database", "error", err)
return
}
*/
if err = db.Migrate(database); err != nil {
logger.Error("failed to migrate database", "error", err)
return

View File

@@ -1,21 +1,73 @@
package handler
import (
"context"
"database/sql"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
queries "vctp/db/queries"
models "vctp/server/models"
)
// VmCreate receives the CloudEvent for a VM creation
func (h *Handler) VmCreate(w http.ResponseWriter, r *http.Request) {
var unixTimestamp int64
reqBody, err := io.ReadAll(r.Body)
if err != nil {
fmt.Fprintf(w, "Invalid data received")
w.WriteHeader(http.StatusInternalServerError)
return
} else {
h.Logger.Debug("received input data", "length", len(reqBody))
}
// Decode the JSON body into vmModel struct
var vm models.CloudEventReceived
//if err := json.NewDecoder(r.Body).Decode(&vm); err != nil {
if err := json.Unmarshal(reqBody, &vm); err != nil {
h.Logger.Error("unable to decode json", "error", err)
http.Error(w, "Invalid JSON body", http.StatusBadRequest)
return
}
// Convert vmModel to CreateInventoryParams using the utility function
//var params queries.CreateInventoryParams
//db.ConvertToSQLParams(&vm, &params)
// Parse the datetime string to a time.Time object
eventTime, err := time.Parse(time.RFC3339, vm.CloudEvent.Time)
if err != nil {
h.Logger.Warn("unable to convert cloud event time to timestamp", "error", err)
unixTimestamp = time.Now().Unix()
} else {
// Convert to Unix timestamp
unixTimestamp = eventTime.Unix()
}
// Create an instance of CreateInventoryParams
params := queries.CreateInventoryParams{
Name: vm.CloudEvent.Data.VM.Name,
Vcenter: vm.CloudEvent.Source,
VmId: sql.NullString{String: "VirtualMachine-" + vm.CloudEvent.Data.VM.VM.Value, Valid: vm.CloudEvent.Data.VM.VM.Value != ""},
CreationTime: sql.NullInt64{Int64: unixTimestamp, Valid: unixTimestamp > 0},
}
h.Logger.Debug("database params", "vm", vm)
// Insert the new inventory record into the database
result, err := h.Database.Queries().CreateInventory(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)
return
}
h.Logger.Debug("received create request", "body", string(reqBody))
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "Create Request (%d): %v\n", len(reqBody), string(reqBody))
fmt.Fprintf(w, "Create Request : %v\n", result)
}

60
server/models/models.go Normal file
View File

@@ -0,0 +1,60 @@
package models
import "time"
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"`
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 time.Time `json:"CreatedTime"`
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"`
SrcTemplate struct {
Name string `json:"Name"`
VM struct {
Type string `json:"Type"`
Value string `json:"Value"`
} `json:"Vm"`
} `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"`
} `json:"data"`
} `json:"cloudEvent"`
}

View File

@@ -109,7 +109,7 @@ func (s *Server) Start() {
}
} 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 {
if err := s.srv.ListenAndServeTLS(s.tlsCertFilename, s.tlsKeyFilename); err != nil && err != http.ErrServerClosed {
s.logger.Warn("failed to start server", "error", err)
}
}