seems to compile

Signed-off-by: Jeff Carr <jcarr@wit.com>
This commit is contained in:
Jeff Carr 2024-10-31 13:07:24 -05:00
parent f4cb9e27ce
commit 10793e365d
11 changed files with 205 additions and 140 deletions

28
add.go
View File

@ -36,8 +36,10 @@ func (all *Droplets) oldFindDroplet(name string) *Droplet {
return nil return nil
} }
func (c *Cluster) FindDropletByName(name string) *Droplet { func (c *NewCluster) FindDropletByName(name string) *Droplet {
for _, d := range c.Droplets { loop := c.DropletsAll() // get the list of droplets
for loop.Scan() {
d := loop.Droplet()
if d.Hostname == name { if d.Hostname == name {
return d return d
} }
@ -45,8 +47,8 @@ func (c *Cluster) FindDropletByName(name string) *Droplet {
return nil return nil
} }
func (c *Cluster) FindHypervisorByName(name string) *Hypervisor { func (c *NewCluster) FindHypervisorByName(name string) *Hypervisor {
for _, h := range c.Hypervisors { for _, h := range c.h.Hypervisors {
if h.Hostname == name { if h.Hostname == name {
return h return h
} }
@ -54,7 +56,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 *NewCluster) 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
@ -71,11 +73,11 @@ func (c *Cluster) AddHypervisor(hostname string, cpus int, mem int) *Hypervisor
h.Cpus = 1 h.Cpus = 1
} }
h.SetMemoryGB(mem * 32) h.SetMemoryGB(mem * 32)
c.Hypervisors = append(c.Hypervisors, h) c.h.Hypervisors = append(c.h.Hypervisors, h)
return h return h
} }
func (c *Cluster) AddDroplet(uuid string, hostname string, cpus int, mem int) *Droplet { func (c *NewCluster) AddDroplet(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
@ -91,7 +93,7 @@ func (c *Cluster) AddDroplet(uuid string, hostname string, cpus int, mem int) *D
d.Cpus = 1 d.Cpus = 1
} }
d.Memory = SetGB(mem * 32) d.Memory = SetGB(mem * 32)
c.Droplets = append(c.Droplets, d) c.d.Droplets = append(c.d.Droplets, d)
return d return d
} }
@ -121,8 +123,10 @@ func HumanFormatBytes(b int64) string {
return fmt.Sprintf("%d TB", tb) return fmt.Sprintf("%d TB", tb)
} }
func (c *Cluster) BlankFields() { func (c *NewCluster) BlankFields() {
for _, d := range c.Droplets { loop := c.DropletsAll() // get the list of droplets
for loop.Scan() {
d := loop.Droplet()
d.Current = nil d.Current = nil
} }
} }
@ -131,7 +135,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 *NewCluster) 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
@ -143,7 +147,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 *NewCluster) DropletReady(d *Droplet) (bool, string) {
if c == nil { if c == nil {
return false, "cluster == nil" return false, "cluster == nil"
} }

View File

@ -94,8 +94,6 @@ func NewAddEvent(a any, fname string, newval any) *Event {
var d *Droplet var d *Droplet
d = a.(*Droplet) d = a.(*Droplet)
e.Droplet = d.Hostname e.Droplet = d.Hostname
case *Cluster:
e.Droplet = "Cluster"
case nil: case nil:
e.Droplet = "<nil>" e.Droplet = "<nil>"
default: default:
@ -131,7 +129,7 @@ func (d *Droplet) SetCpus(b int64) {
} }
// 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 *NewCluster) ChangeDropletState(d *Droplet, newState DropletState) error {
if c == nil { if c == nil {
return errors.New("cluster is nil") return errors.New("cluster is nil")
} }
@ -153,12 +151,12 @@ func (c *Cluster) ChangeDropletState(d *Droplet, newState DropletState) error {
now := time.Now() now := time.Now()
e.Start = timestamppb.New(now) e.Start = timestamppb.New(now)
c.E.Events = append(c.E.Events, e) c.e.Events = append(c.e.Events, e)
return nil return nil
} }
// 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 *NewCluster) DropletMoved(d *Droplet, newh *Hypervisor) error {
if c == nil { if c == nil {
return errors.New("cluster is nil") return errors.New("cluster is nil")
} }
@ -185,7 +183,7 @@ func (c *Cluster) DropletMoved(d *Droplet, newh *Hypervisor) error {
now := time.Now() now := time.Now()
e.Start = timestamppb.New(now) e.Start = timestamppb.New(now)
c.E.Events = append(c.E.Events, e) c.e.Events = append(c.e.Events, e)
// update the droplet record // update the droplet record
d.Current.Hypervisor = newh.Hostname d.Current.Hypervisor = newh.Hostname

View File

@ -7,7 +7,7 @@ import "event.proto";
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/duration.proto"; // Import the well-known type for Timestamp import "google/protobuf/duration.proto"; // Import the well-known type for Timestamp
message Cluster { message OldCluster {
int64 id = 1; int64 id = 1;
repeated string dirs = 2; repeated string dirs = 2;
@ -15,7 +15,7 @@ message Cluster {
repeated Hypervisor hypervisors = 4; repeated Hypervisor hypervisors = 4;
// repeated Event events = 5; // repeated Event events = 5;
Droplets d = 6; // Droplets d = 6;
Hypervisors h = 7; Hypervisors h = 7;
Events e = 8; Events e = 8;
google.protobuf.Timestamp unstable = 9; // the last time we heard anything from this droplet google.protobuf.Timestamp unstable = 9; // the last time we heard anything from this droplet

View File

@ -16,7 +16,7 @@ import (
// 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 *NewCluster) 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
@ -25,9 +25,8 @@ func (c *Cluster) ConfigSave() error {
// make a new droplets struct // make a new droplets struct
var d *Droplets var d *Droplets
d = new(Droplets) d = new(Droplets)
d.Droplets = c.Droplets
// copy all the records over to the new struct // copy all the records over to the new struct
for _, drop := range c.Droplets { for _, drop := range c.d.Droplets {
d.Droplets = append(d.Droplets, drop) d.Droplets = append(d.Droplets, drop)
} }
// delete all the Current data so it's not put in the config file // delete all the Current data so it's not put in the config file
@ -43,83 +42,42 @@ func (c *Cluster) ConfigSave() error {
return err return err
} }
var h *Hypervisors if err := ConfigWriteJSON(c.h, "hypervisors.json"); err != nil {
h = new(Hypervisors)
h.Hypervisors = c.Hypervisors
if err := ConfigWriteJSON(h, "hypervisors.json"); err != nil {
fmt.Println("hypervisors.json write failed") fmt.Println("hypervisors.json write failed")
return err return err
} }
if err := ConfigWriteTEXT(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
} }
if err := ConfigWriteJSON(c.E, "events.json"); err != nil { if err := ConfigWriteJSON(c.e, "events.json"); err != nil {
fmt.Println("events.json write failed") fmt.Println("events.json write failed")
return err return err
} }
if err := ConfigWriteTEXT(c.E, "events.text"); err != nil { if err := ConfigWriteTEXT(c.e, "events.text"); err != nil {
fmt.Println("events.json write failed") fmt.Println("events.json write failed")
return err return err
} }
if err := ConfigWriteTEXT(c, "cluster.full.text"); err != nil {
fmt.Println("Cluster.json write failed")
return err
}
var newc Cluster
newc.Dirs = c.Dirs
newc.Droplets = nil
newc.Hypervisors = nil
newc.E = nil
if err := ConfigWriteTEXT(&newc, "cluster.text"); err != nil {
fmt.Println("cluster.json write failed")
return err
}
return nil return nil
} }
func (c *Cluster) ConfigLoad() error { func (c *NewCluster) 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")
} }
// load the cluster config file
if data, err := loadFile("cluster.text"); err == nil {
if err = prototext.Unmarshal(data, c); err != nil {
fmt.Println("broken cluster.text config file")
fmt.Println(err)
return errors.New("cluster.text file is broken")
}
} else {
return err
}
var d *Droplets
d = new(Droplets)
// load the droplet config file
if data, err := loadFile("droplets.json"); err == nil { if data, err := loadFile("droplets.json"); err == nil {
if err = protojson.Unmarshal(data, d); err != nil { if err = protojson.Unmarshal(data, c.d); err != nil {
fmt.Println("broken droplets.json config file") fmt.Println("broken droplets.json config file")
return err return err
} }
} else { } else {
return err return err
} }
// copy them over. is this needed? does the memory free otherwise?
// also set initial values
for _, drop := range d.Droplets {
c.Droplets = append(c.Droplets, drop)
}
var h *Hypervisors
h = new(Hypervisors)
// load the hypervisors config file
if data, err := loadFile("hypervisors.json"); err == nil { if data, err := loadFile("hypervisors.json"); err == nil {
if err = protojson.Unmarshal(data, h); err != nil { if err = protojson.Unmarshal(data, c.h); err != nil {
fmt.Println("broken hypervisors.json config file") fmt.Println("broken hypervisors.json config file")
return err return err
} }
@ -127,26 +85,15 @@ func (c *Cluster) ConfigLoad() error {
fmt.Println("ERROR HERE IN Hypervisors") fmt.Println("ERROR HERE IN Hypervisors")
return err return err
} }
// copy them over. is this needed? does the memory free otherwise?
for _, a := range h.Hypervisors {
c.Hypervisors = append(c.Hypervisors, a)
}
var e *Events if c.e == nil {
e = new(Events)
if c.E == nil {
// this seems to panic on nil. something is wrong about doing this // this seems to panic on nil. something is wrong about doing this
// 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 := e.loadEvents(); err != nil { if err := c.e.loadEvents(); err != nil {
return err return err
} }
// copy them over. is this needed? does the memory free otherwise?
for _, e := range e.Events {
c.E.Events = append(c.E.Events, e)
}
return nil return nil
} }

View File

@ -1,6 +1,7 @@
syntax = "proto3"; syntax = "proto3";
package virtbuf; package virtbuf;
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
message Droplets { message Droplets {
@ -27,7 +28,10 @@ message Droplet {
string local_only = 14; // this is only defined locally on the hypervisor string local_only = 14; // this is only defined locally on the hypervisor
string custom_xml = 15; // if needed, string custom_xml = 15; // if needed,
DropletArchive 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.Duration unstable_timeout = 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.
@ -58,8 +62,8 @@ enum DropletState {
} }
enum DropletArchive { enum DropletArchive {
ARCHIVE_DUP = 0; DUP = 0;
ARCHIVE_USER = 1; USER = 1;
} }
message Network { message Network {

Binary file not shown.

View File

@ -1,15 +1,11 @@
package main package main
import ( import (
"bufio"
"bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
"google.golang.org/protobuf/proto"
pb "go.wit.com/lib/protobuf/virtbuf" pb "go.wit.com/lib/protobuf/virtbuf"
) )
@ -20,27 +16,30 @@ import (
func main() { func main() {
TestWriteCluster() TestWriteCluster()
in, err := ioutil.ReadFile("/tmp/testing4.protobuf") _, err := ioutil.ReadFile("/tmp/testing4.protobuf")
if err != nil { if err != nil {
log.Fatalln("Error reading file:", err) log.Fatalln("Error reading file:", err)
} }
var aCluster pb.Cluster var c *pb.NewCluster
if err := proto.Unmarshal(in, &aCluster); err != nil { c = new(pb.NewCluster)
log.Fatalln("Failed to parse droplet:", err)
}
log.Println(aCluster.String()) // log.Println(aCluster.String())
// show the droplets to STDOUT // show the droplets to STDOUT
for _, d := range aCluster.Droplets { loop := c.DropletsAll() // get the list of droplets
for loop.Scan() {
d := loop.Droplet()
fmt.Println("\tdroplet =", d.Hostname, "preffered host:", d.PreferredHypervisor) fmt.Println("\tdroplet =", d.Hostname, "preffered host:", d.PreferredHypervisor)
} }
/*
// show the hypervisors to STDOUT // show the hypervisors to STDOUT
for _, h := range aCluster.Hypervisors { for _, h := range aCluster.Hypervisors {
fmt.Println("\thypervisor =", h.Hostname, h.GetMemoryPrintable()) fmt.Println("\thypervisor =", h.Hostname, h.GetMemoryPrintable())
} }
*/
/*
json := aCluster.FormatJSON() json := aCluster.FormatJSON()
fmt.Println(json) fmt.Println(json)
@ -49,9 +48,11 @@ func main() {
text := aCluster.FormatTEXT() text := aCluster.FormatTEXT()
fmt.Println(text) fmt.Println(text)
*/
} }
func marshalWriteToFile(myWriter *bufio.Writer, c *pb.Cluster) { /*
func marshalWriteToFile(myWriter *bufio.Writer, c *pb.NewCluster) {
buf, err := proto.Marshal(c) buf, err := proto.Marshal(c)
if err != nil { if err != nil {
log.Fatal("marshaling error: ", err) log.Fatal("marshaling error: ", err)
@ -65,22 +66,20 @@ func marshalWriteToFile(myWriter *bufio.Writer, c *pb.Cluster) {
myWriter.Flush() myWriter.Flush()
log.Println("bufio.Write() tmp2, err = ", tmp2, err) log.Println("bufio.Write() tmp2, err = ", tmp2, err)
} }
*/
func TestWriteCluster() { func TestWriteCluster() {
buf := new(bytes.Buffer)
c := pb.CreateSampleCluster(7) c := pb.CreateSampleCluster(7)
os.Setenv("VIRTIGO_HOME", "/tmp/virtigo/")
got := buf.String() if err := c.ConfigSave(); err != nil {
log.Println(got) fmt.Println("configsave error", err)
os.Exit(-1)
newfile, _ := os.Create("/tmp/testing4.protobuf") }
myWriter := bufio.NewWriter(newfile)
marshalWriteToFile(myWriter, c)
// marshalUnmarshal() // marshalUnmarshal()
} }
/*
func marshalUnmarshal() { func marshalUnmarshal() {
test := pb.CreateSampleCluster(7) test := pb.CreateSampleCluster(7)
data, err := proto.Marshal(test) data, err := proto.Marshal(test)
@ -96,3 +95,4 @@ func marshalUnmarshal() {
log.Println("proto.Marshal() and proto.Unmarshal() worked") log.Println("proto.Marshal() and proto.Unmarshal() worked")
} }
} }
*/

View File

@ -10,10 +10,6 @@ import (
) )
// human readable JSON // human readable JSON
func (c *Cluster) FormatJSON() string {
return protojson.Format(c)
}
func (d *Droplets) FormatJSON() string { func (d *Droplets) FormatJSON() string {
return protojson.Format(d) return protojson.Format(d)
} }
@ -33,10 +29,6 @@ func (h *Hypervisors) FormatJSON() string {
// apparently this isn't supposed to be used? // apparently this isn't supposed to be used?
// https://protobuf.dev/reference/go/faq/#unstable-text // https://protobuf.dev/reference/go/faq/#unstable-text
// this is a shame because this is much nicer output than JSON Format() // this is a shame because this is much nicer output than JSON Format()
func (c *Cluster) FormatTEXT() string {
return prototext.Format(c)
}
func (d *Droplets) FormatTEXT() string { func (d *Droplets) FormatTEXT() string {
return prototext.Format(d) return prototext.Format(d)
} }
@ -46,10 +38,6 @@ func (e *Events) FormatTEXT() string {
} }
// marshal // marshal
func (c *Cluster) MarshalJSON() ([]byte, error) {
return protojson.Marshal(c)
}
func (d *Droplets) MarshalJSON() ([]byte, error) { func (d *Droplets) MarshalJSON() ([]byte, error) {
return protojson.Marshal(d) return protojson.Marshal(d)
} }
@ -63,10 +51,6 @@ func (e *Events) MarshalJSON() ([]byte, error) {
} }
// unmarshal // unmarshal
func (c *Cluster) UnmarshalJSON(data []byte) error {
return protojson.Unmarshal(data, c)
}
func (d *Droplets) UnmarshalJSON(data []byte) error { func (d *Droplets) UnmarshalJSON(data []byte) error {
return protojson.Unmarshal(data, d) return protojson.Unmarshal(data, d)
} }

19
newCluster.go Normal file
View File

@ -0,0 +1,19 @@
package virtbuf
import (
sync "sync"
durationpb "google.golang.org/protobuf/types/known/durationpb"
"google.golang.org/protobuf/types/known/timestamppb"
)
type NewCluster struct {
sync.RWMutex
Dirs []string
d *Droplets
h *Hypervisors
e *Events
Unstable *timestamppb.Timestamp
UnstableTimeout *durationpb.Duration
}

View File

@ -67,9 +67,12 @@ func CreateSampleEvents(total int) *Events {
return e return e
} }
func CreateSampleCluster(total int) *Cluster { func CreateSampleCluster(total int) *NewCluster {
var c *Cluster var c *NewCluster
c = new(Cluster) c = new(NewCluster)
c.d = new(Droplets)
c.h = new(Hypervisors)
c.e = new(Events)
for i := 0; i < total; i++ { for i := 0; i < total; i++ {
hostname := fmt.Sprintf("bmath%d.wit.com", i) hostname := fmt.Sprintf("bmath%d.wit.com", i)
@ -80,7 +83,7 @@ func CreateSampleCluster(total int) *Cluster {
d.Memory = SetGB(256) d.Memory = SetGB(256)
} }
c.Droplets = append(c.Droplets, d) c.d.Droplets = append(c.d.Droplets, d)
} }
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
@ -88,7 +91,7 @@ func CreateSampleCluster(total int) *Cluster {
h := CreateSampleHypervisor(hostname, i+1) h := CreateSampleHypervisor(hostname, i+1)
h.Comment = fmt.Sprintf("Sample hypervisor %d", i) h.Comment = fmt.Sprintf("Sample hypervisor %d", i)
c.Hypervisors = append(c.Hypervisors, h) c.h.Hypervisors = append(c.h.Hypervisors, h)
} }
return c return c

106
scanIterator.go Normal file
View File

@ -0,0 +1,106 @@
package virtbuf
import (
"fmt"
"os"
"go.wit.com/log"
)
type DropletIterator struct {
droplets []*Droplet
index int
}
// NewDropletIterator initializes a new iterator.
func NewDropletIterator(droplets []*Droplet) *DropletIterator {
return &DropletIterator{droplets: droplets}
}
// Scan moves to the next element and returns false if there are no more droplets.
func (it *DropletIterator) Scan() bool {
if it.index >= len(it.droplets) {
return false
}
it.index++
return true
}
// Droplet returns the current droplet.
func (it *DropletIterator) Droplet() *Droplet {
if it.droplets[it.index-1] == nil {
for i, d := range it.droplets {
fmt.Println("i =", i, d)
}
fmt.Println("len =", len(it.droplets))
fmt.Println("droplet == nil", it.index, it.index-1)
os.Exit(-1)
}
return it.droplets[it.index-1]
}
// Use Scan() in a loop, similar to a while loop
//
// for iterator.Scan() {
// d := iterator.Droplet()
// fmt.Println("Droplet UUID:", d.Uuid)
// }
func (c *NewCluster) GetDropletIterator() *DropletIterator {
dropletPointers := c.SelectDropletPointers()
iterator := NewDropletIterator(dropletPointers)
return iterator
}
func (c *NewCluster) DropletsAll() *DropletIterator {
dropletPointers := c.SelectDropletAll()
iterator := NewDropletIterator(dropletPointers)
return iterator
}
// SelectDropletPointers safely returns a slice of pointers to Droplet records.
func (c *NewCluster) SelectDropletAll() []*Droplet {
c.RLock()
defer c.RUnlock()
// Create a new slice to hold pointers to each Droplet
// dropletPointers := make([]*Droplet, len(c.E.Droplets))
var dropletPointers []*Droplet
if c.d == nil {
log.Info("SelectDropletsAll() c.d == nil")
os.Exit(-1)
}
for _, d := range c.d.Droplets {
if d == nil {
continue
}
if d.Archive != nil {
continue
}
dropletPointers = append(dropletPointers, d) // Copy pointers for safe iteration
}
return dropletPointers
}
// SelectDropletPointers safely returns a slice of pointers to Droplet records.
func (c *NewCluster) SelectDropletPointers() []*Droplet {
c.RLock()
defer c.RUnlock()
// Create a new slice to hold pointers to each Droplet
// dropletPointers := make([]*Droplet, len(c.E.Droplets))
dropletPointers := make([]*Droplet, 1)
if c.d == nil {
log.Info("c.d == nil")
os.Exit(-1)
}
for _, d := range c.d.Droplets {
dropletPointers = append(dropletPointers, d) // Copy pointers for safe iteration
}
return dropletPointers
}