2024-10-11 13:55:13 -05:00
|
|
|
// Copyright 2024 WIT.COM Inc Licensed GPL 3.0
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2024-10-12 00:17:26 -05:00
|
|
|
"embed"
|
2024-10-31 13:37:00 -05:00
|
|
|
"fmt"
|
2024-10-11 13:55:13 -05:00
|
|
|
"os"
|
2024-10-23 00:48:35 -05:00
|
|
|
"path/filepath"
|
2024-10-13 04:34:55 -05:00
|
|
|
"time"
|
2024-10-11 13:55:13 -05:00
|
|
|
|
|
|
|
"go.wit.com/dev/alexflint/arg"
|
2024-10-25 03:11:55 -05:00
|
|
|
pb "go.wit.com/lib/protobuf/virtbuf"
|
2024-10-31 06:50:57 -05:00
|
|
|
"go.wit.com/lib/virtigolib"
|
2024-10-26 05:17:51 -05:00
|
|
|
"go.wit.com/log"
|
2024-10-11 13:55:13 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
var Version string
|
2024-10-12 00:17:26 -05:00
|
|
|
|
|
|
|
//go:embed resources/*
|
|
|
|
var resources embed.FS
|
2024-10-11 13:55:13 -05:00
|
|
|
|
|
|
|
func main() {
|
2024-10-23 00:48:35 -05:00
|
|
|
if os.Getenv("VIRTIGO_HOME") == "" {
|
|
|
|
homeDir, _ := os.UserHomeDir()
|
|
|
|
fullpath := filepath.Join(homeDir, ".config/virtigo")
|
|
|
|
os.Setenv("VIRTIGO_HOME", fullpath)
|
|
|
|
}
|
2024-10-24 15:14:47 -05:00
|
|
|
var pp *arg.Parser
|
|
|
|
pp = arg.MustParse(&argv)
|
2024-10-11 13:55:13 -05:00
|
|
|
|
2024-10-24 15:14:47 -05:00
|
|
|
if pp == nil {
|
2024-10-11 13:55:13 -05:00
|
|
|
pp.WriteHelp(os.Stdout)
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
|
|
|
|
2024-10-31 13:37:00 -05:00
|
|
|
// if argv.Daemon {
|
|
|
|
// log.DaemonMode(true)
|
|
|
|
// }
|
2024-10-12 19:44:43 -05:00
|
|
|
|
2024-10-23 02:56:55 -05:00
|
|
|
// set defaults
|
2024-10-27 11:02:50 -05:00
|
|
|
me.unstable = time.Now() // initialize the grid as unstable
|
2024-10-23 02:56:55 -05:00
|
|
|
me.changed = false
|
2024-10-26 08:54:28 -05:00
|
|
|
me.hmap = make(map[*pb.Hypervisor]*HyperT)
|
2024-10-27 02:29:45 -05:00
|
|
|
|
|
|
|
// how long a droplet can be missing until it's declared dead
|
2024-10-26 20:09:59 -05:00
|
|
|
me.unstableTimeout = 17 * time.Second
|
2024-10-27 07:06:12 -05:00
|
|
|
me.missingDropletTimeout = time.Minute // not sure the difference between these values
|
2024-10-26 07:28:19 -05:00
|
|
|
|
2024-10-27 11:02:50 -05:00
|
|
|
// how often to poll the hypervisors
|
|
|
|
me.hyperPollDelay = 5 * time.Second
|
|
|
|
|
2024-10-27 02:29:45 -05:00
|
|
|
// how long the cluster must be stable before new droplets can be started
|
2024-10-27 02:55:08 -05:00
|
|
|
me.clusterStableDuration = 37 * time.Second
|
2024-10-27 02:29:45 -05:00
|
|
|
|
2024-10-31 13:37:00 -05:00
|
|
|
me.cluster = pb.InitCluster()
|
2024-10-26 07:28:19 -05:00
|
|
|
if err := me.cluster.ConfigLoad(); err != nil {
|
|
|
|
log.Info("config load error", err)
|
2024-10-25 17:01:30 -05:00
|
|
|
os.Exit(-1)
|
|
|
|
}
|
2024-10-12 12:45:43 -05:00
|
|
|
|
2024-10-31 13:37:00 -05:00
|
|
|
loop := me.cluster.DropletsAll() // get the list of droplets
|
|
|
|
for loop.Scan() {
|
|
|
|
d := loop.Droplet()
|
|
|
|
if d == nil {
|
|
|
|
fmt.Println("d == nil")
|
|
|
|
os.Exit(-1)
|
|
|
|
}
|
|
|
|
fmt.Println("Droplet UUID:", d.Uuid)
|
2024-10-31 07:16:23 -05:00
|
|
|
if d.Current == nil {
|
|
|
|
d.Current = new(pb.Current)
|
|
|
|
}
|
2024-10-31 06:41:30 -05:00
|
|
|
d.Current.State = pb.DropletState_OFF
|
2024-10-31 13:37:00 -05:00
|
|
|
log.Info("droplet", d.Hostname)
|
2024-10-26 12:32:17 -05:00
|
|
|
}
|
|
|
|
hmm := "pihole.wit.com"
|
2024-10-31 06:41:30 -05:00
|
|
|
d := me.cluster.FindDropletByName(hmm)
|
2024-10-26 12:32:17 -05:00
|
|
|
if d == nil {
|
|
|
|
log.Info("did not find found droplet", hmm)
|
|
|
|
} else {
|
|
|
|
log.Info("found droplet", d.Hostname, d)
|
|
|
|
}
|
|
|
|
|
2024-10-25 19:16:44 -05:00
|
|
|
var newEvents []*pb.Event
|
|
|
|
|
2024-10-27 02:29:45 -05:00
|
|
|
// sanity check the cluster & droplets
|
2024-10-31 13:37:00 -05:00
|
|
|
if _, _, err := ValidateDroplets(); err != nil {
|
2024-10-27 02:55:08 -05:00
|
|
|
log.Info("todo: add flag to ignore. for now, fix problems in the config file.")
|
|
|
|
os.Exit(0)
|
|
|
|
}
|
2024-10-31 13:37:00 -05:00
|
|
|
newe, err := ValidateDiskFilenames()
|
2024-10-30 13:17:04 -05:00
|
|
|
if err != nil {
|
|
|
|
log.Info(err)
|
|
|
|
os.Exit(-1)
|
|
|
|
}
|
|
|
|
// this is a new droplet. add it to the cluster
|
2024-10-25 19:16:44 -05:00
|
|
|
for _, e := range newe {
|
|
|
|
newEvents = append(newEvents, e)
|
|
|
|
}
|
2024-10-31 13:37:00 -05:00
|
|
|
ValidateUniqueFilenames()
|
2024-10-25 19:16:44 -05:00
|
|
|
|
2024-10-23 01:31:17 -05:00
|
|
|
for _, filename := range argv.Xml {
|
2024-10-31 06:50:57 -05:00
|
|
|
domcfg, err := virtigolib.ReadXml(filename)
|
2024-10-23 02:56:55 -05:00
|
|
|
if err != nil {
|
2024-10-23 04:25:24 -05:00
|
|
|
// parsing the libvirt xml file failed
|
2024-10-23 02:56:55 -05:00
|
|
|
log.Info("error:", filename, err)
|
2024-10-25 15:46:49 -05:00
|
|
|
log.Info("readXml() error", filename)
|
|
|
|
log.Info("readXml() error", err)
|
|
|
|
log.Info("libvirt XML will have to be fixed by hand")
|
|
|
|
os.Exit(-1)
|
2024-10-23 02:56:55 -05:00
|
|
|
}
|
2024-10-25 16:08:55 -05:00
|
|
|
// this is a new droplet. add it to the cluster
|
|
|
|
log.Info("Add XML Droplet here", domcfg.Name)
|
2024-10-31 06:50:57 -05:00
|
|
|
_, newe, err := virtigolib.AddDomainDroplet(me.cluster, domcfg)
|
2024-10-23 02:56:55 -05:00
|
|
|
if err != nil {
|
2024-10-25 16:08:55 -05:00
|
|
|
log.Info("addDomainDroplet() error", filename)
|
|
|
|
log.Info("addDomainDroplet() error", err)
|
2024-10-25 15:46:49 -05:00
|
|
|
log.Info("libvirt XML will have to be fixed by hand")
|
|
|
|
os.Exit(-1)
|
2024-10-23 02:56:55 -05:00
|
|
|
}
|
2024-10-25 17:35:29 -05:00
|
|
|
for _, e := range newe {
|
|
|
|
newEvents = append(newEvents, e)
|
|
|
|
}
|
2024-10-23 02:56:55 -05:00
|
|
|
}
|
2024-10-25 19:16:44 -05:00
|
|
|
for i, e := range newEvents {
|
|
|
|
log.Info(i, "Event:", e.Droplet, e.FieldName, "orig:", e.OrigVal, "new:", e.NewVal)
|
|
|
|
me.changed = true
|
|
|
|
}
|
2024-10-26 08:54:28 -05:00
|
|
|
// if err := me.cluster.ConfigSave(); err != nil {
|
|
|
|
// log.Info("configsave error", err)
|
|
|
|
// }
|
2024-10-26 07:28:19 -05:00
|
|
|
|
2024-10-25 19:16:44 -05:00
|
|
|
if me.changed {
|
2024-10-29 22:55:28 -05:00
|
|
|
if err := me.cluster.ConfigSave(); err != nil {
|
|
|
|
log.Info("configsave error", err)
|
|
|
|
os.Exit(-1)
|
2024-10-23 06:06:38 -05:00
|
|
|
}
|
2024-10-29 22:55:28 -05:00
|
|
|
log.Info("XML changes saved in protobuf config")
|
|
|
|
os.Exit(0)
|
2024-10-25 19:16:44 -05:00
|
|
|
}
|
|
|
|
if len(argv.Xml) != 0 {
|
2024-10-25 16:08:55 -05:00
|
|
|
log.Info("No XML changes found")
|
2024-10-23 02:56:55 -05:00
|
|
|
os.Exit(0)
|
|
|
|
}
|
2024-10-22 19:57:49 -05:00
|
|
|
|
2024-10-26 08:54:28 -05:00
|
|
|
// initialize each hypervisor
|
2024-10-31 13:37:00 -05:00
|
|
|
for _, pbh := range me.cluster.H.Hypervisors {
|
2024-10-26 08:54:28 -05:00
|
|
|
// this is a new unknown droplet (not in the config file)
|
2024-10-27 11:02:50 -05:00
|
|
|
var h *HyperT
|
|
|
|
h = new(HyperT)
|
2024-10-26 08:54:28 -05:00
|
|
|
h.pb = pbh
|
2024-10-27 11:02:50 -05:00
|
|
|
h.lastDroplets = make(map[string]time.Time)
|
2024-10-26 08:54:28 -05:00
|
|
|
h.lastpoll = time.Now()
|
|
|
|
|
|
|
|
me.hmap[pbh] = h
|
2024-10-26 09:33:31 -05:00
|
|
|
me.hypers = append(me.hypers, h)
|
2024-10-26 08:54:28 -05:00
|
|
|
log.Log(EVENT, "config new hypervisors", h.pb.Hostname)
|
|
|
|
}
|
2024-10-25 22:07:28 -05:00
|
|
|
|
2024-10-23 00:54:37 -05:00
|
|
|
// start the watchdog polling for each hypervisor
|
|
|
|
for _, h := range me.hypers {
|
|
|
|
log.Info("starting polling on", h.pb.Hostname)
|
2024-10-26 21:13:25 -05:00
|
|
|
|
|
|
|
// start a watchdog on each hypervisor
|
2024-10-23 00:54:37 -05:00
|
|
|
go h.NewWatchdog()
|
|
|
|
}
|
2024-10-18 14:36:40 -05:00
|
|
|
|
2024-10-23 00:54:37 -05:00
|
|
|
// sit here
|
|
|
|
startHTTP()
|
|
|
|
}
|