Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split PROVIDER_DOCKER_ERROR into more specific reason codes #10212

Merged
merged 3 commits into from
Jan 22, 2021
Merged
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
6 changes: 5 additions & 1 deletion cmd/minikube/cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -740,7 +740,11 @@ func validateDriver(ds registry.DriverState, existing *config.ClusterConfig) {
}, `The '{{.driver}}' provider was not found: {{.error}}`, out.V{"driver": name, "error": st.Error})
}

id := fmt.Sprintf("PROVIDER_%s_ERROR", strings.ToUpper(name))
id := st.Reason
if id == "" {
id = fmt.Sprintf("PROVIDER_%s_ERROR", strings.ToUpper(name))
}

code := reason.ExProviderUnavailable

if !st.Running {
Expand Down
49 changes: 35 additions & 14 deletions pkg/minikube/registry/drvs/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,35 +95,36 @@ func status() registry.State {
cmd := exec.CommandContext(ctx, oci.Docker, "version", "--format", "{{.Server.Os}}-{{.Server.Version}}")
o, err := cmd.Output()
if err != nil {
reason := ""
if ctx.Err() == context.DeadlineExceeded {
err = errors.Wrapf(err, "deadline exceeded running %q", strings.Join(cmd.Args, " "))
reason = "PROVIDER_DOCKER_DEADLINE_EXCEEDED"
}

klog.Warningf("docker version returned error: %v", err)

if exitErr, ok := err.(*exec.ExitError); ok {
stderr := strings.TrimSpace(string(exitErr.Stderr))
newErr := fmt.Errorf(`%q %v: %s`, strings.Join(cmd.Args, " "), exitErr, stderr)

return suggestFix(stderr, newErr)
return suggestFix("version", exitErr.ExitCode(), stderr, newErr)
}

return registry.State{Error: err, Installed: true, Healthy: false, Fix: "Restart the Docker service", Doc: docURL}
return registry.State{Reason: reason, Error: err, Installed: true, Healthy: false, Fix: "Restart the Docker service", Doc: docURL}
}

klog.Infof("docker version: %s", o)
if strings.Contains(string(o), "windows-") {
return registry.State{Error: oci.ErrWindowsContainers, Installed: true, Healthy: false, Fix: "Change container type to \"linux\" in Docker Desktop settings", Doc: docURL + "#verify-docker-container-type-is-linux"}
return registry.State{Reason: "PROVIDER_DOCKER_WINDOWS_CONTAINERS", Error: oci.ErrWindowsContainers, Installed: true, Healthy: false, Fix: "Change container type to \"linux\" in Docker Desktop settings", Doc: docURL + "#verify-docker-container-type-is-linux"}
}

si, err := oci.CachedDaemonInfo("docker")
if err != nil {
// No known fix because we haven't yet seen a failure here
return registry.State{Error: errors.Wrap(err, "docker info"), Installed: true, Healthy: false, Doc: docURL}
return registry.State{Reason: "PROVIDER_DOCKER_INFO_FAILED", Error: errors.Wrap(err, "docker info"), Installed: true, Healthy: false, Doc: docURL}
}

for _, serr := range si.Errors {
return suggestFix(serr, fmt.Errorf("docker info error: %s", serr))
return suggestFix("info", -1, serr, fmt.Errorf("docker info error: %s", serr))
}

return checkNeedsImprovement()
Expand Down Expand Up @@ -157,23 +158,43 @@ func checkOverlayMod() registry.State {
}

// suggestFix matches a stderr with possible fix for the docker driver
func suggestFix(stderr string, err error) registry.State {
func suggestFix(src string, exitcode int, stderr string, err error) registry.State {
if strings.Contains(stderr, "permission denied") && runtime.GOOS == "linux" {
return registry.State{Error: err, Installed: true, Running: true, Healthy: false, Fix: "Add your user to the 'docker' group: 'sudo usermod -aG docker $USER && newgrp docker'", Doc: "https://docs.docker.com/engine/install/linux-postinstall/"}
return registry.State{Reason: "PROVIDER_DOCKER_NEWGRP", Error: err, Installed: true, Running: true, Healthy: false, Fix: "Add your user to the 'docker' group: 'sudo usermod -aG docker $USER && newgrp docker'", Doc: "https://docs.docker.com/engine/install/linux-postinstall/"}
}

if strings.Contains(stderr, "/pipe/docker_engine: The system cannot find the file specified.") && runtime.GOOS == "windows" {
return registry.State{Error: err, Installed: true, Running: false, Healthy: false, Fix: "Start the Docker service. If Docker is already running, you may need to reset Docker to factory settings with: Settings > Reset.", Doc: "https://github.com/docker/for-win/issues/1825#issuecomment-450501157"}
return registry.State{Reason: "PROVIDER_DOCKER_PIPE_NOT_FOUND", Error: err, Installed: true, Running: false, Healthy: false, Fix: "Start the Docker service. If Docker is already running, you may need to reset Docker to factory settings with: Settings > Reset.", Doc: "https://github.com/docker/for-win/issues/1825#issuecomment-450501157"}
}

if dockerNotRunning(stderr) {
return registry.State{Error: err, Installed: true, Running: false, Healthy: false, Fix: "Start the Docker service", Doc: docURL}
reason := dockerNotRunning(stderr)
if reason != "" {
return registry.State{Reason: reason, Error: err, Installed: true, Running: false, Healthy: false, Fix: "Start the Docker service", Doc: docURL}
}

// We don't have good advice, but at least we can provide a good error message
return registry.State{Error: err, Installed: true, Running: true, Healthy: false, Doc: docURL}
reason = strings.ToUpper(fmt.Sprintf("PROVIDER_DOCKER_%s_ERROR", src))
if exitcode > 0 {
reason = strings.ToUpper(fmt.Sprintf("PROVIDER_DOCKER_%s_EXIT_%d", src, exitcode))
}
return registry.State{Reason: reason, Error: err, Installed: true, Running: true, Healthy: false, Doc: docURL}
}

func dockerNotRunning(s string) bool {
return strings.Contains(s, "Cannot connect") || strings.Contains(s, "refused") || strings.Contains(s, "Is the docker daemon running") || strings.Contains(s, "docker daemon is not running")
// Return a reason code for Docker not running
func dockerNotRunning(s string) string {
// These codes are explicitly in order of the most likely to be helpful to a user

if strings.Contains(s, "Is the docker daemon running") || strings.Contains(s, "docker daemon is not running") {
return "PROVIDER_DOCKER_NOT_RUNNING"
}

if strings.Contains(s, "Cannot connect") {
return "PROVIDER_DOCKER_CANNOT_CONNECT"
}

if strings.Contains(s, "refused") {
return "PROVIDER_DOCKER_REFUSED"
}

return ""
}
6 changes: 4 additions & 2 deletions pkg/minikube/registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@ type State struct {
Running bool // it at least appears to be running
NeedsImprovement bool // healthy but could be improved
Error error
Fix string
Doc string

Reason string // A reason ID, propagated to reason.Kind.ID
Fix string
Doc string
}

// DriverDef defines how to initialize and load a machine driver
Expand Down