Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 20 additions & 4 deletions pkg/minikube/driver/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package driver
import (
"fmt"
"os"
"os/exec"
"runtime"
"sort"
"strconv"
Expand Down Expand Up @@ -79,6 +80,7 @@ const (
var (
// systemdResolvConf is path to systemd's DNS configuration. https://github.com/kubernetes/minikube/issues/3511
systemdResolvConf = "/run/systemd/resolve/resolv.conf"
HasSudo = realHasSudo
)

// SupportedDrivers returns a list of supported drivers
Expand Down Expand Up @@ -319,6 +321,14 @@ func FlagDefaults(name string) FlagHints {
func Choices(vm bool) []registry.DriverState {
options := registry.Available(vm)

if !HasSudo() {
for i := range options {
if options[i].NeedsSudo {
options[i].Priority = registry.Discouraged
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We must not do this. Driver priority must not change based on sudo availability.

We can add more info on the driver status, but the priority must not change.

}
}
}

// Descending priority for predictability and appearance
sort.Slice(options, func(i, j int) bool {
return options[i].Priority > options[j].Priority
Expand Down Expand Up @@ -392,10 +402,11 @@ func Status(name string) registry.DriverState {
select {
case s := <-stateChannel:
return registry.DriverState{
Name: d.Name,
Default: d.Default,
Priority: d.Priority,
State: s,
Name: d.Name,
Default: d.Default,
Priority: d.Priority,
State: s,
NeedsSudo: d.NeedsSudo,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is problematic since this info is dynamic. For example vfkit does not need sudo with the default network (nat), but need sudo for setup with vmnet-shared network. This should be done in the driver documentation and not here.

}
case <-timeoutChannel:
klog.Infof("time out when checking for status of %s driver", name)
Expand Down Expand Up @@ -438,3 +449,8 @@ func IndexFromMachineName(machineName string) int {
}
return 1 // master node
}

func realHasSudo() bool {
err := exec.Command("sudo", "-n", "true").Run()
return err == nil
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect check. Nobody configures a system so you can run any command as root without a password. This configuration is use only in throwaway systems like CI VM that is deleted after the CI run, or inside minikube VM where you are not expected to modify the host.

2 changes: 2 additions & 0 deletions pkg/minikube/registry/drvs/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ func init() {
Status: status,
Default: true,
Priority: registry.HighlyPreferred,
// Docker driver does not require sudo
NeedsSudo: false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You must have sudo to install docker on Linux or add your self to docker group. This is same as kvm.

}); err != nil {
panic(fmt.Sprintf("register failed: %v", err))
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/registry/drvs/hyperkit/hyperkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ func init() {
Status: status,
Default: true,
Priority: registry.Deprecated,
// Hyperkit driver requires sudo
NeedsSudo: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minikube has code to configure hyperkit to run without a password, but hyperkit is deprecated so it is not interesting to add this info.

}); err != nil {
panic(fmt.Sprintf("register: %v", err))
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/registry/drvs/hyperv/hyperv.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ func init() {
Status: status,
Default: true,
Priority: registry.Preferred,
// Hyper-V driver requires sudo
NeedsSudo: true,
}); err != nil {
panic(fmt.Sprintf("register: %v", err))
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/registry/drvs/krunkit/krunkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ func init() {
Status: status,
Default: true,
Priority: registry.Experimental,
// Krunkit driver requires sudo
NeedsSudo: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

False, sudo required only to installl vment-helper, same as docker.

}); err != nil {
panic(fmt.Sprintf("register failed: %v", err))
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/registry/drvs/kvm2/kvm2.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ func init() {
Status: status,
Default: true,
Priority: registry.Preferred,
// KVM2 driver does not require sudo
NeedsSudo: false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requires sudo to install libvirt and add yourself to the libvirt group.

}); err != nil {
panic(fmt.Sprintf("register failed: %v", err))
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/registry/drvs/none/none.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ func init() {
Status: status,
Default: false, // no isolation
Priority: registry.Discouraged,
// None driver requires sudo
NeedsSudo: true,
}); err != nil {
panic(fmt.Sprintf("register failed: %v", err))
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/registry/drvs/parallels/parallels.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ func init() {
Default: true,
Priority: registry.Default,
Init: func() drivers.Driver { return parallels.NewDriver("", "") },
// Parallels driver requires sudo
NeedsSudo: true,
})
if err != nil {
panic(fmt.Sprintf("unable to register: %v", err))
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/registry/drvs/podman/podman.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ func init() {
Status: status,
Default: true,
Priority: priority,
// Podman driver may require sudo (on linux)
NeedsSudo: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This depends on the os:

  • Linux: requires sudo to install podman. Using rootless mode by default so no need to configure special group
  • macOS: does not require sudo to install and run podman (using vfkit and gvproxy)

The minikube driver may have limitations and issues with using podman, it is not not well maintained.

}); err != nil {
panic(fmt.Sprintf("register failed: %v", err))
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/registry/drvs/qemu2/qemu2.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ func init() {
Status: status,
Default: true,
Priority: priority,
// QEMU2 driver does not require sudo
NeedsSudo: false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong, qemu can be installed via brew, but to use socket_vment (e.g to support multiple clusters accessing each other, or multi-node clusters), you need root - same as vmnet-helper.

This also depends on the system:

  • Linux: sudo required to install qemu
  • macOS: sudo not required to install qemu (e.g. brew install qemu)

}); err != nil {
panic(fmt.Sprintf("register failed: %v", err))
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/registry/drvs/ssh/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ func init() {
Default: false, // requires external VM
Priority: registry.Discouraged,
Init: func() drivers.Driver { return ssh.NewDriver(ssh.Config{}) },
// SSH driver does not require sudo
NeedsSudo: false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you will need sudo on the host you connect to.

})
if err != nil {
panic(fmt.Sprintf("unable to register: %v", err))
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/registry/drvs/vfkit/vfkit.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ func init() {
Status: status,
Default: true,
Priority: priority,
// VFKit driver requires sudo
NeedsSudo: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sudo required only for the initial setup to install vment-helper.

}); err != nil {
panic(fmt.Sprintf("register failed: %v", err))
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/registry/drvs/virtualbox/virtualbox.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ func init() {
Default: true,
Priority: registry.Fallback,
Init: func() drivers.Driver { return virtualbox.NewDriver("", "") },
// VirtualBox driver requires sudo
NeedsSudo: true,
})
if err != nil {
panic(fmt.Sprintf("unable to register: %v", err))
Expand Down
2 changes: 2 additions & 0 deletions pkg/minikube/registry/drvs/vmware/vmware.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ func init() {
Priority: registry.Deprecated,
Init: func() drivers.Driver { return vmware.NewDriver("", "") },
Status: status,
// VMware driver requires sudo
NeedsSudo: true,
})
if err != nil {
panic(fmt.Sprintf("unable to register: %v", err))
Expand Down
4 changes: 3 additions & 1 deletion pkg/minikube/registry/global.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ type DriverState struct {
Rejection string
// Suggestion is how the user could improve health
Suggestion string
// New field: whether this driver requires sudo permissions
NeedsSudo bool
}

func (d DriverState) String() string {
Expand Down Expand Up @@ -137,7 +139,7 @@ func Available(vm bool) []DriverState {
if !s.Healthy {
priority = Unhealthy
}
sts = append(sts, DriverState{Name: d.Name, Default: d.Default, Preference: preference, Priority: priority, State: s})
sts = append(sts, DriverState{Name: d.Name, Default: d.Default, Preference: preference, Priority: priority, State: s, NeedsSudo: d.NeedsSudo})
}

// Descending priority for predictability
Expand Down
20 changes: 12 additions & 8 deletions pkg/minikube/registry/global_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,20 +72,22 @@ func TestGlobalAvailable(t *testing.T) {
}

bar := DriverDef{
Name: "healthy-bar",
Default: true,
Priority: Default,
Status: func() State { return State{Healthy: true} },
Name: "healthy-bar",
Default: true,
Priority: Default,
NeedsSudo: false,
Status: func() State { return State{Healthy: true} },
}
if err := Register(bar); err != nil {
t.Errorf("register returned error: %v", err)
}

foo := DriverDef{
Name: "unhealthy-foo",
Default: true,
Priority: Default,
Status: func() State { return State{Healthy: false} },
Name: "unhealthy-foo",
Default: true,
Priority: Default,
NeedsSudo: false,
Status: func() State { return State{Healthy: false} },
}
if err := Register(foo); err != nil {
t.Errorf("register returned error: %v", err)
Expand All @@ -97,13 +99,15 @@ func TestGlobalAvailable(t *testing.T) {
Default: true,
Preference: Default,
Priority: Default,
NeedsSudo: false,
State: State{Healthy: true},
},
{
Name: "unhealthy-foo",
Default: true,
Preference: Default,
Priority: Unhealthy,
NeedsSudo: false,
State: State{Healthy: false},
},
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/minikube/registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ type DriverDef struct {

// Priority returns the prioritization for selecting a driver by default.
Priority Priority

// New field: whether this driver requires sudo permissions
NeedsSudo bool
}

// Empty returns true if the driver is nil
Expand Down
51 changes: 51 additions & 0 deletions pkg/minikube/registry/registry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package registry

import (
"os/exec"
"testing"

"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -91,3 +92,53 @@ func TestDriverAlias(t *testing.T) {
t.Errorf("driver.Empty = false, expected true")
}
}

// NeedsSudo try to execute driver related commands to determine if sudo is required
func NeedsSudo(driverName string) bool {
var cmd *exec.Cmd

switch driverName {
case "docker":
cmd = exec.Command("docker", "info")
case "podman":
cmd = exec.Command("podman", "info")
case "kvm2":
cmd = exec.Command("virsh", "list", "--all")
case "qemu2":
cmd = exec.Command("qemu-system-x86_64", "--version")
case "virtualbox":
cmd = exec.Command("VBoxManage", "list", "vms")
case "hyperkit":
cmd = exec.Command("hyperkit", "-v")
case "hyperv":
cmd = exec.Command("powershell", "-Command", "Get-VM") // Windows Hyper-V
case "vmware":
cmd = exec.Command("vmrun", "list")
case "parallels":
cmd = exec.Command("prlctl", "list")
case "vfkit":
cmd = exec.Command("vfctl", "list") // macOS vfkit CLI
case "ssh":
cmd = exec.Command("ssh", "-V")
case "krunkit":
cmd = exec.Command("krun", "--version") // krunkit CLI
case "none":
return true // none driver almost always requires root
default:
return false // By default, no sudo is required
}

// Execute the command and check if it succeeds
if err := cmd.Run(); err != nil {
// If it fails, it may require sudo
return true
}
return false
}

func TestNeedsSudo(t *testing.T) {
drivers := []string{"docker", "podman", "kvm2", "none", "qemu2", "virtualbox", "hyperkit", "vmware", "parallels", "ssh", "krunkit", "hyperv", "vfkit"}
for _, d := range drivers {
t.Logf("%s NeedsSudo = %v", d, NeedsSudo(d))
}
}