Align podman driver with docker and improve check

Make sure to use "sudo podman version" on Linux
(need user namespace support for "podman version")

And improve error output handling for podman-remote
(when the remote service is not running properly)
pull/7631/head
Anders F Björklund 2020-04-27 12:41:16 +02:00
parent 998ab840fb
commit 95c95599c2
1 changed files with 50 additions and 41 deletions

View File

@ -42,12 +42,18 @@ import (
var minReqPodmanVer = semver.Version{Major: 1, Minor: 7, Patch: 0}
func init() {
priority := registry.Experimental
// Staged rollout for default:
// - Linux
// - macOS (podman-remote)
// - Windows (podman-remote)
if err := registry.Register(registry.DriverDef{
Name: driver.Podman,
Config: configure,
Init: func() drivers.Driver { return kic.NewDriver(kic.Config{OCIPrefix: oci.Sudo, OCIBinary: oci.Podman}) },
Status: status,
Priority: registry.Experimental,
Priority: priority,
}); err != nil {
panic(fmt.Sprintf("register failed: %v", err))
}
@ -64,6 +70,8 @@ func configure(cc config.ClusterConfig, n config.Node) (interface{}, error) {
OCIPrefix: oci.Sudo,
OCIBinary: oci.Podman,
APIServerPort: cc.Nodes[0].Port,
KubernetesVersion: cc.KubernetesConfig.KubernetesVersion,
ContainerRuntime: cc.KubernetesConfig.ContainerRuntime,
}), nil
}
@ -74,58 +82,59 @@ func status() registry.State {
return registry.State{Error: err, Installed: false, Healthy: false, Fix: "Install Podman", Doc: docURL}
}
// Allow no more than 2 seconds for version command
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
ctx, cancel := context.WithTimeout(context.Background(), 6*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, oci.Podman, "version", "-f", "{{.Version}}")
o, err := cmd.CombinedOutput()
output := string(o)
if err != nil {
glog.Warningf("podman version returned %s", output)
return registry.State{Error: err, Installed: true, Healthy: false, Fix: "Cant verify mininim required version for podman . See podman website for installation guide.", Doc: "https://podman.io/getting-started/installation.html"}
// Quickly returns an error code if service is not running
cmd := exec.CommandContext(ctx, oci.Podman, "version", "--format", "{{.Server.Version}}")
// Run with sudo on linux (local), otherwise podman-remote (as podman)
if runtime.GOOS == "linux" {
cmd = exec.CommandContext(ctx, oci.Sudo, "-n", oci.Podman, "version", "--format", "{{.Version}}")
cmd.Env = append(os.Environ(), "LANG=C", "LC_ALL=C") // sudo is localized
}
o, err := cmd.Output()
output := string(o)
if err == nil {
v, err := semver.Make(output)
if err != nil {
return registry.State{Error: err, Installed: true, Healthy: false, Fix: "Cant verify mininim required version for podman . See podman website for installation guide.", Doc: "https://podman.io/getting-started/installation.html"}
return registry.State{Error: err, Installed: true, Healthy: false, Fix: "Cant verify minimum required version for podman . See podman website for installation guide.", Doc: "https://podman.io/getting-started/installation.html"}
}
if v.LT(minReqPodmanVer) {
glog.Warningf("Warning ! mininim required version for podman is %s. your version is %q. minikube might not work. use at your own risk. To install latest version please see https://podman.io/getting-started/installation.html ", minReqPodmanVer.String(), v.String())
glog.Warningf("Warning ! minimum required version for podman is %s. your version is %q. minikube might not work. use at your own risk. To install latest version please see https://podman.io/getting-started/installation.html ", minReqPodmanVer.String(), v.String())
}
// Allow no more than 3 seconds for querying state
ctx, cancel = context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
// Run with sudo on linux (local), otherwise podman-remote (as podman)
if runtime.GOOS == "linux" {
cmd = exec.CommandContext(ctx, oci.Sudo, "-n", oci.Podman, "info")
cmd.Env = append(os.Environ(), "LANG=C", "LC_ALL=C") // sudo is localized
} else {
cmd = exec.CommandContext(ctx, oci.Podman, "info")
}
_, err = cmd.Output()
if err == nil {
return registry.State{Installed: true, Healthy: true}
}
glog.Warningf("podman 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)
// Basic timeout
if ctx.Err() == context.DeadlineExceeded {
return registry.State{Error: err, Installed: true, Healthy: false, Fix: "Restart the Podman service", Doc: docURL}
}
username := "$USER"
if u, err := user.Current(); err == nil {
username = u.Username
}
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)
if strings.Contains(stderr, "a password is required") && runtime.GOOS == "linux" {
return registry.State{Error: newErr, Installed: true, Healthy: false, Fix: fmt.Sprintf("Add your user to the 'sudoers' file: '%s ALL=(ALL) NOPASSWD: %s'", username, podman), Doc: "https://podman.io"}
}
// Typical low-level errors from running podman-remote:
// - local: "dial unix /run/podman/io.podman: connect: no such file or directory"
// - remote: "unexpected EOF" (ssh varlink isn't so great at handling rejections)
if strings.Contains(stderr, "could not get runtime") || strings.Contains(stderr, "Unable to obtain server version information") {
return registry.State{Error: newErr, Installed: true, Healthy: false, Fix: "Start the Podman service", Doc: docURL}
}
// We don't have good advice, but at least we can provide a good error message
return registry.State{Error: newErr, Installed: true, Healthy: false, Doc: docURL}
}