diff --git a/pkg/minikube/cluster/cluster.go b/pkg/minikube/cluster/cluster.go index 726402ae43..b8eb400956 100644 --- a/pkg/minikube/cluster/cluster.go +++ b/pkg/minikube/cluster/cluster.go @@ -30,7 +30,6 @@ import ( "github.com/docker/machine/drivers/virtualbox" "github.com/docker/machine/libmachine" - "github.com/docker/machine/libmachine/drivers" "github.com/docker/machine/libmachine/engine" "github.com/docker/machine/libmachine/host" "github.com/docker/machine/libmachine/mcnerror" @@ -58,6 +57,8 @@ func init() { flag.Set("logtostderr", "false") // Setting the default client to native gives much better performance. ssh.SetDefaultClient(ssh.Native) + + registry.Register("virtualbox", createVirtualboxHost) } // StartHost starts a host VM. @@ -180,7 +181,7 @@ func engineOptions(config MachineConfig) *engine.Options { return &o } -func createVirtualboxHost(config MachineConfig) drivers.Driver { +func createVirtualboxHost(config MachineConfig) RawDriver { d := virtualbox.NewDriver(cfg.GetMachineName(), constants.GetMinipath()) d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO) d.Memory = config.Memory @@ -193,20 +194,8 @@ func createVirtualboxHost(config MachineConfig) drivers.Driver { return d } -func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) { - var driver interface{} - - if config.VMDriver != "none" { - if err := config.Downloader.CacheMinikubeISOFromURL(config.MinikubeISO); err != nil { - return nil, errors.Wrap(err, "Error attempting to cache minikube ISO from URL") - } - } - +func preCreateHost(config *MachineConfig) error { switch config.VMDriver { - case "virtualbox": - driver = createVirtualboxHost(config) - case "vmwarefusion": - driver = createVMwareFusionHost(config) case "kvm": if viper.GetBool(cfg.ShowDriverDeprecationNotification) { fmt.Fprintln(os.Stderr, `WARNING: The kvm driver is now deprecated and support for it will be removed in a future release. @@ -214,9 +203,6 @@ func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) { See https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#kvm2-driver for more information. To disable this message, run [minikube config set WantShowDriverDeprecationNotification false]`) } - driver = createKVMHost(config) - case "kvm2": - driver = createKVM2Host(config) case "xhyve": if viper.GetBool(cfg.ShowDriverDeprecationNotification) { fmt.Fprintln(os.Stderr, `WARNING: The xhyve driver is now deprecated and support for it will be removed in a future release. @@ -224,17 +210,34 @@ Please consider switching to the hyperkit driver, which is intended to replace t See https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#hyperkit-driver for more information. To disable this message, run [minikube config set WantShowDriverDeprecationNotification false]`) } - driver = createXhyveHost(config) - case "hyperv": - driver = createHypervHost(config) - case "none": - driver = createNoneHost(config) - case "hyperkit": - driver = createHyperkitHost(config) - default: - glog.Exitf("Unsupported driver: %s\n", config.VMDriver) } + return nil +} + +func createHost(api libmachine.API, config MachineConfig) (*host.Host, error) { + err := preCreateHost(&config) + if err != nil { + return nil, err + } + + driverFunc, err := registry.Driver(config.VMDriver) + if err != nil { + if err == ErrDriverNotFound { + glog.Exitf("Unsupported driver: %s\n", config.VMDriver) + } else { + glog.Exit(err.Error()) + } + } + + if config.VMDriver != "none" { + if err := config.Downloader.CacheMinikubeISOFromURL(config.MinikubeISO); err != nil { + return nil, errors.Wrap(err, "Error attempting to cache minikube ISO from URL") + } + } + + driver := driverFunc(config) + data, err := json.Marshal(driver) if err != nil { return nil, errors.Wrap(err, "Error marshalling json") diff --git a/pkg/minikube/cluster/cluster_darwin.go b/pkg/minikube/cluster/cluster_darwin.go index 3366617310..9dbd4f3939 100644 --- a/pkg/minikube/cluster/cluster_darwin.go +++ b/pkg/minikube/cluster/cluster_darwin.go @@ -27,7 +27,13 @@ import ( "k8s.io/minikube/pkg/minikube/constants" ) -func createVMwareFusionHost(config MachineConfig) drivers.Driver { +func init() { + registry.Register("vmwarefusion", createVMwareFusionHost) + registry.Register("hyperkit", createHyperkitHost) + registry.Register("xhyve", createXhyveHost) +} + +func createVMwareFusionHost(config MachineConfig) RawDriver { d := vmwarefusion.NewDriver(cfg.GetMachineName(), constants.GetMinipath()).(*vmwarefusion.Driver) d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO) d.Memory = config.Memory @@ -59,7 +65,7 @@ type xhyveDriver struct { RawDisk bool } -func createHyperkitHost(config MachineConfig) *hyperkit.Driver { +func createHyperkitHost(config MachineConfig) RawDriver { return &hyperkit.Driver{ BaseDriver: &drivers.BaseDriver{ MachineName: cfg.GetMachineName(), @@ -77,7 +83,7 @@ func createHyperkitHost(config MachineConfig) *hyperkit.Driver { } } -func createXhyveHost(config MachineConfig) *xhyveDriver { +func createXhyveHost(config MachineConfig) RawDriver { useVirtio9p := !config.DisableDriverMounts return &xhyveDriver{ BaseDriver: &drivers.BaseDriver{ diff --git a/pkg/minikube/cluster/cluster_linux.go b/pkg/minikube/cluster/cluster_linux.go index fb21521cef..2023c71fe9 100644 --- a/pkg/minikube/cluster/cluster_linux.go +++ b/pkg/minikube/cluster/cluster_linux.go @@ -27,6 +27,12 @@ import ( "k8s.io/minikube/pkg/minikube/constants" ) +func init() { + registry.Register("kvm", createKVMHost) + registry.Register("kvm2", createKVM2Host) + registry.Register("none", createNoneHost) +} + type kvmDriver struct { *drivers.BaseDriver @@ -42,7 +48,7 @@ type kvmDriver struct { IOMode string } -func createKVMHost(config MachineConfig) *kvmDriver { +func createKVMHost(config MachineConfig) RawDriver { return &kvmDriver{ BaseDriver: &drivers.BaseDriver{ MachineName: cfg.GetMachineName(), @@ -62,7 +68,7 @@ func createKVMHost(config MachineConfig) *kvmDriver { } } -func createKVM2Host(config MachineConfig) *kvmDriver { +func createKVM2Host(config MachineConfig) RawDriver { return &kvmDriver{ BaseDriver: &drivers.BaseDriver{ MachineName: cfg.GetMachineName(), @@ -90,7 +96,7 @@ func detectVBoxManageCmd() string { return cmd } -func createNoneHost(config MachineConfig) *none.Driver { +func createNoneHost(config MachineConfig) RawDriver { return &none.Driver{ BaseDriver: &drivers.BaseDriver{ MachineName: cfg.GetMachineName(), diff --git a/pkg/minikube/cluster/cluster_windows.go b/pkg/minikube/cluster/cluster_windows.go index a6aa37343a..df5307fce8 100644 --- a/pkg/minikube/cluster/cluster_windows.go +++ b/pkg/minikube/cluster/cluster_windows.go @@ -23,7 +23,6 @@ import ( "path/filepath" "github.com/docker/machine/drivers/hyperv" - "github.com/docker/machine/libmachine/drivers" "github.com/golang/glog" "github.com/pkg/errors" "golang.org/x/sys/windows/registry" @@ -31,7 +30,11 @@ import ( "k8s.io/minikube/pkg/minikube/constants" ) -func createHypervHost(config MachineConfig) drivers.Driver { +func init() { + registry.Register("hyperkit", createHypervHost) +} + +func createHypervHost(config MachineConfig) RawDriver { d := hyperv.NewDriver(cfg.GetMachineName(), constants.GetMinipath()) d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO) d.VSwitch = config.HypervVirtualSwitch diff --git a/pkg/minikube/cluster/registry.go b/pkg/minikube/cluster/registry.go new file mode 100644 index 0000000000..5793901c6c --- /dev/null +++ b/pkg/minikube/cluster/registry.go @@ -0,0 +1,112 @@ +/* +Copyright 2018 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 ( + "sync" + + "github.com/pkg/errors" +) + +var ( + // ErrDriverNameExist is the error returned when trying to register a driver + // which already exists in registry + ErrDriverNameExist = errors.New("registry: duplicated driver name") + + // ErrDriverNotFound is the error returned when driver of a given name does + // not exist in registry + ErrDriverNotFound = errors.New("registry: driver not found") +) + +// DriverFunc creates a Driver from MachineConfig +type DriverFunc func(MachineConfig) RawDriver + +// RawDriver is the configuration of a driver that you can marshal into json bytes +// and pass to libmachine's NewHost method +type RawDriver interface{} + +// Registry contains all the supported driver types on the host +type Registry interface { + // Register a driver in registry + Register(name string, f DriverFunc) error + + // Driver returns the registered driver from a given name + Driver(name string) (DriverFunc, error) + + DriverLister +} + +// DriverLister lists the name of the supported drivers +type DriverLister interface { + // List lists all the driver types + List() []string +} + +type driverRegistry struct { + drivers map[string]DriverFunc + lock sync.Mutex +} + +func createRegistry() *driverRegistry { + return &driverRegistry{ + drivers: make(map[string]DriverFunc), + } +} + +var ( + registry = createRegistry() +) + +func ListDrivers() []string { + return registry.List() +} + +func (r *driverRegistry) Register(name string, f DriverFunc) error { + r.lock.Lock() + defer r.lock.Unlock() + + if _, ok := r.drivers[name]; ok { + return ErrDriverNameExist + } + + r.drivers[name] = f + return nil +} + +func (r *driverRegistry) List() []string { + r.lock.Lock() + defer r.lock.Unlock() + + result := make([]string, 0, len(r.drivers)) + + for name := range r.drivers { + result = append(result, name) + } + + return result +} + +func (r *driverRegistry) Driver(name string) (DriverFunc, error) { + r.lock.Lock() + defer r.lock.Unlock() + + if driver, ok := r.drivers[name]; ok { + return driver, nil + } + + return nil, ErrDriverNotFound +} diff --git a/pkg/minikube/cluster/registry_test.go b/pkg/minikube/cluster/registry_test.go new file mode 100644 index 0000000000..d66efd5f7b --- /dev/null +++ b/pkg/minikube/cluster/registry_test.go @@ -0,0 +1,68 @@ +/* +Copyright 2018 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 ( + "sort" + "testing" +) + +func TestRegistry(t *testing.T) { + dummy := func(_ MachineConfig) RawDriver { + return nil + } + + registry := createRegistry() + + err := registry.Register("foo", dummy) + if err != nil { + t.Fatal("expect nil") + } + + err = registry.Register("foo", dummy) + if err != ErrDriverNameExist { + t.Fatal("expect ErrDriverNameExist") + } + + err = registry.Register("bar", dummy) + if err != nil { + t.Fatal("expect nil") + } + + list := registry.List() + if len(list) != 2 { + t.Fatalf("expect len(list) to be %d; got %d", 2, len(list)) + } + + sort.Strings(list) + if list[0] != "bar" || list[1] != "foo" { + t.Fatalf("expect registry.List return %s; got %s", []string{"bar", "foo"}, list) + } + + driver, err := registry.Driver("foo") + if err != nil { + t.Fatal("expect nil") + } + if driver == nil { + t.Fatal("expect registry.Driver(foo) returns registered driver") + } + + driver, err = registry.Driver("foo2") + if err != ErrDriverNotFound { + t.Fatal("expect ErrDriverNotFound") + } +}