From 5042c4bfef111991550ce2aa746dbcafcf332b72 Mon Sep 17 00:00:00 2001 From: Nathan Coad Date: Fri, 13 Sep 2024 14:50:04 +1000 Subject: [PATCH] test cron job --- README.md | 1 + .../20240913043145_extend_events.sql | 17 +++++ db/queries/models.go | 25 ++++--- db/queries/query.sql | 4 +- db/queries/query.sql.go | 59 +++++++++------ go.mod | 4 + go.sum | 10 +++ internal/tasks/processEvents.go | 73 +++++++++++++++++++ internal/vcenter/vcenter.go | 32 ++++---- main.go | 52 +++++++++++++ server/handler/vmCreate.go | 41 ++++++----- server/server.go | 19 ++++- 12 files changed, 268 insertions(+), 69 deletions(-) create mode 100644 db/migrations/20240913043145_extend_events.sql diff --git a/README.md b/README.md index 81a2233..49b6871 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,7 @@ A few different technologies are configured to help getting off the ground easie - The script `upgrade_htmx.sh` is available to make upgrading easier - [goose](https://github.com/pressly/goose) for DB migrations +TODO: investigate https://github.com/DATA-DOG/go-sqlmock for testing Technologies we're no longer using: - [golang migrate](https://github.com/golang-migrate/migrate) for DB migrations diff --git a/db/migrations/20240913043145_extend_events.sql b/db/migrations/20240913043145_extend_events.sql new file mode 100644 index 0000000..ee0173e --- /dev/null +++ b/db/migrations/20240913043145_extend_events.sql @@ -0,0 +1,17 @@ +-- +goose Up +-- +goose StatementBegin +ALTER TABLE "Events" RENAME COLUMN Datacenter to DatacenterName; +ALTER TABLE "Events" RENAME COLUMN ComputeResource to ComputeResourceName; +ALTER TABLE "Events" ADD COLUMN DatacenterId TEXT; +ALTER TABLE "Events" ADD COLUMN ComputeResourceId TEXT; +ALTER TABLE "Events" ADD COLUMN VmName TEXT; +-- +goose StatementEnd + +-- +goose Down +-- +goose StatementBegin +ALTER TABLE "Events" DROP COLUMN VmName; +ALTER TABLE "Updates" DROP COLUMN ComputeResourceId; +ALTER TABLE "Updates" DROP COLUMN DatacenterId; +ALTER TABLE "Events" RENAME COLUMN ComputeResourceName to ComputeResource; +ALTER TABLE "Events" RENAME COLUMN DatacenterName to Datacenter; +-- +goose StatementEnd diff --git a/db/queries/models.go b/db/queries/models.go index a6792a6..baaa08f 100644 --- a/db/queries/models.go +++ b/db/queries/models.go @@ -9,17 +9,20 @@ import ( ) type Events struct { - Eid int64 - CloudId string - Source string - EventTime sql.NullInt64 - ChainId string - VmId sql.NullString - EventKey sql.NullString - Datacenter sql.NullString - ComputeResource sql.NullString - UserName sql.NullString - Processed int64 + Eid int64 + CloudId string + Source string + EventTime sql.NullInt64 + ChainId string + VmId sql.NullString + EventKey sql.NullString + DatacenterName sql.NullString + ComputeResourceName sql.NullString + UserName sql.NullString + Processed int64 + DatacenterId sql.NullString + ComputeResourceId sql.NullString + VmName sql.NullString } type Inventory struct { diff --git a/db/queries/query.sql b/db/queries/query.sql index 7f23c4f..f5ba6a8 100644 --- a/db/queries/query.sql +++ b/db/queries/query.sql @@ -32,9 +32,9 @@ RETURNING *; -- name: CreateEvent :one INSERT INTO "Events" ( - "CloudId", "Source", "EventTime", "ChainId", "VmId", "EventKey", "Datacenter", "ComputeResource", "UserName" + "CloudId", "Source", "EventTime", "ChainId", "VmId", "VmName", "EventKey", "DatacenterId", "DatacenterName", "ComputeResourceId", "ComputeResourceName", "UserName" ) VALUES( - ?, ?, ?, ?, ?, ?, ?, ?, ? + ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) RETURNING *; diff --git a/db/queries/query.sql.go b/db/queries/query.sql.go index 186500c..3e4588a 100644 --- a/db/queries/query.sql.go +++ b/db/queries/query.sql.go @@ -12,23 +12,26 @@ import ( const createEvent = `-- name: CreateEvent :one INSERT INTO "Events" ( - "CloudId", "Source", "EventTime", "ChainId", "VmId", "EventKey", "Datacenter", "ComputeResource", "UserName" + "CloudId", "Source", "EventTime", "ChainId", "VmId", "VmName", "EventKey", "DatacenterId", "DatacenterName", "ComputeResourceId", "ComputeResourceName", "UserName" ) VALUES( - ?, ?, ?, ?, ?, ?, ?, ?, ? + ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? ) -RETURNING Eid, CloudId, Source, EventTime, ChainId, VmId, EventKey, Datacenter, ComputeResource, UserName, Processed +RETURNING Eid, CloudId, Source, EventTime, ChainId, VmId, EventKey, DatacenterName, ComputeResourceName, UserName, Processed, DatacenterId, ComputeResourceId, VmName ` type CreateEventParams struct { - CloudId string - Source string - EventTime sql.NullInt64 - ChainId string - VmId sql.NullString - EventKey sql.NullString - Datacenter sql.NullString - ComputeResource sql.NullString - UserName sql.NullString + CloudId string + Source string + EventTime sql.NullInt64 + ChainId string + VmId sql.NullString + VmName sql.NullString + EventKey sql.NullString + DatacenterId sql.NullString + DatacenterName sql.NullString + ComputeResourceId sql.NullString + ComputeResourceName sql.NullString + UserName sql.NullString } func (q *Queries) CreateEvent(ctx context.Context, arg CreateEventParams) (Events, error) { @@ -38,9 +41,12 @@ func (q *Queries) CreateEvent(ctx context.Context, arg CreateEventParams) (Event arg.EventTime, arg.ChainId, arg.VmId, + arg.VmName, arg.EventKey, - arg.Datacenter, - arg.ComputeResource, + arg.DatacenterId, + arg.DatacenterName, + arg.ComputeResourceId, + arg.ComputeResourceName, arg.UserName, ) var i Events @@ -52,10 +58,13 @@ func (q *Queries) CreateEvent(ctx context.Context, arg CreateEventParams) (Event &i.ChainId, &i.VmId, &i.EventKey, - &i.Datacenter, - &i.ComputeResource, + &i.DatacenterName, + &i.ComputeResourceName, &i.UserName, &i.Processed, + &i.DatacenterId, + &i.ComputeResourceId, + &i.VmName, ) return i, err } @@ -281,7 +290,7 @@ func (q *Queries) GetInventoryVmId(ctx context.Context, vmid sql.NullString) (In } const listEvents = `-- name: ListEvents :many -SELECT Eid, CloudId, Source, EventTime, ChainId, VmId, EventKey, Datacenter, ComputeResource, UserName, Processed FROM "Events" +SELECT Eid, CloudId, Source, EventTime, ChainId, VmId, EventKey, DatacenterName, ComputeResourceName, UserName, Processed, DatacenterId, ComputeResourceId, VmName FROM "Events" ORDER BY "EventTime" ` @@ -302,10 +311,13 @@ func (q *Queries) ListEvents(ctx context.Context) ([]Events, error) { &i.ChainId, &i.VmId, &i.EventKey, - &i.Datacenter, - &i.ComputeResource, + &i.DatacenterName, + &i.ComputeResourceName, &i.UserName, &i.Processed, + &i.DatacenterId, + &i.ComputeResourceId, + &i.VmName, ); err != nil { return nil, err } @@ -367,7 +379,7 @@ func (q *Queries) ListInventory(ctx context.Context) ([]Inventory, error) { } const listUnprocessedEvents = `-- name: ListUnprocessedEvents :many -SELECT Eid, CloudId, Source, EventTime, ChainId, VmId, EventKey, Datacenter, ComputeResource, UserName, Processed FROM "Events" +SELECT Eid, CloudId, Source, EventTime, ChainId, VmId, EventKey, DatacenterName, ComputeResourceName, UserName, Processed, DatacenterId, ComputeResourceId, VmName FROM "Events" WHERE "Processed" = 0 ORDER BY "EventTime" ` @@ -389,10 +401,13 @@ func (q *Queries) ListUnprocessedEvents(ctx context.Context) ([]Events, error) { &i.ChainId, &i.VmId, &i.EventKey, - &i.Datacenter, - &i.ComputeResource, + &i.DatacenterName, + &i.ComputeResourceName, &i.UserName, &i.Processed, + &i.DatacenterId, + &i.ComputeResourceId, + &i.VmName, ); err != nil { return nil, err } diff --git a/go.mod b/go.mod index 3dd56a3..4817ea0 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.23.1 require ( github.com/a-h/templ v0.2.778 + github.com/go-co-op/gocron/v2 v2.11.0 github.com/jmoiron/sqlx v1.4.0 github.com/joho/godotenv v1.5.1 github.com/pressly/goose/v3 v3.22.0 @@ -15,12 +16,15 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/jonboulle/clockwork v0.4.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mfridman/interpolate v0.0.2 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + github.com/robfig/cron/v3 v3.0.1 // indirect github.com/sethvargo/go-retry v0.3.0 // indirect go.uber.org/multierr v1.11.0 // indirect + golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.25.0 // indirect golang.org/x/tools v0.25.0 // indirect diff --git a/go.sum b/go.sum index 2592025..c6f496d 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/go-co-op/gocron/v2 v2.11.0 h1:IOowNA6SzwdRFnD4/Ol3Kj6G2xKfsoiiGq2Jhhm9bvE= +github.com/go-co-op/gocron/v2 v2.11.0/go.mod h1:xY7bJxGazKam1cz04EebrlP4S9q4iWdiAylMGP3jY9w= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -20,6 +22,8 @@ github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/jonboulle/clockwork v0.4.0 h1:p4Cf1aMWXnXAUh8lVfewRBx1zaTSYKrKMF2g3ST4RZ4= +github.com/jonboulle/clockwork v0.4.0/go.mod h1:xgRqUGwRcjKCO1vbZUEtSLrqKoPSsUpK7fnezOII0kc= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= @@ -36,14 +40,20 @@ github.com/pressly/goose/v3 v3.22.0 h1:wd/7kNiPTuNAztWun7iaB98DrhulbWPrzMAaw2DEZ github.com/pressly/goose/v3 v3.22.0/go.mod h1:yJM3qwSj2pp7aAaCvso096sguezamNb2OBgxCnh/EYg= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= +github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/sethvargo/go-retry v0.3.0 h1:EEt31A35QhrcRZtrYFDTBg91cqZVnFL2navjDrah2SE= github.com/sethvargo/go-retry v0.3.0/go.mod h1:mNX17F0C/HguQMyMyJxcnU471gOZGxCLyYaFyAZraas= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/vmware/govmomi v0.43.0 h1:7Kg3Bkdly+TrE67BYXzRq7ZrDnn7xqpKX95uEh2f9Go= github.com/vmware/govmomi v0.43.0/go.mod h1:IOv5nTXCPqH9qVJAlRuAGffogaLsNs8aF+e7vLgsHJU= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY= +golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= diff --git a/internal/tasks/processEvents.go b/internal/tasks/processEvents.go index 5cfe120..83d521f 100644 --- a/internal/tasks/processEvents.go +++ b/internal/tasks/processEvents.go @@ -1,3 +1,76 @@ package tasks +import ( + "context" + "log/slog" + "time" + "vctp/db" + "vctp/internal/vcenter" +) + +// Handler handles requests. +type CronTask struct { + Logger *slog.Logger + Database db.Database +} + // use gocron to check events in the Events table +func (c *CronTask) RunVmCheck(ctx context.Context, logger *slog.Logger) error { + var ( + //unixTimestamp int64 + numVcpus int32 + numRam int32 + datacenter string + ) + + logger.Debug("Started Events processing", "time", time.Now()) + + // Query events table + events, err := c.Database.Queries().ListUnprocessedEvents(ctx) + if err != nil { + logger.Error("Unable to query for unprocessed events", "error", err) + return nil // TODO - what to do with this error? + } + + for _, evt := range events { + logger.Debug("Checking event", "event", evt) + + c.Logger.Debug("connecting to vcenter") + vc := vcenter.New(c.Logger) + vc.Login(evt.Source) + //vmObject, err := vc.FindVMByName(vm.CloudEvent.Data.VM.Name) + //vmObject, err := vc.FindVMByID(vm.CloudEvent.Data.VM.VM.Value) + vmObject, err := vc.FindVMByIDWithDatacenter(evt.VmId.String, evt.DatacenterId.String) + + if err != nil { + c.Logger.Error("Can't locate vm in vCenter", "vmID", evt.VmId.String, "error", err) + } else if vmObject == nil { + c.Logger.Debug("didn't find VM", "vm_id", evt.VmId.String) + numRam = 0 + numVcpus = 0 + datacenter = evt.DatacenterName.String + } else { + c.Logger.Debug("found VM") + //prettyPrint(vmObject) + + // calculate VM properties we want to store + if vmObject.Vm.Config != nil { + numRam = vmObject.Vm.Config.Hardware.MemoryMB + numVcpus = vmObject.Vm.Config.Hardware.NumCPU * vmObject.Vm.Config.Hardware.NumCoresPerSocket + } else { + c.Logger.Error("Empty VM config") + } + + } + err = vc.Logout() + if err != nil { + c.Logger.Error("unable to logout of vcenter", "error", err) + } + + c.Logger.Debug("Simulate adding to Inventory", "vm_name", evt.VmName.String, "vcpus", numVcpus, "ram", numRam, "dc", datacenter) + + } + + //fmt.Printf("processing at %s", time.Now()) + return nil +} diff --git a/internal/vcenter/vcenter.go b/internal/vcenter/vcenter.go index 5a045b9..615e143 100644 --- a/internal/vcenter/vcenter.go +++ b/internal/vcenter/vcenter.go @@ -24,8 +24,8 @@ type Vcenter struct { } type VmProperties struct { - Vm mo.VirtualMachine - Datacenter string + Vm mo.VirtualMachine + //Datacenter string } // New creates a new Vcenter with the given logger @@ -159,14 +159,14 @@ func (v *Vcenter) FindVMByID(vmID string) (*VmProperties, error) { if err == nil { return &VmProperties{ - Datacenter: dc.Name(), - Vm: vm, + //Datacenter: dc.Name(), + Vm: vm, }, nil } else if _, ok := err.(*find.NotFoundError); !ok { // If the error is not a NotFoundError, return it //return nil, fmt.Errorf("failed to retrieve VM with ID %s in datacenter %s: %w", vmID, dc.Name(), err) v.Logger.Debug("Couldn't find vm in datacenter", "vm_id", vmID, "datacenter_name", dc.Name()) - } else if err != nil { + } else { return nil, fmt.Errorf("failed to retrieve VM: %w", err) } } @@ -175,7 +175,7 @@ func (v *Vcenter) FindVMByID(vmID string) (*VmProperties, error) { } func (v *Vcenter) FindVMByIDWithDatacenter(vmID string, dcID string) (*VmProperties, error) { - var dcName string + //var dcName string var err error v.Logger.Debug("searching for vm id", "vm_id", vmID, "datacenter_id", dcID) @@ -196,11 +196,13 @@ func (v *Vcenter) FindVMByIDWithDatacenter(vmID string, dcID string) (*VmPropert // Use finder.SetDatacenter to set the datacenter finder.SetDatacenter(datacenter) - dcName, err = datacenter.ObjectName(v.ctx) - if err != nil { - v.Logger.Error("Couldn't find the name of the datacenter", "error", err) - dcName = "" - } + /* + dcName, err = datacenter.ObjectName(v.ctx) + if err != nil { + v.Logger.Error("Couldn't find the name of the datacenter", "error", err) + dcName = "" + } + */ // Create a ManagedObjectReference for the VM vmRef := types.ManagedObjectReference{ @@ -214,14 +216,14 @@ func (v *Vcenter) FindVMByIDWithDatacenter(vmID string, dcID string) (*VmPropert if err == nil { v.Logger.Debug("Found VM", "vm", vm) return &VmProperties{ - Datacenter: dcName, - Vm: vm, + //Datacenter: dcName, + Vm: vm, }, nil } else if _, ok := err.(*find.NotFoundError); !ok { // If the error is not a NotFoundError, return it //return nil, fmt.Errorf("failed to retrieve VM with ID %s in datacenter %s: %w", vmID, dc.Name(), err) - v.Logger.Debug("Couldn't find vm in datacenter", "vm_id", vmID, "datacenter_name", dcName) - } else if err != nil { + v.Logger.Debug("Couldn't find vm in datacenter", "vm_id", vmID, "datacenter_id", dcID) + } else { return nil, fmt.Errorf("failed to retrieve VM: %w", err) } diff --git a/main.go b/main.go index 45ce151..964c72f 100644 --- a/main.go +++ b/main.go @@ -1,15 +1,19 @@ package main import ( + "context" "fmt" "log/slog" "os" + "time" "vctp/db" + "vctp/internal/tasks" utils "vctp/internal/utils" "vctp/log" "vctp/server" "vctp/server/router" + "github.com/go-co-op/gocron/v2" "github.com/joho/godotenv" ) @@ -17,6 +21,7 @@ var ( bindDisableTls bool sha1ver string // sha1 revision used to build the program buildTime string // when the executable was built + cronFrequency time.Duration ) func main() { @@ -32,6 +37,8 @@ func main() { log.GetOutput(), ) + ctx, cancel := context.WithCancel(context.Background()) + // Configure database database, err := db.New(logger, "./db.sqlite3") if err != nil { @@ -45,6 +52,19 @@ func main() { return } + // Prepare the task scheduler + s, err := gocron.NewScheduler() + if err != nil { + logger.Error("failed to create scheduler", "error", err) + os.Exit(1) + } + + // Pass useful information to the cron jobs + c := &tasks.CronTask{ + Logger: logger, + Database: database, + } + // Determine bind IP bindIP := os.Getenv("BIND_IP") if bindIP == "" { @@ -85,9 +105,41 @@ func main() { utils.GenerateCerts(tlsCertFilename, tlsKeyFilename) } + cronFrequencyString := os.Getenv("VCENTER_POLLING_SECONDS") + if cronFrequencyString != "" { + cronFrequency, err = time.ParseDuration(cronFrequencyString) + if err != nil { + slog.Error("Can't convert VCENTER_POLLING_SECONDS value to time duration. Defaulting to 60s", "value", cronFrequencyString, "error", err) + cronFrequency = time.Second * 60 + } + } else { + cronFrequency = time.Second * 60 + } + logger.Debug("Setting VM polling cronjob frequency to", "frequency", cronFrequency) + + // start background processing + startsAt := time.Now().Add(time.Second * 10) + job, err := s.NewJob( + gocron.DurationJob(cronFrequency), + gocron.NewTask(func() { + c.RunVmCheck(ctx, logger) + }), gocron.WithSingletonMode(gocron.LimitModeReschedule), + gocron.WithStartAt(gocron.WithStartDateTime(startsAt)), + ) + if err != nil { + logger.Error("failed to start cron jobs", "error", err) + os.Exit(1) + } + + slog.Debug("Created cron job", "job", job) + + s.Start() + // Start server svr := server.New( logger, + s, + cancel, bindAddress, server.WithRouter(router.New(logger, database)), ) diff --git a/server/handler/vmCreate.go b/server/handler/vmCreate.go index d0e35a1..3454c94 100644 --- a/server/handler/vmCreate.go +++ b/server/handler/vmCreate.go @@ -44,6 +44,8 @@ func (h *Handler) VmCreate(w http.ResponseWriter, r *http.Request) { prettyPrint(event) } + e := event.CloudEvent.Data + // Convert vmModel to CreateInventoryParams using the utility function //var params queries.CreateInventoryParams //db.ConvertToSQLParams(&vm, ¶ms) @@ -65,15 +67,15 @@ func (h *Handler) VmCreate(w http.ResponseWriter, r *http.Request) { vc.Login(event.CloudEvent.Source) //vmObject, err := vc.FindVMByName(vm.CloudEvent.Data.VM.Name) //vmObject, err := vc.FindVMByID(vm.CloudEvent.Data.VM.VM.Value) - vmObject, err := vc.FindVMByIDWithDatacenter(event.CloudEvent.Data.VM.VM.Value, event.CloudEvent.Data.Datacenter.Datacenter.Value) + vmObject, err := vc.FindVMByIDWithDatacenter(e.VM.VM.Value, e.Datacenter.Datacenter.Value) if err != nil { - h.Logger.Error("Can't locate vm in vCenter", "vmID", event.CloudEvent.Data.VM.VM.Value, "error", err) + h.Logger.Error("Can't locate vm in vCenter", "vmID", e.VM.VM.Value, "error", err) } else if vmObject == nil { - h.Logger.Debug("didn't find VM", "vm_id", event.CloudEvent.Data.VM.VM.Value) + h.Logger.Debug("didn't find VM", "vm_id", e.VM.VM.Value) numRam = 0 numVcpus = 0 - datacenter = event.CloudEvent.Data.Datacenter.Name + datacenter = e.Datacenter.Name } else { h.Logger.Debug("found VM") //prettyPrint(vmObject) @@ -95,15 +97,16 @@ func (h *Handler) VmCreate(w http.ResponseWriter, r *http.Request) { // Create an instance of CreateInventoryParams h.Logger.Debug("Creating database parameters") + /* params := queries.CreateInventoryParams{ - Name: event.CloudEvent.Data.VM.Name, + Name: e.VM.Name, Vcenter: event.CloudEvent.Source, EventId: sql.NullString{String: event.CloudEvent.ID, Valid: event.CloudEvent.ID != ""}, - EventKey: sql.NullString{String: strconv.Itoa(event.CloudEvent.Data.Key), Valid: strconv.Itoa(event.CloudEvent.Data.Key) != ""}, - VmId: sql.NullString{String: event.CloudEvent.Data.VM.VM.Value, Valid: event.CloudEvent.Data.VM.VM.Value != ""}, + EventKey: sql.NullString{String: strconv.Itoa(e.Key), Valid: strconv.Itoa(e.Key) != ""}, + VmId: sql.NullString{String: e.VM.VM.Value, Valid: e.VM.VM.Value != ""}, Datacenter: sql.NullString{String: datacenter, Valid: datacenter != ""}, - Cluster: sql.NullString{String: event.CloudEvent.Data.ComputeResource.Name, Valid: event.CloudEvent.Data.ComputeResource.Name != ""}, + Cluster: sql.NullString{String: e.ComputeResource.Name, Valid: e.ComputeResource.Name != ""}, CreationTime: sql.NullInt64{Int64: unixTimestamp, Valid: unixTimestamp > 0}, InitialVcpus: sql.NullInt64{Int64: int64(numVcpus), Valid: numVcpus > 0}, InitialRam: sql.NullInt64{Int64: int64(numRam), Valid: numRam > 0}, @@ -111,15 +114,18 @@ func (h *Handler) VmCreate(w http.ResponseWriter, r *http.Request) { */ params2 := queries.CreateEventParams{ - Source: event.CloudEvent.Source, - CloudId: event.CloudEvent.ID, - EventTime: sql.NullInt64{Int64: unixTimestamp, Valid: unixTimestamp > 0}, - ChainId: strconv.Itoa(event.CloudEvent.Data.ChainID), - VmId: sql.NullString{String: event.CloudEvent.Data.VM.VM.Value, Valid: event.CloudEvent.Data.VM.VM.Value != ""}, - EventKey: sql.NullString{String: strconv.Itoa(event.CloudEvent.Data.Key), Valid: strconv.Itoa(event.CloudEvent.Data.Key) != ""}, - Datacenter: sql.NullString{String: event.CloudEvent.Data.Datacenter.Name, Valid: event.CloudEvent.Data.Datacenter.Name != ""}, - ComputeResource: sql.NullString{String: event.CloudEvent.Data.ComputeResource.Name, Valid: event.CloudEvent.Data.ComputeResource.Name != ""}, - UserName: sql.NullString{String: event.CloudEvent.Data.UserName, Valid: event.CloudEvent.Data.UserName != ""}, + Source: event.CloudEvent.Source, + CloudId: event.CloudEvent.ID, + EventTime: sql.NullInt64{Int64: unixTimestamp, Valid: unixTimestamp > 0}, + ChainId: strconv.Itoa(e.ChainID), + VmId: sql.NullString{String: e.VM.VM.Value, Valid: e.VM.VM.Value != ""}, + VmName: sql.NullString{String: e.VM.Name, Valid: e.VM.Name != ""}, + EventKey: sql.NullString{String: strconv.Itoa(e.Key), Valid: strconv.Itoa(e.Key) != ""}, + DatacenterName: sql.NullString{String: e.Datacenter.Name, Valid: e.Datacenter.Name != ""}, + DatacenterId: sql.NullString{String: e.Datacenter.Datacenter.Value, Valid: e.Datacenter.Datacenter.Value != ""}, + ComputeResourceName: sql.NullString{String: e.ComputeResource.Name, Valid: e.ComputeResource.Name != ""}, + ComputeResourceId: sql.NullString{String: e.ComputeResource.ComputeResource.Value, Valid: e.ComputeResource.ComputeResource.Value != ""}, + UserName: sql.NullString{String: e.UserName, Valid: e.UserName != ""}, } h.Logger.Debug("database params", "params", params2) @@ -140,6 +146,7 @@ func (h *Handler) VmCreate(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Create Request : %v\n", result) } +// prettyPrint comes from https://gist.github.com/sfate/9d45f6c5405dc4c9bf63bf95fe6d1a7c func prettyPrint(args ...interface{}) { var caller string diff --git a/server/server.go b/server/server.go index d0eb8ab..af5827d 100644 --- a/server/server.go +++ b/server/server.go @@ -8,19 +8,23 @@ import ( "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 } // New creates a new server with the given logger, address and options. -func New(logger *slog.Logger, addr string, opts ...Option) *Server { +func New(logger *slog.Logger, cron gocron.Scheduler, cancel context.CancelFunc, addr string, opts ...Option) *Server { // Set some options for TLS tlsConfig := &tls.Config{ @@ -50,6 +54,8 @@ func New(logger *slog.Logger, addr string, opts ...Option) *Server { return &Server{ srv: srv, logger: logger, + cron: cron, + cancel: cancel, } } @@ -113,7 +119,6 @@ func (s *Server) Start() { s.logger.Warn("failed to start server", "error", err) } } - }() } @@ -133,6 +138,16 @@ func (s *Server) GracefulShutdown() { // 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.