droplet create makes the network and disks
This commit is contained in:
parent
bf01596f30
commit
65563eb8e2
137
doDroplet.go
137
doDroplet.go
|
@ -7,11 +7,15 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"go.wit.com/lib/gui/shell"
|
||||||
"go.wit.com/lib/protobuf/virtpb"
|
"go.wit.com/lib/protobuf/virtpb"
|
||||||
"go.wit.com/log"
|
"go.wit.com/log"
|
||||||
)
|
)
|
||||||
|
@ -132,12 +136,12 @@ func doEvent(e *virtpb.Event) *virtpb.Event {
|
||||||
}
|
}
|
||||||
result.DropletName = e.Droplet.Hostname
|
result.DropletName = e.Droplet.Hostname
|
||||||
result.Error = e.Droplet.FormatTEXT() // feedback to the other side for debugging
|
result.Error = e.Droplet.FormatTEXT() // feedback to the other side for debugging
|
||||||
if e.Droplet != nil {
|
|
||||||
if err := createDroplet(e.Droplet, result); err != nil {
|
// attempt to create the new droplet
|
||||||
result.Error += fmt.Sprintf("createDroplet() err: %v", err)
|
if err := createDroplet(e.Droplet, result); err != nil {
|
||||||
result.State = virtpb.Event_FAIL
|
result.Error += fmt.Sprintf("createDroplet() err: %v", err)
|
||||||
return result
|
result.State = virtpb.Event_FAIL
|
||||||
}
|
return result
|
||||||
}
|
}
|
||||||
log.Println("create droplet worked", e.Droplet.FormatTEXT())
|
log.Println("create droplet worked", e.Droplet.FormatTEXT())
|
||||||
result.State = virtpb.Event_DONE
|
result.State = virtpb.Event_DONE
|
||||||
|
@ -224,23 +228,134 @@ func createDroplet(newd *virtpb.Droplet, result *virtpb.Event) error {
|
||||||
return fmt.Errorf("hostname already defined")
|
return fmt.Errorf("hostname already defined")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// by default, on locally imported domains, set the preferred hypervisor!
|
||||||
newd.LocalOnly = "yes on: " + "farm03"
|
newd.LocalOnly = "yes on: " + "farm03"
|
||||||
|
|
||||||
// by default, on locally imported domains, set the preferred hypervisor!
|
|
||||||
newd.PreferredHypervisor = "farm03"
|
newd.PreferredHypervisor = "farm03"
|
||||||
|
newd.StartState = virtpb.DropletState_OFF
|
||||||
|
|
||||||
newd.Current = new(virtpb.Current)
|
newd.Current = new(virtpb.Current)
|
||||||
newd.Current.Hypervisor = "farm03"
|
|
||||||
newd.StartState = virtpb.DropletState_OFF
|
|
||||||
newd.Current.State = 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 {
|
if err := me.cluster.ConfigSave(); err != nil {
|
||||||
log.Info("configsave error", err)
|
log.Info("configsave error", err)
|
||||||
return fmt.Errorf("ConfigSave() error: %v", err)
|
return fmt.Errorf("ConfigSave() error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
result.State = virtpb.Event_DONE
|
|
||||||
return nil
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
13
start.go
13
start.go
|
@ -52,14 +52,13 @@ func Start(id string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.Current == nil {
|
if d.Current == nil {
|
||||||
// result = d.Hostname + " d.Current == nil"
|
d.Current = new(virtpb.Current)
|
||||||
// return result, errors.New(result)
|
}
|
||||||
|
|
||||||
// is the droplet already on?
|
// is the droplet already on?
|
||||||
if d.Current.State == virtpb.DropletState_ON {
|
if d.Current.State == virtpb.DropletState_ON {
|
||||||
result = "EVENT start droplet " + d.Hostname + " is already ON"
|
result = "EVENT start droplet " + d.Hostname + " is already ON"
|
||||||
return result, errors.New(result)
|
return result, errors.New(result)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// make the list of hypervisors that are active and can start new droplets
|
// make the list of hypervisors that are active and can start new droplets
|
||||||
|
|
35
validate.go
35
validate.go
|
@ -15,7 +15,6 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -163,40 +162,6 @@ func ValidateDiskFilenames() ([]*virtpb.Event, error) {
|
||||||
return alle, nil
|
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
|
// consistancy check. run on a regular basis
|
||||||
//
|
//
|
||||||
// runs on startup. dies if there are duplicates
|
// runs on startup. dies if there are duplicates
|
||||||
|
|
Loading…
Reference in New Issue