Skip to content

Commit fe7f8f5

Browse files
dlorencdlorenc
dlorenc
authored andcommitted
Initial hyperkit driver implementation.
1 parent 2e9ebb6 commit fe7f8f5

File tree

9 files changed

+494
-1
lines changed

9 files changed

+494
-1
lines changed

Makefile

+9
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,15 @@ out/minikube-installer.exe: out/minikube-windows-amd64.exe
193193
mv out/windows_tmp/minikube-installer.exe out/minikube-installer.exe
194194
rm -rf out/windows_tmp
195195

196+
out/docker-machine-driver-hyperkit:
197+
go build -o $(BUILD_DIR)/hyperkit k8s.io/minikube/cmd/drivers/hyperkit
198+
199+
.PHONY: install-hyperkit-driver
200+
install-hyperkit-driver: out/docker-machine-driver-hyperkit
201+
sudo cp out/hyperkit $(HOME)/bin/docker-machine-driver-hyperkit
202+
sudo chown root:wheel $(HOME)/bin/docker-machine-driver-hyperkit
203+
sudo chmod u+s $(HOME)/bin/docker-machine-driver-hyperkit
204+
196205
.PHONY: check-release
197206
check-release:
198207
go test -v ./deploy/minikube/release_sanity_test.go -tags=release

cmd/drivers/hyperkit/main.go

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package main
2+
3+
import (
4+
"github.com/docker/machine/libmachine/drivers/plugin"
5+
"k8s.io/minikube/pkg/minikube/drivers/hyperkit"
6+
)
7+
8+
func main() {
9+
plugin.RegisterDriver(hyperkit.NewDriver("", ""))
10+
}

pkg/minikube/cluster/cluster.go

+5
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"github.com/docker/machine/libmachine/engine"
3535
"github.com/docker/machine/libmachine/host"
3636
"github.com/docker/machine/libmachine/mcnerror"
37+
"github.com/docker/machine/libmachine/ssh"
3738
"github.com/docker/machine/libmachine/state"
3839
"github.com/golang/glog"
3940
"github.com/pkg/errors"
@@ -56,6 +57,8 @@ const fileScheme = "file"
5657
//see: https://github.com/kubernetes/kubernetes/blob/master/pkg/util/logs/logs.go#L32-34
5758
func init() {
5859
flag.Set("logtostderr", "false")
60+
// Setting the default client to native gives much better performance.
61+
ssh.SetDefaultClient(ssh.Native)
5962
}
6063

6164
// StartHost starts a host VM.
@@ -366,6 +369,8 @@ func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) {
366369
driver = createHypervHost(config)
367370
case "none":
368371
driver = createNoneHost(config)
372+
case "hyperkit":
373+
driver = createHyperkitHost(config)
369374
default:
370375
glog.Exitf("Unsupported driver: %s\n", config.VMDriver)
371376
}

pkg/minikube/cluster/cluster_darwin.go

+16
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/docker/machine/libmachine/drivers"
2424
cfg "k8s.io/minikube/pkg/minikube/config"
2525
"k8s.io/minikube/pkg/minikube/constants"
26+
"k8s.io/minikube/pkg/minikube/drivers/hyperkit"
2627
)
2728

2829
func createVMwareFusionHost(config MachineConfig) drivers.Driver {
@@ -57,6 +58,21 @@ type xhyveDriver struct {
5758
RawDisk bool
5859
}
5960

61+
func createHyperkitHost(config MachineConfig) *hyperkit.Driver {
62+
return &hyperkit.Driver{
63+
BaseDriver: &drivers.BaseDriver{
64+
MachineName: cfg.GetMachineName(),
65+
StorePath: constants.GetMinipath(),
66+
SSHUser: "docker",
67+
},
68+
Boot2DockerURL: config.Downloader.GetISOFileURI(config.MinikubeISO),
69+
DiskSize: config.DiskSize,
70+
Memory: config.Memory,
71+
CPU: config.CPUs,
72+
Cmdline: "loglevel=3 user=docker console=ttyS0 console=tty0 noembed nomodeset norestore waitusb=10 systemd.legacy_systemd_cgroup_controller=yes base host=" + cfg.GetMachineName(),
73+
}
74+
}
75+
6076
func createXhyveHost(config MachineConfig) *xhyveDriver {
6177
useVirtio9p := !config.DisableDriverMounts
6278
return &xhyveDriver{

pkg/minikube/drivers/hyperkit/disk.go

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package hyperkit
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
"path/filepath"
7+
"syscall"
8+
9+
"github.com/cloudflare/cfssl/log"
10+
"github.com/docker/machine/libmachine/mcnutils"
11+
)
12+
13+
func createDiskImage(sshKeyPath, diskPath string, diskSize int) error {
14+
tarBuf, err := mcnutils.MakeDiskImage(sshKeyPath)
15+
if err != nil {
16+
return err
17+
}
18+
19+
file, err := os.OpenFile(diskPath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)
20+
if err != nil {
21+
return err
22+
}
23+
defer file.Close()
24+
file.Seek(0, os.SEEK_SET)
25+
26+
if _, err := file.Write(tarBuf.Bytes()); err != nil {
27+
return err
28+
}
29+
file.Close()
30+
31+
if err := os.Truncate(diskPath, int64(diskSize*1048576)); err != nil {
32+
return err
33+
}
34+
return nil
35+
}
36+
37+
func fixPermissions(path string) error {
38+
os.Chown(path, syscall.Getuid(), syscall.Getegid())
39+
files, _ := ioutil.ReadDir(path)
40+
for _, f := range files {
41+
fp := filepath.Join(path, f.Name())
42+
log.Debugf(fp)
43+
if err := os.Chown(fp, syscall.Getuid(), syscall.Getegid()); err != nil {
44+
return err
45+
}
46+
}
47+
return nil
48+
}
+247
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
package hyperkit
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
"syscall"
8+
"time"
9+
10+
"github.com/docker/machine/libmachine/drivers"
11+
"github.com/docker/machine/libmachine/log"
12+
"github.com/docker/machine/libmachine/mcnflag"
13+
"github.com/docker/machine/libmachine/mcnutils"
14+
"github.com/docker/machine/libmachine/ssh"
15+
"github.com/docker/machine/libmachine/state"
16+
hyperkit "github.com/moby/hyperkit/go"
17+
"github.com/pborman/uuid"
18+
vmnet "github.com/zchee/go-vmnet"
19+
commonutil "k8s.io/minikube/pkg/util"
20+
)
21+
22+
const (
23+
isoFilename = "boot2docker.iso"
24+
)
25+
26+
type Driver struct {
27+
*drivers.BaseDriver
28+
Boot2DockerURL string
29+
DiskSize int
30+
Pid int
31+
CPU int
32+
Memory int
33+
Cmdline string
34+
}
35+
36+
func NewDriver(hostName, storePath string) *Driver {
37+
return &Driver{
38+
BaseDriver: &drivers.BaseDriver{
39+
SSHUser: "docker",
40+
},
41+
}
42+
}
43+
44+
func (d *Driver) Create() error {
45+
b2dutils := mcnutils.NewB2dUtils(d.StorePath)
46+
47+
if err := ssh.GenerateSSHKey(d.GetSSHKeyPath()); err != nil {
48+
return err
49+
}
50+
51+
if err := b2dutils.CopyIsoToMachineDir(d.Boot2DockerURL, d.MachineName); err != nil {
52+
return err
53+
}
54+
isoPath := d.ResolveStorePath(isoFilename)
55+
if err := d.extractKernel(isoPath); err != nil {
56+
return err
57+
}
58+
59+
return d.Start()
60+
}
61+
62+
// DriverName returns the name of the driver
63+
func (d *Driver) DriverName() string {
64+
return "hyperkit"
65+
}
66+
67+
// GetCreateFlags returns the mcnflag.Flag slice representing the flags
68+
// that can be set, their descriptions and defaults.
69+
func (d *Driver) GetCreateFlags() []mcnflag.Flag {
70+
return nil
71+
}
72+
73+
// GetSSHHostname returns hostname for use with ssh
74+
func (d *Driver) GetSSHHostname() (string, error) {
75+
return d.IPAddress, nil
76+
}
77+
78+
// GetURL returns a Docker compatible host URL for connecting to this host
79+
// e.g. tcp://1.2.3.4:2376
80+
func (d *Driver) GetURL() (string, error) {
81+
ip, err := d.GetIP()
82+
if err != nil {
83+
return "", err
84+
}
85+
return fmt.Sprintf("tcp://%s:2376", ip), nil
86+
}
87+
88+
// GetState returns the state that the host is in (running, stopped, etc)
89+
func (d *Driver) GetState() (state.State, error) {
90+
if d.Pid == 0 {
91+
return state.Stopped, nil
92+
}
93+
p, err := os.FindProcess(d.Pid)
94+
if err != nil {
95+
return state.Error, err
96+
}
97+
if p == nil {
98+
return state.Stopped, nil
99+
}
100+
return state.Running, nil
101+
}
102+
103+
// Kill stops a host forcefully
104+
func (d *Driver) Kill() error {
105+
return d.sendSignal(syscall.SIGKILL)
106+
}
107+
108+
// PreCreateCheck allows for pre-create operations to make sure a driver is ready for creation
109+
func (d *Driver) PreCreateCheck() error {
110+
return nil
111+
}
112+
113+
// Remove a host
114+
func (d *Driver) Remove() error {
115+
s, err := d.GetState()
116+
if err != nil || s == state.Error {
117+
log.Infof("Error checking machine status: %s, assuming it has been removed already", err)
118+
return nil
119+
}
120+
if s == state.Running {
121+
if err := d.Stop(); err != nil {
122+
return err
123+
}
124+
}
125+
return nil
126+
}
127+
128+
// Restart a host. This may just call Stop(); Start() if the provider does not
129+
// have any special restart behaviour.
130+
func (d *Driver) Restart() error {
131+
for _, f := range []func() error{d.Stop, d.Start} {
132+
if err := f(); err != nil {
133+
return err
134+
}
135+
}
136+
return nil
137+
}
138+
139+
// SetConfigFromFlags configures the driver with the object that was returned
140+
// by RegisterCreateFlags
141+
func (d *Driver) SetConfigFromFlags(opts drivers.DriverOptions) error {
142+
return nil
143+
}
144+
145+
// Start a host
146+
func (d *Driver) Start() error {
147+
148+
// TODO: handle the disk already existing.
149+
// TODO: handle different disk types.
150+
diskPath := filepath.Join(d.ResolveStorePath("."), d.MachineName+".rawdisk")
151+
if err := createDiskImage(d.publicSSHKeyPath(), diskPath, d.DiskSize); err != nil {
152+
return err
153+
}
154+
155+
if err := fixPermissions(d.ResolveStorePath(".")); err != nil {
156+
return err
157+
}
158+
159+
h, err := hyperkit.New("", "", filepath.Join(d.StorePath, "machines", d.MachineName))
160+
if err != nil {
161+
return err
162+
}
163+
164+
// TODO: handle the rest of our settings.
165+
h.Kernel = d.ResolveStorePath("bzimage")
166+
h.Initrd = d.ResolveStorePath("initrd")
167+
h.VMNet = true
168+
h.ISOImage = d.ResolveStorePath(isoFilename)
169+
h.Console = hyperkit.ConsoleFile
170+
h.CPUs = d.CPU
171+
h.Memory = d.Memory
172+
173+
// Set UUID
174+
h.UUID = uuid.NewUUID().String()
175+
log.Infof("Generated UUID %s", h.UUID)
176+
mac, err := vmnet.GetMACAddressFromUUID(h.UUID)
177+
if err != nil {
178+
return err
179+
}
180+
181+
// Need to strip 0's
182+
mac = trimMacAddress(mac)
183+
log.Infof("Generated MAC %s", mac)
184+
185+
h.Disks = []hyperkit.DiskConfig{
186+
{
187+
Path: diskPath,
188+
Size: d.DiskSize,
189+
Driver: "virtio-blk",
190+
},
191+
}
192+
log.Infof("Starting with cmdline: %s", d.Cmdline)
193+
if err := h.Start(d.Cmdline); err != nil {
194+
return err
195+
}
196+
197+
d.Pid = h.Pid
198+
199+
getIP := func() error {
200+
var err error
201+
d.IPAddress, err = GetIPAddressByMACAddress(mac)
202+
if err != nil {
203+
return &commonutil.RetriableError{Err: err}
204+
}
205+
return nil
206+
}
207+
208+
if err := commonutil.RetryAfter(30, getIP, 2*time.Second); err != nil {
209+
return fmt.Errorf("IP address never found in dhcp leases file %v", err)
210+
}
211+
return nil
212+
}
213+
214+
// Stop a host gracefully
215+
func (d *Driver) Stop() error {
216+
return d.sendSignal(syscall.SIGTERM)
217+
}
218+
219+
func (d *Driver) extractKernel(isoPath string) error {
220+
for _, f := range []struct {
221+
pathInIso string
222+
destPath string
223+
}{
224+
{"/boot/bzimage", "bzimage"},
225+
{"/boot/initrd", "initrd"},
226+
{"/isolinux/isolinux.cfg", "isolinux.cfg"},
227+
} {
228+
fullDestPath := d.ResolveStorePath(f.destPath)
229+
if err := ExtractFile(isoPath, f.pathInIso, fullDestPath); err != nil {
230+
return err
231+
}
232+
}
233+
return nil
234+
}
235+
236+
func (d *Driver) publicSSHKeyPath() string {
237+
return d.GetSSHKeyPath() + ".pub"
238+
}
239+
240+
func (d *Driver) sendSignal(s os.Signal) error {
241+
proc, err := os.FindProcess(d.Pid)
242+
if err != nil {
243+
return err
244+
}
245+
246+
return proc.Signal(s)
247+
}

0 commit comments

Comments
 (0)