start migration to protobufs

Signed-off-by: Jeff Carr <jcarr@wit.com>
This commit is contained in:
Jeff Carr 2024-10-22 17:27:24 -05:00
parent 3b64d342d2
commit 673bcc6cc9
8 changed files with 63 additions and 62 deletions

View File

@ -11,10 +11,8 @@ import (
"go.wit.com/log" "go.wit.com/log"
) )
var cluster *pb.Cluster
func readConfigFile() { func readConfigFile() {
cluster = new(pb.Cluster) me.cluster = new(pb.Cluster)
homeDir, _ := os.UserHomeDir() homeDir, _ := os.UserHomeDir()
fullname := filepath.Join(homeDir, ".config/virtigo.json") fullname := filepath.Join(homeDir, ".config/virtigo.json")
pfile, err := os.ReadFile(fullname) pfile, err := os.ReadFile(fullname)
@ -22,7 +20,7 @@ func readConfigFile() {
log.Info("open config file :", err) log.Info("open config file :", err)
return return
} }
err = cluster.UnmarshalJSON(pfile) err = me.cluster.UnmarshalJSON(pfile)
if err != nil { if err != nil {
log.Info("create json failed", err) log.Info("create json failed", err)
return return
@ -37,7 +35,7 @@ func writeConfigFile() {
log.Info("open config file :", err) log.Info("open config file :", err)
return return
} }
json := cluster.FormatJSON() json := me.cluster.FormatJSON()
fmt.Fprintln(cfgfile, json) fmt.Fprintln(cfgfile, json)
} }
@ -63,7 +61,6 @@ func readDropletFile(filename string) {
if d == nil { if d == nil {
// this is a new unknown droplet (not in the config file) // this is a new unknown droplet (not in the config file)
d = new(DropletT) d = new(DropletT)
d.Hostname = name
if len(fields) > 1 && fields[1] != "ON" { if len(fields) > 1 && fields[1] != "ON" {
d.ConfigState = "OFF" d.ConfigState = "OFF"
} else { } else {
@ -72,9 +69,9 @@ func readDropletFile(filename string) {
if len(fields) >= 3 { if len(fields) >= 3 {
d.hyperPreferred = fields[2] d.hyperPreferred = fields[2]
} }
d.pb = me.cluster.AddDroplet(name, 16, 256)
me.droplets = append(me.droplets, d) me.droplets = append(me.droplets, d)
log.Log(EVENT, "config new droplet", d.Hostname, d.ConfigState, d.hyperPreferred) log.Log(EVENT, "config new droplet", d.pb.Hostname, d.ConfigState, d.hyperPreferred)
cluster.AddDroplet(d.Hostname, 16, 256)
} else { } else {
log.Info("not sure what to do here. duplicate droplet", name, "in config file") log.Info("not sure what to do here. duplicate droplet", name, "in config file")
} }
@ -118,14 +115,13 @@ func addHypervisor(name string) *HyperT {
} }
log.Log(EVENT, "config new hypervisor", name) log.Log(EVENT, "config new hypervisor", name)
h = new(HyperT) h = new(HyperT)
h.Hostname = name
h.Autoscan = true h.Autoscan = true
h.Delay = 5 * time.Second h.Delay = 5 * time.Second
h.lastpoll = time.Now() h.lastpoll = time.Now()
h.Scan = func() { h.Scan = func() {
h.pollHypervisor() h.pollHypervisor()
} }
h.pb = me.cluster.AddHypervisor(name, 16, 256)
me.hypers = append(me.hypers, h) me.hypers = append(me.hypers, h)
cluster.AddHypervisor(name, 16, 256)
return h return h
} }

View File

@ -14,14 +14,14 @@ func (d *DropletT) Start() {
} }
func (h *HyperT) RestartDaemon() { func (h *HyperT) RestartDaemon() {
url := "http://" + h.Hostname + ":2520/kill" url := "http://" + h.pb.Hostname + ":2520/kill"
s := shell.Wget(url) s := shell.Wget(url)
log.Info("EVENT RestartDaemon", url, s) log.Info("EVENT RestartDaemon", url, s)
h.lastpoll = time.Now() h.lastpoll = time.Now()
h.killcount += 1 h.killcount += 1
dur := time.Since(h.lastpoll) // Calculate the elapsed time dur := time.Since(h.lastpoll) // Calculate the elapsed time
log.Info("KILLED DAEMON", h.Hostname, shell.FormatDuration(dur), "curl", url) log.Info("KILLED DAEMON", h.pb.Hostname, shell.FormatDuration(dur), "curl", url)
me.killcount += 1 me.killcount += 1
// mark the cluster as unstable so droplet starts can be throttled // mark the cluster as unstable so droplet starts can be throttled
@ -63,7 +63,7 @@ func (h *HyperT) Start(d *DropletT) (bool, string) {
return false, result return false, result
} }
url := "http://" + h.Hostname + ":2520/start?start=" + d.Hostname url := "http://" + h.pb.Hostname + ":2520/start?start=" + d.pb.Hostname
s := shell.Wget(url) s := shell.Wget(url)
result = "EVENT start droplet url: " + url + "\n" result = "EVENT start droplet url: " + url + "\n"
result += "EVENT start droplet response: " + s.String() result += "EVENT start droplet response: " + s.String()
@ -100,8 +100,8 @@ func Start(name string) (bool, string) {
// make the list of hypervisors that are active and can start new droplets // make the list of hypervisors that are active and can start new droplets
var pool []*HyperT var pool []*HyperT
for _, h := range me.hypers { for _, h := range me.hypers {
result += fmt.Sprintln("could start droplet on", name, "on", h.Hostname, h.Active) result += fmt.Sprintln("could start droplet on", name, "on", h.pb.Hostname, h.Active)
if d.hyperPreferred == h.Hostname { if d.hyperPreferred == h.pb.Hostname {
// the config file says this droplet should run on this hypervisor // the config file says this droplet should run on this hypervisor
a, b := h.Start(d) a, b := h.Start(d)
return a, result + b return a, result + b

12
http.go
View File

@ -28,10 +28,10 @@ func okHandler(w http.ResponseWriter, r *http.Request) {
} }
dur := time.Since(d.lastpoll) // Calculate the elapsed time dur := time.Since(d.lastpoll) // Calculate the elapsed time
if d.CurrentState != "ON" { if d.CurrentState != "ON" {
fmt.Fprintln(w, "BAD STATE ", d.Hostname, d.hname, "(", d.ConfigState, "vs", d.CurrentState, ")", shell.FormatDuration(dur)) fmt.Fprintln(w, "BAD STATE ", d.pb.Hostname, d.hname, "(", d.ConfigState, "vs", d.CurrentState, ")", shell.FormatDuration(dur))
} else { } else {
dur := time.Since(d.lastpoll) // Calculate the elapsed time dur := time.Since(d.lastpoll) // Calculate the elapsed time
fmt.Fprintln(w, "GOOD STATE ON", d.Hostname, d.hname, shell.FormatDuration(dur)) fmt.Fprintln(w, "GOOD STATE ON", d.pb.Hostname, d.hname, shell.FormatDuration(dur))
} }
} }
return return
@ -51,20 +51,20 @@ func okHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, s) fmt.Fprintln(w, s)
} }
for _, h := range me.hypers { for _, h := range me.hypers {
url := "http://" + h.Hostname + ":2520/kill" url := "http://" + h.pb.Hostname + ":2520/kill"
dur := time.Since(h.lastpoll) // Calculate the elapsed time dur := time.Since(h.lastpoll) // Calculate the elapsed time
if dur > 90*time.Second { if dur > 90*time.Second {
h.RestartDaemon() h.RestartDaemon()
continue continue
} }
if h.killcount != 0 { if h.killcount != 0 {
log.Info("KILL count =", h.killcount, "FOR", h.Hostname, dur, "curl", url) log.Info("KILL count =", h.killcount, "FOR", h.pb.Hostname, dur, "curl", url)
} }
if h.killcount > 10 { if h.killcount > 10 {
log.Info("KILL count is greater than 10 for host", h.Hostname, dur, "curl", url) log.Info("KILL count is greater than 10 for host", h.pb.Hostname, dur, "curl", url)
} }
// l := shell.FormatDuration(dur) // l := shell.FormatDuration(dur)
// log.Warn("HOST =", h.Hostname, "Last poll =", l) // log.Warn("HOST =", h.pb.Hostname, "Last poll =", l)
//if d.ConfigState != "ON" { //if d.ConfigState != "ON" {
// continue // continue
//} //}

View File

@ -54,7 +54,7 @@ func main() {
log.Info("droplet is unknown:", argv.Start) log.Info("droplet is unknown:", argv.Start)
os.Exit(0) os.Exit(0)
} }
log.Info("start droplet here:", d.Hostname) log.Info("start droplet here:", d.pb.Hostname)
domcfg := makeStandardXml(d) domcfg := makeStandardXml(d)
fmt.Printf("Virt type %s\n", domcfg.Type) fmt.Printf("Virt type %s\n", domcfg.Type)
@ -78,7 +78,7 @@ func main() {
macs = getMacs(domcfg) macs = getMacs(domcfg)
fmt.Printf("Virt mac addr:%s\n", macs) fmt.Printf("Virt mac addr:%s\n", macs)
qcow := "/home/nfs/" + d.Hostname + ".qcow2" qcow := "/home/nfs/" + d.pb.Hostname + ".qcow2"
setSimpleDisk(domcfg, qcow) setSimpleDisk(domcfg, qcow)
writeoutXml(domcfg, "blahcarr") writeoutXml(domcfg, "blahcarr")
@ -87,7 +87,7 @@ func main() {
// start the watchdog polling for each hypervisor // start the watchdog polling for each hypervisor
for _, h := range me.hypers { for _, h := range me.hypers {
log.Info("starting polling on", h.Hostname) log.Info("starting polling on", h.pb.Hostname)
go h.NewWatchdog() go h.NewWatchdog()
} }

38
poll.go
View File

@ -10,7 +10,7 @@ import (
) )
func (h *HyperT) pollHypervisor() { func (h *HyperT) pollHypervisor() {
url := "http://" + h.Hostname + ":2520/vms" url := "http://" + h.pb.Hostname + ":2520/vms"
log.Log(POLL, "wget url =", url) log.Log(POLL, "wget url =", url)
s := shell.Wget(url) s := shell.Wget(url)
if s == nil { if s == nil {
@ -30,26 +30,26 @@ func (h *HyperT) pollHypervisor() {
state := fields[0] state := fields[0]
name := fields[1] name := fields[1]
if state == "ON" { if state == "ON" {
log.Log(POLL, h.Hostname, "STATE:", state, "HOST:", name, "rest:", fields[2:]) log.Log(POLL, h.pb.Hostname, "STATE:", state, "HOST:", name, "rest:", fields[2:])
d := findDroplet(name) d := findDroplet(name)
if d == nil { if d == nil {
// this is a new unknown droplet (not in the config file) // this is a new unknown droplet (not in the config file)
d = new(DropletT) d = new(DropletT)
d.Hostname = name d.pb.Hostname = name
d.hname = h.Hostname d.hname = h.pb.Hostname
d.lastpoll = time.Now() d.lastpoll = time.Now()
d.CurrentState = "ON" d.CurrentState = "ON"
me.droplets = append(me.droplets, d) me.droplets = append(me.droplets, d)
log.Log(EVENT, name, "IS NEW. ADDED ON", h.Hostname) log.Log(EVENT, name, "IS NEW. ADDED ON", h.pb.Hostname)
} }
log.Log(INFO, "ALREADY RECORDED", d.Hostname) log.Log(INFO, "ALREADY RECORDED", d.pb.Hostname)
// update the status to ON and the last polled value // update the status to ON and the last polled value
d.CurrentState = "ON" d.CurrentState = "ON"
d.lastpoll = time.Now() d.lastpoll = time.Now()
// this means the droplet is still where it was before // this means the droplet is still where it was before
if d.hname == h.Hostname { if d.hname == h.pb.Hostname {
continue continue
} }
@ -58,15 +58,15 @@ func (h *HyperT) pollHypervisor() {
// but this is the first time it's shown up as running // but this is the first time it's shown up as running
// this should mean a droplet is running where the config file says it probably should be running // this should mean a droplet is running where the config file says it probably should be running
if d.hyperPreferred == h.Hostname { if d.hyperPreferred == h.pb.Hostname {
log.Log(EVENT, "new droplet", d.Hostname, "(matches config hypervisor", h.Hostname+")") log.Log(EVENT, "new droplet", d.pb.Hostname, "(matches config hypervisor", h.pb.Hostname+")")
d.hname = h.Hostname d.hname = h.pb.Hostname
continue continue
} }
log.Log(EVENT, "new droplet", d.Hostname, "on", h.Hostname, "(in config file without preferred hypervisor)") log.Log(EVENT, "new droplet", d.pb.Hostname, "on", h.pb.Hostname, "(in config file without preferred hypervisor)")
} }
d.hname = h.Hostname d.hname = h.pb.Hostname
} }
continue continue
} }
@ -76,7 +76,7 @@ func (h *HyperT) pollHypervisor() {
func findDroplet(name string) *DropletT { func findDroplet(name string) *DropletT {
for _, d := range me.droplets { for _, d := range me.droplets {
if d.Hostname == name { if d.pb.Hostname == name {
return d return d
} }
} }
@ -85,7 +85,7 @@ func findDroplet(name string) *DropletT {
func findHypervisor(name string) *HyperT { func findHypervisor(name string) *HyperT {
for _, h := range me.hypers { for _, h := range me.hypers {
if h.Hostname == name { if h.pb.Hostname == name {
return h return h
} }
} }
@ -110,19 +110,19 @@ func clusterHealthy() (bool, string) {
} }
dur := time.Since(d.lastpoll) // Calculate the elapsed time dur := time.Since(d.lastpoll) // Calculate the elapsed time
if d.CurrentState == "" { if d.CurrentState == "" {
// log.Info("SKIP. hostname has not been polled yet", d.Hostname, d.hname) // log.Info("SKIP. hostname has not been polled yet", d.pb.Hostname, d.hname)
unknown += 1 unknown += 1
unknownList = append(unknownList, d.Hostname) unknownList = append(unknownList, d.pb.Hostname)
continue continue
} }
if d.CurrentState != "ON" { if d.CurrentState != "ON" {
log.Info("BAD STATE", d.ConfigState, d.Hostname, d.hname, "CurrentState =", d.CurrentState, shell.FormatDuration(dur)) log.Info("BAD STATE", d.ConfigState, d.pb.Hostname, d.hname, "CurrentState =", d.CurrentState, shell.FormatDuration(dur))
good = false good = false
failed += 1 failed += 1
} else { } else {
dur := time.Since(d.lastpoll) // Calculate the elapsed time dur := time.Since(d.lastpoll) // Calculate the elapsed time
if dur > time.Minute { if dur > time.Minute {
log.Info("GOOD STATE MISSING", d.Hostname, d.hname, shell.FormatDuration(dur)) log.Info("GOOD STATE MISSING", d.pb.Hostname, d.hname, shell.FormatDuration(dur))
good = false good = false
d.CurrentState = "MISSING" d.CurrentState = "MISSING"
failed += 1 failed += 1
@ -135,7 +135,7 @@ func clusterHealthy() (bool, string) {
continue continue
} }
working += 1 working += 1
// log.Info("GOOD STATE ON", d.Hostname, d.hname, "dur =", l) // log.Info("GOOD STATE ON", d.pb.Hostname, d.hname, "dur =", l)
} }
} }
var summary string = "(" var summary string = "("

View File

@ -1,6 +1,10 @@
package main package main
import "time" import (
"time"
pb "go.wit.com/lib/protobuf/virtbuf"
)
var me virtigoT var me virtigoT
@ -16,6 +20,7 @@ func (b *virtigoT) Enable() {
// this app's variables // this app's variables
type virtigoT struct { type virtigoT struct {
cluster *pb.Cluster
names []string names []string
hypers []*HyperT hypers []*HyperT
droplets []*DropletT droplets []*DropletT
@ -25,24 +30,24 @@ type virtigoT struct {
// the stuff that is needed for a hypervisor // the stuff that is needed for a hypervisor
type HyperT struct { type HyperT struct {
Hostname string // the hypervisor hostname pb *pb.Hypervisor // the Hypervisor protobuf
Active bool // is allowed to start new droplets Active bool // is allowed to start new droplets
Scan func() // the function to run to scan the hypervisor Scan func() // the function to run to scan the hypervisor
Autoscan bool // to scan or not to scan Autoscan bool // to scan or not to scan
Delay time.Duration // how often to poll the hypervisor Delay time.Duration // how often to poll the hypervisor
Dog *time.Ticker // the watchdog timer itself Dog *time.Ticker // the watchdog timer itself
lastpoll time.Time // the last time the hypervisor polled lastpoll time.Time // the last time the hypervisor polled
killcount int killcount int
} }
// the stuff that is needed for a hypervisor // the stuff that is needed for a hypervisor
type DropletT struct { type DropletT struct {
Hostname string // the name of the virtual machine. should be unique (probably enforce this forever) pb *pb.Droplet // the Droplet protobuf
ConfigState string // what the state of the droplet is SUPPOSED TO BE ConfigState string // what the state of the droplet is SUPPOSED TO BE
CurrentState string // what the state of the droplet is ACTUALLY IS CurrentState string // what the state of the droplet is ACTUALLY IS
hyperPreferred string // the hypervisor to prefer to run the droplet on hyperPreferred string // the hypervisor to prefer to run the droplet on
hname string // the hypervisor it's currently running on hname string // the hypervisor it's currently running on
h *HyperT // 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 lastpoll time.Time // the last time the droplet was seen running
starts int // how many times a start event has been attempted starts int // how many times a start event has been attempted
} }

View File

@ -31,7 +31,7 @@ func (h *HyperT) NewWatchdog() {
fmt.Println("Done!") fmt.Println("Done!")
return return
case t := <-h.Dog.C: case t := <-h.Dog.C:
log.Log(POLL, "Watchdog() ticked", h.Hostname, "Current time: ", t) log.Log(POLL, "Watchdog() ticked", h.pb.Hostname, "Current time: ", t)
h.Scan() h.Scan()
} }
} }

4
xml.go
View File

@ -11,7 +11,7 @@ import (
) )
func makeStandardXml(d *DropletT) *libvirtxml.Domain { func makeStandardXml(d *DropletT) *libvirtxml.Domain {
log.Info("create new xml file for:", d.Hostname) log.Info("create new xml file for:", d.pb.Hostname)
domcfg := &libvirtxml.Domain{} domcfg := &libvirtxml.Domain{}
addDefaults(domcfg, "standard.x86") addDefaults(domcfg, "standard.x86")
@ -19,7 +19,7 @@ func makeStandardXml(d *DropletT) *libvirtxml.Domain {
addDefaults(domcfg, "network") addDefaults(domcfg, "network")
addDefaults(domcfg, "spice") addDefaults(domcfg, "spice")
addDefaults(domcfg, "qcow") addDefaults(domcfg, "qcow")
addDefaults(domcfg, d.Hostname) addDefaults(domcfg, d.pb.Hostname)
return domcfg return domcfg
} }