continued work on the GUI
This commit is contained in:
parent
a7e639cdb0
commit
1fd6b1d36d
26
argv.go
26
argv.go
|
@ -16,36 +16,16 @@ type args struct {
|
|||
Port int `arg:"--port" default:"8080" help:"allow droplet events via http"`
|
||||
Server string `arg:"env:VIRTIGO_SERVER" help:"what virtigo cluster to connect to"`
|
||||
Xml []string `arg:"--libvirt" help:"import qemu xml files: --libvirt /etc/libvirt/qemu/*.xml"`
|
||||
Admin bool `arg:"--admin" help:"enter admin mode"`
|
||||
}
|
||||
|
||||
// Daemon bool `arg:"--daemon" help:"run in daemon mode"`
|
||||
// IgnoreCpu bool `arg:"--xml-ignore-cpu" default:"true" help:"ignore non-standard libvirt xml cpus"`
|
||||
// IgnoreBr bool `arg:"--xml-ignore-net" default:"true" help:"ignore network bridge name changes"`
|
||||
// IgnDisk bool `arg:"--xml-ignore-disk" default:"false" help:"ignore duplicate disk names"`
|
||||
|
||||
// Save bool `arg:"--save" default:"false" help:"save protobuf config after import"`
|
||||
// Start string `arg:"--start" help:"start a droplet"`
|
||||
// Uptime bool `arg:"--uptime" default:"true" help:"allow uptime checks for things like Kuma"`
|
||||
// Hosts []string `arg:"--hosts" help:"hosts to connect to"`
|
||||
|
||||
func (a args) Description() string {
|
||||
return `
|
||||
virtigo will help control your cluster
|
||||
virtigo: control your cluster
|
||||
|
||||
This maintains a master list of all your vm's (aka 'droplets')
|
||||
in your homelab cloud. You can import libvirt xml files.
|
||||
This app talks to your hypervisors via the virtigod daemon.
|
||||
|
||||
At this time, this _only_ supports qcow2 images. If you need
|
||||
something else you'll have to add it in virtigolib.
|
||||
|
||||
This runs a http server so you can control your virtual machines.
|
||||
For example to start a vm called 'www.wit.com' your cluster 'foo.bar.com':
|
||||
|
||||
curl http://virtigo.foo.com/start?www.wit.com
|
||||
|
||||
Use 'virtigoctl' to import xml files from libvirt and configure new
|
||||
hypervisors in your cluster.
|
||||
`
|
||||
}
|
||||
|
||||
|
@ -56,7 +36,6 @@ func (args) Version() string {
|
|||
var INFO *log.LogFlag
|
||||
var POLL *log.LogFlag
|
||||
var WARN *log.LogFlag
|
||||
var SPEW *log.LogFlag
|
||||
var EVENT *log.LogFlag
|
||||
|
||||
func init() {
|
||||
|
@ -66,6 +45,5 @@ func init() {
|
|||
INFO = log.NewFlag("INFO", false, full, short, "general virtigo")
|
||||
POLL = log.NewFlag("POLL", false, full, short, "virtigo polling")
|
||||
WARN = log.NewFlag("WARN", true, full, short, "bad things")
|
||||
SPEW = log.NewFlag("SPEW", true, full, short, "dump everything")
|
||||
EVENT = log.NewFlag("EVENT", true, full, short, "hypeprvisor/droplet events")
|
||||
}
|
||||
|
|
106
doAdminGui.go
106
doAdminGui.go
|
@ -10,6 +10,7 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/user"
|
||||
"time"
|
||||
|
@ -26,11 +27,15 @@ func (admin *adminT) refresh() {
|
|||
log.Info("virtigo scan here")
|
||||
}
|
||||
|
||||
url := argv.Server
|
||||
if admin.url == nil {
|
||||
log.Info("admin url == nil")
|
||||
return
|
||||
}
|
||||
|
||||
msg := []byte(`{"message": "Hello"}`)
|
||||
|
||||
// display the uptime
|
||||
if data, err := postData(url+"/uptime", msg); err != nil {
|
||||
if data, err := postData(admin.url.String()+"/uptime", msg); err != nil {
|
||||
log.Info("/uptime Error:", err)
|
||||
} else {
|
||||
log.Info("Response:", string(data))
|
||||
|
@ -38,7 +43,7 @@ func (admin *adminT) refresh() {
|
|||
}
|
||||
|
||||
// update the droplet list
|
||||
if data, err := postData(url+"/DropletsPB", msg); err != nil {
|
||||
if data, err := postData(admin.url.String()+"/DropletsPB", msg); err != nil {
|
||||
log.Info("/DropletsPB Error:", err)
|
||||
} else {
|
||||
fmt.Println("DropletsPB Response len:", len(data))
|
||||
|
@ -51,7 +56,7 @@ func (admin *adminT) refresh() {
|
|||
}
|
||||
|
||||
// update the hypervisor list
|
||||
if data, err := postData(url+"/HypervisorsPB", msg); err != nil {
|
||||
if data, err := postData(admin.url.String()+"/HypervisorsPB", msg); err != nil {
|
||||
log.Info("Error:", err)
|
||||
} else {
|
||||
fmt.Println("HypervisorsPB Response len:", len(data))
|
||||
|
@ -64,7 +69,7 @@ func (admin *adminT) refresh() {
|
|||
}
|
||||
|
||||
// update the events list
|
||||
if data, err := postData(url+"/EventsPB", msg); err != nil {
|
||||
if data, err := postData(admin.url.String()+"/EventsPB", msg); err != nil {
|
||||
log.Info("Error:", err)
|
||||
} else {
|
||||
fmt.Println("EventsPB Response len:", len(data))
|
||||
|
@ -92,11 +97,12 @@ func (admin *adminT) doAdminGui() {
|
|||
Timeout: 10 * time.Second, // Set a reasonable timeout
|
||||
}
|
||||
|
||||
win := gadgets.NewGenericWindow("Virtigo: (run your cluster)", "virtigo stuff")
|
||||
win := gadgets.NewGenericWindow("Virtigo: (run your cluster)", "localhost")
|
||||
win.Custom = func() {
|
||||
log.Warn("Main window close")
|
||||
os.Exit(0)
|
||||
}
|
||||
me.gwin = win
|
||||
|
||||
admin.uptime = win.Group.NewLabel("uptime")
|
||||
|
||||
|
@ -161,6 +167,14 @@ func (admin *adminT) doAdminGui() {
|
|||
// okExit("admin close")
|
||||
})
|
||||
|
||||
me.cmap = make(map[*virtpb.Cluster]*adminT)
|
||||
for c := range me.clusters.IterAll() {
|
||||
a := new(adminT)
|
||||
me.cmap[c] = a
|
||||
log.Info("found in the config file", c.URL)
|
||||
a.makeClusterGroup(c)
|
||||
}
|
||||
|
||||
// sit here forever refreshing the GUI
|
||||
for {
|
||||
admin.refresh()
|
||||
|
@ -168,6 +182,67 @@ func (admin *adminT) doAdminGui() {
|
|||
}
|
||||
}
|
||||
|
||||
func (admin *adminT) makeClusterGroup(c *virtpb.Cluster) {
|
||||
var err error
|
||||
admin.url, err = url.Parse(c.URL)
|
||||
if err != nil {
|
||||
badExit(err)
|
||||
}
|
||||
|
||||
group := me.gwin.Bottom.NewGroup(admin.url.Hostname())
|
||||
admin.uptime = group.NewLabel("uptime")
|
||||
|
||||
grid := group.RawGrid()
|
||||
|
||||
grid.NewButton("show hypervisors", func() {
|
||||
if admin.hypervisors == nil {
|
||||
log.Info("hypervisors not initialized")
|
||||
return
|
||||
}
|
||||
log.Info("Hypervisors len=", admin.hypervisors.Len())
|
||||
admin.hwin = newHypervisorsWindow()
|
||||
admin.hwin.doStdHypervisors(admin.hypervisors)
|
||||
admin.hwin.win.Custom = func() {
|
||||
log.Info("hiding table window")
|
||||
}
|
||||
})
|
||||
|
||||
grid.NewButton("droplets", func() {
|
||||
if admin.droplets == nil {
|
||||
log.Info("droplets not initialized")
|
||||
return
|
||||
}
|
||||
admin.dwin = newDropletsWindow()
|
||||
admin.dwin.win.Custom = func() {
|
||||
log.Info("hiding droplet table window")
|
||||
}
|
||||
var found *virtpb.Droplets
|
||||
found = virtpb.NewDroplets()
|
||||
all := admin.droplets.All()
|
||||
for all.Scan() {
|
||||
vm := all.Next()
|
||||
if vm.Current.State != virtpb.DropletState_ON {
|
||||
continue
|
||||
}
|
||||
found.Append(vm)
|
||||
}
|
||||
admin.dwin.doActiveDroplets(found)
|
||||
})
|
||||
|
||||
grid.NewButton("events", func() {
|
||||
if admin.events == nil {
|
||||
log.Info("events are not initialized")
|
||||
return
|
||||
}
|
||||
log.Info("Events len=", admin.events.Len())
|
||||
admin.ewin = newEventsWindow()
|
||||
admin.ewin.doStdEvents(admin.events)
|
||||
admin.ewin.win.Custom = func() {
|
||||
log.Info("hiding table window")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func postData(url string, data []byte) ([]byte, error) {
|
||||
req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(data))
|
||||
if err != nil {
|
||||
|
@ -191,22 +266,3 @@ func postData(url string, data []byte) ([]byte, error) {
|
|||
|
||||
return body, nil
|
||||
}
|
||||
|
||||
/*
|
||||
func main() {
|
||||
url := "http://example.com/endpoint"
|
||||
data := []byte(`{"message": "Hello"}`)
|
||||
|
||||
ticker := time.NewTicker(1 * time.Minute)
|
||||
defer ticker.Stop()
|
||||
|
||||
for range ticker.C {
|
||||
response, err := postData(url, data)
|
||||
if err != nil {
|
||||
fmt.Println("Error:", err)
|
||||
} else {
|
||||
fmt.Println("Response:", string(response))
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
11
doGui.go
11
doGui.go
|
@ -45,17 +45,6 @@ func doGui() {
|
|||
func drawWindow(win *gadgets.GenericWindow) {
|
||||
grid := win.Group.RawGrid()
|
||||
|
||||
/*
|
||||
var hyperWin *gadgets.GenericWindow
|
||||
grid.NewButton("hypervisors", func() {
|
||||
if hyperWin != nil {
|
||||
hyperWin.Toggle()
|
||||
return
|
||||
}
|
||||
hyperWin = makeHypervisorsWindow(me.cluster.H)
|
||||
})
|
||||
*/
|
||||
|
||||
var newHyperWin *stdHypervisorTableWin
|
||||
grid.NewButton("show hypervisors", func() {
|
||||
if newHyperWin != nil {
|
||||
|
|
36
main.go
36
main.go
|
@ -5,10 +5,12 @@ package main
|
|||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"go.wit.com/dev/alexflint/arg"
|
||||
"go.wit.com/gui"
|
||||
"go.wit.com/lib/protobuf/virtpb"
|
||||
|
@ -37,12 +39,44 @@ func main() {
|
|||
os.Setenv("VIRTIGO_HOME", fullpath)
|
||||
}
|
||||
|
||||
if argv.Server != "" {
|
||||
me.clusters = virtpb.NewClusters()
|
||||
|
||||
if argv.Admin {
|
||||
err := me.clusters.ConfigLoad()
|
||||
if err != nil {
|
||||
badExit(err)
|
||||
}
|
||||
|
||||
me.admin = new(adminT)
|
||||
me.admin.doAdminGui()
|
||||
okExit("admin close")
|
||||
}
|
||||
|
||||
if argv.Server != "" {
|
||||
log.Info("start admin interface")
|
||||
me.admin = new(adminT)
|
||||
var err error
|
||||
me.admin.url, err = url.Parse(argv.Server)
|
||||
if err != nil {
|
||||
badExit(err)
|
||||
}
|
||||
err = me.clusters.ConfigLoad()
|
||||
if err != nil {
|
||||
clusters := virtpb.NewClusters()
|
||||
c := new(virtpb.Cluster)
|
||||
c.Uuid = uuid.New().String()
|
||||
c.URL = argv.Server
|
||||
clusters.Append(c)
|
||||
virtpb.ConfigWriteTEXT(clusters, "cluster.text")
|
||||
|
||||
badExit(err)
|
||||
}
|
||||
|
||||
me.admin.doAdminGui()
|
||||
okExit("admin close")
|
||||
}
|
||||
os.Exit(-1)
|
||||
|
||||
// set defaults
|
||||
me.unstable = time.Now() // initialize the grid as unstable
|
||||
me.changed = false
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"go.wit.com/gui"
|
||||
"go.wit.com/lib/gadgets"
|
||||
"go.wit.com/lib/protobuf/virtpb"
|
||||
)
|
||||
|
||||
|
@ -21,7 +23,7 @@ func (b *virtigoT) Enable() {
|
|||
|
||||
// this app's variables
|
||||
type virtigoT struct {
|
||||
cluster *virtpb.Cluster // basic cluster settings
|
||||
cluster *virtpb.OldCluster // basic cluster settings
|
||||
myGui *gui.Node // the gui toolkit handle
|
||||
e *virtpb.Events // virt protobuf events
|
||||
hmap map[*virtpb.Hypervisor]*HyperT // map to the local struct
|
||||
|
@ -37,6 +39,9 @@ type virtigoT struct {
|
|||
status *gui.Node // the cluster status
|
||||
lastuptime *gui.Node // the last time uptime was checked by Kuma
|
||||
admin *adminT // the admin struct
|
||||
clusters *virtpb.Clusters // clusters protobuf
|
||||
cmap map[*virtpb.Cluster]*adminT // map to local GUI objects and the protobuf
|
||||
gwin *gadgets.GenericWindow // main window
|
||||
}
|
||||
|
||||
type adminT struct {
|
||||
|
@ -48,6 +53,7 @@ type adminT struct {
|
|||
dwin *stdDropletTableWin // the droplet window
|
||||
hwin *stdHypervisorTableWin // the hypervisor window
|
||||
ewin *stdEventTableWin // the events window
|
||||
url *url.URL // URL for the cloud
|
||||
}
|
||||
|
||||
// the stuff that is needed for a hypervisor
|
||||
|
|
|
@ -161,7 +161,7 @@ func (dw *stdDropletTableWin) doInactiveDroplets(pb *virtpb.Droplets) {
|
|||
return d.Current.Hypervisor
|
||||
})
|
||||
*/
|
||||
vp := t.AddButtonFunc("Configure Hostname", func(p *virtpb.Droplet) string {
|
||||
vp := t.AddButtonFunc("Verify Config", func(p *virtpb.Droplet) string {
|
||||
return p.Hostname
|
||||
})
|
||||
vp.Custom = func(d *virtpb.Droplet) {
|
||||
|
|
Loading…
Reference in New Issue