Skip to content

Commit

Permalink
Initial hyperkit driver implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
dlorenc authored and dlorenc committed Aug 1, 2017
1 parent 2e9ebb6 commit fe7f8f5
Show file tree
Hide file tree
Showing 9 changed files with 494 additions and 1 deletion.
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,15 @@ out/minikube-installer.exe: out/minikube-windows-amd64.exe
mv out/windows_tmp/minikube-installer.exe out/minikube-installer.exe
rm -rf out/windows_tmp

out/docker-machine-driver-hyperkit:
go build -o $(BUILD_DIR)/hyperkit k8s.io/minikube/cmd/drivers/hyperkit

.PHONY: install-hyperkit-driver
install-hyperkit-driver: out/docker-machine-driver-hyperkit
sudo cp out/hyperkit $(HOME)/bin/docker-machine-driver-hyperkit
sudo chown root:wheel $(HOME)/bin/docker-machine-driver-hyperkit
sudo chmod u+s $(HOME)/bin/docker-machine-driver-hyperkit

.PHONY: check-release
check-release:
go test -v ./deploy/minikube/release_sanity_test.go -tags=release
Expand Down
10 changes: 10 additions & 0 deletions cmd/drivers/hyperkit/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package main

import (
"github.com/docker/machine/libmachine/drivers/plugin"
"k8s.io/minikube/pkg/minikube/drivers/hyperkit"
)

func main() {
plugin.RegisterDriver(hyperkit.NewDriver("", ""))
}
5 changes: 5 additions & 0 deletions pkg/minikube/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/docker/machine/libmachine/engine"
"github.com/docker/machine/libmachine/host"
"github.com/docker/machine/libmachine/mcnerror"
"github.com/docker/machine/libmachine/ssh"
"github.com/docker/machine/libmachine/state"
"github.com/golang/glog"
"github.com/pkg/errors"
Expand All @@ -56,6 +57,8 @@ const fileScheme = "file"
//see: https://github.com/kubernetes/kubernetes/blob/master/pkg/util/logs/logs.go#L32-34
func init() {
flag.Set("logtostderr", "false")
// Setting the default client to native gives much better performance.
ssh.SetDefaultClient(ssh.Native)
}

// StartHost starts a host VM.
Expand Down Expand Up @@ -366,6 +369,8 @@ func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) {
driver = createHypervHost(config)
case "none":
driver = createNoneHost(config)
case "hyperkit":
driver = createHyperkitHost(config)
default:
glog.Exitf("Unsupported driver: %s\n", config.VMDriver)
}
Expand Down
16 changes: 16 additions & 0 deletions pkg/minikube/cluster/cluster_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/docker/machine/libmachine/drivers"
cfg "k8s.io/minikube/pkg/minikube/config"
"k8s.io/minikube/pkg/minikube/constants"
"k8s.io/minikube/pkg/minikube/drivers/hyperkit"
)

func createVMwareFusionHost(config MachineConfig) drivers.Driver {
Expand Down Expand Up @@ -57,6 +58,21 @@ type xhyveDriver struct {
RawDisk bool
}

func createHyperkitHost(config MachineConfig) *hyperkit.Driver {
return &hyperkit.Driver{
BaseDriver: &drivers.BaseDriver{
MachineName: cfg.GetMachineName(),
StorePath: constants.GetMinipath(),
SSHUser: "docker",
},
Boot2DockerURL: config.Downloader.GetISOFileURI(config.MinikubeISO),
DiskSize: config.DiskSize,
Memory: config.Memory,
CPU: config.CPUs,
Cmdline: "loglevel=3 user=docker console=ttyS0 console=tty0 noembed nomodeset norestore waitusb=10 systemd.legacy_systemd_cgroup_controller=yes base host=" + cfg.GetMachineName(),
}
}

func createXhyveHost(config MachineConfig) *xhyveDriver {
useVirtio9p := !config.DisableDriverMounts
return &xhyveDriver{
Expand Down
48 changes: 48 additions & 0 deletions pkg/minikube/drivers/hyperkit/disk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package hyperkit

import (
"io/ioutil"
"os"
"path/filepath"
"syscall"

"github.com/cloudflare/cfssl/log"
"github.com/docker/machine/libmachine/mcnutils"
)

func createDiskImage(sshKeyPath, diskPath string, diskSize int) error {
tarBuf, err := mcnutils.MakeDiskImage(sshKeyPath)
if err != nil {
return err
}

file, err := os.OpenFile(diskPath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer file.Close()
file.Seek(0, os.SEEK_SET)

if _, err := file.Write(tarBuf.Bytes()); err != nil {
return err
}
file.Close()

if err := os.Truncate(diskPath, int64(diskSize*1048576)); err != nil {
return err
}
return nil
}

func fixPermissions(path string) error {
os.Chown(path, syscall.Getuid(), syscall.Getegid())
files, _ := ioutil.ReadDir(path)
for _, f := range files {
fp := filepath.Join(path, f.Name())
log.Debugf(fp)
if err := os.Chown(fp, syscall.Getuid(), syscall.Getegid()); err != nil {
return err
}
}
return nil
}
247 changes: 247 additions & 0 deletions pkg/minikube/drivers/hyperkit/driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
package hyperkit

import (
"fmt"
"os"
"path/filepath"
"syscall"
"time"

"github.com/docker/machine/libmachine/drivers"
"github.com/docker/machine/libmachine/log"
"github.com/docker/machine/libmachine/mcnflag"
"github.com/docker/machine/libmachine/mcnutils"
"github.com/docker/machine/libmachine/ssh"
"github.com/docker/machine/libmachine/state"
hyperkit "github.com/moby/hyperkit/go"
"github.com/pborman/uuid"
vmnet "github.com/zchee/go-vmnet"
commonutil "k8s.io/minikube/pkg/util"
)

const (
isoFilename = "boot2docker.iso"
)

type Driver struct {
*drivers.BaseDriver
Boot2DockerURL string
DiskSize int
Pid int
CPU int
Memory int
Cmdline string
}

func NewDriver(hostName, storePath string) *Driver {
return &Driver{
BaseDriver: &drivers.BaseDriver{
SSHUser: "docker",
},
}
}

func (d *Driver) Create() error {
b2dutils := mcnutils.NewB2dUtils(d.StorePath)

if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
return err
}

if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil {
return err
}
isoPath := d.ResolveStorePath(isoFilename)
if err := d.extractKernel(isoPath); err != nil {
return err
}

return d.Start()
}

// DriverName returns the name of the driver
func (d *Driver) DriverName() string {
return "hyperkit"
}

// GetCreateFlags returns the mcnflag.Flag slice representing the flags
// that can be set, their descriptions and defaults.
func (d *Driver) GetCreateFlags() []mcnflag.Flag {
return nil
}

// GetSSHHostname returns hostname for use with ssh
func (d *Driver) GetSSHHostname() (string, error) {
return d.IPAddress, nil
}

// GetURL returns a Docker compatible host URL for connecting to this host
// e.g. tcp://1.2.3.4:2376
func (d *Driver) GetURL() (string, error) {
ip, err := d.GetIP()
if err != nil {
return "", err
}
return fmt.Sprintf("tcp://%s:2376", ip), nil
}

// GetState returns the state that the host is in (running, stopped, etc)
func (d *Driver) GetState() (state.State, error) {
if d.Pid == 0 {
return state.Stopped, nil
}
p, err := os.FindProcess(d.Pid)
if err != nil {
return state.Error, err
}
if p == nil {
return state.Stopped, nil
}
return state.Running, nil
}

// Kill stops a host forcefully
func (d *Driver) Kill() error {
return d.sendSignal(syscall.SIGKILL)
}

// PreCreateCheck allows for pre-create operations to make sure a driver is ready for creation
func (d *Driver) PreCreateCheck() error {
return nil
}

// Remove a host
func (d *Driver) Remove() error {
s, err := d.GetState()
if err != nil || s == state.Error {
log.Infof("Error checking machine status: %s, assuming it has been removed already", err)
return nil
}
if s == state.Running {
if err := d.Stop(); err != nil {
return err
}
}
return nil
}

// Restart a host. This may just call Stop(); Start() if the provider does not
// have any special restart behaviour.
func (d *Driver) Restart() error {
for _, f := range []func() error{d.Stop, d.Start} {
if err := f(); err != nil {
return err
}
}
return nil
}

// SetConfigFromFlags configures the driver with the object that was returned
// by RegisterCreateFlags
func (d *Driver) SetConfigFromFlags(opts drivers.DriverOptions) error {
return nil
}

// Start a host
func (d *Driver) Start() error {

// TODO: handle the disk already existing.
// TODO: handle different disk types.
diskPath := filepath.Join(d.ResolveStorePath("."), d.MachineName+".rawdisk")
if err := createDiskImage(d.publicSSHKeyPath(), diskPath, d.DiskSize); err != nil {
return err
}

if err := fixPermissions(d.ResolveStorePath(".")); err != nil {
return err
}

h, err := hyperkit.New("", "", filepath.Join(d.StorePath, "machines", d.MachineName))
if err != nil {
return err
}

// TODO: handle the rest of our settings.
h.Kernel = d.ResolveStorePath("bzimage")
h.Initrd = d.ResolveStorePath("initrd")
h.VMNet = true
h.ISOImage = d.ResolveStorePath(isoFilename)
h.Console = hyperkit.ConsoleFile
h.CPUs = d.CPU
h.Memory = d.Memory

// Set UUID
h.UUID = uuid.NewUUID().String()
log.Infof("Generated UUID %s", h.UUID)
mac, err := vmnet.GetMACAddressFromUUID(h.UUID)
if err != nil {
return err
}

// Need to strip 0's
mac = trimMacAddress(mac)
log.Infof("Generated MAC %s", mac)

h.Disks = []hyperkit.DiskConfig{
{
Path: diskPath,
Size: d.DiskSize,
Driver: "virtio-blk",
},
}
log.Infof("Starting with cmdline: %s", d.Cmdline)
if err := h.Start(d.Cmdline); err != nil {
return err
}

d.Pid = h.Pid

getIP := func() error {
var err error
d.IPAddress, err = GetIPAddressByMACAddress(mac)
if err != nil {
return &commonutil.RetriableError{Err: err}
}
return nil
}

if err := commonutil.RetryAfter(30, getIP, 2*time.Second); err != nil {
return fmt.Errorf("IP address never found in dhcp leases file %v", err)
}
return nil
}

// Stop a host gracefully
func (d *Driver) Stop() error {
return d.sendSignal(syscall.SIGTERM)
}

func (d *Driver) extractKernel(isoPath string) error {
for _, f := range []struct {
pathInIso string
destPath string
}{
{"/boot/bzimage", "bzimage"},
{"/boot/initrd", "initrd"},
{"/isolinux/isolinux.cfg", "isolinux.cfg"},
} {
fullDestPath := d.ResolveStorePath(f.destPath)
if err := ExtractFile(isoPath, f.pathInIso, fullDestPath); err != nil {
return err
}
}
return nil
}

func (d *Driver) publicSSHKeyPath() string {
return d.GetSSHKeyPath() + ".pub"
}

func (d *Driver) sendSignal(s os.Signal) error {
proc, err := os.FindProcess(d.Pid)
if err != nil {
return err
}

return proc.Signal(s)
}
Loading

0 comments on commit fe7f8f5

Please sign in to comment.