Add --interactive flag support
parent
97ebe91c68
commit
c0874e2a7e
|
|
@ -105,6 +105,7 @@ const (
|
|||
hostDNSResolver = "host-dns-resolver"
|
||||
waitUntilHealthy = "wait"
|
||||
force = "force"
|
||||
interactive = "interactive"
|
||||
waitTimeout = "wait-timeout"
|
||||
nativeSSH = "native-ssh"
|
||||
)
|
||||
|
|
@ -140,6 +141,7 @@ func initMinikubeFlags() {
|
|||
viper.AutomaticEnv()
|
||||
|
||||
startCmd.Flags().Bool(force, false, "Force minikube to perform possibly dangerous operations")
|
||||
startCmd.Flags().Bool(interactive, true, "Allow user prompts for more information")
|
||||
|
||||
startCmd.Flags().Int(cpus, constants.DefaultCPUS, "Number of CPUs allocated to the minikube VM.")
|
||||
startCmd.Flags().String(memory, constants.DefaultMemorySize, "Amount of RAM allocated to the minikube VM (format: <number>[<unit>], where unit = b, k, m or g).")
|
||||
|
|
@ -290,7 +292,10 @@ func runStart(cmd *cobra.Command, args []string) {
|
|||
|
||||
validateFlags(driver)
|
||||
validateUser(driver)
|
||||
installOrUpdateDriver(driver)
|
||||
if err := drivers.InstallOrUpdate(driver, viper.GetBool(interactive)); err != nil {
|
||||
glog.Errorf("error: %v", err)
|
||||
out.WarningT("Unable to update {{.driver}} driver: {{.error}}", out.V{"driver": driver, "error": err})
|
||||
}
|
||||
|
||||
k8sVersion, isUpgrade := getKubernetesVersion(oldConfig)
|
||||
config, err := generateCfgFromFlags(cmd, k8sVersion, driver)
|
||||
|
|
@ -1055,27 +1060,3 @@ func configureMounts() {
|
|||
func saveConfig(clusterCfg *cfg.Config) error {
|
||||
return cfg.CreateProfile(viper.GetString(cfg.MachineProfile), clusterCfg)
|
||||
}
|
||||
|
||||
func installOrUpdateDriver(driver string) {
|
||||
var driverExecutable string
|
||||
switch driver {
|
||||
case constants.DriverKvm2:
|
||||
driverExecutable = fmt.Sprintf("docker-machine-driver-%s", constants.DriverKvm2)
|
||||
case constants.DriverHyperkit:
|
||||
driverExecutable = fmt.Sprintf("docker-machine-driver-%s", constants.DriverHyperkit)
|
||||
default: // driver doesn't install or update
|
||||
return
|
||||
}
|
||||
|
||||
minikubeVersion, err := version.GetSemverVersion()
|
||||
if err != nil {
|
||||
out.WarningT("Error parsing minikube version: {{.error}}", out.V{"error": err})
|
||||
return
|
||||
}
|
||||
|
||||
targetDir := constants.MakeMiniPath("bin")
|
||||
err = drivers.InstallOrUpdate(driverExecutable, targetDir, minikubeVersion)
|
||||
if err != nil {
|
||||
out.WarningT("Error downloading driver: {{.error}}", out.V{"error": err})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
|
@ -38,6 +37,7 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
"k8s.io/minikube/pkg/version"
|
||||
|
||||
"k8s.io/minikube/pkg/minikube/constants"
|
||||
"k8s.io/minikube/pkg/minikube/out"
|
||||
"k8s.io/minikube/pkg/util"
|
||||
)
|
||||
|
|
@ -123,14 +123,14 @@ func MakeDiskImage(d *drivers.BaseDriver, boot2dockerURL string, diskSize int) e
|
|||
return errors.Wrapf(err, "createRawDiskImage(%s)", diskPath)
|
||||
}
|
||||
machPath := d.ResolveStorePath(".")
|
||||
if err := fixPermissions(machPath); err != nil {
|
||||
if err := fixMachinePermissions(machPath); err != nil {
|
||||
return errors.Wrapf(err, "fixing permissions on %s", machPath)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func fixPermissions(path string) error {
|
||||
func fixMachinePermissions(path string) error {
|
||||
glog.Infof("Fixing permissions on %s ...", path)
|
||||
if err := os.Chown(path, syscall.Getuid(), syscall.Getegid()); err != nil {
|
||||
return errors.Wrap(err, "chown dir")
|
||||
|
|
@ -149,44 +149,110 @@ func fixPermissions(path string) error {
|
|||
}
|
||||
|
||||
// InstallOrUpdate downloads driver if it is not present, or updates it if there's a newer version
|
||||
func InstallOrUpdate(driver, destination string, v semver.Version) error {
|
||||
glog.Infof("InstallOrUpdate(%s): dest=%s, version=%s, PATH=%s", driver, destination, v, os.Getenv("PATH"))
|
||||
|
||||
_, err := exec.LookPath(driver)
|
||||
// if file driver doesn't exist, download it
|
||||
if err != nil {
|
||||
glog.Infof("LookPath %s: %v", driver, err)
|
||||
return download(driver, v, destination)
|
||||
func InstallOrUpdate(driver string, interactive bool) error {
|
||||
if driver != constants.DriverKvm2 && driver != constants.DriverHyperkit {
|
||||
return nil
|
||||
}
|
||||
|
||||
cmd := exec.Command(driver, "version")
|
||||
output, err := cmd.Output()
|
||||
// if driver doesnt support 'version', it is old, download it
|
||||
v, err := version.GetSemverVersion()
|
||||
if err != nil {
|
||||
glog.Infof("%s version: %v", driver, err)
|
||||
return download(driver, v, destination)
|
||||
out.WarningT("Error parsing minikube version: {{.error}}", out.V{"error": err})
|
||||
return err
|
||||
}
|
||||
|
||||
ev := ExtractVMDriverVersion(string(output))
|
||||
executable := fmt.Sprintf("docker-machine-driver-%s", driver)
|
||||
path, err := validateDriver(executable, v)
|
||||
if err != nil {
|
||||
glog.Warningf("%s: %v", driver, executable)
|
||||
path = filepath.Join(constants.MakeMiniPath("bin"), executable)
|
||||
derr := download(executable, path, v)
|
||||
if derr != nil {
|
||||
return derr
|
||||
}
|
||||
}
|
||||
return fixDriverPermissions(driver, path, interactive)
|
||||
}
|
||||
|
||||
// if the driver doesn't return any version, download it
|
||||
// fixDriverPermissions fixes the permissions on a driver
|
||||
func fixDriverPermissions(driver string, path string, interactive bool) error {
|
||||
// Everything is easy but hyperkit
|
||||
if driver != constants.DriverHyperkit {
|
||||
return os.Chmod(path, 0755)
|
||||
}
|
||||
|
||||
// Hyperkit land
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cmds := []*exec.Cmd{}
|
||||
owner := info.Sys().(*syscall.Stat_t).Uid
|
||||
m := info.Mode()
|
||||
glog.Infof("%s owner: %d - permissions: %s", path, owner, m)
|
||||
if owner != 0 {
|
||||
cmds = append(cmds, exec.Command("sudo", "chown", "root:wheel", path))
|
||||
}
|
||||
|
||||
if m&os.ModeSetuid == 0 {
|
||||
cmds = append(cmds, exec.Command("sudo", "chmod", "u+s", path))
|
||||
}
|
||||
|
||||
// No work to be done!
|
||||
if len(cmds) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var example strings.Builder
|
||||
for _, c := range cmds {
|
||||
example.WriteString(fmt.Sprintf(" $ %s \n", strings.Join(c.Args, " ")))
|
||||
}
|
||||
|
||||
out.T(out.Permissions, "The '{{.driver}}' driver requires elevated permissions. The following commands will be executed:\n\n{{ .example }}\n", out.V{"driver": driver, "example": example.String()})
|
||||
for _, c := range cmds {
|
||||
testArgs := append([]string{"-n"}, c.Args[1:]...)
|
||||
test := exec.Command("sudo", testArgs...)
|
||||
glog.Infof("testing: %v", test.Args)
|
||||
if err := test.Run(); err != nil {
|
||||
glog.Infof("%v may require a password: %v", c.Args, err)
|
||||
if !interactive {
|
||||
return fmt.Errorf("%v requires a password, and --interactive=false", c.Args)
|
||||
}
|
||||
}
|
||||
glog.Infof("running: %v", c.Args)
|
||||
err := c.Run()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "%v", c.Args)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateDriver validates if a driver appears to be up-to-date and installed properly
|
||||
func validateDriver(driver string, v semver.Version) (string, error) {
|
||||
path, err := exec.LookPath(driver)
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
|
||||
output, err := exec.Command(path, "version").Output()
|
||||
if err != nil {
|
||||
return path, err
|
||||
}
|
||||
|
||||
ev := extractVMDriverVersion(string(output))
|
||||
if len(ev) == 0 {
|
||||
glog.Infof("%s: unable to extract version from %q", driver, output)
|
||||
return download(driver, v, destination)
|
||||
return path, fmt.Errorf("%s: unable to extract version from %q", driver, output)
|
||||
}
|
||||
|
||||
vmDriverVersion, err := semver.Make(ev)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "can't parse driver version")
|
||||
return path, errors.Wrap(err, "can't parse driver version")
|
||||
}
|
||||
|
||||
// if the current driver version is older, download newer
|
||||
if vmDriverVersion.LT(v) {
|
||||
glog.Infof("%s is version %s, want %s", driver, vmDriverVersion, v)
|
||||
return download(driver, v, destination)
|
||||
return path, fmt.Errorf("%s is version %s, want %s", driver, vmDriverVersion, v)
|
||||
}
|
||||
|
||||
return nil
|
||||
return path, nil
|
||||
}
|
||||
|
||||
func driverWithChecksumURL(driver string, v semver.Version) string {
|
||||
|
|
@ -194,50 +260,31 @@ func driverWithChecksumURL(driver string, v semver.Version) string {
|
|||
return fmt.Sprintf("%s?checksum=file:%s.sha256", base, base)
|
||||
}
|
||||
|
||||
func download(driver string, v semver.Version, destination string) error {
|
||||
// supports kvm2 and hyperkit
|
||||
if driver != "docker-machine-driver-kvm2" && driver != "docker-machine-driver-hyperkit" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// download an arbitrary driver
|
||||
func download(driver string, destination string, v semver.Version) error {
|
||||
out.T(out.FileDownload, "Downloading driver {{.driver}}:", out.V{"driver": driver})
|
||||
targetFilepath := path.Join(destination, driver)
|
||||
os.Remove(targetFilepath)
|
||||
os.Remove(destination)
|
||||
url := driverWithChecksumURL(driver, v)
|
||||
client := &getter.Client{
|
||||
Src: url,
|
||||
Dst: targetFilepath,
|
||||
Dst: destination,
|
||||
Mode: getter.ClientModeFile,
|
||||
Options: []getter.ClientOption{getter.WithProgress(util.DefaultProgressBar)},
|
||||
}
|
||||
|
||||
glog.Infof("Downloading: %+v", client)
|
||||
|
||||
if err := client.Get(); err != nil {
|
||||
return errors.Wrapf(err, "download failed: %s", url)
|
||||
}
|
||||
|
||||
err := os.Chmod(targetFilepath, 0755)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "chmod error")
|
||||
}
|
||||
|
||||
if driver == "docker-machine-driver-hyperkit" {
|
||||
err := setHyperKitPermissions(targetFilepath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "setting hyperkit permission")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtractVMDriverVersion extracts the driver version.
|
||||
// extractVMDriverVersion extracts the driver version.
|
||||
// KVM and Hyperkit drivers support the 'version' command, that display the information as:
|
||||
// version: vX.X.X
|
||||
// commit: XXXX
|
||||
// This method returns the version 'vX.X.X' or empty if the version isn't found.
|
||||
func ExtractVMDriverVersion(s string) string {
|
||||
func extractVMDriverVersion(s string) string {
|
||||
versionRegex := regexp.MustCompile(`version:(.*)`)
|
||||
matches := versionRegex.FindStringSubmatch(s)
|
||||
|
||||
|
|
@ -248,22 +295,3 @@ func ExtractVMDriverVersion(s string) string {
|
|||
v := strings.TrimSpace(matches[1])
|
||||
return strings.TrimPrefix(v, version.VersionPrefix)
|
||||
}
|
||||
|
||||
func setHyperKitPermissions(driverPath string) error {
|
||||
msg := fmt.Sprintf("A new hyperkit driver was installed. It needs elevated permissions to run. The following commands will be executed:\n\n $ sudo chown root:wheel %s\n $ sudo chmod u+s %s\n", driverPath, driverPath)
|
||||
out.T(out.Permissions, msg, out.V{})
|
||||
|
||||
cmd := exec.Command("sudo", "chown", "root:wheel", driverPath)
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "chown root:wheel")
|
||||
}
|
||||
|
||||
cmd = exec.Command("sudo", "chmod", "u+s", driverPath)
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "chmod u+s")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,24 +50,24 @@ func Test_createDiskImage(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestExtractVMDriverVersion(t *testing.T) {
|
||||
v := ExtractVMDriverVersion("")
|
||||
v := extractVMDriverVersion("")
|
||||
if len(v) != 0 {
|
||||
t.Error("Expected empty string")
|
||||
}
|
||||
|
||||
v = ExtractVMDriverVersion("random text")
|
||||
v = extractVMDriverVersion("random text")
|
||||
if len(v) != 0 {
|
||||
t.Error("Expected empty string")
|
||||
}
|
||||
|
||||
expectedVersion := "1.2.3"
|
||||
|
||||
v = ExtractVMDriverVersion("version: v1.2.3")
|
||||
v = extractVMDriverVersion("version: v1.2.3")
|
||||
if expectedVersion != v {
|
||||
t.Errorf("Expected version: %s, got: %s", expectedVersion, v)
|
||||
}
|
||||
|
||||
v = ExtractVMDriverVersion("version: 1.2.3")
|
||||
v = extractVMDriverVersion("version: 1.2.3")
|
||||
if expectedVersion != v {
|
||||
t.Errorf("Expected version: %s, got: %s", expectedVersion, v)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ var styles = map[StyleEnum]style{
|
|||
Documentation: {Prefix: "📘 "},
|
||||
Issues: {Prefix: "⁉️ "},
|
||||
Issue: {Prefix: " ▪ ", LowPrefix: lowIndent}, // Indented bullet
|
||||
Check: {Prefix: "✔️ "},
|
||||
Check: {Prefix: "✅ "},
|
||||
Celebration: {Prefix: "🎉 "},
|
||||
Workaround: {Prefix: "👉 ", LowPrefix: lowIndent},
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue