Skip to content

Commit 2526a9c

Browse files
authored
Merge pull request #5397 from tstromberg/interactive
Add --interactive flag to prevent stdin prompts
2 parents 8fefeb1 + d0bff38 commit 2526a9c

File tree

5 files changed

+103
-102
lines changed

5 files changed

+103
-102
lines changed

Diff for: cmd/minikube/cmd/start.go

+12-25
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ const (
105105
hostDNSResolver = "host-dns-resolver"
106106
waitUntilHealthy = "wait"
107107
force = "force"
108+
interactive = "interactive"
108109
waitTimeout = "wait-timeout"
109110
nativeSSH = "native-ssh"
110111
)
@@ -140,6 +141,7 @@ func initMinikubeFlags() {
140141
viper.AutomaticEnv()
141142

142143
startCmd.Flags().Bool(force, false, "Force minikube to perform possibly dangerous operations")
144+
startCmd.Flags().Bool(interactive, true, "Allow user prompts for more information")
143145

144146
startCmd.Flags().Int(cpus, constants.DefaultCPUS, "Number of CPUs allocated to the minikube VM.")
145147
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,16 @@ func runStart(cmd *cobra.Command, args []string) {
290292

291293
validateFlags(driver)
292294
validateUser(driver)
293-
installOrUpdateDriver(driver)
295+
296+
v, err := version.GetSemverVersion()
297+
if err != nil {
298+
out.WarningT("Error parsing minikube version: {{.error}}", out.V{"error": err})
299+
} else {
300+
if err := drivers.InstallOrUpdate(driver, constants.MakeMiniPath("bin"), v, viper.GetBool(interactive)); err != nil {
301+
glog.Errorf("error: %v", err)
302+
out.WarningT("Unable to update {{.driver}} driver: {{.error}}", out.V{"driver": driver, "error": err})
303+
}
304+
}
294305

295306
k8sVersion, isUpgrade := getKubernetesVersion(oldConfig)
296307
config, err := generateCfgFromFlags(cmd, k8sVersion, driver)
@@ -1055,27 +1066,3 @@ func configureMounts() {
10551066
func saveConfig(clusterCfg *cfg.Config) error {
10561067
return cfg.CreateProfile(viper.GetString(cfg.MachineProfile), clusterCfg)
10571068
}
1058-
1059-
func installOrUpdateDriver(driver string) {
1060-
var driverExecutable string
1061-
switch driver {
1062-
case constants.DriverKvm2:
1063-
driverExecutable = fmt.Sprintf("docker-machine-driver-%s", constants.DriverKvm2)
1064-
case constants.DriverHyperkit:
1065-
driverExecutable = fmt.Sprintf("docker-machine-driver-%s", constants.DriverHyperkit)
1066-
default: // driver doesn't install or update
1067-
return
1068-
}
1069-
1070-
minikubeVersion, err := version.GetSemverVersion()
1071-
if err != nil {
1072-
out.WarningT("Error parsing minikube version: {{.error}}", out.V{"error": err})
1073-
return
1074-
}
1075-
1076-
targetDir := constants.MakeMiniPath("bin")
1077-
err = drivers.InstallOrUpdate(driverExecutable, targetDir, minikubeVersion)
1078-
if err != nil {
1079-
out.WarningT("Error downloading driver: {{.error}}", out.V{"error": err})
1080-
}
1081-
}

Diff for: pkg/drivers/drivers.go

+84-70
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"io/ioutil"
2323
"os"
2424
"os/exec"
25-
"path"
2625
"path/filepath"
2726
"regexp"
2827
"strings"
@@ -38,6 +37,7 @@ import (
3837
"github.com/pkg/errors"
3938
"k8s.io/minikube/pkg/version"
4039

40+
"k8s.io/minikube/pkg/minikube/constants"
4141
"k8s.io/minikube/pkg/minikube/out"
4242
"k8s.io/minikube/pkg/util"
4343
)
@@ -123,14 +123,14 @@ func MakeDiskImage(d *drivers.BaseDriver, boot2dockerURL string, diskSize int) e
123123
return errors.Wrapf(err, "createRawDiskImage(%s)", diskPath)
124124
}
125125
machPath := d.ResolveStorePath(".")
126-
if err := fixPermissions(machPath); err != nil {
126+
if err := fixMachinePermissions(machPath); err != nil {
127127
return errors.Wrapf(err, "fixing permissions on %s", machPath)
128128
}
129129
}
130130
return nil
131131
}
132132

133-
func fixPermissions(path string) error {
133+
func fixMachinePermissions(path string) error {
134134
glog.Infof("Fixing permissions on %s ...", path)
135135
if err := os.Chown(path, syscall.Getuid(), syscall.Getegid()); err != nil {
136136
return errors.Wrap(err, "chown dir")
@@ -149,95 +149,128 @@ func fixPermissions(path string) error {
149149
}
150150

151151
// InstallOrUpdate downloads driver if it is not present, or updates it if there's a newer version
152-
func InstallOrUpdate(driver, destination string, v semver.Version) error {
153-
glog.Infof("InstallOrUpdate(%s): dest=%s, version=%s, PATH=%s", driver, destination, v, os.Getenv("PATH"))
152+
func InstallOrUpdate(driver string, directory string, v semver.Version, interactive bool) error {
153+
if driver != constants.DriverKvm2 && driver != constants.DriverHyperkit {
154+
return nil
155+
}
154156

155-
_, err := exec.LookPath(driver)
156-
// if file driver doesn't exist, download it
157+
executable := fmt.Sprintf("docker-machine-driver-%s", driver)
158+
path, err := validateDriver(executable, v)
157159
if err != nil {
158-
glog.Infof("LookPath %s: %v", driver, err)
159-
return download(driver, v, destination)
160+
glog.Warningf("%s: %v", executable, err)
161+
path = filepath.Join(directory, executable)
162+
derr := download(executable, path, v)
163+
if derr != nil {
164+
return derr
165+
}
166+
}
167+
return fixDriverPermissions(driver, path, interactive)
168+
}
169+
170+
// fixDriverPermissions fixes the permissions on a driver
171+
func fixDriverPermissions(driver string, path string, interactive bool) error {
172+
// This method only supports hyperkit so far (because it's complicated)
173+
if driver != constants.DriverHyperkit {
174+
return nil
160175
}
161176

162-
cmd := exec.Command(driver, "version")
163-
output, err := cmd.Output()
164-
// if driver doesnt support 'version', it is old, download it
177+
// Using the find command for hyperkit is far easier than cross-platform uid checks in Go.
178+
stdout, err := exec.Command("find", path, "-uid", "0", "-perm", "4755").Output()
179+
glog.Infof("stdout: %s", stdout)
180+
if err == nil && strings.TrimSpace(string(stdout)) == path {
181+
glog.Infof("%s looks good", path)
182+
return nil
183+
}
184+
185+
cmds := []*exec.Cmd{
186+
exec.Command("sudo", "chown", "root:wheel", path),
187+
exec.Command("sudo", "chmod", "u+s", path),
188+
}
189+
190+
var example strings.Builder
191+
for _, c := range cmds {
192+
example.WriteString(fmt.Sprintf(" $ %s \n", strings.Join(c.Args, " ")))
193+
}
194+
195+
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()})
196+
for _, c := range cmds {
197+
testArgs := append([]string{"-n"}, c.Args[1:]...)
198+
test := exec.Command("sudo", testArgs...)
199+
glog.Infof("testing: %v", test.Args)
200+
if err := test.Run(); err != nil {
201+
glog.Infof("%v may require a password: %v", c.Args, err)
202+
if !interactive {
203+
return fmt.Errorf("%v requires a password, and --interactive=false", c.Args)
204+
}
205+
}
206+
glog.Infof("running: %v", c.Args)
207+
err := c.Run()
208+
if err != nil {
209+
return errors.Wrapf(err, "%v", c.Args)
210+
}
211+
}
212+
return nil
213+
}
214+
215+
// validateDriver validates if a driver appears to be up-to-date and installed properly
216+
func validateDriver(driver string, v semver.Version) (string, error) {
217+
glog.Infof("Validating %s, PATH=%s", driver, os.Getenv("PATH"))
218+
path, err := exec.LookPath(driver)
165219
if err != nil {
166-
glog.Infof("%s version: %v", driver, err)
167-
return download(driver, v, destination)
220+
return path, err
168221
}
169222

170-
ev := ExtractVMDriverVersion(string(output))
223+
output, err := exec.Command(path, "version").Output()
224+
if err != nil {
225+
return path, err
226+
}
171227

172-
// if the driver doesn't return any version, download it
228+
ev := extractVMDriverVersion(string(output))
173229
if len(ev) == 0 {
174-
glog.Infof("%s: unable to extract version from %q", driver, output)
175-
return download(driver, v, destination)
230+
return path, fmt.Errorf("%s: unable to extract version from %q", driver, output)
176231
}
177232

178233
vmDriverVersion, err := semver.Make(ev)
179234
if err != nil {
180-
return errors.Wrap(err, "can't parse driver version")
235+
return path, errors.Wrap(err, "can't parse driver version")
181236
}
182-
183-
// if the current driver version is older, download newer
184237
if vmDriverVersion.LT(v) {
185-
glog.Infof("%s is version %s, want %s", driver, vmDriverVersion, v)
186-
return download(driver, v, destination)
238+
return path, fmt.Errorf("%s is version %s, want %s", driver, vmDriverVersion, v)
187239
}
188-
189-
return nil
240+
return path, nil
190241
}
191242

192243
func driverWithChecksumURL(driver string, v semver.Version) string {
193244
base := fmt.Sprintf("https://github.com/kubernetes/minikube/releases/download/v%s/%s", v, driver)
194245
return fmt.Sprintf("%s?checksum=file:%s.sha256", base, base)
195246
}
196247

197-
func download(driver string, v semver.Version, destination string) error {
198-
// supports kvm2 and hyperkit
199-
if driver != "docker-machine-driver-kvm2" && driver != "docker-machine-driver-hyperkit" {
200-
return nil
201-
}
202-
248+
// download an arbitrary driver
249+
func download(driver string, destination string, v semver.Version) error {
203250
out.T(out.FileDownload, "Downloading driver {{.driver}}:", out.V{"driver": driver})
204-
targetFilepath := path.Join(destination, driver)
205-
os.Remove(targetFilepath)
251+
os.Remove(destination)
206252
url := driverWithChecksumURL(driver, v)
207253
client := &getter.Client{
208254
Src: url,
209-
Dst: targetFilepath,
255+
Dst: destination,
210256
Mode: getter.ClientModeFile,
211257
Options: []getter.ClientOption{getter.WithProgress(util.DefaultProgressBar)},
212258
}
213259

214260
glog.Infof("Downloading: %+v", client)
215-
216261
if err := client.Get(); err != nil {
217262
return errors.Wrapf(err, "download failed: %s", url)
218263
}
219-
220-
err := os.Chmod(targetFilepath, 0755)
221-
if err != nil {
222-
return errors.Wrap(err, "chmod error")
223-
}
224-
225-
if driver == "docker-machine-driver-hyperkit" {
226-
err := setHyperKitPermissions(targetFilepath)
227-
if err != nil {
228-
return errors.Wrap(err, "setting hyperkit permission")
229-
}
230-
}
231-
232-
return nil
264+
// Give downloaded drivers a baseline decent file permission
265+
return os.Chmod(destination, 0755)
233266
}
234267

235-
// ExtractVMDriverVersion extracts the driver version.
268+
// extractVMDriverVersion extracts the driver version.
236269
// KVM and Hyperkit drivers support the 'version' command, that display the information as:
237270
// version: vX.X.X
238271
// commit: XXXX
239272
// This method returns the version 'vX.X.X' or empty if the version isn't found.
240-
func ExtractVMDriverVersion(s string) string {
273+
func extractVMDriverVersion(s string) string {
241274
versionRegex := regexp.MustCompile(`version:(.*)`)
242275
matches := versionRegex.FindStringSubmatch(s)
243276

@@ -248,22 +281,3 @@ func ExtractVMDriverVersion(s string) string {
248281
v := strings.TrimSpace(matches[1])
249282
return strings.TrimPrefix(v, version.VersionPrefix)
250283
}
251-
252-
func setHyperKitPermissions(driverPath string) error {
253-
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)
254-
out.T(out.Permissions, msg, out.V{})
255-
256-
cmd := exec.Command("sudo", "chown", "root:wheel", driverPath)
257-
err := cmd.Run()
258-
if err != nil {
259-
return errors.Wrap(err, "chown root:wheel")
260-
}
261-
262-
cmd = exec.Command("sudo", "chmod", "u+s", driverPath)
263-
err = cmd.Run()
264-
if err != nil {
265-
return errors.Wrap(err, "chmod u+s")
266-
}
267-
268-
return nil
269-
}

Diff for: pkg/drivers/drivers_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -50,24 +50,24 @@ func Test_createDiskImage(t *testing.T) {
5050
}
5151

5252
func TestExtractVMDriverVersion(t *testing.T) {
53-
v := ExtractVMDriverVersion("")
53+
v := extractVMDriverVersion("")
5454
if len(v) != 0 {
5555
t.Error("Expected empty string")
5656
}
5757

58-
v = ExtractVMDriverVersion("random text")
58+
v = extractVMDriverVersion("random text")
5959
if len(v) != 0 {
6060
t.Error("Expected empty string")
6161
}
6262

6363
expectedVersion := "1.2.3"
6464

65-
v = ExtractVMDriverVersion("version: v1.2.3")
65+
v = extractVMDriverVersion("version: v1.2.3")
6666
if expectedVersion != v {
6767
t.Errorf("Expected version: %s, got: %s", expectedVersion, v)
6868
}
6969

70-
v = ExtractVMDriverVersion("version: 1.2.3")
70+
v = extractVMDriverVersion("version: 1.2.3")
7171
if expectedVersion != v {
7272
t.Errorf("Expected version: %s, got: %s", expectedVersion, v)
7373
}

Diff for: pkg/minikube/out/style.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ var styles = map[StyleEnum]style{
7878
Documentation: {Prefix: "📘 "},
7979
Issues: {Prefix: "⁉️ "},
8080
Issue: {Prefix: " ▪ ", LowPrefix: lowIndent}, // Indented bullet
81-
Check: {Prefix: "✔️ "},
81+
Check: {Prefix: " "},
8282
Celebration: {Prefix: "🎉 "},
8383
Workaround: {Prefix: "👉 ", LowPrefix: lowIndent},
8484

Diff for: test/integration/driver_install_or_update_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func TestKVMDriverInstallOrUpdate(t *testing.T) {
8484
t.Fatalf("Expected new semver. test: %v, got: %v", tc.name, err)
8585
}
8686

87-
err = drivers.InstallOrUpdate("docker-machine-driver-kvm2", dir, newerVersion)
87+
err = drivers.InstallOrUpdate("kvm2", dir, newerVersion, true)
8888
if err != nil {
8989
t.Fatalf("Failed to update driver to %v. test: %s, got: %v", newerVersion, tc.name, err)
9090
}
@@ -147,7 +147,7 @@ func TestHyperKitDriverInstallOrUpdate(t *testing.T) {
147147
t.Fatalf("Expected new semver. test: %v, got: %v", tc.name, err)
148148
}
149149

150-
err = drivers.InstallOrUpdate("docker-machine-driver-hyperkit", dir, newerVersion)
150+
err = drivers.InstallOrUpdate("hyperkit", dir, newerVersion, true)
151151
if err != nil {
152152
t.Fatalf("Failed to update driver to %v. test: %s, got: %v", newerVersion, tc.name, err)
153153
}

0 commit comments

Comments
 (0)