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 *DropletState: var s *DropletState s = x.(*DropletState) return s.String() case DropletState: var s DropletState s = x.(DropletState) return s.String() 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 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) } // update the droplet memory func (d *Droplet) SetState(newState DropletState) { if d.Current == nil { d.Current = new(Current) } if d.Current.State == newState { // nothing has changed return } switch newState { case DropletState_ON: d.Current.OnSince = timestamppb.New(time.Now()) d.Current.OffSince = nil case DropletState_OFF: d.Current.OffSince = timestamppb.New(time.Now()) d.Current.OnSince = nil default: // zero on OnSince to indicate something hickup'd? // not sure if this should be done here. probably trust qemu dom0 instead // but I can't do that right now so for now this will work d.Current.OnSince = timestamppb.New(time.Now()) d.Current.OffSince = timestamppb.New(time.Now()) } d.Current.State = newState d.NewChangeEvent("STATE", d.Current.State, newState) log.Info("Droplet", d.Hostname, "changed state from", d.Current.State, "to", newState) } // records an event that the droplet changed state (aka turned on, turned off, etc) func (c *Cluster) ChangeDropletState(d *Droplet, newState DropletState) error { if c == nil { return errors.New("cluster is nil") } if d == nil { return errors.New("droplet is nil") } if d.Current.State == newState { // droplet status didn't change return nil } var e *Event e = new(Event) e.Droplet = d.Hostname e.OrigVal = convertToString(d.Current.State) e.NewVal = convertToString(newState) e.FieldName = "status" now := time.Now() e.Start = timestamppb.New(now) c.e.Events = append(c.e.Events, e) return nil } // records an event that the droplet migrated to another hypervisor func (c *Cluster) DropletMoved(d *Droplet, newh *Hypervisor) error { if c == nil { return errors.New("cluster is nil") } if d == nil { return errors.New("droplet is nil") } if newh == nil { return errors.New("hypervisor is nil") } if d.Current.Hypervisor == newh.Hostname { // droplet didn't move return nil } // make a change event var e *Event e = new(Event) e.Droplet = d.Hostname e.OrigVal = d.Current.Hypervisor e.NewVal = newh.Hostname e.FieldName = "droplet migrate" now := time.Now() e.Start = timestamppb.New(now) c.e.Events = append(c.e.Events, e) // update the droplet record d.Current.Hypervisor = newh.Hostname return nil }