diff --git a/README.md b/README.md index 73e1c78841..353a6842e6 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ a single-node Kubernetes cluster inside a VM on your laptop for users looking to try out Kubernetes or develop with it day-to-day. ## Requirements For Running Minikube -* VirtualBox installation +* [VirtualBox](https://www.virtualbox.org/wiki/Downloads) or [VMware Fusion](https://www.vmware.com/products/fusion) installation * VT-x/AMD-v virtualization must be enabled in BIOS ## Installation @@ -20,6 +20,8 @@ See the installation instructions for the [latest release](https://github.com/ku ## Usage Here's a brief demo of minikube usage. We're using the code from this [Kubernetes tutorial](http://kubernetes.io/docs/hellonode/). +If you want to change the VM driver to VMware Fusion add the `--vm-driver=vmwarefusion` flag to `minikube start`. + Note that the IP below is dynamic and can change. It can be retrieved with `minikube ip`. ```shell diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go index 161924ea78..78b5f7fa17 100644 --- a/cmd/minikube/cmd/start.go +++ b/cmd/minikube/cmd/start.go @@ -34,6 +34,7 @@ import ( var ( minikubeISO string + vmDriver string ) // startCmd represents the start command @@ -52,6 +53,7 @@ func runStart(cmd *cobra.Command, args []string) { config := cluster.MachineConfig{ MinikubeISO: minikubeISO, + VMDriver: vmDriver, } var host *host.Host @@ -150,5 +152,6 @@ func setupKubeconfig(name, server, certAuth, cliCert, cliKey string) (activeCont func init() { startCmd.Flags().StringVarP(&minikubeISO, "iso-url", "", constants.DefaultIsoUrl, "Location of the minikube iso") + startCmd.Flags().StringVarP(&vmDriver, "vm-driver", "", constants.DefaultVMDriver, fmt.Sprintf("VM driver is one of: %v", constants.SupportedVMDrivers)) RootCmd.AddCommand(startCmd) } diff --git a/docs/minikube_start.md b/docs/minikube_start.md index e76e4e44ee..00ee0a1fbc 100644 --- a/docs/minikube_start.md +++ b/docs/minikube_start.md @@ -16,6 +16,7 @@ minikube start ``` --iso-url="https://storage.googleapis.com/minikube/minikube-0.3.iso": Location of the minikube iso + --vm-driver="virtualbox": VM driver is one of: [virtualbox vmwarefusion] ``` ### Options inherited from parent commands diff --git a/pkg/minikube/cluster/cluster.go b/pkg/minikube/cluster/cluster.go index 22c982aa7f..1b973b5d16 100644 --- a/pkg/minikube/cluster/cluster.go +++ b/pkg/minikube/cluster/cluster.go @@ -155,6 +155,7 @@ type sshAble interface { // MachineConfig contains the parameters used to start a cluster. type MachineConfig struct { MinikubeISO string + VMDriver string } // StartCluster starts a k8s cluster on the specified Host. @@ -261,15 +262,25 @@ func SetupCerts(d drivers.Driver) error { } func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) { - driver := virtualbox.NewDriver(constants.MachineName, constants.Minipath) - driver.Boot2DockerURL = config.MinikubeISO + var driver drivers.Driver + + switch config.VMDriver { + case "virtualbox": + d := virtualbox.NewDriver(constants.MachineName, constants.Minipath) + d.Boot2DockerURL = config.MinikubeISO + driver = d + case "vmwarefusion": + driver = createVMwareFusionHost(config) + default: + glog.Exitf("Unsupported driver: %s\n", config.VMDriver) + } + data, err := json.Marshal(driver) if err != nil { return nil, err } - driverName := "virtualbox" - h, err := api.NewHost(driverName, data) + h, err := api.NewHost(config.VMDriver, data) if err != nil { return nil, fmt.Errorf("Error creating new host: %s", err) } diff --git a/pkg/minikube/cluster/cluster_darwin.go b/pkg/minikube/cluster/cluster_darwin.go new file mode 100644 index 0000000000..242f05a4d4 --- /dev/null +++ b/pkg/minikube/cluster/cluster_darwin.go @@ -0,0 +1,34 @@ +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cluster + +import ( + "github.com/docker/machine/drivers/vmwarefusion" + "github.com/docker/machine/libmachine/drivers" + "k8s.io/minikube/pkg/minikube/constants" +) + +func createVMwareFusionHost(config MachineConfig) drivers.Driver { + d := vmwarefusion.NewDriver(constants.MachineName, constants.Minipath).(*vmwarefusion.Driver) + d.Boot2DockerURL = config.MinikubeISO + + // TODO(philips): push these defaults upstream to fixup this driver + d.CPU = 1 + d.SSHPort = 22 + d.ISO = d.ResolveStorePath("boot2docker.iso") + return d +} diff --git a/pkg/minikube/cluster/cluster_platform_panic.go b/pkg/minikube/cluster/cluster_platform_panic.go new file mode 100644 index 0000000000..50923f7798 --- /dev/null +++ b/pkg/minikube/cluster/cluster_platform_panic.go @@ -0,0 +1,25 @@ +// +build !darwin + +/* +Copyright 2016 The Kubernetes Authors All rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package cluster + +import "github.com/docker/machine/libmachine/drivers" + +func createVMwareFusionHost(config MachineConfig) drivers.Driver { + panic("vmwarefusion not supported") +} diff --git a/pkg/minikube/cluster/cluster_test.go b/pkg/minikube/cluster/cluster_test.go index 52ec3c159b..98561b1a1b 100644 --- a/pkg/minikube/cluster/cluster_test.go +++ b/pkg/minikube/cluster/cluster_test.go @@ -32,6 +32,8 @@ import ( "k8s.io/minikube/pkg/minikube/tests" ) +var defaultMachineConfig = MachineConfig{VMDriver: constants.DefaultVMDriver} + func TestCreateHost(t *testing.T) { api := tests.NewMockAPI() @@ -39,7 +41,7 @@ func TestCreateHost(t *testing.T) { if exists { t.Fatal("Machine already exists.") } - _, err := createHost(api, MachineConfig{}) + _, err := createHost(api, defaultMachineConfig) if err != nil { t.Fatalf("Error creating host: %v", err) } @@ -57,8 +59,16 @@ func TestCreateHost(t *testing.T) { t.Fatalf("Machine is not running. State is: %s", s) } - if h.DriverName != "virtualbox" { - t.Fatalf("Wrong driver name: %v. Should be virtualbox.", h.DriverName) + found := false + for _, driver := range constants.SupportedVMDrivers { + if h.DriverName == driver { + found = true + break + } + } + + if !found { + t.Fatalf("Wrong driver name: %v. Should be virtualbox or vmwarefusion.", h.DriverName) } } @@ -117,7 +127,7 @@ func TestStartClusterError(t *testing.T) { func TestStartHostExists(t *testing.T) { api := tests.NewMockAPI() // Create an initial host. - _, err := createHost(api, MachineConfig{}) + _, err := createHost(api, defaultMachineConfig) if err != nil { t.Fatalf("Error creating host: %v", err) } @@ -129,7 +139,7 @@ func TestStartHostExists(t *testing.T) { } // This should pass without calling Create because the host exists already. - h, err := StartHost(api, MachineConfig{}) + h, err := StartHost(api, defaultMachineConfig) if err != nil { t.Fatal("Error starting host.") } @@ -144,7 +154,7 @@ func TestStartHostExists(t *testing.T) { func TestStartStoppedHost(t *testing.T) { api := tests.NewMockAPI() // Create an initial host. - h, err := createHost(api, MachineConfig{}) + h, err := createHost(api, defaultMachineConfig) if err != nil { t.Fatalf("Error creating host: %v", err) } @@ -152,7 +162,7 @@ func TestStartStoppedHost(t *testing.T) { h.Driver = &d d.CurrentState = state.Stopped - h, err = StartHost(api, MachineConfig{}) + h, err = StartHost(api, defaultMachineConfig) if err != nil { t.Fatal("Error starting host.") } @@ -172,7 +182,7 @@ func TestStartStoppedHost(t *testing.T) { func TestStartHost(t *testing.T) { api := tests.NewMockAPI() - h, err := StartHost(api, MachineConfig{}) + h, err := StartHost(api, defaultMachineConfig) if err != nil { t.Fatal("Error starting host.") } @@ -196,7 +206,7 @@ func TestStopHostError(t *testing.T) { func TestStopHost(t *testing.T) { api := tests.NewMockAPI() - h, _ := createHost(api, MachineConfig{}) + h, _ := createHost(api, defaultMachineConfig) if err := StopHost(api); err != nil { t.Fatal("An error should be thrown when stopping non-existing machine.") } @@ -227,7 +237,7 @@ Error 2` func TestDeleteHost(t *testing.T) { api := tests.NewMockAPI() - createHost(api, MachineConfig{}) + createHost(api, defaultMachineConfig) if err := DeleteHost(api); err != nil { t.Fatalf("Unexpected error deleting host: %s", err) @@ -236,7 +246,7 @@ func TestDeleteHost(t *testing.T) { func TestDeleteHostErrorDeletingVM(t *testing.T) { api := tests.NewMockAPI() - h, _ := createHost(api, MachineConfig{}) + h, _ := createHost(api, defaultMachineConfig) d := &tests.MockDriver{RemoveError: true} @@ -250,7 +260,7 @@ func TestDeleteHostErrorDeletingVM(t *testing.T) { func TestDeleteHostErrorDeletingFiles(t *testing.T) { api := tests.NewMockAPI() api.RemoveError = true - createHost(api, MachineConfig{}) + createHost(api, defaultMachineConfig) if err := DeleteHost(api); err == nil { t.Fatal("Expected error deleting host.") @@ -260,7 +270,7 @@ func TestDeleteHostErrorDeletingFiles(t *testing.T) { func TestDeleteHostMultipleErrors(t *testing.T) { api := tests.NewMockAPI() api.RemoveError = true - h, _ := createHost(api, MachineConfig{}) + h, _ := createHost(api, defaultMachineConfig) d := &tests.MockDriver{RemoveError: true} @@ -295,7 +305,7 @@ func TestGetHostStatus(t *testing.T) { checkState("Does Not Exist") - createHost(api, MachineConfig{}) + createHost(api, defaultMachineConfig) checkState(state.Running.String()) StopHost(api) @@ -335,7 +345,7 @@ func TestSetupCerts(t *testing.T) { func TestGetHostDockerEnv(t *testing.T) { api := tests.NewMockAPI() - h, err := createHost(api, MachineConfig{}) + h, err := createHost(api, defaultMachineConfig) if err != nil { t.Fatalf("Error creating host: %v", err) } diff --git a/pkg/minikube/constants/constants.go b/pkg/minikube/constants/constants.go index cf7f5c96a2..b05040abf0 100644 --- a/pkg/minikube/constants/constants.go +++ b/pkg/minikube/constants/constants.go @@ -46,6 +46,12 @@ var LogFlags = [...]string{ } const DefaultIsoUrl = "https://storage.googleapis.com/minikube/minikube-0.3.iso" +const DefaultVMDriver = "virtualbox" + +var SupportedVMDrivers = [...]string{ + "virtualbox", + "vmwarefusion", +} const ( RemoteLocalKubeErrPath = "/var/log/localkube.err" diff --git a/pkg/minikube/machine/client.go b/pkg/minikube/machine/client.go index 01e37b8854..3b5f28b9d7 100644 --- a/pkg/minikube/machine/client.go +++ b/pkg/minikube/machine/client.go @@ -20,6 +20,7 @@ import ( "os" "github.com/docker/machine/drivers/virtualbox" + "github.com/docker/machine/drivers/vmwarefusion" "github.com/docker/machine/libmachine/drivers/plugin" "github.com/docker/machine/libmachine/drivers/plugin/localbinary" "github.com/golang/glog" @@ -32,6 +33,8 @@ func StartDriver() { switch driverName { case "virtualbox": plugin.RegisterDriver(virtualbox.NewDriver("", "")) + case "vmwarefusion": + plugin.RegisterDriver(vmwarefusion.NewDriver("", "")) default: glog.Exitf("Unsupported driver: %s\n", driverName) }