add --daemon

This commit is contained in:
Jeff Carr 2025-04-21 08:16:32 -05:00
parent 3cd1f64d15
commit 8eda4cf2da
5 changed files with 281 additions and 117 deletions

View File

@ -15,6 +15,7 @@ type args struct {
Droplet *DropletCmd `arg:"subcommand:droplet" help:"send events to a droplet"` Droplet *DropletCmd `arg:"subcommand:droplet" help:"send events to a droplet"`
Config string `arg:"env:VIRTIGO_HOME" help:"defaults to ~/.config/virtigo/"` Config string `arg:"env:VIRTIGO_HOME" help:"defaults to ~/.config/virtigo/"`
Server string `arg:"env:VIRTIGO_SERVER" help:"what virtigo cluster to connect to"` Server string `arg:"env:VIRTIGO_SERVER" help:"what virtigo cluster to connect to"`
Daemon bool `arg:"--daemon" help:"run as a daemon"`
Verbose bool `arg:"--verbose" help:"talk more"` Verbose bool `arg:"--verbose" help:"talk more"`
Port int `arg:"--port" default:"8080" help:"allow droplet events via http"` Port int `arg:"--port" default:"8080" help:"allow droplet events via http"`
Xml []string `arg:"--libvirt" help:"import qemu xml files: --libvirt /etc/libvirt/qemu/*.xml"` Xml []string `arg:"--libvirt" help:"import qemu xml files: --libvirt /etc/libvirt/qemu/*.xml"`

154
doDaemon.go Normal file
View File

@ -0,0 +1,154 @@
// Copyright 2024 WIT.COM Inc Licensed GPL 3.0
package main
import (
"fmt"
"time"
"go.wit.com/lib/protobuf/virtpb"
"go.wit.com/lib/virtigolib"
"go.wit.com/log"
)
func doDaemon() error {
// set defaults
me.unstable = time.Now() // initialize the grid as unstable
me.changed = false
me.hmap = make(map[*virtpb.Hypervisor]*HyperT)
// how long a droplet can be missing until it's declared dead
me.unstableTimeout = 17 * time.Second
me.missingDropletTimeout = time.Minute // not sure the difference between these values
// how often to poll the hypervisors
me.hyperPollDelay = 5 * time.Second
// how long the cluster must be stable before new droplets can be started
me.clusterStableDuration = 37 * time.Second
me.cluster = virtpb.InitCluster()
if err := me.cluster.ConfigLoad(); err != nil {
log.Info("config load error", err)
log.Info("")
log.Info("You have never run this before")
log.Info("init example cloud here")
log.Sleep(2)
return err
}
loop := me.cluster.DropletsAll() // get the list of droplets
for loop.Scan() {
d := loop.Next()
if d == nil {
fmt.Println("d == nil")
return fmt.Errorf("d == nil")
}
fmt.Println("Droplet UUID:", d.Uuid)
if d.Current == nil {
d.Current = new(virtpb.Current)
}
d.SetState(virtpb.DropletState_OFF)
log.Info("droplet", d.Hostname)
}
hmm := "pihole.wit.com"
d := me.cluster.FindDropletByName(hmm)
if d == nil {
log.Info("did not find found droplet", hmm)
} else {
log.Info("found droplet", d.Hostname, d)
}
var newEvents []*virtpb.Event
// sanity check the cluster & droplets
if _, _, err := ValidateDroplets(); err != nil {
log.Info("todo: add flag to ignore. for now, fix problems in the config file.")
return err
}
newe, err := ValidateDiskFilenames()
if err != nil {
log.Info(err)
return err
}
// this is a new droplet. add it to the cluster
for _, e := range newe {
newEvents = append(newEvents, e)
}
ValidateUniqueFilenames()
for _, filename := range argv.Xml {
domcfg, err := virtigolib.ReadXml(filename)
if err != nil {
// parsing the libvirt xml file failed
log.Info("error:", filename, err)
log.Info("readXml() error", filename)
log.Info("readXml() error", err)
log.Info("libvirt XML will have to be fixed by hand")
return err
}
// this is a new droplet. add it to the cluster
log.Info("Add XML Droplet here", domcfg.Name)
_, newe, err := virtigolib.AddDomainDroplet(me.cluster, domcfg)
if err != nil {
log.Info("addDomainDroplet() error", filename)
log.Info("addDomainDroplet() error", err)
log.Info("libvirt XML will have to be fixed by hand")
return err
}
for _, e := range newe {
newEvents = append(newEvents, e)
}
}
for i, e := range newEvents {
log.Info(i, "Event:", e.Droplet, e.FieldName, "orig:", e.OrigVal, "new:", e.NewVal)
me.changed = true
}
if me.changed {
if err := me.cluster.ConfigSave(); err != nil {
log.Info("configsave error", err)
return err
}
log.Info("XML changes saved in protobuf config")
return nil
}
if len(argv.Xml) != 0 {
log.Info("No XML changes found")
return fmt.Errorf("No XML changes found")
}
// initialize each hypervisor
for _, pbh := range me.cluster.H.Hypervisors {
// this is a new unknown droplet (not in the config file)
var h *HyperT
h = new(HyperT)
h.pb = pbh
h.lastDroplets = make(map[string]time.Time)
h.lastpoll = time.Now()
me.hmap[pbh] = h
me.hypers = append(me.hypers, h)
log.Log(EVENT, "config new hypervisors", h.pb.Hostname)
}
// start the watchdog polling for each hypervisor
for _, h := range me.hypers {
log.Info("starting polling on", h.pb.Hostname)
// start a watchdog on each hypervisor
go h.NewWatchdog()
}
var cloud *virtigolib.CloudManager
cloud = virtigolib.NewCloud()
found, _ := cloud.FindDropletByName("www.wit.com")
if found == nil {
log.Info("d == nil")
} else {
log.Info("d == ", found)
}
startHTTP()
return nil
}

View File

@ -130,6 +130,10 @@ func drawWindow(win *gadgets.GenericWindow) {
} }
func updateUptimeGui(uptime string) { func updateUptimeGui(uptime string) {
if me.status == nil {
// gui is not initialized
return
}
me.status.SetLabel(uptime) me.status.SetLabel(uptime)
datestamp := time.Now().Format("2006-01-02 15:04:03") datestamp := time.Now().Format("2006-01-02 15:04:03")

View File

@ -31,7 +31,7 @@ func okHandler(w http.ResponseWriter, r *http.Request) {
} }
if route == "/uptime" { if route == "/uptime" {
ok, s := uptimeCheck() ok, s := uptimeCheck()
fmt.Fprint(w, s) fmt.Fprintln(w, s)
// log.Info(s) // log.Info(s)
updateUptimeGui(s) updateUptimeGui(s)
if ok { if ok {

237
main.go
View File

@ -4,17 +4,14 @@ package main
import ( import (
"embed" "embed"
"fmt"
"net/url" "net/url"
"os" "os"
"path/filepath" "path/filepath"
"time"
"github.com/google/uuid" "github.com/google/uuid"
"go.wit.com/dev/alexflint/arg" "go.wit.com/dev/alexflint/arg"
"go.wit.com/gui" "go.wit.com/gui"
"go.wit.com/lib/protobuf/virtpb" "go.wit.com/lib/protobuf/virtpb"
"go.wit.com/lib/virtigolib"
"go.wit.com/log" "go.wit.com/log"
) )
@ -101,143 +98,151 @@ func main() {
me.admin.doAdminGui() me.admin.doAdminGui()
okExit("admin close") okExit("admin close")
} }
os.Exit(-1)
// set defaults /*
me.unstable = time.Now() // initialize the grid as unstable // set defaults
me.changed = false me.unstable = time.Now() // initialize the grid as unstable
me.hmap = make(map[*virtpb.Hypervisor]*HyperT) me.changed = false
me.hmap = make(map[*virtpb.Hypervisor]*HyperT)
// how long a droplet can be missing until it's declared dead // how long a droplet can be missing until it's declared dead
me.unstableTimeout = 17 * time.Second me.unstableTimeout = 17 * time.Second
me.missingDropletTimeout = time.Minute // not sure the difference between these values me.missingDropletTimeout = time.Minute // not sure the difference between these values
// how often to poll the hypervisors // how often to poll the hypervisors
me.hyperPollDelay = 5 * time.Second me.hyperPollDelay = 5 * time.Second
// how long the cluster must be stable before new droplets can be started // how long the cluster must be stable before new droplets can be started
me.clusterStableDuration = 37 * time.Second me.clusterStableDuration = 37 * time.Second
me.cluster = virtpb.InitCluster() me.cluster = virtpb.InitCluster()
if err := me.cluster.ConfigLoad(); err != nil { if err := me.cluster.ConfigLoad(); err != nil {
log.Info("config load error", err) log.Info("config load error", err)
log.Info("") log.Info("")
log.Info("You have never run this before") log.Info("You have never run this before")
log.Info("init example cloud here") log.Info("init example cloud here")
log.Sleep(2) log.Sleep(2)
os.Exit(-1)
}
loop := me.cluster.DropletsAll() // get the list of droplets
for loop.Scan() {
d := loop.Next()
if d == nil {
fmt.Println("d == nil")
os.Exit(-1) os.Exit(-1)
} }
fmt.Println("Droplet UUID:", d.Uuid)
if d.Current == nil { loop := me.cluster.DropletsAll() // get the list of droplets
d.Current = new(virtpb.Current) for loop.Scan() {
d := loop.Next()
if d == nil {
fmt.Println("d == nil")
os.Exit(-1)
}
fmt.Println("Droplet UUID:", d.Uuid)
if d.Current == nil {
d.Current = new(virtpb.Current)
}
d.SetState(virtpb.DropletState_OFF)
log.Info("droplet", d.Hostname)
}
hmm := "pihole.wit.com"
d := me.cluster.FindDropletByName(hmm)
if d == nil {
log.Info("did not find found droplet", hmm)
} else {
log.Info("found droplet", d.Hostname, d)
} }
d.SetState(virtpb.DropletState_OFF)
log.Info("droplet", d.Hostname)
}
hmm := "pihole.wit.com"
d := me.cluster.FindDropletByName(hmm)
if d == nil {
log.Info("did not find found droplet", hmm)
} else {
log.Info("found droplet", d.Hostname, d)
}
var newEvents []*virtpb.Event var newEvents []*virtpb.Event
// sanity check the cluster & droplets // sanity check the cluster & droplets
if _, _, err := ValidateDroplets(); err != nil { if _, _, err := ValidateDroplets(); err != nil {
log.Info("todo: add flag to ignore. for now, fix problems in the config file.") log.Info("todo: add flag to ignore. for now, fix problems in the config file.")
os.Exit(0) os.Exit(0)
} }
newe, err := ValidateDiskFilenames() newe, err := ValidateDiskFilenames()
if err != nil {
log.Info(err)
os.Exit(-1)
}
// this is a new droplet. add it to the cluster
for _, e := range newe {
newEvents = append(newEvents, e)
}
ValidateUniqueFilenames()
for _, filename := range argv.Xml {
domcfg, err := virtigolib.ReadXml(filename)
if err != nil { if err != nil {
// parsing the libvirt xml file failed log.Info(err)
log.Info("error:", filename, err)
log.Info("readXml() error", filename)
log.Info("readXml() error", err)
log.Info("libvirt XML will have to be fixed by hand")
os.Exit(-1) os.Exit(-1)
} }
// this is a new droplet. add it to the cluster // this is a new droplet. add it to the cluster
log.Info("Add XML Droplet here", domcfg.Name)
_, newe, err := virtigolib.AddDomainDroplet(me.cluster, domcfg)
if err != nil {
log.Info("addDomainDroplet() error", filename)
log.Info("addDomainDroplet() error", err)
log.Info("libvirt XML will have to be fixed by hand")
os.Exit(-1)
}
for _, e := range newe { for _, e := range newe {
newEvents = append(newEvents, e) newEvents = append(newEvents, e)
} }
} ValidateUniqueFilenames()
for i, e := range newEvents {
log.Info(i, "Event:", e.Droplet, e.FieldName, "orig:", e.OrigVal, "new:", e.NewVal)
me.changed = true
}
if me.changed { for _, filename := range argv.Xml {
if err := me.cluster.ConfigSave(); err != nil { domcfg, err := virtigolib.ReadXml(filename)
log.Info("configsave error", err) if err != nil {
os.Exit(-1) // parsing the libvirt xml file failed
log.Info("error:", filename, err)
log.Info("readXml() error", filename)
log.Info("readXml() error", err)
log.Info("libvirt XML will have to be fixed by hand")
os.Exit(-1)
}
// this is a new droplet. add it to the cluster
log.Info("Add XML Droplet here", domcfg.Name)
_, newe, err := virtigolib.AddDomainDroplet(me.cluster, domcfg)
if err != nil {
log.Info("addDomainDroplet() error", filename)
log.Info("addDomainDroplet() error", err)
log.Info("libvirt XML will have to be fixed by hand")
os.Exit(-1)
}
for _, e := range newe {
newEvents = append(newEvents, e)
}
}
for i, e := range newEvents {
log.Info(i, "Event:", e.Droplet, e.FieldName, "orig:", e.OrigVal, "new:", e.NewVal)
me.changed = true
} }
log.Info("XML changes saved in protobuf config")
os.Exit(0)
}
if len(argv.Xml) != 0 {
log.Info("No XML changes found")
os.Exit(0)
}
// initialize each hypervisor if me.changed {
for _, pbh := range me.cluster.H.Hypervisors { if err := me.cluster.ConfigSave(); err != nil {
// this is a new unknown droplet (not in the config file) log.Info("configsave error", err)
var h *HyperT os.Exit(-1)
h = new(HyperT) }
h.pb = pbh log.Info("XML changes saved in protobuf config")
h.lastDroplets = make(map[string]time.Time) os.Exit(0)
h.lastpoll = time.Now() }
if len(argv.Xml) != 0 {
log.Info("No XML changes found")
os.Exit(0)
}
me.hmap[pbh] = h // initialize each hypervisor
me.hypers = append(me.hypers, h) for _, pbh := range me.cluster.H.Hypervisors {
log.Log(EVENT, "config new hypervisors", h.pb.Hostname) // this is a new unknown droplet (not in the config file)
} var h *HyperT
h = new(HyperT)
h.pb = pbh
h.lastDroplets = make(map[string]time.Time)
h.lastpoll = time.Now()
// start the watchdog polling for each hypervisor me.hmap[pbh] = h
for _, h := range me.hypers { me.hypers = append(me.hypers, h)
log.Info("starting polling on", h.pb.Hostname) log.Log(EVENT, "config new hypervisors", h.pb.Hostname)
}
// start a watchdog on each hypervisor // start the watchdog polling for each hypervisor
go h.NewWatchdog() for _, h := range me.hypers {
} log.Info("starting polling on", h.pb.Hostname)
var cloud *virtigolib.CloudManager // start a watchdog on each hypervisor
cloud = virtigolib.NewCloud() go h.NewWatchdog()
found, _ := cloud.FindDropletByName("www.wit.com") }
if found == nil {
log.Info("d == nil") var cloud *virtigolib.CloudManager
} else { cloud = virtigolib.NewCloud()
log.Info("d == ", found) found, _ := cloud.FindDropletByName("www.wit.com")
if found == nil {
log.Info("d == nil")
} else {
log.Info("d == ", found)
}
*/
if argv.Daemon {
if err := doDaemon(); err != nil {
badExit(err)
}
okExit("")
} }
// sit here // sit here