From 5aca495d73442c72eae6fd9e721de82c9e4bf454 Mon Sep 17 00:00:00 2001 From: Clayton Coleman Date: Mon, 8 Feb 2016 12:40:19 -0500 Subject: [PATCH] Regression: Kubelet fails on older distro Dockers Changes broke compatibility with released versions of Docker on some distributions like Fedora and RHEL (value 1.8.1.fc21 is in the wild). --- pkg/kubelet/dockertools/manager.go | 20 ++++++++++++----- pkg/kubelet/dockertools/manager_test.go | 29 +++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/pkg/kubelet/dockertools/manager.go b/pkg/kubelet/dockertools/manager.go index 90abf0f8e3e..3d9e2e69447 100644 --- a/pkg/kubelet/dockertools/manager.go +++ b/pkg/kubelet/dockertools/manager.go @@ -25,6 +25,7 @@ import ( "os" "os/exec" "path" + "regexp" "strconv" "strings" "sync" @@ -780,24 +781,33 @@ type dockerVersion struct { *semver.Version } +// Older versions of Docker could return non-semantically versioned values (distros like Fedora +// included partial values such as 1.8.1.fc21 which is not semver). Force those values to be semver. +var almostSemverRegexp = regexp.MustCompile(`^(\d+\.\d+\.\d+)\.(.*)$`) + +// newDockerVersion returns a semantically versioned docker version value func newDockerVersion(version string) (dockerVersion, error) { sem, err := semver.NewVersion(version) if err != nil { - return dockerVersion{}, err + matches := almostSemverRegexp.FindStringSubmatch(version) + if matches == nil { + return dockerVersion{}, err + } + sem, err = semver.NewVersion(strings.Join(matches[1:], "-")) } - return dockerVersion{sem}, nil + return dockerVersion{sem}, err } func (r dockerVersion) Compare(other string) (int, error) { - v, err := semver.NewVersion(other) + v, err := newDockerVersion(other) if err != nil { return -1, err } - if r.LessThan(*v) { + if r.LessThan(*v.Version) { return -1, nil } - if v.LessThan(*r.Version) { + if v.Version.LessThan(*r.Version) { return 1, nil } return 0, nil diff --git a/pkg/kubelet/dockertools/manager_test.go b/pkg/kubelet/dockertools/manager_test.go index 1dce60ee792..1f06b71fb76 100644 --- a/pkg/kubelet/dockertools/manager_test.go +++ b/pkg/kubelet/dockertools/manager_test.go @@ -115,6 +115,35 @@ func matchString(t *testing.T, pattern, str string) bool { return match } +func TestNewDockerVersion(t *testing.T) { + cases := []struct { + value string + out string + err bool + }{ + {value: "1", err: true}, + {value: "1.8", err: true}, + {value: "1.8.1", out: "1.8.1"}, + {value: "1.8.1.fc21", out: "1.8.1-fc21"}, + {value: "1.8.1.fc21.other", out: "1.8.1-fc21.other"}, + {value: "1.8.1-fc21.other", out: "1.8.1-fc21.other"}, + {value: "1.8.1-beta.12", out: "1.8.1-beta.12"}, + } + for _, test := range cases { + v, err := newDockerVersion(test.value) + switch { + case err != nil && test.err: + continue + case (err != nil) != test.err: + t.Errorf("error for %q: expected %t, got %v", test.value, test.err, err) + continue + } + if v.String() != test.out { + t.Errorf("unexpected parsed version %q for %q", v, test.value) + } + } +} + func TestSetEntrypointAndCommand(t *testing.T) { cases := []struct { name string