diff --git a/cmd/minikube/cmd/start.go b/cmd/minikube/cmd/start.go index 909b37d7340e..324d6d9d3243 100644 --- a/cmd/minikube/cmd/start.go +++ b/cmd/minikube/cmd/start.go @@ -786,12 +786,19 @@ func validateUser(drvName string) { useForce := viper.GetBool(force) - if driver.NeedsRoot(drvName) && u.Uid != "0" && !useForce { - exit.Message(reason.DrvNeedsRoot, `The "{{.driver_name}}" driver requires root privileges. Please run minikube using 'sudo -E minikube start --driver={{.driver_name}}'.`, out.V{"driver_name": drvName}) + // None driver works with root and without root on Linux + if runtime.GOOS == "linux" && drvName == driver.None { + if !viper.GetBool(interactive) { + test := exec.Command("sudo", "-n", "echo", "-n") + if err := test.Run(); err != nil { + exit.Message(reason.DrvNeedsRoot, `sudo requires a password, and --interactive=false`) + } + } + return } - // If root is required, or we are not root, exit early - if driver.NeedsRoot(drvName) || u.Uid != "0" { + // If we are not root, exit early + if u.Uid != "0" { return } diff --git a/pkg/minikube/command/exec_runner.go b/pkg/minikube/command/exec_runner.go index 7b5b61acdbf7..6e5caf5708a2 100644 --- a/pkg/minikube/command/exec_runner.go +++ b/pkg/minikube/command/exec_runner.go @@ -20,10 +20,12 @@ import ( "bytes" "fmt" "io" + "io/ioutil" "os" "os/exec" "path" "path/filepath" + "runtime" "strconv" "time" @@ -85,11 +87,11 @@ func (*execRunner) RunCmd(cmd *exec.Cmd) (*RunResult, error) { } // Copy copies a file and its permissions -func (*execRunner) Copy(f assets.CopyableFile) error { +func (e *execRunner) Copy(f assets.CopyableFile) error { dst := path.Join(f.GetTargetDir(), f.GetTargetName()) if _, err := os.Stat(dst); err == nil { klog.Infof("found %s, removing ...", dst) - if err := os.Remove(dst); err != nil { + if err := e.Remove(f); err != nil { return errors.Wrapf(err, "error removing file %s", dst) } } @@ -105,12 +107,47 @@ func (*execRunner) Copy(f assets.CopyableFile) error { return errors.Wrapf(err, "error converting permissions %s to integer", f.GetPermissions()) } - return writeFile(dst, f, os.FileMode(perms)) + switch runtime.GOOS { + case "linux": + // write to temp location ... + tmpfile, err := ioutil.TempFile("", "minikube") + if err != nil { + return errors.Wrapf(err, "error creating tempfile") + } + defer os.Remove(tmpfile.Name()) + err = writeFile(tmpfile.Name(), f, os.FileMode(perms)) + if err != nil { + return errors.Wrapf(err, "error writing to tempfile %s", tmpfile.Name()) + } + + // ... then use sudo to move to target ... + _, err = e.RunCmd(exec.Command("sudo", "cp", "-a", tmpfile.Name(), dst)) + if err != nil { + return errors.Wrapf(err, "error copying tempfile %s to dst %s", tmpfile.Name(), dst) + } + + // ... then fix file permission that should have been fine because of "cp -a" + err = os.Chmod(dst, os.FileMode(perms)) + return err + + default: + return writeFile(dst, f, os.FileMode(perms)) + } + } // Remove removes a file -func (*execRunner) Remove(f assets.CopyableFile) error { +func (e *execRunner) Remove(f assets.CopyableFile) error { dst := filepath.Join(f.GetTargetDir(), f.GetTargetName()) klog.Infof("rm: %s", dst) - return os.Remove(dst) + if err := os.Remove(dst); err != nil { + if !os.IsPermission(err) { + return err + } + _, err = e.RunCmd(exec.Command("sudo", "rm", "-f", dst)) + if err != nil { + return err + } + } + return nil } diff --git a/pkg/minikube/driver/driver.go b/pkg/minikube/driver/driver.go index 8d876f1c8302..c7b6a6c26c3d 100644 --- a/pkg/minikube/driver/driver.go +++ b/pkg/minikube/driver/driver.go @@ -141,11 +141,6 @@ func BareMetal(name string) bool { return name == None || name == Mock } -// NeedsRoot returns true if driver needs to run with root privileges -func NeedsRoot(name string) bool { - return name == None -} - // NeedsPortForward returns true if driver is unable provide direct IP connectivity func NeedsPortForward(name string) bool { // Docker for Desktop diff --git a/pkg/minikube/registry/drvs/none/none.go b/pkg/minikube/registry/drvs/none/none.go index 7afae87987df..6ca39eb10a1b 100644 --- a/pkg/minikube/registry/drvs/none/none.go +++ b/pkg/minikube/registry/drvs/none/none.go @@ -67,8 +67,10 @@ func status() registry.State { } if u.Uid != "0" { - return registry.State{Error: fmt.Errorf("the 'none' driver must be run as the root user"), Healthy: false, Fix: "For non-root usage, try the newer 'docker' driver", Installed: true} + test := exec.Command("sudo", "-n", "echo", "-n") + if err := test.Run(); err != nil { + return registry.State{Error: fmt.Errorf("running the 'none' driver as a regular user requires sudo permissions"), Healthy: false} + } } - return registry.State{Installed: true, Healthy: true} }