diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go index 5e633d1b2f73..b568519b9ea0 100644 --- a/cmd/minikube/cmd/start.go +++ b/cmd/minikube/cmd/start.go @@ -73,59 +73,61 @@ import ( ) const ( - isoURL = "iso-url" - memory = "memory" - cpus = "cpus" - humanReadableDiskSize = "disk-size" - nfsSharesRoot = "nfs-shares-root" - nfsShare = "nfs-share" - kubernetesVersion = "kubernetes-version" - hostOnlyCIDR = "host-only-cidr" - containerRuntime = "container-runtime" - criSocket = "cri-socket" - networkPlugin = "network-plugin" - enableDefaultCNI = "enable-default-cni" - hypervVirtualSwitch = "hyperv-virtual-switch" - kvmNetwork = "kvm-network" - kvmQemuURI = "kvm-qemu-uri" - kvmGPU = "kvm-gpu" - kvmHidden = "kvm-hidden" - minikubeEnvPrefix = "MINIKUBE" - defaultMemorySize = "2000mb" - installAddons = "install-addons" - defaultDiskSize = "20000mb" - keepContext = "keep-context" - createMount = "mount" - featureGates = "feature-gates" - apiServerName = "apiserver-name" - apiServerPort = "apiserver-port" - dnsDomain = "dns-domain" - serviceCIDR = "service-cluster-ip-range" - imageRepository = "image-repository" - imageMirrorCountry = "image-mirror-country" - mountString = "mount-string" - disableDriverMounts = "disable-driver-mounts" - cacheImages = "cache-images" - uuid = "uuid" - vpnkitSock = "hyperkit-vpnkit-sock" - vsockPorts = "hyperkit-vsock-ports" - embedCerts = "embed-certs" - noVTXCheck = "no-vtx-check" - downloadOnly = "download-only" - dnsProxy = "dns-proxy" - hostDNSResolver = "host-dns-resolver" - waitUntilHealthy = "wait" - force = "force" - dryRun = "dry-run" - interactive = "interactive" - waitTimeout = "wait-timeout" - nativeSSH = "native-ssh" - minimumMemorySize = "1024mb" - minimumCPUS = 2 - minimumDiskSize = "2000mb" - autoUpdate = "auto-update-drivers" - hostOnlyNicType = "host-only-nic-type" - natNicType = "nat-nic-type" + isoURL = "iso-url" + memory = "memory" + cpus = "cpus" + humanReadableDiskSize = "disk-size" + nfsSharesRoot = "nfs-shares-root" + nfsShare = "nfs-share" + kubernetesVersion = "kubernetes-version" + hostOnlyCIDR = "host-only-cidr" + containerRuntime = "container-runtime" + criSocket = "cri-socket" + networkPlugin = "network-plugin" + enableDefaultCNI = "enable-default-cni" + hypervVirtualSwitch = "hyperv-virtual-switch" + hypervUseExternalSwitch = "hyperv-use-external-switch" + hypervExternalAdapter = "hyperv-external-adapter" + kvmNetwork = "kvm-network" + kvmQemuURI = "kvm-qemu-uri" + kvmGPU = "kvm-gpu" + kvmHidden = "kvm-hidden" + minikubeEnvPrefix = "MINIKUBE" + defaultMemorySize = "2000mb" + installAddons = "install-addons" + defaultDiskSize = "20000mb" + keepContext = "keep-context" + createMount = "mount" + featureGates = "feature-gates" + apiServerName = "apiserver-name" + apiServerPort = "apiserver-port" + dnsDomain = "dns-domain" + serviceCIDR = "service-cluster-ip-range" + imageRepository = "image-repository" + imageMirrorCountry = "image-mirror-country" + mountString = "mount-string" + disableDriverMounts = "disable-driver-mounts" + cacheImages = "cache-images" + uuid = "uuid" + vpnkitSock = "hyperkit-vpnkit-sock" + vsockPorts = "hyperkit-vsock-ports" + embedCerts = "embed-certs" + noVTXCheck = "no-vtx-check" + downloadOnly = "download-only" + dnsProxy = "dns-proxy" + hostDNSResolver = "host-dns-resolver" + waitUntilHealthy = "wait" + force = "force" + dryRun = "dry-run" + interactive = "interactive" + waitTimeout = "wait-timeout" + nativeSSH = "native-ssh" + minimumMemorySize = "1024mb" + minimumCPUS = 2 + minimumDiskSize = "2000mb" + autoUpdate = "auto-update-drivers" + hostOnlyNicType = "host-only-nic-type" + natNicType = "nat-nic-type" ) var ( @@ -227,6 +229,8 @@ func initDriverFlags() { // hyperv startCmd.Flags().String(hypervVirtualSwitch, "", "The hyperv virtual switch name. Defaults to first found. (hyperv driver only)") + startCmd.Flags().Bool(hypervUseExternalSwitch, false, "Whether to use external switch over Default Switch if virtual switch not explicitly specified. (hyperv driver only)") + startCmd.Flags().String(hypervExternalAdapter, "", "External Adapter on which external switch will be created if no external switch is found. (hyperv driver only)") } // initNetworkingFlags inits the commandline flags for connectivity related flags for start @@ -943,36 +947,38 @@ func generateCfgFromFlags(cmd *cobra.Command, k8sVersion string, drvName string) } cfg := config.MachineConfig{ - Name: viper.GetString(config.MachineProfile), - KeepContext: viper.GetBool(keepContext), - EmbedCerts: viper.GetBool(embedCerts), - MinikubeISO: viper.GetString(isoURL), - Memory: pkgutil.CalculateSizeInMB(viper.GetString(memory)), - CPUs: viper.GetInt(cpus), - DiskSize: pkgutil.CalculateSizeInMB(viper.GetString(humanReadableDiskSize)), - VMDriver: drvName, - HyperkitVpnKitSock: viper.GetString(vpnkitSock), - HyperkitVSockPorts: viper.GetStringSlice(vsockPorts), - NFSShare: viper.GetStringSlice(nfsShare), - NFSSharesRoot: viper.GetString(nfsSharesRoot), - DockerEnv: dockerEnv, - DockerOpt: dockerOpt, - InsecureRegistry: insecureRegistry, - RegistryMirror: registryMirror, - HostOnlyCIDR: viper.GetString(hostOnlyCIDR), - HypervVirtualSwitch: viper.GetString(hypervVirtualSwitch), - KVMNetwork: viper.GetString(kvmNetwork), - KVMQemuURI: viper.GetString(kvmQemuURI), - KVMGPU: viper.GetBool(kvmGPU), - KVMHidden: viper.GetBool(kvmHidden), - Downloader: pkgutil.DefaultDownloader{}, - DisableDriverMounts: viper.GetBool(disableDriverMounts), - UUID: viper.GetString(uuid), - NoVTXCheck: viper.GetBool(noVTXCheck), - DNSProxy: viper.GetBool(dnsProxy), - HostDNSResolver: viper.GetBool(hostDNSResolver), - HostOnlyNicType: viper.GetString(hostOnlyNicType), - NatNicType: viper.GetString(natNicType), + Name: viper.GetString(config.MachineProfile), + KeepContext: viper.GetBool(keepContext), + EmbedCerts: viper.GetBool(embedCerts), + MinikubeISO: viper.GetString(isoURL), + Memory: pkgutil.CalculateSizeInMB(viper.GetString(memory)), + CPUs: viper.GetInt(cpus), + DiskSize: pkgutil.CalculateSizeInMB(viper.GetString(humanReadableDiskSize)), + VMDriver: drvName, + HyperkitVpnKitSock: viper.GetString(vpnkitSock), + HyperkitVSockPorts: viper.GetStringSlice(vsockPorts), + NFSShare: viper.GetStringSlice(nfsShare), + NFSSharesRoot: viper.GetString(nfsSharesRoot), + DockerEnv: dockerEnv, + DockerOpt: dockerOpt, + InsecureRegistry: insecureRegistry, + RegistryMirror: registryMirror, + HostOnlyCIDR: viper.GetString(hostOnlyCIDR), + HypervVirtualSwitch: viper.GetString(hypervVirtualSwitch), + HypervUseExternalSwitch: viper.GetBool(hypervUseExternalSwitch), + HypervExternalAdapter: viper.GetString(hypervExternalAdapter), + KVMNetwork: viper.GetString(kvmNetwork), + KVMQemuURI: viper.GetString(kvmQemuURI), + KVMGPU: viper.GetBool(kvmGPU), + KVMHidden: viper.GetBool(kvmHidden), + Downloader: pkgutil.DefaultDownloader{}, + DisableDriverMounts: viper.GetBool(disableDriverMounts), + UUID: viper.GetString(uuid), + NoVTXCheck: viper.GetBool(noVTXCheck), + DNSProxy: viper.GetBool(dnsProxy), + HostDNSResolver: viper.GetBool(hostDNSResolver), + HostOnlyNicType: viper.GetString(hostOnlyNicType), + NatNicType: viper.GetString(natNicType), KubernetesConfig: config.KubernetesConfig{ KubernetesVersion: k8sVersion, ClusterName: viper.GetString(config.MachineProfile), diff --git a/pkg/minikube/cluster/cluster_test.go b/pkg/minikube/cluster/cluster_test.go index 14c809360c5e..332f768eba06 100644 --- a/pkg/minikube/cluster/cluster_test.go +++ b/pkg/minikube/cluster/cluster_test.go @@ -41,8 +41,8 @@ type MockDownloader struct{} func (d MockDownloader) GetISOFileURI(isoURL string) string { return "" } func (d MockDownloader) CacheMinikubeISOFromURL(isoURL string) error { return nil } -func createMockDriverHost(c config.MachineConfig) interface{} { - return nil +func createMockDriverHost(c config.MachineConfig) (interface{}, error) { + return nil, nil } func RegisterMockDriver(t *testing.T) { diff --git a/pkg/minikube/cluster/start.go b/pkg/minikube/cluster/start.go index 7f30942238df..6742e030f9ee 100644 --- a/pkg/minikube/cluster/start.go +++ b/pkg/minikube/cluster/start.go @@ -114,7 +114,10 @@ func createHost(api libmachine.API, cfg config.MachineConfig) (*host.Host, error if def.Empty() { return nil, fmt.Errorf("unsupported/missing driver: %s", cfg.VMDriver) } - dd := def.Config(cfg) + dd, err := def.Config(cfg) + if err != nil { + return nil, errors.Wrap(err, "config") + } data, err := json.Marshal(dd) if err != nil { return nil, errors.Wrap(err, "marshal") diff --git a/pkg/minikube/config/types.go b/pkg/minikube/config/types.go index 1b3b3b19c9d9..b05ff2e970a3 100644 --- a/pkg/minikube/config/types.go +++ b/pkg/minikube/config/types.go @@ -32,39 +32,41 @@ type Profile struct { // MachineConfig contains the parameters used to start a cluster. type MachineConfig struct { - Name string - KeepContext bool // used by start and profile command to or not to switch kubectl's current context - EmbedCerts bool // used by kubeconfig.Setup - MinikubeISO string - Memory int - CPUs int - DiskSize int - VMDriver string - HyperkitVpnKitSock string // Only used by the Hyperkit driver - HyperkitVSockPorts []string // Only used by the Hyperkit driver - DockerEnv []string // Each entry is formatted as KEY=VALUE. - InsecureRegistry []string - RegistryMirror []string - HostOnlyCIDR string // Only used by the virtualbox driver - HypervVirtualSwitch string - KVMNetwork string // Only used by the KVM driver - KVMQemuURI string // Only used by kvm2 - KVMGPU bool // Only used by kvm2 - KVMHidden bool // Only used by kvm2 - Downloader util.ISODownloader `json:"-"` - DockerOpt []string // Each entry is formatted as KEY=VALUE. - DisableDriverMounts bool // Only used by virtualbox - NFSShare []string - NFSSharesRoot string - UUID string // Only used by hyperkit to restore the mac address - NoVTXCheck bool // Only used by virtualbox - DNSProxy bool // Only used by virtualbox - HostDNSResolver bool // Only used by virtualbox - HostOnlyNicType string // Only used by virtualbox - NatNicType string // Only used by virtualbox - KubernetesConfig KubernetesConfig - Nodes []Node - Addons map[string]bool + Name string + KeepContext bool // used by start and profile command to or not to switch kubectl's current context + EmbedCerts bool // used by kubeconfig.Setup + MinikubeISO string + Memory int + CPUs int + DiskSize int + VMDriver string + HyperkitVpnKitSock string // Only used by the Hyperkit driver + HyperkitVSockPorts []string // Only used by the Hyperkit driver + DockerEnv []string // Each entry is formatted as KEY=VALUE. + InsecureRegistry []string + RegistryMirror []string + HostOnlyCIDR string // Only used by the virtualbox driver + HypervVirtualSwitch string + HypervUseExternalSwitch bool + HypervExternalAdapter string + KVMNetwork string // Only used by the KVM driver + KVMQemuURI string // Only used by kvm2 + KVMGPU bool // Only used by kvm2 + KVMHidden bool // Only used by kvm2 + Downloader util.ISODownloader `json:"-"` + DockerOpt []string // Each entry is formatted as KEY=VALUE. + DisableDriverMounts bool // Only used by virtualbox + NFSShare []string + NFSSharesRoot string + UUID string // Only used by hyperkit to restore the mac address + NoVTXCheck bool // Only used by virtualbox + DNSProxy bool // Only used by virtualbox + HostDNSResolver bool // Only used by virtualbox + HostOnlyNicType string // Only used by virtualbox + NatNicType string // Only used by virtualbox + KubernetesConfig KubernetesConfig + Nodes []Node + Addons map[string]bool } // KubernetesConfig contains the parameters used to configure the VM Kubernetes. diff --git a/pkg/minikube/registry/drvs/docker/docker.go b/pkg/minikube/registry/drvs/docker/docker.go index 0d912150dec2..d74947db0ca9 100644 --- a/pkg/minikube/registry/drvs/docker/docker.go +++ b/pkg/minikube/registry/drvs/docker/docker.go @@ -43,7 +43,7 @@ func init() { } } -func configure(mc config.MachineConfig) interface{} { +func configure(mc config.MachineConfig) (interface{}, error) { return kic.NewDriver(kic.Config{ MachineName: mc.Name, StorePath: localpath.MiniPath(), @@ -52,8 +52,7 @@ func configure(mc config.MachineConfig) interface{} { Memory: mc.Memory, OCIBinary: oci.Docker, APIServerPort: mc.Nodes[0].Port, - }) - + }), nil } func status() registry.State { diff --git a/pkg/minikube/registry/drvs/hyperkit/hyperkit.go b/pkg/minikube/registry/drvs/hyperkit/hyperkit.go index cc544488f681..50a4e5a40817 100644 --- a/pkg/minikube/registry/drvs/hyperkit/hyperkit.go +++ b/pkg/minikube/registry/drvs/hyperkit/hyperkit.go @@ -57,7 +57,7 @@ func init() { } } -func configure(config cfg.MachineConfig) interface{} { +func configure(config cfg.MachineConfig) (interface{}, error) { u := config.UUID if u == "" { u = uuid.NewUUID().String() @@ -79,7 +79,7 @@ func configure(config cfg.MachineConfig) interface{} { VpnKitSock: config.HyperkitVpnKitSock, VSockPorts: config.HyperkitVSockPorts, Cmdline: "loglevel=3 console=ttyS0 console=tty0 noembed nomodeset norestore waitusb=10 systemd.legacy_systemd_cgroup_controller=yes random.trust_cpu=on hw_rng_model=virtio base host=" + config.Name, - } + }, nil } func status() registry.State { diff --git a/pkg/minikube/registry/drvs/hyperv/hyperv.go b/pkg/minikube/registry/drvs/hyperv/hyperv.go index 877c81555d70..9f15d0c47007 100644 --- a/pkg/minikube/registry/drvs/hyperv/hyperv.go +++ b/pkg/minikube/registry/drvs/hyperv/hyperv.go @@ -27,6 +27,7 @@ import ( "github.com/docker/machine/drivers/hyperv" "github.com/docker/machine/libmachine/drivers" + "github.com/pkg/errors" cfg "k8s.io/minikube/pkg/minikube/config" "k8s.io/minikube/pkg/minikube/driver" @@ -35,7 +36,8 @@ import ( ) const ( - docURL = "https://minikube.sigs.k8s.io/docs/reference/drivers/hyperv/" + docURL = "https://minikube.sigs.k8s.io/docs/reference/drivers/hyperv/" + defaultExternalSwitchName = "minikube" ) func init() { @@ -50,16 +52,31 @@ func init() { } } -func configure(config cfg.MachineConfig) interface{} { +func configure(config cfg.MachineConfig) (interface{}, error) { d := hyperv.NewDriver(config.Name, localpath.MiniPath()) d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO) d.VSwitch = config.HypervVirtualSwitch + if d.VSwitch == "" && config.HypervUseExternalSwitch { + switchName, adapter, err := chooseSwitch(config.HypervExternalAdapter) + if err != nil { + return nil, errors.Wrapf(err, "failed to choose switch for Hyper-V driver") + } + if config.HypervExternalAdapter == "" && switchName == "" { + // create a switch on the returned adapter + switchName = defaultExternalSwitchName + err := createVMSwitch(switchName, adapter) + if err != nil { + return "", err + } + } + d.VSwitch = switchName + } d.MemSize = config.Memory d.CPU = config.CPUs d.DiskSize = config.DiskSize d.SSHUser = "docker" d.DisableDynamicMemory = true // default to disable dynamic memory as minikube is unlikely to work properly with dynamic memory - return d + return d, nil } func status() registry.State { diff --git a/pkg/minikube/registry/drvs/hyperv/powershell.go b/pkg/minikube/registry/drvs/hyperv/powershell.go new file mode 100644 index 000000000000..d93dfc2a053d --- /dev/null +++ b/pkg/minikube/registry/drvs/hyperv/powershell.go @@ -0,0 +1,64 @@ +// +build windows + +/* +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 hyperv + +import ( + "bufio" + "bytes" + "os/exec" + "strings" + + "github.com/golang/glog" +) + +var powershell string + +func init() { + powershell, _ = exec.LookPath("powershell") +} + +func cmdOut(args ...string) (string, error) { + args = append([]string{"-NoProfile", "-NonInteractive"}, args...) + cmd := exec.Command(powershell, args...) + glog.Infof("[executing ==>] : %v %v", powershell, strings.Join(args, " ")) + var stdout bytes.Buffer + var stderr bytes.Buffer + cmd.Stdout = &stdout + cmd.Stderr = &stderr + err := cmd.Run() + glog.Infof("[stdout =====>] : %s", stdout.String()) + glog.Infof("[stderr =====>] : %s", stderr.String()) + return stdout.String(), err +} + +func cmd(args ...string) error { + _, err := cmdOut(args...) + return err +} + +func parseLines(stdout string) []string { + var resp []string + + s := bufio.NewScanner(strings.NewReader(stdout)) + for s.Scan() { + resp = append(resp, s.Text()) + } + + return resp +} diff --git a/pkg/minikube/registry/drvs/hyperv/vswitch.go b/pkg/minikube/registry/drvs/hyperv/vswitch.go new file mode 100644 index 000000000000..012b169025c6 --- /dev/null +++ b/pkg/minikube/registry/drvs/hyperv/vswitch.go @@ -0,0 +1,202 @@ +// +build windows + +/* +Copyright 2019 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 hyperv + +import ( + "encoding/json" + "fmt" + "strings" + + "github.com/pkg/errors" +) + +type netAdapter struct { + InterfaceGUID string `json:"interfaceGuid"` + InterfaceDescription string +} + +type vmSwitch struct { + Name string + NetAdapterInterfaceGuid []string +} + +// returns network adapters matching to the given filtering condition +func getNetAdapters(physical bool, condition string) ([]netAdapter, error) { + cmdlet := []string{"Get-NetAdapter"} + if physical { + cmdlet = append(cmdlet, "-Physical") + } + cmd := []string{strings.Join(cmdlet, " ")} + if condition != "" { + cmd = append(cmd, fmt.Sprintf("Where-Object {%s}", condition)) + } + cmd = append(cmd, "Select-Object -Property InterfaceGuid, InterfaceDescription") + stdout, err := cmdOut(fmt.Sprintf("ConvertTo-Json @(%s)", strings.Join(cmd, " | "))) + if err != nil { + return nil, err + } + + var adapters []netAdapter + err = json.Unmarshal([]byte(strings.TrimSpace(stdout)), &adapters) + if err != nil { + return nil, err + } + + return adapters, nil +} + +// returns Hyper-V switches matching to the given filtering condition +func getVMSwitch(condition string) ([]vmSwitch, error) { + cmd := []string{"Hyper-V\\Get-VMSwitch"} + if condition != "" { + cmd = append(cmd, fmt.Sprintf("Where-Object {%s}", condition)) + } + cmd = append(cmd, "Select-Object -Property Name, NetAdapterInterfaceGuid") + stdout, err := cmdOut(fmt.Sprintf("ConvertTo-Json @(%s)", strings.Join(cmd, " | "))) + if err != nil { + return nil, err + } + + var vmSwitches []vmSwitch + err = json.Unmarshal([]byte(strings.TrimSpace(stdout)), &vmSwitches) + if err != nil { + return nil, err + } + + return vmSwitches, nil +} + +// returns Hyper-V switches which connects to the adapter of the given GUID +func findConnectedVMSwitch(adapterGUID string) (string, error) { + foundSwitches, err := getVMSwitch(fmt.Sprintf("($_.SwitchType -eq 2) -And ($_.NetAdapterInterfaceGuid -contains \"%s\")", adapterGUID)) + if err != nil { + return "", err + } + + if len(foundSwitches) > 0 { + return foundSwitches[0].Name, nil + } + + return "", nil +} + +// returns "up" net adapters in the order Physical LAN adapters then other adapters +func getOrderedAdapters() ([]netAdapter, error) { + // look for "Up" adapters and prefer physical LAN over other options + lanAdapters, err := getNetAdapters(true, "($_.Status -eq \"Up\") -And ($_.PhysicalMediaType -like \"*802.3*\")") + if err != nil { + return nil, err + } + + upAdapters, err := getNetAdapters(true, "$_.Status -eq \"Up\"") + if err != nil { + return nil, err + } + + var orderedAdapters []netAdapter + adapterGuids := map[string]interface{}{} + + // all adapters will be checked in the following order: + // 1. Connected physical LAN adapters + // 2. Any other connected adapters + for _, adapter := range lanAdapters { + if _, ok := adapterGuids[adapter.InterfaceGUID]; !ok { + adapterGuids[adapter.InterfaceGUID] = nil + orderedAdapters = append(orderedAdapters, adapter) + } + } + + for _, adapter := range upAdapters { + if _, ok := adapterGuids[adapter.InterfaceGUID]; !ok { + adapterGuids[adapter.InterfaceGUID] = nil + orderedAdapters = append(orderedAdapters, adapter) + } + } + + return orderedAdapters, nil +} + +// create a new VM switch of the given name and network adapter +func createVMSwitch(switchName string, adapter netAdapter) error { + err := cmd(fmt.Sprintf("Hyper-V\\New-VMSwitch -Name \"%s\" -NetAdapterInterfaceDescription \"%s\"", switchName, adapter.InterfaceDescription)) + if err != nil { + return errors.Wrapf(err, "failed to create VM switch %s with adapter %s", switchName, adapter.InterfaceGUID) + } + + return nil +} + +// choose VM switch connected to an adapter. If adapter name is not specified, +// it tries to use an "up" LAN adapter then other adapters for external network +func chooseSwitch(adapterName string) (string, netAdapter, error) { + var adapter netAdapter + if adapterName != "" { + foundAdapters, err := getNetAdapters(false, fmt.Sprintf("($_.InterfaceDescription -eq \"%s\")", adapterName)) + if err != nil { + return "", netAdapter{}, err + } + + if len(foundAdapters) == 0 { + return "", netAdapter{}, errors.Errorf("adapter %s not found", adapterName) + } + + adapter = foundAdapters[0] + foundSwitch, err := findConnectedVMSwitch(adapter.InterfaceGUID) + return foundSwitch, adapter, err + } + + adapters, err := getOrderedAdapters() + if err != nil { + return "", netAdapter{}, err + } + + if len(adapters) == 0 { + return "", netAdapter{}, errors.Errorf("no connected adapter available") + } + + externalVMSwitches, err := getVMSwitch("($_.SwitchType -eq 2)") + if err != nil { + return "", netAdapter{}, errors.Wrapf(err, "failed to list external VM switches") + } + + if len(externalVMSwitches) > 0 { + // it doesn't seem like Windows allows one VM switch for each adapter + adapterSwitches := map[string][]string{} + for _, vmSwitch := range externalVMSwitches { + for _, connectedAdapter := range vmSwitch.NetAdapterInterfaceGuid { + var switches []string + key := strings.ToUpper(fmt.Sprintf("{%s}", connectedAdapter)) + if _, ok := adapterSwitches[key]; ok { + switches = adapterSwitches[key] + } + switches = append(switches, vmSwitch.Name) + adapterSwitches[key] = switches + } + } + + for _, adapter := range adapters { + if switches, ok := adapterSwitches[adapter.InterfaceGUID]; ok && len(switches) > 0 { + return switches[0], adapter, nil + } + } + } + + adapter = adapters[0] + return "", adapter, nil +} diff --git a/pkg/minikube/registry/drvs/kvm2/kvm2.go b/pkg/minikube/registry/drvs/kvm2/kvm2.go index 52c5766b2d30..dedad73bfb80 100644 --- a/pkg/minikube/registry/drvs/kvm2/kvm2.go +++ b/pkg/minikube/registry/drvs/kvm2/kvm2.go @@ -67,7 +67,7 @@ type kvmDriver struct { ConnectionURI string } -func configure(mc config.MachineConfig) interface{} { +func configure(mc config.MachineConfig) (interface{}, error) { name := mc.Name return kvmDriver{ BaseDriver: &drivers.BaseDriver{ @@ -86,7 +86,7 @@ func configure(mc config.MachineConfig) interface{} { GPU: mc.KVMGPU, Hidden: mc.KVMHidden, ConnectionURI: mc.KVMQemuURI, - } + }, nil } // defaultURI returns the QEMU URI to connect to for health checks diff --git a/pkg/minikube/registry/drvs/none/none.go b/pkg/minikube/registry/drvs/none/none.go index 371663d7d877..aa8523cab65a 100644 --- a/pkg/minikube/registry/drvs/none/none.go +++ b/pkg/minikube/registry/drvs/none/none.go @@ -42,12 +42,12 @@ func init() { } } -func configure(mc config.MachineConfig) interface{} { +func configure(mc config.MachineConfig) (interface{}, error) { return none.NewDriver(none.Config{ MachineName: mc.Name, StorePath: localpath.MiniPath(), ContainerRuntime: mc.KubernetesConfig.ContainerRuntime, - }) + }), nil } func status() registry.State { diff --git a/pkg/minikube/registry/drvs/parallels/parallels.go b/pkg/minikube/registry/drvs/parallels/parallels.go index 63c769376cba..de319ec8fbac 100644 --- a/pkg/minikube/registry/drvs/parallels/parallels.go +++ b/pkg/minikube/registry/drvs/parallels/parallels.go @@ -44,13 +44,13 @@ func init() { } -func configure(config cfg.MachineConfig) interface{} { +func configure(config cfg.MachineConfig) (interface{}, error) { d := parallels.NewDriver(config.Name, localpath.MiniPath()).(*parallels.Driver) d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO) d.Memory = config.Memory d.CPU = config.CPUs d.DiskSize = config.DiskSize - return d + return d, nil } func status() registry.State { diff --git a/pkg/minikube/registry/drvs/virtualbox/virtualbox.go b/pkg/minikube/registry/drvs/virtualbox/virtualbox.go index 60931a38f7e8..bfba0e42db89 100644 --- a/pkg/minikube/registry/drvs/virtualbox/virtualbox.go +++ b/pkg/minikube/registry/drvs/virtualbox/virtualbox.go @@ -49,7 +49,7 @@ func init() { } } -func configure(mc config.MachineConfig) interface{} { +func configure(mc config.MachineConfig) (interface{}, error) { d := virtualbox.NewDriver(mc.Name, localpath.MiniPath()) d.Boot2DockerURL = mc.Downloader.GetISOFileURI(mc.MinikubeISO) d.Memory = mc.Memory @@ -62,7 +62,7 @@ func configure(mc config.MachineConfig) interface{} { d.HostOnlyNicType = mc.HostOnlyNicType d.DNSProxy = mc.DNSProxy d.HostDNSResolver = mc.HostDNSResolver - return d + return d, nil } func status() registry.State { diff --git a/pkg/minikube/registry/drvs/vmware/vmware.go b/pkg/minikube/registry/drvs/vmware/vmware.go index 318a73c80bab..885063cde28a 100644 --- a/pkg/minikube/registry/drvs/vmware/vmware.go +++ b/pkg/minikube/registry/drvs/vmware/vmware.go @@ -39,7 +39,7 @@ func init() { } } -func configure(mc config.MachineConfig) interface{} { +func configure(mc config.MachineConfig) (interface{}, error) { d := vmwcfg.NewConfig(mc.Name, localpath.MiniPath()) d.Boot2DockerURL = mc.Downloader.GetISOFileURI(mc.MinikubeISO) d.Memory = mc.Memory @@ -49,7 +49,7 @@ func configure(mc config.MachineConfig) interface{} { // TODO(frapposelli): push these defaults upstream to fixup this driver d.SSHPort = 22 d.ISO = d.ResolveStorePath("boot2docker.iso") - return d + return d, nil } func status() registry.State { diff --git a/pkg/minikube/registry/drvs/vmwarefusion/vmwarefusion.go b/pkg/minikube/registry/drvs/vmwarefusion/vmwarefusion.go index 6fd6972e1e55..bb5ed4196bca 100644 --- a/pkg/minikube/registry/drvs/vmwarefusion/vmwarefusion.go +++ b/pkg/minikube/registry/drvs/vmwarefusion/vmwarefusion.go @@ -44,7 +44,7 @@ func init() { } } -func configure(config cfg.MachineConfig) interface{} { +func configure(config cfg.MachineConfig) (interface{}, error) { d := vmwarefusion.NewDriver(config.Name, localpath.MiniPath()).(*vmwarefusion.Driver) d.Boot2DockerURL = config.Downloader.GetISOFileURI(config.MinikubeISO) d.Memory = config.Memory @@ -54,7 +54,7 @@ func configure(config cfg.MachineConfig) interface{} { // TODO(philips): push these defaults upstream to fixup this driver d.SSHPort = 22 d.ISO = d.ResolveStorePath("boot2docker.iso") - return d + return d, nil } func status() registry.State { diff --git a/pkg/minikube/registry/registry.go b/pkg/minikube/registry/registry.go index a506a28aeb8b..159c7a4568a0 100644 --- a/pkg/minikube/registry/registry.go +++ b/pkg/minikube/registry/registry.go @@ -60,7 +60,7 @@ type Registry interface { } // Configurator emits a struct to be marshalled into JSON for Machine Driver -type Configurator func(config.MachineConfig) interface{} +type Configurator func(config.MachineConfig) (interface{}, error) // Loader is a function that loads a byte stream and creates a driver. type Loader func() drivers.Driver