diff --git a/doDroplet.go b/doDroplet.go index adba47c..7e40242 100644 --- a/doDroplet.go +++ b/doDroplet.go @@ -7,11 +7,15 @@ 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" ) @@ -132,12 +136,12 @@ func doEvent(e *virtpb.Event) *virtpb.Event { } result.DropletName = e.Droplet.Hostname result.Error = e.Droplet.FormatTEXT() // feedback to the other side for debugging - if e.Droplet != nil { - if err := createDroplet(e.Droplet, result); err != nil { - result.Error += fmt.Sprintf("createDroplet() err: %v", err) - result.State = virtpb.Event_FAIL - return result - } + + // 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 @@ -224,23 +228,134 @@ func createDroplet(newd *virtpb.Droplet, result *virtpb.Event) error { return fmt.Errorf("hostname already defined") } + // by default, on locally imported domains, set the preferred hypervisor! newd.LocalOnly = "yes on: " + "farm03" - // by default, on locally imported domains, set the preferred hypervisor! newd.PreferredHypervisor = "farm03" + newd.StartState = virtpb.DropletState_OFF newd.Current = new(virtpb.Current) - newd.Current.Hypervisor = "farm03" - newd.StartState = virtpb.DropletState_OFF newd.Current.State = virtpb.DropletState_OFF - me.cluster.AddDroplet(newd) + // 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) } - result.State = virtpb.Event_DONE 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) + } +} diff --git a/start.go b/start.go index a7cf493..76ba91c 100644 --- a/start.go +++ b/start.go @@ -52,14 +52,13 @@ func Start(id string) (string, error) { } if d.Current == nil { - // result = d.Hostname + " d.Current == nil" - // return result, errors.New(result) + d.Current = new(virtpb.Current) + } - // 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 diff --git a/validate.go b/validate.go index e648813..c2f788b 100644 --- a/validate.go +++ b/validate.go @@ -15,7 +15,6 @@ package main import ( "errors" - "fmt" "os" "path/filepath" "strings" @@ -163,40 +162,6 @@ 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