From d08d9f99bee4d4e93a8beda780d8e9f6099e32cb Mon Sep 17 00:00:00 2001 From: Jeff Carr Date: Sat, 12 Oct 2024 10:59:11 -0500 Subject: [PATCH] ugly but limping along progress Signed-off-by: Jeff Carr --- README | 3 ++- argv.go | 6 ++--- event.go | 9 ++++++++ http.go | 21 ++---------------- main.go | 30 ++++++++++++++++++++----- poll.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++ structs.go | 39 ++++++++++++++++++++++++++++++++ watchdog.go | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 201 insertions(+), 28 deletions(-) create mode 100644 event.go create mode 100644 poll.go create mode 100644 structs.go create mode 100644 watchdog.go diff --git a/README b/README index c006767..4810076 100644 --- a/README +++ b/README @@ -16,8 +16,9 @@ Notes & Goals: * Be super easy to use. * Automatically map access to serial and graphical consoles +* This is intended for managing Virtual Machines, not for containers * This often uses the DO nomenclature 'droplets' instead of 'virtual machines' or 'domU' -* When possible, use protobuf over the wire +* When possible, use protobuf * Let security be handled externally at the socket layer with other tools * Put network, cpu, etc stats in external tools * Automatic live migration to decommission nodes diff --git a/argv.go b/argv.go index 7221523..4bed667 100644 --- a/argv.go +++ b/argv.go @@ -9,9 +9,9 @@ package main var argv args type args struct { - Hosts []string `arg:"--hosts" help:"hosts to connect to"` - Uptime bool `arg:"--uptime" default:"true" help:"allow uptime checks for things like Kuma"` - Port int `arg:"--port" default:"8080" help:"specify a different default port"` + Hosts []string `arg:"--hosts" help:"hosts to connect to"` + Uptime bool `arg:"--uptime" default:"true" help:"allow uptime checks for things like Kuma"` + Port int `arg:"--port" default:"8080" help:"specify a different default port"` } func (a args) Description() string { diff --git a/event.go b/event.go new file mode 100644 index 0000000..5a31eb1 --- /dev/null +++ b/event.go @@ -0,0 +1,9 @@ +package main + +import ( + "go.wit.com/log" +) + +func (d *DropletT) Start() { + log.Info("a new virtual machine is running") +} diff --git a/http.go b/http.go index 6c5e397..2188ed5 100644 --- a/http.go +++ b/http.go @@ -5,7 +5,6 @@ import ( "net/http" "strings" - "go.wit.com/lib/gui/shell" "go.wit.com/log" ) @@ -30,24 +29,8 @@ func okHandler(w http.ResponseWriter, r *http.Request) { } if tmp == "/vms" { - for _, hostname := range argv.Hosts { - url := "http://" + hostname + ":2520/vms" - log.Info("wget url =", url) - s := shell.Wget(url) - if s == nil { - continue; - } - var bytesSplice []byte - bytesSplice = s.Bytes() - // fmt.Fprintln(w, string(bytesSplice)) - for _, line := range strings.Split(string(bytesSplice), "\n") { - if line == "" { - continue - } - fmt.Fprintln(w, hostname, line) - log.Info("LINE: =", hostname, line) - } - // log.Info("i, s =", hostname, i, s) + for _, d := range me.droplets { + fmt.Fprintln(w, d.Hostname, d.hname, d.lastpoll) } return } diff --git a/main.go b/main.go index bf56a04..2ba5dda 100644 --- a/main.go +++ b/main.go @@ -3,9 +3,9 @@ package main import ( - // "log" "embed" "os" + "time" "go.wit.com/dev/alexflint/arg" "go.wit.com/log" @@ -19,15 +19,35 @@ var resources embed.FS func main() { pp := arg.MustParse(&argv) - if ! argv.Uptime { + if !argv.Uptime { pp.WriteHelp(os.Stdout) os.Exit(0) } log.Info("connect to cluser here", argv.Hosts) - for i, s := range argv.Hosts { - log.Info("i, s =", i, s) + for _, s := range argv.Hosts { + me.names = append(me.names, s) + + log.Info("Make a hypervisor struct for", s) + var h HyperT + h.Hostname = s + h.Autoscan = true + h.Delay = 3 * time.Second + h.Scan = func() { + log.Info("scanned farm03?") + h.pollHypervisor() + } + me.hypers = append(me.hypers, h) + } + go startHTTP() + + log.Info("me.names =", me.names) + for _, h := range me.hypers { + log.Info("me hostname =", h.Hostname) + if h.Hostname == "farm03" { + log.Info("should start watchdog here for hostname =", h.Hostname) + h.NewWatchdog() + } } - startHTTP() } diff --git a/poll.go b/poll.go new file mode 100644 index 0000000..b7daeb9 --- /dev/null +++ b/poll.go @@ -0,0 +1,57 @@ +package main + +import ( + "strings" + "time" + + "go.wit.com/lib/gui/shell" + "go.wit.com/log" +) + +func (h HyperT) pollHypervisor() { + url := "http://" + h.Hostname + ":2520/vms" + log.Info("wget url =", url) + s := shell.Wget(url) + if s == nil { + return + } + var bytesSplice []byte + bytesSplice = s.Bytes() + // fmt.Fprintln(w, string(bytesSplice)) + for _, line := range strings.Split(string(bytesSplice), "\n") { + if line == "" { + continue + } + fields := strings.Fields(line) + if len(fields) < 2 { + continue + } + state := fields[0] + name := fields[1] + if state == "ON" { + log.Info("POLL", h.Hostname, "STATE:", state, "HOST:", name, "rest:", fields[2:]) + var found = false + for _, d := range me.droplets { + if d.Hostname == name { + log.Info("ALREADY RECORDED", d.Hostname) + found = true + d.lastpoll = time.Now() + if d.hname != h.Hostname { + log.Info("DROPLET", d.Hostname, "MOVED FROM", d.hname, "TO", d.Hostname) + } + + d.hname = h.Hostname + } + } + if found { + continue + } + var d DropletT + d.Hostname = name + d.hname = h.Hostname + me.droplets = append(me.droplets, d) + log.Info(name, "IS NEW. ADDED ON", h.Hostname) + } + } + // log.Info("i, s =", hostname, i, s) +} diff --git a/structs.go b/structs.go new file mode 100644 index 0000000..7a0f0ee --- /dev/null +++ b/structs.go @@ -0,0 +1,39 @@ +package main + +import "time" + +var me virtigoT + +// disable the GUI +func (b *virtigoT) Disable() { + // b.mainbox.Disable() +} + +// enable the GUI +func (b *virtigoT) Enable() { + // b.mainbox.Enable() +} + +// this app's variables +type virtigoT struct { + names []string + hypers []HyperT + droplets []DropletT +} + +// the stuff that is needed for a hypervisor +type HyperT struct { + Hostname string // the hypervisor hostname + Scan func() // the function to run to scan the hypervisor + Autoscan bool // to scan or not to scan + Delay time.Duration // how often to poll the hypervisor + Dog *time.Ticker // the watchdog timer itself +} + +// the stuff that is needed for a hypervisor +type DropletT struct { + Hostname string // the name of the virtual machine. should be unique (probably enforce this forever) + hname string // the hypervisor it's currently running on + h *HyperT // the hypervisor it's currently running on + lastpoll time.Time // the last time the droplet was seen running +} diff --git a/watchdog.go b/watchdog.go new file mode 100644 index 0000000..155c79d --- /dev/null +++ b/watchdog.go @@ -0,0 +1,64 @@ +package main + +import ( + "fmt" + "os" + "time" + + "go.wit.com/log" +) + +// scan hypervisors every i seconds +func (h *HyperT) NewWatchdog() { + var delay int = 99 + var i int = delay + h.MyTicker(h.Delay, "new Watchdog() "+h.Hostname, func() { + i += 1 + // check if the env var is set to autoscan + if os.Getenv("WATCHDOG_AUTO_SCAN") != "true" { + if i < delay { + i = delay + } + // print every 'delay' seconds + if i%delay == 0 { + log.Info("Not auto scanning", i, "WATCHDOG_AUTO_SCAN =", os.Getenv("WATCHDOG_AUTO_SCAN")) + } + return + } + if i < delay { + return + } + i = 0 + }) +} + +// timeFunction takes a function as an argument and returns the execution time. +func TimeFunction(f func()) time.Duration { + startTime := time.Now() // Record the start time + f() // Execute the function + return time.Since(startTime) // Calculate the elapsed time +} + +func (h *HyperT) MyTicker(t time.Duration, name string, f func()) { + h.Dog = time.NewTicker(t) + defer h.Dog.Stop() + done := make(chan bool) + /* + // this example would exit/destroy the ticker in 10 seconds + go func() { + time.Sleep(10 * time.Second) + done <- true + }() + */ + for { + select { + case <-done: + fmt.Println("Done!") + return + case t := <-h.Dog.C: + log.Info(name, "Current time: ", t) + h.Scan() + // f() + } + } +}