Compare commits
No commits in common. "master" and "v0.2.54" have entirely different histories.
4
Makefile
4
Makefile
|
@ -92,7 +92,7 @@ redomod:
|
|||
clean:
|
||||
rm -f go.*
|
||||
rm -f virtigo*
|
||||
go-mod-clean purge
|
||||
go-mod-clean --purge
|
||||
|
||||
# git clone the sources and all the golang dependancies into ~/go/src
|
||||
# if you don't have go-clone, you can get it from http://go.wit.com/
|
||||
|
@ -120,7 +120,7 @@ protogen:
|
|||
|
||||
gocui: install
|
||||
virtigo --gui gocui --gui-verbose --gui-file ../../toolkits/gocui/gocui.so --admin
|
||||
# virtigo --gui gocui --gui-verbose --gui-file ../../toolkits/gocui/gocui.so --admin >/tmp/forge.log 2>&1
|
||||
# virtigo --gui gocui --gui-verbose --gui-file ../../toolkits/gocui/gocui.so >/tmp/forge.log 2>&1
|
||||
|
||||
log:
|
||||
journalctl -f -xeu virtigod.service
|
||||
|
|
32
argv.go
32
argv.go
|
@ -1,11 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"go.wit.com/log"
|
||||
)
|
||||
import "go.wit.com/log"
|
||||
|
||||
/*
|
||||
this parses the command line arguements
|
||||
|
@ -79,28 +74,3 @@ func init() {
|
|||
WARN = log.NewFlag("WARN", true, full, short, "bad things")
|
||||
EVENT = log.NewFlag("EVENT", true, full, short, "hypeprvisor/droplet events")
|
||||
}
|
||||
|
||||
/*
|
||||
handles shell autocomplete
|
||||
*/
|
||||
|
||||
func (a args) DoAutoComplete(argv []string) {
|
||||
switch argv[0] {
|
||||
case "list":
|
||||
fmt.Println("droplets hypervisors")
|
||||
case "droplet":
|
||||
fmt.Println("start stop")
|
||||
case "devel":
|
||||
fmt.Println("--force")
|
||||
case "master":
|
||||
fmt.Println("")
|
||||
case "verify":
|
||||
fmt.Println("user devel master")
|
||||
default:
|
||||
if argv[0] == ARGNAME {
|
||||
// list the subcommands here
|
||||
fmt.Println("--bash list droplet")
|
||||
}
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
/*
|
||||
handles shell autocomplete
|
||||
*/
|
||||
|
||||
// used for shell auto completion
|
||||
// var ARGNAME string = "forge" // todo: get this from $0 ?
|
||||
|
||||
func deleteMatch() {
|
||||
// f := forgedb.InitSimple()
|
||||
fmt.Println("go.wit.com/lib/gui/repostatus todo: need to do this")
|
||||
}
|
||||
|
||||
func (args) doBashAuto() {
|
||||
argv.doBashHelp()
|
||||
switch argv.BashAuto[0] {
|
||||
case "list":
|
||||
fmt.Println("droplets hypervisors")
|
||||
case "droplet":
|
||||
fmt.Println("start stop")
|
||||
case "devel":
|
||||
fmt.Println("--force")
|
||||
case "master":
|
||||
fmt.Println("")
|
||||
case "verify":
|
||||
fmt.Println("user devel master")
|
||||
default:
|
||||
if argv.BashAuto[0] == ARGNAME {
|
||||
// list the subcommands here
|
||||
fmt.Println("--bash list droplet")
|
||||
}
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// prints help to STDERR // TODO: move everything below this to go-args
|
||||
func (args) doBashHelp() {
|
||||
if argv.BashAuto[1] != "''" {
|
||||
// if this is not blank, then the user has typed something
|
||||
return
|
||||
}
|
||||
if argv.BashAuto[0] != ARGNAME {
|
||||
// if this is not the name of the command, the user already started doing something
|
||||
return
|
||||
}
|
||||
if argv.BashAuto[0] == ARGNAME {
|
||||
me.pp.WriteHelp(os.Stderr)
|
||||
return
|
||||
}
|
||||
fmt.Fprintln(os.Stderr, "")
|
||||
fmt.Fprintln(os.Stderr, "hello world")
|
||||
fmt.Fprintln(os.Stderr, "")
|
||||
}
|
||||
|
||||
// complete -F forge --bash forge
|
||||
func (args) doBash() {
|
||||
fmt.Println("# add this in your bashrc:")
|
||||
fmt.Println("")
|
||||
fmt.Println("# todo: add this to go-arg as a 'hidden' go-arg option --bash")
|
||||
fmt.Println("#")
|
||||
fmt.Println("# todo: can this output work/parse with:")
|
||||
fmt.Println("# complete -C `" + ARGNAME + " --bash` " + ARGNAME)
|
||||
fmt.Println("")
|
||||
fmt.Println("_" + ARGNAME + "_complete()")
|
||||
fmt.Println("{")
|
||||
fmt.Println(" # sets local to this func vars")
|
||||
fmt.Println(" local cur prev all")
|
||||
fmt.Println(" cur=${COMP_WORDS[COMP_CWORD]}")
|
||||
fmt.Println(" prev=${COMP_WORDS[COMP_CWORD-1]}")
|
||||
fmt.Println(" all=${COMP_WORDS[@]}")
|
||||
fmt.Println("")
|
||||
fmt.Println(" # this is where we generate the go-arg output")
|
||||
fmt.Println(" GOARGS=$(" + ARGNAME + " --auto-complete $prev \\'$cur\\' $all)")
|
||||
fmt.Println("")
|
||||
fmt.Println(" # this compares the command line input from the user")
|
||||
fmt.Println(" # to whatever strings we output")
|
||||
fmt.Println(" COMPREPLY=( $(compgen -W \"$GOARGS\" -- $cur) ) # THIS WORKS")
|
||||
fmt.Println(" return 0")
|
||||
fmt.Println("}")
|
||||
fmt.Println("complete -F _" + ARGNAME + "_complete " + ARGNAME)
|
||||
fmt.Println("")
|
||||
fmt.Println("# copy and paste the above into your bash shell should work")
|
||||
os.Exit(0)
|
||||
}
|
|
@ -150,6 +150,10 @@ func doLocalhostAdminGui() *adminT {
|
|||
}
|
||||
|
||||
func doAdminGui() {
|
||||
me.myGui = gui.New()
|
||||
me.myGui.InitEmbed(resources)
|
||||
me.myGui.Default()
|
||||
|
||||
// Initialize a persistent client with a custom Transport
|
||||
client = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
|
@ -181,6 +185,10 @@ func doAdminGui() {
|
|||
}
|
||||
|
||||
func (admin *adminT) doAdminGui() {
|
||||
me.myGui = gui.New()
|
||||
me.myGui.InitEmbed(resources)
|
||||
me.myGui.Default()
|
||||
|
||||
// Initialize a persistent client with a custom Transport
|
||||
client = &http.Client{
|
||||
Transport: &http.Transport{
|
||||
|
@ -255,7 +263,7 @@ func (admin *adminT) doAdminGui() {
|
|||
})
|
||||
|
||||
grid.NewButton("test gui close", func() {
|
||||
gui.StandardExit()
|
||||
me.myGui.Close()
|
||||
// okExit("admin close")
|
||||
})
|
||||
|
||||
|
@ -392,10 +400,8 @@ func (admin *adminT) postEvent(e *virtpb.Event) error {
|
|||
return err
|
||||
}
|
||||
|
||||
url := admin.url.String() + "/event"
|
||||
|
||||
// update the droplet list
|
||||
if data, err := postData(url, msg); err != nil {
|
||||
if data, err := postData(admin.url.String()+"/event", msg); err != nil {
|
||||
log.Info("postEvent() /event Error:", err)
|
||||
return err
|
||||
} else {
|
||||
|
@ -403,14 +409,11 @@ func (admin *adminT) postEvent(e *virtpb.Event) error {
|
|||
log.Println("postEvent() result marshal failed", err, "len(dat) =", len(data))
|
||||
log.Println("postEvent() data =", string(data))
|
||||
return err
|
||||
} else {
|
||||
log.Println("postEvent() result marshal worked on len(dat) =", len(data))
|
||||
log.Println("postEvent() result =", result.FormatTEXT())
|
||||
}
|
||||
}
|
||||
if result.Error != "" {
|
||||
return fmt.Errorf("%s", result.Error)
|
||||
}
|
||||
log.Printf("Event worked to %s uuid=%s\n", url, result.DropletUuid)
|
||||
log.Printf("Event worked: %s\n", result.DropletUuid)
|
||||
return nil
|
||||
}
|
||||
|
|
246
doDroplet.go
246
doDroplet.go
|
@ -7,15 +7,10 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"go.wit.com/lib/gui/shell"
|
||||
"go.wit.com/lib/protobuf/virtpb"
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
@ -114,248 +109,7 @@ func doEvent(e *virtpb.Event) *virtpb.Event {
|
|||
if err != nil {
|
||||
result.Error = fmt.Sprintf("%v", err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
if e.Etype == virtpb.EventType_EDIT {
|
||||
log.Println("edit event", e.DropletUuid)
|
||||
result.State = virtpb.Event_DONE
|
||||
if e.Droplet != nil {
|
||||
return updateDroplet(e.Droplet)
|
||||
}
|
||||
log.Println("unknown edit event")
|
||||
result.State = virtpb.Event_FAIL
|
||||
return result
|
||||
}
|
||||
|
||||
if e.Etype == virtpb.EventType_ADD {
|
||||
log.Println("START ADD droplet event", e.Droplet.FormatTEXT())
|
||||
if e.Droplet == nil {
|
||||
result.State = virtpb.Event_FAIL
|
||||
return result
|
||||
}
|
||||
result.DropletName = e.Droplet.Hostname
|
||||
result.Error = e.Droplet.FormatTEXT() // feedback to the other side for debugging
|
||||
|
||||
// attempt to create the new droplet
|
||||
if err := createDroplet(e.Droplet, result); err != nil {
|
||||
result.Error += fmt.Sprintf("createDroplet() err: %v", err)
|
||||
result.State = virtpb.Event_FAIL
|
||||
return result
|
||||
}
|
||||
log.Println("create droplet worked", e.Droplet.FormatTEXT())
|
||||
result.State = virtpb.Event_DONE
|
||||
return result
|
||||
}
|
||||
|
||||
log.Println("unknown event", e)
|
||||
result.Etype = e.Etype
|
||||
result.State = virtpb.Event_FAIL
|
||||
return result
|
||||
}
|
||||
|
||||
func updateDroplet(newd *virtpb.Droplet) *virtpb.Event {
|
||||
var changed bool = false
|
||||
result := new(virtpb.Event)
|
||||
|
||||
if newd == nil {
|
||||
result.Error = "updateDroplet() d == nil"
|
||||
result.State = virtpb.Event_FAIL
|
||||
return result
|
||||
}
|
||||
|
||||
d := me.cluster.FindDropletByUuid(newd.Uuid)
|
||||
if d == nil {
|
||||
result.Error = "updateDroplet() could not find uuid"
|
||||
result.State = virtpb.Event_FAIL
|
||||
return result
|
||||
}
|
||||
log.Println("found droplet to update:", newd.Uuid, newd.Hostname, newd.Cpus, newd.Memory)
|
||||
|
||||
if d.Hostname != newd.Hostname && newd.Hostname != "" {
|
||||
d.Hostname = newd.Hostname
|
||||
changed = true
|
||||
}
|
||||
|
||||
if d.Cpus != newd.Cpus && newd.Cpus > 0 {
|
||||
d.Cpus = newd.Cpus
|
||||
changed = true
|
||||
}
|
||||
|
||||
// arbitrary check. don't make vm's with less than 64 MB of RAM
|
||||
// big enough most things will load with some stdout
|
||||
if d.Memory != newd.Memory && newd.Memory > (64*1024*1024) {
|
||||
d.Memory = newd.Memory
|
||||
changed = true
|
||||
}
|
||||
|
||||
if changed {
|
||||
if err := me.cluster.ConfigSave(); err != nil {
|
||||
log.Info("configsave error", err)
|
||||
result.Error = fmt.Sprintf("%v", err)
|
||||
result.State = virtpb.Event_FAIL
|
||||
return result
|
||||
}
|
||||
} else {
|
||||
log.Println("nothing changed in", newd.Uuid, newd.Hostname)
|
||||
}
|
||||
|
||||
result.State = virtpb.Event_DONE
|
||||
return result
|
||||
}
|
||||
|
||||
func createDroplet(newd *virtpb.Droplet, result *virtpb.Event) error {
|
||||
if newd == nil {
|
||||
return fmt.Errorf("droplet protobuf == nil")
|
||||
}
|
||||
|
||||
if newd.Uuid == "" {
|
||||
newd.Uuid = uuid.New().String()
|
||||
}
|
||||
|
||||
d := me.cluster.FindDropletByUuid(newd.Uuid)
|
||||
if d != nil {
|
||||
return fmt.Errorf("droplet uuid already used")
|
||||
}
|
||||
|
||||
log.Println("found droplet to update:", newd.Uuid, newd.Hostname, newd.Cpus, newd.Memory)
|
||||
|
||||
if newd.Hostname == "" {
|
||||
return fmt.Errorf("Hostname can not be blank")
|
||||
}
|
||||
d = me.cluster.FindDropletByName(newd.Hostname)
|
||||
if d != nil {
|
||||
return fmt.Errorf("hostname already defined")
|
||||
}
|
||||
|
||||
// by default, on locally imported domains, set the preferred hypervisor!
|
||||
newd.LocalOnly = "yes on: " + "farm03"
|
||||
|
||||
newd.PreferredHypervisor = "farm03"
|
||||
newd.StartState = virtpb.DropletState_OFF
|
||||
|
||||
newd.Current = new(virtpb.Current)
|
||||
newd.Current.State = virtpb.DropletState_OFF
|
||||
|
||||
// create the network
|
||||
if err := createNetwork(newd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// create the disks
|
||||
if err := createDisks(newd); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// append the protobuf and save it
|
||||
me.cluster.AddDroplet(newd)
|
||||
if err := me.cluster.ConfigSave(); err != nil {
|
||||
log.Info("configsave error", err)
|
||||
return fmt.Errorf("ConfigSave() error: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func findDisks(d *virtpb.Droplet) error {
|
||||
log.Info("need to do this")
|
||||
return nil
|
||||
}
|
||||
|
||||
func createDisks(d *virtpb.Droplet) error {
|
||||
if d.Disks != nil {
|
||||
return findDisks(d)
|
||||
}
|
||||
|
||||
newdisk := new(virtpb.Disk)
|
||||
newdisk.Filename = d.Hostname + ".qcow2"
|
||||
newdisk.Filepath = "/home/nfs2"
|
||||
d.Disks = append(d.Disks, newdisk)
|
||||
|
||||
basefile := "/home/nfs2/base2025.wit-5.qcow2"
|
||||
newfile := filepath.Join(newdisk.Filepath, newdisk.Filename)
|
||||
|
||||
if !shell.Exists(newdisk.Filepath) {
|
||||
return fmt.Errorf("disk image path missing: %s", newdisk.Filepath)
|
||||
}
|
||||
|
||||
if !shell.Exists(basefile) {
|
||||
return fmt.Errorf("basefile %s missing", basefile)
|
||||
}
|
||||
|
||||
if shell.Exists(newfile) {
|
||||
return fmt.Errorf("disk image already exists: %s", newfile)
|
||||
}
|
||||
|
||||
cmd := []string{"dd", "bs=100M", "status=progress", "oflag=dsync", "if=" + basefile, "of=" + newfile}
|
||||
result := shell.RunRealtime(cmd)
|
||||
if result.Exit != 0 {
|
||||
return fmt.Errorf("dd to %s failed %d\n%s\n%s", newfile, result.Exit, strings.Join(result.Stdout, "\n"), strings.Join(result.Stderr, "\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createNetwork(d *virtpb.Droplet) error {
|
||||
if d.Networks != nil {
|
||||
// network already done
|
||||
return nil
|
||||
}
|
||||
if len(d.Networks) > 0 {
|
||||
// network already done
|
||||
return nil
|
||||
}
|
||||
|
||||
n := new(virtpb.Network)
|
||||
n.Mac = getNewMac()
|
||||
n.Name = "worldbr"
|
||||
d.Networks = append(d.Networks, n)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getNewMac() string {
|
||||
// mac address map to check for duplicates
|
||||
var macs map[string]string
|
||||
macs = make(map[string]string)
|
||||
|
||||
loop := me.cluster.DropletsAll() // get the list of droplets
|
||||
for loop.Scan() {
|
||||
d := loop.Next()
|
||||
for _, n := range d.Networks {
|
||||
// log.Println("network:", n.Mac, d.Uuid, d.Hostname)
|
||||
if _, ok := macs[n.Mac]; ok {
|
||||
// UUID already exists
|
||||
log.Info("duplicate MAC", n.Mac, macs[n.Mac])
|
||||
log.Info("duplicate MAC", n.Mac, d.Hostname)
|
||||
return ""
|
||||
}
|
||||
macs[n.Mac] = d.Hostname
|
||||
}
|
||||
}
|
||||
|
||||
return generateMAC(macs)
|
||||
}
|
||||
|
||||
func generateMAC(macs map[string]string) string {
|
||||
prefix := []byte{0x22, 0x22, 0x22}
|
||||
for {
|
||||
// Generate last 3 bytes randomly
|
||||
suffix := make([]byte, 3)
|
||||
if _, err := rand.Read(suffix); err != nil {
|
||||
log.Fatalf("Failed to generate random bytes: %v", err)
|
||||
}
|
||||
|
||||
// Format full MAC address
|
||||
mac := fmt.Sprintf("%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
prefix[0], prefix[1], prefix[2],
|
||||
suffix[0], suffix[1], suffix[2])
|
||||
|
||||
// Check if MAC is already used
|
||||
if _, exists := macs[mac]; !exists {
|
||||
log.Println("Using new MAC:", mac)
|
||||
return mac
|
||||
}
|
||||
log.Println("MAC already defined:", mac)
|
||||
}
|
||||
}
|
||||
|
|
9
doGui.go
9
doGui.go
|
@ -11,6 +11,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"go.wit.com/gui"
|
||||
"go.wit.com/lib/gadgets"
|
||||
"go.wit.com/lib/protobuf/virtpb"
|
||||
"go.wit.com/log"
|
||||
|
@ -24,6 +25,10 @@ func debug() {
|
|||
}
|
||||
|
||||
func doGui() {
|
||||
me.myGui = gui.New()
|
||||
me.myGui.InitEmbed(resources)
|
||||
me.myGui.Default()
|
||||
|
||||
mainWindow := gadgets.NewGenericWindow("Virtigo: (inventory your cluster)", "Local Cluster Settings")
|
||||
mainWindow.Custom = func() {
|
||||
log.Warn("Main window close")
|
||||
|
@ -31,6 +36,10 @@ func doGui() {
|
|||
}
|
||||
|
||||
drawWindow(mainWindow)
|
||||
|
||||
// sits here forever
|
||||
debug()
|
||||
|
||||
}
|
||||
|
||||
func drawWindow(win *gadgets.GenericWindow) {
|
||||
|
|
7
exit.go
7
exit.go
|
@ -6,7 +6,6 @@ package main
|
|||
import (
|
||||
"os"
|
||||
|
||||
"go.wit.com/gui"
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
|
@ -14,13 +13,13 @@ func okExit(note string) {
|
|||
if note != "" {
|
||||
log.Info(ARGNAME, "exit:", note, "ok")
|
||||
}
|
||||
gui.StandardExit()
|
||||
me.myGui.Close()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func badExit(err error) {
|
||||
log.Info(ARGNAME, "failed: ", err)
|
||||
gui.StandardExit()
|
||||
me.myGui.Close()
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
|
@ -28,7 +27,7 @@ func exit(note string, err error) {
|
|||
if note != "" {
|
||||
log.Info(ARGNAME, "exit:", note, "ok")
|
||||
}
|
||||
gui.StandardExit()
|
||||
me.myGui.Close()
|
||||
if err == nil {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
|
21
main.go
21
main.go
|
@ -10,7 +10,7 @@ import (
|
|||
|
||||
"github.com/google/uuid"
|
||||
"go.wit.com/dev/alexflint/arg"
|
||||
"go.wit.com/lib/gui/prep"
|
||||
"go.wit.com/gui"
|
||||
"go.wit.com/lib/protobuf/virtpb"
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
@ -26,10 +26,18 @@ var resources embed.FS
|
|||
|
||||
func main() {
|
||||
me = new(virtigoT)
|
||||
prep.Bash(ARGNAME, argv.DoAutoComplete) // this line should be: prep.Bash(argv)
|
||||
me.myGui = prep.Gui() // prepares the GUI package for go-args
|
||||
gui.InitArg()
|
||||
me.pp = arg.MustParse(&argv)
|
||||
|
||||
if argv.Bash {
|
||||
argv.doBash()
|
||||
os.Exit(0)
|
||||
}
|
||||
if len(argv.BashAuto) != 0 {
|
||||
argv.doBashAuto()
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
if me.pp == nil {
|
||||
me.pp.WriteHelp(os.Stdout)
|
||||
os.Exit(0)
|
||||
|
@ -56,8 +64,6 @@ func main() {
|
|||
exit(doDroplet())
|
||||
}
|
||||
|
||||
me.myGui.Start() // loads the GUI toolkit
|
||||
|
||||
if argv.Admin {
|
||||
err := me.clusters.ConfigLoad()
|
||||
if err != nil {
|
||||
|
@ -99,6 +105,7 @@ func main() {
|
|||
okExit("")
|
||||
}
|
||||
|
||||
doGui() // start making our forge GUI
|
||||
startHTTP() // sit here forever
|
||||
// sit here
|
||||
go startHTTP()
|
||||
doGui()
|
||||
}
|
||||
|
|
13
start.go
13
start.go
|
@ -52,13 +52,14 @@ func Start(id string) (string, error) {
|
|||
}
|
||||
|
||||
if d.Current == nil {
|
||||
d.Current = new(virtpb.Current)
|
||||
}
|
||||
// result = d.Hostname + " d.Current == nil"
|
||||
// return result, errors.New(result)
|
||||
|
||||
// is the droplet already on?
|
||||
if d.Current.State == virtpb.DropletState_ON {
|
||||
result = "EVENT start droplet " + d.Hostname + " is already ON"
|
||||
return result, errors.New(result)
|
||||
// is the droplet already on?
|
||||
if d.Current.State == virtpb.DropletState_ON {
|
||||
result = "EVENT start droplet " + d.Hostname + " is already ON"
|
||||
return result, errors.New(result)
|
||||
}
|
||||
}
|
||||
|
||||
// make the list of hypervisors that are active and can start new droplets
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"go.wit.com/dev/alexflint/arg"
|
||||
"go.wit.com/gui"
|
||||
"go.wit.com/lib/gadgets"
|
||||
"go.wit.com/lib/gui/prep"
|
||||
"go.wit.com/lib/protobuf/virtpb"
|
||||
)
|
||||
|
||||
|
@ -26,7 +25,7 @@ func (b *virtigoT) Enable() {
|
|||
// this app's variables
|
||||
type virtigoT struct {
|
||||
pp *arg.Parser // go-arg parser
|
||||
myGui *prep.GuiPrep // the gui toolkit handle
|
||||
myGui *gui.Node // the gui toolkit handle
|
||||
e *virtpb.Events // virt protobuf events
|
||||
hmap map[*virtpb.Hypervisor]*HyperT // map to the local struct
|
||||
names []string // ?
|
||||
|
|
35
validate.go
35
validate.go
|
@ -15,6 +15,7 @@ package main
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
@ -162,6 +163,40 @@ func ValidateDiskFilenames() ([]*virtpb.Event, error) {
|
|||
return alle, nil
|
||||
}
|
||||
|
||||
func getNewMac() string {
|
||||
// mac address map to check for duplicates
|
||||
var macs map[string]string
|
||||
macs = make(map[string]string)
|
||||
|
||||
loop := me.cluster.DropletsAll() // get the list of droplets
|
||||
for loop.Scan() {
|
||||
d := loop.Next()
|
||||
for _, n := range d.Networks {
|
||||
// log.Println("network:", n.Mac, d.Uuid, d.Hostname)
|
||||
if _, ok := macs[n.Mac]; ok {
|
||||
// UUID already exists
|
||||
log.Info("duplicate MAC", n.Mac, macs[n.Mac])
|
||||
log.Info("duplicate MAC", n.Mac, d.Hostname)
|
||||
return ""
|
||||
}
|
||||
macs[n.Mac] = d.Hostname
|
||||
}
|
||||
}
|
||||
|
||||
var i int = 9
|
||||
var mac string
|
||||
for {
|
||||
mac = fmt.Sprintf("22:22:22:22:22:%02d", i)
|
||||
if _, ok := macs[mac]; ok {
|
||||
log.Info("MAC already defined", mac, macs[mac])
|
||||
i += 1
|
||||
continue
|
||||
}
|
||||
log.Info("using new MAC:", mac)
|
||||
return mac
|
||||
}
|
||||
}
|
||||
|
||||
// consistancy check. run on a regular basis
|
||||
//
|
||||
// runs on startup. dies if there are duplicates
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
// Copyright 2017-2025 WIT.COM Inc. All rights reserved.
|
||||
// Use of this source code is governed by the GPL 3.0
|
||||
|
||||
package main
|
||||
|
||||
// An app to submit patches for the 30 GO GUI repos
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"go.wit.com/gui"
|
||||
"go.wit.com/lib/gadgets"
|
||||
"go.wit.com/lib/protobuf/virtpb"
|
||||
"go.wit.com/log"
|
||||
)
|
||||
|
||||
func (admin *adminT) createDropletWindow() *gadgets.GenericWindow {
|
||||
d := new(virtpb.Droplet)
|
||||
|
||||
win := gadgets.NewGenericWindow("Create Droplet "+d.Hostname, "settings")
|
||||
win.Custom = func() {
|
||||
log.Warn("edit window close")
|
||||
}
|
||||
|
||||
grid := win.Group.RawGrid()
|
||||
|
||||
var save *gui.Node
|
||||
|
||||
grid.NewLabel("name")
|
||||
name := grid.NewTextbox("new2.wit.com")
|
||||
d.Hostname = "new2.wit.com"
|
||||
name.SetText(d.Hostname)
|
||||
name.Custom = func() {
|
||||
if d.Hostname == name.String() {
|
||||
return
|
||||
}
|
||||
d.Hostname = name.String()
|
||||
log.Info("changed droplet name to", d.Hostname)
|
||||
save.Enable()
|
||||
}
|
||||
grid.NextRow()
|
||||
|
||||
mem := gadgets.NewBasicEntry(grid, "memory (GB)")
|
||||
mem.SetText("16")
|
||||
d.Memory = int64(16 * 1024 * 2024 * 1024)
|
||||
grid.NextRow()
|
||||
mem.Custom = func() {
|
||||
newmem, err := strconv.Atoi(mem.String())
|
||||
if err != nil {
|
||||
log.Info("mem value error", mem.String(), err)
|
||||
mem.SetText(fmt.Sprintf("%d", d.Memory/(1024*1024*1024)))
|
||||
return
|
||||
}
|
||||
if newmem < 1 {
|
||||
log.Info("mem can not be < 1")
|
||||
mem.SetText(fmt.Sprintf("%d", d.Memory/(1024*1024*1024)))
|
||||
return
|
||||
}
|
||||
d.Memory = int64(newmem * (1024 * 2024 * 1024))
|
||||
log.Info("changed mem value. new val =", d.Memory)
|
||||
|
||||
save.Enable()
|
||||
}
|
||||
grid.NextRow() // each entry is on it's own row
|
||||
|
||||
cpus := gadgets.NewBasicEntry(grid, "cpus")
|
||||
cpus.SetText("4")
|
||||
d.Cpus = int64(4)
|
||||
cpus.Custom = func() {
|
||||
newcpu, err := strconv.Atoi(cpus.String())
|
||||
if err != nil {
|
||||
log.Info("cpus value error", cpus.String(), err)
|
||||
cpus.SetText(fmt.Sprintf("%d", d.Cpus))
|
||||
return
|
||||
}
|
||||
if newcpu < 1 {
|
||||
log.Info("cpus can not be < 1")
|
||||
cpus.SetText(fmt.Sprintf("%d", d.Cpus))
|
||||
return
|
||||
}
|
||||
d.Cpus = int64(newcpu)
|
||||
log.Info("changed cpus value. new val =", d.Cpus)
|
||||
|
||||
save.Enable()
|
||||
}
|
||||
grid.NextRow() // each entry is on it's own row
|
||||
|
||||
/*
|
||||
save = grid.NewButton("postEvent() EDIT", func() {
|
||||
log.Info("save droplet changes here")
|
||||
|
||||
e := new(virtpb.Event)
|
||||
e.Etype = virtpb.EventType_EDIT
|
||||
e.Droplet = d
|
||||
|
||||
if err := admin.postEvent(e); err != nil {
|
||||
log.Info("event edit err", err)
|
||||
} else {
|
||||
log.Info("admin.postEvent() worked (?)")
|
||||
}
|
||||
})
|
||||
*/
|
||||
|
||||
save = grid.NewButton("Create", func() {
|
||||
log.Info("save droplet changes here")
|
||||
|
||||
e := new(virtpb.Event)
|
||||
e.Etype = virtpb.EventType_ADD
|
||||
e.Droplet = d
|
||||
|
||||
if err := admin.postEvent(e); err != nil {
|
||||
log.Info("event edit err", err)
|
||||
} else {
|
||||
log.Info("admin.postEvent() worked (?)")
|
||||
}
|
||||
})
|
||||
|
||||
// save.Disable()
|
||||
return win
|
||||
}
|
|
@ -7,7 +7,6 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"go.wit.com/gui"
|
||||
"go.wit.com/lib/gadgets"
|
||||
|
@ -29,12 +28,7 @@ func (admin *adminT) editDropletWindow(d *virtpb.Droplet) *gadgets.GenericWindow
|
|||
name := grid.NewTextbox("something")
|
||||
name.SetText(d.Hostname)
|
||||
name.Custom = func() {
|
||||
if d.Hostname == name.String() {
|
||||
return
|
||||
}
|
||||
d.Hostname = name.String()
|
||||
log.Info("changed droplet name to", d.Hostname)
|
||||
save.Enable()
|
||||
log.Info("changed droplet name")
|
||||
}
|
||||
grid.NextRow()
|
||||
|
||||
|
@ -42,42 +36,15 @@ func (admin *adminT) editDropletWindow(d *virtpb.Droplet) *gadgets.GenericWindow
|
|||
mem.SetText(fmt.Sprintf("%d", d.Memory/(1024*1024*1024)))
|
||||
grid.NextRow()
|
||||
mem.Custom = func() {
|
||||
newmem, err := strconv.Atoi(mem.String())
|
||||
if err != nil {
|
||||
log.Info("mem value error", mem.String(), err)
|
||||
mem.SetText(fmt.Sprintf("%d", d.Memory/(1024*1024*1024)))
|
||||
return
|
||||
}
|
||||
if newmem < 1 {
|
||||
log.Info("mem can not be < 1")
|
||||
mem.SetText(fmt.Sprintf("%d", d.Memory/(1024*1024*1024)))
|
||||
return
|
||||
}
|
||||
d.Memory = int64(newmem * (1024 * 2024 * 1024))
|
||||
log.Info("changed mem value. new val =", d.Memory)
|
||||
|
||||
save.Enable()
|
||||
log.Info("changed mem value. new val =", mem.String())
|
||||
}
|
||||
|
||||
cpus := gadgets.NewBasicEntry(grid, "cpus")
|
||||
cpus.SetText(fmt.Sprintf("%d", d.Cpus))
|
||||
grid.NextRow()
|
||||
cpus.Custom = func() {
|
||||
newcpu, err := strconv.Atoi(cpus.String())
|
||||
if err != nil {
|
||||
log.Info("cpus value error", cpus.String(), err)
|
||||
cpus.SetText(fmt.Sprintf("%d", d.Cpus))
|
||||
return
|
||||
}
|
||||
if newcpu < 1 {
|
||||
log.Info("cpus can not be < 1")
|
||||
cpus.SetText(fmt.Sprintf("%d", d.Cpus))
|
||||
return
|
||||
}
|
||||
d.Cpus = int64(newcpu)
|
||||
log.Info("changed cpus value. new val =", d.Cpus)
|
||||
|
||||
save.Enable()
|
||||
log.Info("changed cpus value")
|
||||
}
|
||||
|
||||
grid.NewLabel("hypervisor")
|
||||
|
@ -87,8 +54,6 @@ func (admin *adminT) editDropletWindow(d *virtpb.Droplet) *gadgets.GenericWindow
|
|||
hyper.AddText("farm05")
|
||||
if d.Current != nil {
|
||||
hyper.SetText(d.Current.Hypervisor)
|
||||
} else {
|
||||
hyper.SetText("farm03")
|
||||
}
|
||||
grid.NextRow()
|
||||
|
||||
|
@ -101,14 +66,11 @@ func (admin *adminT) editDropletWindow(d *virtpb.Droplet) *gadgets.GenericWindow
|
|||
|
||||
e := new(virtpb.Event)
|
||||
e.Etype = virtpb.EventType_EDIT
|
||||
e.Droplet = d
|
||||
/*
|
||||
e.Droplet = new(virtpb.Droplet)
|
||||
e.Droplet.Uuid = d.Uuid
|
||||
e.Droplet.Cpus = 4
|
||||
e.Droplet.Memory = 8 * (1024 * 1024 * 1024)
|
||||
e.Droplet.Hostname = name.String()
|
||||
*/
|
||||
e.Droplet = new(virtpb.Droplet)
|
||||
e.Droplet.Uuid = d.Uuid
|
||||
e.Droplet.Cpus = 4
|
||||
e.Droplet.Memory = 8 * (1024 * 1024 * 1024)
|
||||
e.Droplet.Hostname = name.String()
|
||||
|
||||
if err := admin.postEvent(e); err != nil {
|
||||
log.Info("event edit err", err)
|
||||
|
|
|
@ -73,11 +73,6 @@ func newDropletsWindow(admin *adminT) *stdDropletTableWin {
|
|||
dwin.doInactiveDroplets(found)
|
||||
})
|
||||
|
||||
grid.NewButton("Create", func() {
|
||||
log.Info("create droplet here")
|
||||
admin.createDropletWindow()
|
||||
})
|
||||
|
||||
// make a box at the bottom of the window for the protobuf table
|
||||
dwin.box = dwin.win.Bottom.Box().SetProgName("TBOX")
|
||||
return dwin
|
||||
|
@ -113,15 +108,6 @@ func (dw *stdDropletTableWin) doInactiveDroplets(pb *virtpb.Droplets) {
|
|||
})
|
||||
dropon.Custom = func(d *virtpb.Droplet) {
|
||||
log.Info("start droplet here", d.Hostname)
|
||||
log.Info("should start droplet here")
|
||||
log.Info(d.SprintHeader())
|
||||
e := new(virtpb.Event)
|
||||
e.Etype = virtpb.EventType_POWERON
|
||||
e.DropletUuid = d.Uuid
|
||||
|
||||
if err := dw.admin.postEvent(e); err != nil {
|
||||
log.Info("droplet start err", err)
|
||||
}
|
||||
}
|
||||
|
||||
vp := t.AddButtonFunc("Verify Config", func(p *virtpb.Droplet) string {
|
||||
|
@ -178,15 +164,7 @@ func (dw *stdDropletTableWin) doActiveDroplets(pb *virtpb.Droplets) {
|
|||
log.Info("data", string(data), "err =", err)
|
||||
}
|
||||
|
||||
// t.AddHostname()
|
||||
vp := t.AddButtonFunc("Hostname", func(p *virtpb.Droplet) string {
|
||||
return p.Hostname
|
||||
})
|
||||
vp.Custom = func(d *virtpb.Droplet) {
|
||||
log.Info("edit droplet here", d.Hostname)
|
||||
dw.admin.editDropletWindow(d)
|
||||
}
|
||||
|
||||
t.AddHostname()
|
||||
t.AddStringFunc("location", func(d *virtpb.Droplet) string {
|
||||
return d.Current.Hypervisor
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue