Skip to content

Commit

Permalink
allow the creation of > 128 VMs over the lifetime a given corectld se…
Browse files Browse the repository at this point in the history
…ssion

according to https://developer.apple.com/library/mac/documentation/DriversKernelHardware/Reference/vmnet/
one only "can create a maximum of 32 interfaces with a limit of 4 per guest
operating system" which in practice means that a given Pid/corectld instance in
aggregate can't create more than 128 VMs (interfaces).
by doing the UUIDs lookup/validation as an external process "unrelated" from its
parent we get around this limitation and so each corectld session stops having
an 2ˆ7 upper bound on the number the VMs it can create over its lifetime

this commit handles the first part of #77

Signed-off-by: António Meireles <[email protected]>
  • Loading branch information
AntonioMeireles committed Jul 5, 2016
1 parent 421d1fd commit 0fb028c
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 19 deletions.
2 changes: 2 additions & 0 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ func init() {
return
}
session.Caller.User = usr
} else if cmd.Name() == "uuid2mac" {
return
} else {
return fmt.Errorf("too many privileges invoking corectl. " +
"running directly as root, or via 'sudo', only " +
Expand Down
29 changes: 28 additions & 1 deletion cmd/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ import (
"fmt"

"github.com/TheNewNormal/corectl/components/common"
"github.com/TheNewNormal/corectl/components/host/darwin/misc/uuid2ip"
"github.com/TheNewNormal/corectl/components/host/session"
"github.com/TheNewNormal/corectl/components/server"
"github.com/TheNewNormal/corectl/release"
"github.com/helm/helm/log"
"github.com/satori/go.uuid"

"github.com/everdev/mack"
"github.com/spf13/cobra"
Expand All @@ -44,8 +47,32 @@ var (
Short: "Shows corectld status",
RunE: common.PScommand,
}
uuidToMacCmd = &cobra.Command{
Use: "uuid2mac",
Short: "returns the MAC address that will assembled from the " +
"given UUID",
RunE: uuidToMacCommand,
Hidden: true,
}
)

func uuidToMacCommand(cmd *cobra.Command, args []string) (err error) {
var macAddr string
if _, err = uuid.FromString(args[0]); err != nil {
log.Warn("%s not a valid UUID as it doesn't follow RFC "+
"4122", args[0])
// given that we only call this with dats generated with
// uuid.NewV4().String() ...
err = fmt.Errorf("Something went very wrong, as we're unable to "+
"generate a MAC address from the provided UUID (%s). Please fill "+
"a bug at https://github.com/TheNewNormal/corectl/issues with "+
"this error and wait there for our feedback...", args[0])
} else if macAddr, err = uuid2ip.GuestMACfromUUID(args[0]); err == nil {
fmt.Println(macAddr)
}
return
}

func shutdownCommand(cmd *cobra.Command, args []string) (err error) {
if _, err = server.Daemon.Running(); err != nil {
return
Expand Down Expand Up @@ -87,5 +114,5 @@ func init() {
"sets the user that will 'own' the corectld instance")
serverStartCmd.Flags().BoolP("force", "f", false,
"rebuilds config drive iso even if a suitable one is already present")
rootCmd.AddCommand(shutdownCmd, statusCmd, serverStartCmd)
rootCmd.AddCommand(shutdownCmd, statusCmd, serverStartCmd, uuidToMacCmd)
}
72 changes: 54 additions & 18 deletions components/server/rpcservices.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,26 @@
package server

import (
"bufio"
"bytes"
"fmt"
"io"
"net/http"
"os/exec"
"path/filepath"
"strings"
"syscall"

"os"
"path"
"time"

"github.com/TheNewNormal/corectl/components/host/darwin/misc/uuid2ip"
"github.com/TheNewNormal/corectl/components/host/session"
"github.com/TheNewNormal/corectl/release"
"github.com/blang/semver"
"github.com/helm/helm/log"
"github.com/gorilla/rpc"
"github.com/gorilla/rpc/json"
"github.com/helm/helm/log"
"github.com/satori/go.uuid"
)

Expand Down Expand Up @@ -116,37 +118,71 @@ func (s *RPCservice) RemoveImage(r *http.Request,
func (s *RPCservice) UUIDtoMACaddr(r *http.Request,
args *RPCquery, reply *RPCreply) (err error) {
var (
MAC string
i int
macAddr string
stdout io.ReadCloser
UUID, original = args.Input[0], args.Input[1]
)
log.Debug("vm:uuid2mac")
log.Debug("vm:uuid2mac (%v:%v)", args.Input[0], args.Input[1])

// handles UUIDs
if _, found := Daemon.Active[UUID]; found {
err = fmt.Errorf("Aborted: Another VM is "+
"already running with the exact same UUID (%s)", UUID)
err = fmt.Errorf("Aborted: Another VM is already running with the "+
"exact same UUID [%s]", UUID)
} else {
for {
// we keep the loop just in case as the check
// above is supposed to avoid most failures...
// XXX
if MAC, err =
uuid2ip.GuestMACfromUUID(UUID); err == nil {
// var ip string
// if ip, err = uuid2ip.GuestIPfromMAC(MAC); err == nil {
// log.Info("GUEST IP will be %v", ip)
for i < 3 {
//
// we just can't call uuid2ip.GuestMACfromUUID(UUID) directly here.
//
// according to https://developer.apple.com/library/mac/documentation/DriversKernelHardware/Reference/vmnet/
// one "can create a maximum of 32 interfaces with a limit of
// 4 per guest operating system" which in practice means that a
// given Pid/corectld instance in aggregate can't create more than
// 128 VMs (interfaces).
// by doing the lookup as an external process that we "unrelate"
// from its parent we get around this limitation and so each
// corectld session stops having an 2ˆ7 upper bound on the number
// the VMs it can create over its lifetime
//
cmd := exec.Command(session.Executable(), "uuid2mac", UUID)
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
Setsid: false,
Pgid: 0,
}
if stdout, err = cmd.StdoutPipe(); err != nil {
break
// }
}
fmt.Println("=>", original, err)
rd := bufio.NewReader(stdout)
if err = cmd.Start(); err != nil {
break
}
macAddr, _ = rd.ReadString('\n')
macAddr = strings.TrimSuffix(macAddr, "\n")
if err = cmd.Wait(); err == nil {
if len(macAddr) > 0 {
if _, found := Daemon.Active[UUID]; !found {
// unlikely statistically but ...
break
}
}
}
log.Debug("=> %v:%v [%v]", original, err, i)
if original != "random" {
log.Warn("unable to guess the MAC Address from the provided "+
"UUID (%s). Using a randomly generated one\n", original)
}
UUID = uuid.NewV4().String()
i += 1
}
if i == 3 && err != nil {
err = fmt.Errorf("Something went very wrong, as we're unable to " +
"generate a MAC address from the provided UUID. Please fill " +
"a bug at https://github.com/TheNewNormal/corectl/issues with " +
"this error and wait there for our feedback...")
}
}
reply.Output = []string{MAC, strings.ToUpper(UUID)}
reply.Output = []string{macAddr, strings.ToUpper(UUID)}
return
}

Expand Down

0 comments on commit 0fb028c

Please sign in to comment.