Compare commits

..

25 Commits

Author SHA1 Message Date
Jeff Carr e6fb7352ae quiet debugging 2025-04-23 02:43:18 -05:00
Jeff Carr c9ef4f0b82 make an EDIT event 2025-04-22 20:50:00 -05:00
Jeff Carr 688b5039a0 new ConfigSave() 2025-04-21 20:54:45 -05:00
Jeff Carr 814d36b9c9 working on droplet start event 2025-04-21 20:54:43 -05:00
Jeff Carr a07033d181 move these into cluster.pb 2025-04-21 20:54:38 -05:00
Jeff Carr 7cdb2a33ef do a whole cluster protobuf at once 2025-04-20 19:41:02 -05:00
Jeff Carr 63148556af add Name and allow multiple URLs 2025-04-12 11:28:05 -05:00
Jeff Carr a510dd6474 this is actually a 'scanner' 2025-03-27 07:31:50 -05:00
Jeff Carr e4345c8ad6 moving to a cluster.proto config file 2025-03-24 21:54:13 -05:00
Jeff Carr 276c5cec2f pass out hypervisors 2025-03-11 04:02:45 -05:00
Jeff Carr e78fc1235e rm code now made by autogenpb 2025-03-10 18:10:40 -05:00
Jeff Carr c82997ed61 hypervisor poll time attempt 1 2025-02-23 13:13:30 -06:00
Jeff Carr 4aef241137 update worked to gocui 2025-02-23 13:13:30 -06:00
Jeff Carr c6cb62c86d sends the table across 2025-02-23 13:13:30 -06:00
Jeff Carr 0f546d57fc set uuid 2025-02-23 13:13:30 -06:00
Jeff Carr 13159b5b64 add daemon killcount and lastpoll 2025-02-23 13:13:30 -06:00
Jeff Carr 9dfcbb0432 early attempt at pb table update() 2025-02-23 13:13:30 -06:00
Jeff Carr 3ca7403aa6 minor 2025-02-23 13:13:30 -06:00
Jeff Carr 65f9089a7a remove _ names rather than fix the autogenpb parser 2025-02-22 18:17:31 -06:00
Jeff Carr b25d86f277 also need gui table support for this 2025-02-22 18:14:49 -06:00
Jeff Carr d40dc91130 switch virtbuf to virtpb 2025-02-22 17:45:59 -06:00
Jeff Carr 2381c65887 cleanups for gui pb tables 2025-02-22 15:23:40 -06:00
Jeff Carr ddc0410126 fix proto files to conform with autogenpb 2025-02-07 04:41:25 -06:00
Jeff Carr 9160268326 duh. TRUNCATE on new files 2024-12-11 13:54:36 -06:00
Jeff Carr 0888e51c91 trick to easily detect protobuf libraries 2024-12-02 05:15:58 -06:00
18 changed files with 269 additions and 212 deletions

4
.gitignore vendored
View File

@ -1,5 +1,3 @@
go.* go.*
*.pb.go *.pb.go
*.swp
example/example

3
.protobuf Normal file
View File

@ -0,0 +1,3 @@
droplet.proto
event.proto
hypervisor.proto

View File

@ -3,7 +3,7 @@
# cd ~/go/src/google.golang.org/protobuf/cmd/protoc-gen-go # cd ~/go/src/google.golang.org/protobuf/cmd/protoc-gen-go
# go install # go install
all: droplet.pb.go hypervisor.pb.go event.pb.go experiments.pb.go vet all: proto goimports vet
vet: vet:
@GO111MODULE=off go vet @GO111MODULE=off go vet
@ -22,6 +22,8 @@ clean:
rm -f *.pb.go rm -f *.pb.go
-rm -f go.* -rm -f go.*
proto:droplet.pb.go hypervisor.pb.go event.pb.go cluster.pb.go
droplet.pb.go: droplet.proto droplet.pb.go: droplet.proto
autogenpb --proto droplet.proto autogenpb --proto droplet.proto
@ -31,8 +33,8 @@ hypervisor.pb.go: hypervisor.proto
event.pb.go: event.proto event.pb.go: event.proto
autogenpb --proto event.proto autogenpb --proto event.proto
experiments.pb.go: experiments.proto cluster.pb.go: cluster.proto
autogenpb --proto experiments.proto autogenpb --proto cluster.proto
deps: deps:
apt install golang-goprotobuf-dev apt install golang-goprotobuf-dev

35
add.go
View File

@ -1,4 +1,4 @@
package virtbuf package virtpb
import ( import (
"fmt" "fmt"
@ -9,7 +9,7 @@ import (
) )
/* /*
func (c *Cluster) InitDroplet(hostname string) (*Droplet, error) { func (c *OldCluster) InitDroplet(hostname string) (*Droplet, error) {
var d *Droplet var d *Droplet
d = new(Droplet) d = new(Droplet)
d.Current = new(Current) d.Current = new(Current)
@ -50,7 +50,7 @@ func (x *Hypervisor) SetMemoryGB(gb int) {
x.Memory = int64(gb * 1024 * 1024 * 1024) x.Memory = int64(gb * 1024 * 1024 * 1024)
} }
func (c *Cluster) FindDropletByName(name string) *Droplet { func (c *OldCluster) FindDropletByName(name string) *Droplet {
loop := c.d.All() // get the list of droplets loop := c.d.All() // get the list of droplets
for loop.Scan() { for loop.Scan() {
d := loop.Next() d := loop.Next()
@ -61,7 +61,20 @@ func (c *Cluster) FindDropletByName(name string) *Droplet {
return nil return nil
} }
func (c *Cluster) FindHypervisorByName(name string) *Hypervisor { func (c *OldCluster) FindDropletByUuid(id string) *Droplet {
/*
log.Info("START FIND", id)
loop := c.d.All() // get the list of droplets
for loop.Scan() {
d := loop.Next()
log.Info("droplet:", d.Hostname, d.Uuid)
}
log.Info("END FIND", id)
*/
return c.d.FindByUuid(id)
}
func (c *OldCluster) FindHypervisorByName(name string) *Hypervisor {
for _, h := range c.H.Hypervisors { for _, h := range c.H.Hypervisors {
if h.Hostname == name { if h.Hostname == name {
return h return h
@ -70,7 +83,7 @@ func (c *Cluster) FindHypervisorByName(name string) *Hypervisor {
return nil return nil
} }
func (c *Cluster) AddHypervisor(hostname string, cpus int, mem int) *Hypervisor { func (c *OldCluster) AddHypervisor(hostname string, cpus int, mem int) *Hypervisor {
h := c.FindHypervisorByName(hostname) h := c.FindHypervisorByName(hostname)
if h != nil { if h != nil {
return h return h
@ -91,7 +104,7 @@ func (c *Cluster) AddHypervisor(hostname string, cpus int, mem int) *Hypervisor
return h return h
} }
func (c *Cluster) AddEvent(e *Event) { func (c *OldCluster) AddEvent(e *Event) {
c.e.Events = append(c.e.Events, e) c.e.Events = append(c.e.Events, e)
} }
@ -109,7 +122,7 @@ func NewDefaultDroplet(hostname string) *Droplet {
return d return d
} }
func (c *Cluster) AddDropletSimple(uuid string, hostname string, cpus int, mem int) *Droplet { func (c *OldCluster) AddDropletSimple(uuid string, hostname string, cpus int, mem int) *Droplet {
d := c.FindDropletByName(hostname) d := c.FindDropletByName(hostname)
if d != nil { if d != nil {
return d return d
@ -131,7 +144,7 @@ func (c *Cluster) AddDropletSimple(uuid string, hostname string, cpus int, mem i
} }
// This isn't for the marketing department // This isn't for the marketing department
func (c *Cluster) AddDropletLocal(name string, hypername string) *Droplet { func (c *OldCluster) AddDropletLocal(name string, hypername string) *Droplet {
d := &Droplet{ d := &Droplet{
Hostname: name, Hostname: name,
} }
@ -149,7 +162,7 @@ func (c *Cluster) AddDropletLocal(name string, hypername string) *Droplet {
return d return d
} }
func (c *Cluster) BlankFields() { func (c *OldCluster) BlankFields() {
loop := c.d.All() // get the list of droplets loop := c.d.All() // get the list of droplets
for loop.Scan() { for loop.Scan() {
d := loop.Next() d := loop.Next()
@ -161,7 +174,7 @@ func (epb *Events) AppendEvent(e *Event) {
epb.Events = append(epb.Events, e) epb.Events = append(epb.Events, e)
} }
func (c *Cluster) ClusterStable() (bool, string) { func (c *OldCluster) ClusterStable() (bool, string) {
last := time.Since(c.Unstable.AsTime()) last := time.Since(c.Unstable.AsTime())
if last > c.UnstableTimeout.AsDuration() { if last > c.UnstableTimeout.AsDuration() {
// the cluster has not been stable for 133 seconds // the cluster has not been stable for 133 seconds
@ -173,7 +186,7 @@ func (c *Cluster) ClusterStable() (bool, string) {
} }
// check the cluster and droplet to make sure it's ready to start // check the cluster and droplet to make sure it's ready to start
func (c *Cluster) DropletReady(d *Droplet) (bool, string) { func (c *OldCluster) DropletReady(d *Droplet) (bool, string) {
if c == nil { if c == nil {
return false, "cluster == nil" return false, "cluster == nil"
} }

View File

@ -1,4 +1,4 @@
package virtbuf package virtpb
// thank chatgpt for this because why. why write this if you can have it // thank chatgpt for this because why. why write this if you can have it
// kick this out in 30 seconds // kick this out in 30 seconds

View File

@ -1,4 +1,4 @@
package virtbuf package virtpb
import ( import (
// "reflect" // "reflect"
@ -73,7 +73,7 @@ func (d *Droplet) NewChangeEvent(fname string, origval any, newval any) *Event {
var e *Event var e *Event
e = new(Event) e = new(Event)
e.Droplet = d.Hostname e.DropletName = d.Hostname
e.OrigVal = convertToString(origval) e.OrigVal = convertToString(origval)
e.NewVal = convertToString(newval) e.NewVal = convertToString(newval)
e.FieldName = fname e.FieldName = fname
@ -99,12 +99,12 @@ func NewAddEvent(a any, fname string, newval any) *Event {
case *Droplet: case *Droplet:
var d *Droplet var d *Droplet
d = a.(*Droplet) d = a.(*Droplet)
e.Droplet = d.Hostname e.DropletName = d.Hostname
case nil: case nil:
e.Droplet = "<nil>" e.DropletName = "<nil>"
default: default:
log.Info("newAddEvent() unknown type", v) log.Info("newAddEvent() unknown type", v)
e.Droplet = "on something somewhere" e.DropletName = "on something somewhere"
} }
e.NewVal = convertToString(newval) e.NewVal = convertToString(newval)
@ -163,7 +163,7 @@ func (d *Droplet) SetState(newState DropletState) {
} }
// records an event that the droplet changed state (aka turned on, turned off, etc) // records an event that the droplet changed state (aka turned on, turned off, etc)
func (c *Cluster) ChangeDropletState(d *Droplet, newState DropletState) error { func (c *OldCluster) ChangeDropletState(d *Droplet, newState DropletState) error {
if c == nil { if c == nil {
return errors.New("cluster is nil") return errors.New("cluster is nil")
} }
@ -177,7 +177,7 @@ func (c *Cluster) ChangeDropletState(d *Droplet, newState DropletState) error {
var e *Event var e *Event
e = new(Event) e = new(Event)
e.Droplet = d.Hostname e.DropletName = d.Hostname
e.OrigVal = convertToString(d.Current.State) e.OrigVal = convertToString(d.Current.State)
e.NewVal = convertToString(newState) e.NewVal = convertToString(newState)
e.FieldName = "status" e.FieldName = "status"
@ -190,7 +190,7 @@ func (c *Cluster) ChangeDropletState(d *Droplet, newState DropletState) error {
} }
// records an event that the droplet migrated to another hypervisor // records an event that the droplet migrated to another hypervisor
func (c *Cluster) DropletMoved(d *Droplet, newh *Hypervisor) error { func (c *OldCluster) DropletMoved(d *Droplet, newh *Hypervisor) error {
if c == nil { if c == nil {
return errors.New("cluster is nil") return errors.New("cluster is nil")
} }
@ -209,7 +209,7 @@ func (c *Cluster) DropletMoved(d *Droplet, newh *Hypervisor) error {
var e *Event var e *Event
e = new(Event) e = new(Event)
e.Droplet = d.Hostname e.DropletName = d.Hostname
e.OrigVal = d.Current.Hypervisor e.OrigVal = d.Current.Hypervisor
e.NewVal = newh.Hostname e.NewVal = newh.Hostname
e.FieldName = "droplet migrate" e.FieldName = "droplet migrate"

23
cluster.proto Normal file
View File

@ -0,0 +1,23 @@
syntax = "proto3";
package virtpb;
import "google/protobuf/timestamp.proto";
import "droplet.proto";
import "hypervisor.proto";
import "event.proto";
message Cluster { // `autogenpb:marshal`
string uuid = 1; // `autogenpb:unique`
string name = 2;
repeated string URL = 3;
google.protobuf.Timestamp ctime = 4; // when the cluster was created
Droplets droplets = 5;
Hypervisors hypervisors = 6;
Events events = 7;
}
message Clusters { // `autogenpb:marshal`
string uuid = 1; // `autogenpb:uuid:57ddd763-75f6-4003-bf0e-8dd0f8a44044`
string version = 2; // `autogenpb:version:v0.0.1`
repeated Cluster clusters = 3;
}

100
config.go
View File

@ -1,4 +1,4 @@
package virtbuf package virtpb
// functions to import and export the protobuf // functions to import and export the protobuf
// data to and from config files // data to and from config files
@ -9,14 +9,37 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"go.wit.com/log"
"google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoreflect"
) )
func (c *Cluster) ConfigSave() error {
name := c.Name
if name == "" {
name = c.Uuid
}
fullname := filepath.Join(os.Getenv("VIRTIGO_HOME"), name+".pb")
cfgfile, err := os.OpenFile(fullname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
defer cfgfile.Close()
if err != nil {
fmt.Println("open config file :", err)
return err
}
log.Info("ConfigSave()", fullname)
data, err := c.Marshal()
if err != nil {
fmt.Println("cluster Marshal() err:", err)
return err
}
fmt.Fprintln(cfgfile, data)
return nil
}
// writes out the cluster information it seperate files // writes out the cluster information it seperate files
// to make it humanly possible to hand edit things as needed // to make it humanly possible to hand edit things as needed
func (c *Cluster) ConfigSave() error { func (c *OldCluster) ConfigSave() error {
// try to backup the current cluster config files // try to backup the current cluster config files
if err := backupConfig(); err != nil { if err := backupConfig(); err != nil {
return err return err
@ -34,20 +57,12 @@ func (c *Cluster) ConfigSave() error {
for _, drop := range dcopy.Droplets { for _, drop := range dcopy.Droplets {
drop.Current = nil drop.Current = nil
} }
if err := ConfigWriteJSON(dcopy, "droplets.json"); err != nil {
fmt.Println("droplets.json write failed")
return err
}
if err := ConfigWriteTEXT(dcopy, "droplets.text"); err != nil { if err := ConfigWriteTEXT(dcopy, "droplets.text"); err != nil {
fmt.Println("droplets.json write failed") fmt.Println("droplets.json write failed")
return err return err
} }
c.configWriteDroplets() c.configWriteDroplets()
if err := ConfigWriteJSON(c.H, "hypervisors.json"); err != nil {
fmt.Println("hypervisors.json write failed")
return err
}
if err := ConfigWriteTEXT(c.H, "hypervisors.text"); err != nil { if err := ConfigWriteTEXT(c.H, "hypervisors.text"); err != nil {
fmt.Println("hypervisors.json write failed") fmt.Println("hypervisors.json write failed")
return err return err
@ -64,27 +79,27 @@ func (c *Cluster) ConfigSave() error {
return nil return nil
} }
func (c *Cluster) ConfigLoad() error { func (c *OldCluster) ConfigLoad() error {
if c == nil { if c == nil {
return errors.New("It's not safe to run ConfigLoad() on a nil cluster") return errors.New("It's not safe to run ConfigLoad() on a nil cluster")
} }
if data, err := loadFile("droplets.json"); err == nil { if data, err := loadFile("droplets.text"); err == nil {
if err = protojson.Unmarshal(data, c.d); err != nil { if err = prototext.Unmarshal(data, c.d); err != nil {
fmt.Println("broken droplets.json config file") fmt.Println("broken droplets.text config file")
return err return err
} }
} else { } else {
return err return err
} }
if data, err := loadFile("hypervisors.json"); err == nil { if data, err := loadFile("hypervisors.text"); err == nil {
if err = protojson.Unmarshal(data, c.H); err != nil { if err = prototext.Unmarshal(data, c.H); err != nil {
fmt.Println("broken hypervisors.json config file") fmt.Println("broken hypervisors.text config file")
return err return err
} }
} else { } else {
fmt.Println("ERROR HERE IN Hypervisors") log.Warn("ERROR HERE IN Hypervisors")
return err return err
} }
@ -93,8 +108,11 @@ func (c *Cluster) ConfigLoad() error {
// does it not stay allocated after this function ends? // does it not stay allocated after this function ends?
c.e = new(Events) c.e = new(Events)
} }
if err := c.e.loadEvents(); err != nil { if err := c.e.loadEvents(); err != nil {
return err // ignore events.pb since these should be sent elsewhere
log.Warn("Events failed to load, ignoring:", err)
return nil
} }
return nil return nil
} }
@ -142,7 +160,7 @@ func loadFile(filename string) ([]byte, error) {
func ConfigWriteJSON(a any, filename string) error { func ConfigWriteJSON(a any, filename string) error {
fullname := filepath.Join(os.Getenv("VIRTIGO_HOME"), filename) fullname := filepath.Join(os.Getenv("VIRTIGO_HOME"), filename)
cfgfile, err := os.OpenFile(fullname, os.O_RDWR|os.O_CREATE, 0666) cfgfile, err := os.OpenFile(fullname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
defer cfgfile.Close() defer cfgfile.Close()
if err != nil { if err != nil {
fmt.Println("open config file :", err) fmt.Println("open config file :", err)
@ -157,9 +175,26 @@ func ConfigWriteJSON(a any, filename string) error {
return nil return nil
} }
func (c *OldCluster) configWriteDroplets() error {
fullname := filepath.Join(os.Getenv("VIRTIGO_HOME"), "droplets.new.text")
cfgfile, err := os.OpenFile(fullname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
defer cfgfile.Close()
if err != nil {
fmt.Println("open config file :", err)
return err
}
loop := c.d.All() // get the list of droplets
for loop.Scan() {
d := loop.Next()
text := prototext.Format(d)
fmt.Fprintln(cfgfile, text)
}
return nil
}
func ConfigWriteTEXT(a any, filename string) error { func ConfigWriteTEXT(a any, filename string) error {
fullname := filepath.Join(os.Getenv("VIRTIGO_HOME"), filename) fullname := filepath.Join(os.Getenv("VIRTIGO_HOME"), filename)
cfgfile, err := os.OpenFile(fullname, os.O_RDWR|os.O_CREATE, 0666) cfgfile, err := os.OpenFile(fullname, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644)
defer cfgfile.Close() defer cfgfile.Close()
if err != nil { if err != nil {
fmt.Println("open config file :", err) fmt.Println("open config file :", err)
@ -174,19 +209,18 @@ func ConfigWriteTEXT(a any, filename string) error {
return nil return nil
} }
func (c *Cluster) configWriteDroplets() error { func (c *Clusters) ConfigLoad() error {
fullname := filepath.Join(os.Getenv("VIRTIGO_HOME"), "droplets.new.text") if c == nil {
cfgfile, err := os.OpenFile(fullname, os.O_RDWR|os.O_CREATE, 0666) return errors.New("It's not safe to run ConfigLoad() on a nil cluster")
defer cfgfile.Close()
if err != nil {
fmt.Println("open config file :", err)
return err
} }
loop := c.d.All() // get the list of droplets
for loop.Scan() { if data, err := loadFile("cluster.text"); err == nil {
d := loop.Next() if err = prototext.Unmarshal(data, c); err != nil {
text := prototext.Format(d) fmt.Println("broken cluster.textconfig file")
fmt.Fprintln(cfgfile, text) return err
}
} else {
return err
} }
return nil return nil
} }

View File

@ -1,4 +1,4 @@
package virtbuf package virtpb
// thank chatgpt for this because why. why write this if you can have it // thank chatgpt for this because why. why write this if you can have it
// kick this out in 30 seconds // kick this out in 30 seconds

View File

@ -1,83 +1,82 @@
syntax = "proto3"; syntax = "proto3";
package virtbuf; package virtpb;
import "google/protobuf/duration.proto"; // Import the well-known type for Timestamp import "google/protobuf/duration.proto"; // Import the well-known type for Timestamp
import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp
// global settings for autogenpb `autogenpb:mutex` // global settings for autogenpb `autogenpb:mutex`
message Droplets { // `autogenpb:marshal` message Droplets { // `autogenpb:marshal` `autogenpb:gui`
string uuid = 1; // I guess why not just have this on each file string uuid = 1; // `autogenpb:uuid:d5d492e2-38d4-476b-86f3-f5abf01f9d6d`
string version = 2; // maybe can be used for protobuf schema change violations string version = 2; // `autogenpb:version:v0.0.1`
repeated Droplet droplets = 3; repeated Droplet droplets = 3;
} }
message Droplet { // `autogenpb:marshal` message Droplet { // `autogenpb:marshal`
string uuid = 1; // `autogenpb:unique` // should be unique across the cluster string uuid = 1; // `autogenpb:unique` // should be unique across the cluster
string hostname = 2; // `autogenpb:unique` // should be unique and work in DNS string hostname = 2; // `autogenpb:unique` // should be unique and work in DNS
int64 cpus = 3; // what's the point of int64 vs int32 int64 cpus = 3; // what's the point of int64 vs int32
int64 memory = 4; // in bytes int64 memory = 4; // in bytes
Current current = 5; // what the state and values of the droplet is Current current = 5; // what the state and values of the droplet is
DropletState start_state = 6; // what the state of the droplet is SUPPOSED TO BE ('on' or 'off') DropletState startState = 6; // what the state of the droplet is SUPPOSED TO BE ('on' or 'off')
string qemu_machine = 7; // the qemu machine type to use "pc-q35-9.0" string qemuMachine = 7; // the qemu machine type to use "pc-q35-9.0"
int64 spice_port = 8; // preferred port to use for spice int64 spicePort = 8; // preferred port to use for spice
string preferred_hypervisor = 9; // the hypervisor to prefer to run the droplet on string preferredHypervisor = 9; // the hypervisor to prefer to run the droplet on
string force_hypervisor = 10; // use this hypervisor and this hypervisor only string forceHypervisor = 10; // use this hypervisor and this hypervisor only
string preferred_arch = 11; // the cpu arch to use "x86_64" (should really get this from the disk?) string preferredArch = 11; // the cpu arch to use "x86_64" (should really get this from the disk?)
repeated Network networks = 12; // really just mac addresses. should be unique across cluster repeated Network networks = 12; // really just mac addresses. should be unique across cluster
repeated Disk disks = 13; // disks to attach repeated Disk disks = 13; // disks to attach
string local_only = 14; // this is only defined locally on the hypervisor string localOnly = 14; // this is only defined locally on the hypervisor
string custom_xml = 15; // if needed, string customXml = 15; // if needed,
Archive archive = 16; // what the state of the droplet is SUPPOSED TO BE ('on' or 'off') Archive archive = 16; // what the state of the droplet is SUPPOSED TO BE ('on' or 'off')
google.protobuf.Timestamp unstable = 39; // the last time we heard anything from this droplet google.protobuf.Timestamp unstable = 39; // the last time we heard anything from this droplet
google.protobuf.Duration unstable_timeout = 40; // the last time we heard anything from this droplet google.protobuf.Duration unstableTimeout = 40; // the last time we heard anything from this droplet
} }
// volatile data. the current settings and values of things. // volatile data. the current settings and values of things.
// These are passed around while the cluster to monitor and control the systems // These are passed around while the cluster to monitor and control the systems
// but they are not saved to the config file // but they are not saved to the config file
message Current { message Current {
DropletState state = 1; // used to track the current state before taking any action DropletState state = 1; // used to track the current state before taking any action
string hypervisor = 2; // the current hypervisor the droplet is running on string hypervisor = 2; // the current hypervisor the droplet is running on
int64 start_attempts = 3; // how many times a start has been attempted int64 startAttempts = 3; // how many times a start has been attempted
string full_xml = 4; // the full libvirt xml to import string fullXml = 4; // the full libvirt xml to import
google.protobuf.Timestamp last_poll = 5; // the last time we heard anything from this droplet google.protobuf.Timestamp lastPoll = 5; // the last time we heard anything from this droplet
string image_url = 6; // url to the image string imageUrl = 6; // url to the image
google.protobuf.Timestamp off_since = 7; // when the droplet was turned off google.protobuf.Timestamp offSince = 7; // when the droplet was turned off
google.protobuf.Timestamp on_since = 8; // when the droplet was turned on google.protobuf.Timestamp onSince = 8; // when the droplet was turned on
} }
message Archive { message Archive {
DropletArchive reason = 1; // why the droplet was archived DropletArchive reason = 1; // why the droplet was archived
google.protobuf.Timestamp when = 2; // when it was archived google.protobuf.Timestamp when = 2; // when it was archived
} }
// virtual machine state
enum DropletState { enum DropletState {
ON = 0; ON = 0;
OFF = 1; OFF = 1;
UNKNOWN = 2; // qemu says 'Shutdown' UNKNOWN = 2; // qemu says 'Shutdown'
PAUSED = 3; PAUSED = 3;
CRASHED = 4; CRASHED = 4;
INMIGRATE = 5; INMIGRATE = 5;
} }
enum DropletArchive { enum DropletArchive {
DUP = 0; DUP = 0;
USER = 1; USER = 1;
} }
message Network { message Network {
string mac = 1; string mac = 1;
string name = 2; string name = 2;
} }
message Disk { message Disk {
string filename = 1; string filename = 1;
string filepath = 2; string filepath = 2;
int64 size = 3; int64 size = 3;
string qemu_arch = 4; // what arch. example: "x86_64" or "riscv64" string qemuArch = 4; // what arch. example: "x86_64" or "riscv64"
} }

View File

@ -1,16 +1,17 @@
syntax = "proto3"; syntax = "proto3";
package virtbuf; package virtpb;
import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp
import "google/protobuf/any.proto"; // Import the well-known type for Timestamp import "google/protobuf/any.proto"; // Import the well-known type for Timestamp
import "droplet.proto";
// global settings for autogenpb `autogenpb:no-sort` `autogenpb:mutex` // global settings for autogenpb `autogenpb:no-sort` `autogenpb:mutex`
message Events { // `autogenpb:marshal` message Events { // `autogenpb:marshal` `autogenpb:gui`
string uuid = 1; // I guess why not just have this on each file string uuid = 1; // `autogenpb:uuid:1e3a50c7-5916-4423-b33c-f0b977a7e446`
string version = 2; // maybe can be used for protobuf schema change violations string version = 2; // `autogenpb:version:v0.0.1`
int64 event_size = 3; // max events to store in a single int64 eventSize = 3; // max events to store in a single
repeated Event events = 4; // all the events repeated Event events = 4; // all the events
} }
// this information leans towards being human readable not programatic // this information leans towards being human readable not programatic
@ -18,34 +19,42 @@ message Events { // `autogenpb:marshal`
// at least for now in the early days. but maybe forever. // at least for now in the early days. but maybe forever.
// homelab clouds normally don't have many events. // homelab clouds normally don't have many events.
// we are talking less than 1 a minute. even 1 an hour is often a lot // we are talking less than 1 a minute. even 1 an hour is often a lot
message Event { message Event { // `autogenpb:marshal`
int32 id = 1; // `autogenpb:unique` // should be unique across the cluster enum status {
EventType etype = 2; DONE = 0;
string droplet = 3; // name of the droplet FAIL = 1;
string droplet_uuid = 4; // uuid of the droplet RUNNING = 2;
string hypervisor = 5; // name of the hypervisor }
string hypervisor_uuid = 6; // uuid of the hypervisor int32 id = 1; // `autogenpb:unique` // should be unique across the cluster
google.protobuf.Timestamp start = 7; // start time EventType etype = 2;
google.protobuf.Timestamp end = 8; // end time string dropletName = 3; // name of the droplet
string field_name = 9; // the field name that changed string dropletUuid = 4; // uuid of the droplet
string orig_val = 10; // original value string hypervisor = 5; // name of the hypervisor
string new_val = 11; // new value string hypervisorUuid = 6; // uuid of the hypervisor
google.protobuf.Any orig_any = 12; // anypb format. probably overkill google.protobuf.Timestamp start = 7; // start time
google.protobuf.Any new_any = 13; // anypb format google.protobuf.Timestamp end = 8; // end time
string fieldName = 9; // the field name that changed
string origVal = 10; // original value
string newVal = 11; // new value
google.protobuf.Any origAny = 12; // anypb format. probably overkill
google.protobuf.Any newAny = 13; // anypb format
string error = 14; // what went wrong
status state = 15; // state of the event
Droplet droplet = 16; // droplet
} }
enum EventType { enum EventType {
ADD = 0; ADD = 0;
DELETE = 1; DELETE = 1;
POWERON = 2; POWERON = 2;
POWEROFF = 3; // should indicate a "normal" shutdown POWEROFF = 3; // should indicate a "normal" shutdown
HIBERNATE = 4; HIBERNATE = 4;
MIGRATE = 5; MIGRATE = 5;
DEMO = 6; DEMO = 6;
GET = 7; // request something GET = 7; // request something
LOGIN = 8; // attempt to login LOGIN = 8; // attempt to login
OK = 9; // everything is ok OK = 9; // everything is ok
FAIL = 10; // everything failed FAIL = 10; // everything failed
CRASH = 11; // droplet hard crashed CRASH = 11; // droplet hard crashed
CHANGE = 12; // droplet or hypervisor config change CHANGE = 12; // droplet or hypervisor config change
EDIT = 13; // edit droplet settings
} }

View File

@ -1,21 +0,0 @@
syntax = "proto3";
package virtbuf;
import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp
import "google/protobuf/any.proto"; // Import the well-known type for Timestamp
// global settings for autogenpb `autogenpb:no-sort` `autogenpb:no-marshal`
message WhatsThis {
// is it possible to have custom formatting in JSON and TEXT marshal/unmarshal ?
WhatInfo humantest = 1;
google.protobuf.Timestamp end = 2; // end time
google.protobuf.Any orig_val = 3; // original value
google.protobuf.Any new_val = 4; // new value
}
// this is for exerimenting
message WhatInfo {
int64 capacity = 1; // Stores the storage capacity in bytes.
}

View File

@ -1,17 +1,17 @@
package virtbuf package virtpb
// functions to import and export the protobuf // functions to import and export the protobuf
// data to and from config files // data to and from config files
func InitCluster() *Cluster { func InitCluster() *OldCluster {
var c *Cluster var c *OldCluster
c = new(Cluster) c = new(OldCluster)
c.d = new(Droplets) c.d = new(Droplets)
c.H = new(Hypervisors) c.H = new(Hypervisors)
c.e = new(Events) c.e = new(Events)
return c return c
} }
func (c *Cluster) DropletsAll() *DropletIterator { func (c *OldCluster) DropletsAll() *DropletScanner {
return c.d.All() return c.d.All()
} }

View File

@ -1,4 +1,4 @@
package virtbuf package virtpb
// mostly just functions related to making STDOUT // mostly just functions related to making STDOUT
// more readable by us humans // more readable by us humans
@ -185,7 +185,7 @@ func (d *Droplet) DumpDroplet(w http.ResponseWriter, r *http.Request) (string, e
return t, nil return t, nil
} }
func (c *Cluster) DumpDroplet(w http.ResponseWriter, r *http.Request) (string, error) { func (c *OldCluster) DumpDroplet(w http.ResponseWriter, r *http.Request) (string, error) {
hostname := r.URL.Query().Get("hostname") hostname := r.URL.Query().Get("hostname")
d := c.FindDropletByName(hostname) d := c.FindDropletByName(hostname)
if d == nil { if d == nil {

View File

@ -1,28 +1,29 @@
syntax = "proto3"; syntax = "proto3";
package virtbuf; package virtpb;
// global settings for autogenpb `autogenpb:mutex` import "google/protobuf/timestamp.proto";
message Hypervisors { // `autogenpb:marshal` message Hypervisors { // `autogenpb:marshal` `autogenpb:gui`
string uuid = 1; // I guess why not just have this on each file string uuid = 1; // `autogenpb:uuid:6e3aa8b9-cf98-40f6-af58-3c6ad1edf4d4`
string version = 2; // maybe can be used for protobuf schema change violations string version = 2; // `autogenpb:version:v0.0.1`
repeated Hypervisor hypervisors = 3; repeated Hypervisor hypervisors = 3;
} }
message Hypervisor { message Hypervisor {
string uuid = 1; // `autogenpb:unique` string uuid = 1; // `autogenpb:unique`
string hostname = 2; // `autogenpb:unique` string hostname = 2; // `autogenpb:unique`
bool active = 3; // is allowed to start new droplets bool active = 3; // is allowed to start new droplets
int64 cpus = 4; int64 cpus = 4;
int64 memory = 5; // in bytes int64 memory = 5; // in bytes
string comment = 6; string comment = 6;
bool autoscan = 7; // to scan or not to scan by virtigo bool autoscan = 7; // to scan or not to scan by virtigo
HypervisorArch arch = 8; HypervisorArch arch = 8;
int64 killcount = 9; // in bytes
google.protobuf.Timestamp lastPoll = 10; // the last time we heard anything
} }
// think about this more
enum HypervisorArch { enum HypervisorArch {
RISCV64 = 0; RISCV64 = 0;
X86_64 = 1; X86_64 = 1;
ARM64 = 2; ARM64 = 2;
} }

View File

@ -1,4 +1,4 @@
package virtbuf package virtpb
import ( import (
sync "sync" sync "sync"
@ -7,7 +7,7 @@ import (
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
) )
type Cluster struct { type OldCluster struct {
sync.RWMutex sync.RWMutex
Dirs []string Dirs []string
@ -18,8 +18,20 @@ type Cluster struct {
UnstableTimeout *durationpb.Duration UnstableTimeout *durationpb.Duration
} }
func (c *OldCluster) GetDropletsPB() *Droplets {
return c.d
}
func (c *OldCluster) GetHypervisorsPB() *Hypervisors {
return c.H
}
func (c *OldCluster) GetEventsPB() *Events {
return c.e
}
// adds a new droplet. enforce unique hostnames // adds a new droplet. enforce unique hostnames
func (c *Cluster) AddDroplet(newd *Droplet) bool { func (c *OldCluster) AddDroplet(newd *Droplet) bool {
c.Lock() c.Lock()
defer c.Unlock() defer c.Unlock()

View File

@ -1,4 +1,4 @@
package virtbuf package virtpb
import ( import (
"fmt" "fmt"
@ -39,22 +39,6 @@ func CreateSampleHypervisor(hostname string, mem int) *Hypervisor {
return h return h
} }
func CreateExperiment(total int) *WhatsThis {
var e *WhatsThis
e = new(WhatsThis)
// info := StorageInfo{Capacity: 64}
// e.Humantest = &info
if e.Humantest == nil {
var newInfo WhatInfo
newInfo = WhatInfo{Capacity: 64}
e.Humantest = &newInfo
} else {
e.Humantest.Capacity = SetGB(total * 32)
}
return e
}
func CreateSampleEvents(total int) *Events { func CreateSampleEvents(total int) *Events {
var e *Events var e *Events
e = new(Events) e = new(Events)
@ -67,7 +51,7 @@ func CreateSampleEvents(total int) *Events {
return e return e
} }
func CreateSampleCluster(total int) *Cluster { func CreateSampleCluster(total int) *OldCluster {
c := InitCluster() c := InitCluster()
for i := 0; i < total; i++ { for i := 0; i < total; i++ {

View File

@ -1,4 +1,4 @@
package virtbuf package virtpb
/* /*
// MarshalJSON custom marshals the WhatInfo struct to JSON // MarshalJSON custom marshals the WhatInfo struct to JSON