diff --git a/change.go b/change.go new file mode 100644 index 0000000..840b6d5 --- /dev/null +++ b/change.go @@ -0,0 +1,131 @@ +package virtbuf + +import ( + // "reflect" + + "errors" + "fmt" + "time" + + "google.golang.org/protobuf/types/known/anypb" + "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" + + "go.wit.com/log" +) + +func convertToAnypb(x any) *anypb.Any { + switch v := x.(type) { + case int64: + var a *anypb.Any + a, _ = anypb.New(wrapperspb.Int64(x.(int64))) + return a + case string: + var a *anypb.Any + a, _ = anypb.New(wrapperspb.String(x.(string))) + return a + case int: + var a *anypb.Any + a, _ = anypb.New(wrapperspb.Int64(x.(int64))) + return a + case bool: + var a *anypb.Any + a, _ = anypb.New(wrapperspb.Bool(x.(bool))) + return a + default: + log.Error(errors.New("convertToAnypb() unknown type"), "v =", v, "x =", x) + return nil + } + return nil +} + +func convertToString(x any) string { + switch v := x.(type) { + case int64: + return fmt.Sprintf("%d", x.(int64)) + case string: + return x.(string) + case int: + return fmt.Sprintf("%d", x.(int)) + case uint: + return fmt.Sprintf("%d", x.(uint)) + case bool: + if x.(bool) { + return "true" + } + return "false" + default: + log.Info("convertToSTring() unknown type", v) + log.Error(errors.New("convertToSTring() unknown type"), "v =", v, "x =", x) + return "" + } + return "" +} + +// Wrapping the int into a protobuf message +func (d *Droplet) NewChangeEvent(fname string, origval any, newval any) *Event { + var e *Event + e = new(Event) + + e.Droplet = d.Hostname + e.OrigVal = convertToString(origval) + e.NewVal = convertToString(newval) + e.FieldName = fname + + now := time.Now() + e.Start = timestamppb.New(now) + + // this also works, but it's a bit overkill + // e.NewAny = convertToAnypb(newval) + + // me.events.Events = append(me.events.Events, e) + // stuff := me.events.FormatJSON() + // log.Info("events:", stuff) + return e +} + +// work in progress +func NewAddEvent(a any, fname string, newval any) *Event { + var e *Event + e = new(Event) + + switch v := a.(type) { + case *Droplet: + var d *Droplet + d = a.(*Droplet) + e.Droplet = d.Hostname + case *Cluster: + e.Droplet = "Cluster" + case nil: + e.Droplet = "" + default: + log.Info("newAddEvent() unknown type", v) + e.Droplet = "on something somewhere" + } + + e.NewVal = convertToString(newval) + e.FieldName = fname + + now := time.Now() + e.Start = timestamppb.New(now) + + return e +} + +// update the droplet memory +func (d *Droplet) SetMemory(b int64) *Event { + oldm := HumanFormatBytes(d.Memory) + newm := HumanFormatBytes(b) + if d.Memory == b { + // log.Info("droplet", d.Hostname, "memory unchanged", oldm, "to", newm) + return nil + } + log.Info("droplet", d.Hostname, "memory change from", oldm, "to", newm) + + return d.NewChangeEvent("Droplet.Memory", d.Memory, b) +} + +// update the droplet memory +func (d *Droplet) SetCpus(b int64) { + log.Info("Set the number of cpus for the droplet", b) +} diff --git a/config.go b/config.go index 57fa319..01a397d 100644 --- a/config.go +++ b/config.go @@ -71,6 +71,41 @@ func (c *Cluster) ConfigSave() error { return nil } +func (c *Cluster) ConfigLoadOld() error { + if c == nil { + return errors.New("It's not safe to run ConfigLoad() on a nil cluster") + } + + // load the cluster config file + if data, err := loadFile("virtigo.json"); err == nil { + if err = protojson.Unmarshal(data, c); err != nil { + fmt.Println("broken cluster.json config file") + fmt.Println(err) + return errors.New("cluster.json file is broken") + } + } else { + return err + } + + var e *Events + e = new(Events) + // load the events config file + if data, err := loadFile("events.json"); err == nil { + if err = protojson.Unmarshal(data, e); err != nil { + fmt.Println("broken events.json config file") + return err + } + } else { + return err + } + // copy them over. is this needed? does the memory free otherwise? + for _, a := range e.Events { + c.Events = append(c.Events, a) + } + return nil +} + + func (c *Cluster) ConfigLoad() error { if c == nil { return errors.New("It's not safe to run ConfigLoad() on a nil cluster") @@ -185,6 +220,7 @@ func ConfigWriteTEXT(a any, filename string) error { return nil } +/* func WriteConfig(d *Droplets, h *Hypervisors, e *Events) bool { if !d.WriteConfigJSON() { return false @@ -279,6 +315,7 @@ func (d *Droplets) WriteConfigTEXT() bool { fmt.Println("Write:", fullname, "OK") return true } +*/ // human readable JSON func (c *Cluster) FormatJSON() string { diff --git a/droplet.proto b/droplet.proto index 9ac8e42..d7b8e07 100644 --- a/droplet.proto +++ b/droplet.proto @@ -2,6 +2,7 @@ syntax = "proto3"; package virtbuf; import "google/protobuf/any.proto"; +import "google/protobuf/timestamp.proto"; // Import the well-known type for Timestamp message Droplets { string uuid = 1; // I guess why not just have this on each file @@ -27,6 +28,10 @@ message Droplet { DropletState state = 14; // if the droplet is on, off, etc string image_url = 15; // url to the image + DropletState current_state = 16; // used to track the current state before taking any action + int64 starts = 17; // how many times a start has been attempted + string current_hypervisor = 18; // the current hypervisor the droplet is running on + google.protobuf.Timestamp last_poll = 19; // the last time we heard anything from this droplet } enum DropletState {