diff --git a/hack/.linted_packages b/hack/.linted_packages index 4b32ccac3cc..6740498cb50 100644 --- a/hack/.linted_packages +++ b/hack/.linted_packages @@ -266,6 +266,7 @@ pkg/util/ratelimit pkg/util/replicaset pkg/util/restoptions pkg/util/validation/field +pkg/util/version pkg/util/workqueue pkg/version/prometheus pkg/volume diff --git a/pkg/apiserver/BUILD b/pkg/apiserver/BUILD index 946e4365ccd..133bc48f615 100644 --- a/pkg/apiserver/BUILD +++ b/pkg/apiserver/BUILD @@ -52,8 +52,8 @@ go_library( "//pkg/util/sets:go_default_library", "//pkg/util/strategicpatch:go_default_library", "//pkg/util/strings:go_default_library", + "//pkg/util/version:go_default_library", "//pkg/util/wsstream:go_default_library", - "//pkg/version:go_default_library", "//pkg/watch:go_default_library", "//pkg/watch/versioned:go_default_library", "//vendor:bitbucket.org/ww/goautoneg", diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 5e5a16a56ec..d4c91d7d377 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -43,8 +43,8 @@ import ( "k8s.io/kubernetes/pkg/util/flushwriter" utilruntime "k8s.io/kubernetes/pkg/util/runtime" "k8s.io/kubernetes/pkg/util/sets" + utilversion "k8s.io/kubernetes/pkg/util/version" "k8s.io/kubernetes/pkg/util/wsstream" - "k8s.io/kubernetes/pkg/version" "github.com/emicklei/go-restful" "github.com/golang/glog" @@ -358,11 +358,11 @@ func isOldKubectl(userAgent string) bool { if len(subs) != 2 { return false } - kubectlVersion, versionErr := version.Parse(subs[1]) + kubectlVersion, versionErr := utilversion.ParseSemantic(subs[1]) if versionErr != nil { return false } - return kubectlVersion.LT(version.MustParse("v1.5.0")) + return kubectlVersion.LessThan(utilversion.MustParseSemantic("v1.5.0")) } // TODO: Remove in 1.6. This is for backward compatibility with 1.4 kubectl. diff --git a/pkg/controller/node/BUILD b/pkg/controller/node/BUILD index 923ce9877df..a1cf79ac322 100644 --- a/pkg/controller/node/BUILD +++ b/pkg/controller/node/BUILD @@ -42,8 +42,8 @@ go_library( "//pkg/util/runtime:go_default_library", "//pkg/util/sets:go_default_library", "//pkg/util/system:go_default_library", + "//pkg/util/version:go_default_library", "//pkg/util/wait:go_default_library", - "//pkg/version:go_default_library", "//vendor:github.com/golang/glog", "//vendor:github.com/prometheus/client_golang/prometheus", ], diff --git a/pkg/controller/node/controller_utils.go b/pkg/controller/node/controller_utils.go index f69e2ddc91b..19d1a0c4f5c 100644 --- a/pkg/controller/node/controller_utils.go +++ b/pkg/controller/node/controller_utils.go @@ -33,7 +33,7 @@ import ( utilerrors "k8s.io/kubernetes/pkg/util/errors" "k8s.io/kubernetes/pkg/util/node" utilruntime "k8s.io/kubernetes/pkg/util/runtime" - "k8s.io/kubernetes/pkg/version" + utilversion "k8s.io/kubernetes/pkg/util/version" "github.com/golang/glog" ) @@ -178,13 +178,13 @@ func (nc *NodeController) maybeDeleteTerminatingPod(obj interface{}) { // guarantee backwards compatibility of master API to kubelets with // versions less than 1.1.0 node := nodeObj.(*v1.Node) - v, err := version.Parse(node.Status.NodeInfo.KubeletVersion) + v, err := utilversion.ParseSemantic(node.Status.NodeInfo.KubeletVersion) if err != nil { glog.V(0).Infof("couldn't parse verions %q of minion: %v", node.Status.NodeInfo.KubeletVersion, err) utilruntime.HandleError(nc.forcefullyDeletePod(pod)) return } - if gracefulDeletionVersion.GT(v) { + if v.LessThan(gracefulDeletionVersion) { utilruntime.HandleError(nc.forcefullyDeletePod(pod)) return } @@ -239,12 +239,12 @@ func markAllPodsNotReady(kubeClient clientset.Interface, node *v1.Node) error { // Older versions were inflexible and modifying pod.Status directly through // the apiserver would result in unexpected outcomes. func nodeRunningOutdatedKubelet(node *v1.Node) bool { - v, err := version.Parse(node.Status.NodeInfo.KubeletVersion) + v, err := utilversion.ParseSemantic(node.Status.NodeInfo.KubeletVersion) if err != nil { glog.Errorf("couldn't parse version %q of node %v", node.Status.NodeInfo.KubeletVersion, err) return true } - if podStatusReconciliationVersion.GT(v) { + if v.LessThan(podStatusReconciliationVersion) { glog.Infof("Node %v running kubelet at (%v) which is less than the minimum version that allows nodecontroller to mark pods NotReady (%v).", node.Name, v, podStatusReconciliationVersion) return true } diff --git a/pkg/controller/node/nodecontroller.go b/pkg/controller/node/nodecontroller.go index cb961b96d44..e621a30b494 100644 --- a/pkg/controller/node/nodecontroller.go +++ b/pkg/controller/node/nodecontroller.go @@ -41,8 +41,8 @@ import ( utilnode "k8s.io/kubernetes/pkg/util/node" utilruntime "k8s.io/kubernetes/pkg/util/runtime" "k8s.io/kubernetes/pkg/util/system" + utilversion "k8s.io/kubernetes/pkg/util/version" "k8s.io/kubernetes/pkg/util/wait" - "k8s.io/kubernetes/pkg/version" ) func init() { @@ -52,11 +52,11 @@ func init() { var ( ErrCloudInstance = errors.New("cloud provider doesn't support instances.") - gracefulDeletionVersion = version.MustParse("v1.1.0") + gracefulDeletionVersion = utilversion.MustParseSemantic("v1.1.0") // The minimum kubelet version for which the nodecontroller // can safely flip pod.Status to NotReady. - podStatusReconciliationVersion = version.MustParse("v1.2.0") + podStatusReconciliationVersion = utilversion.MustParseSemantic("v1.2.0") ) const ( diff --git a/pkg/kubelet/cm/BUILD b/pkg/kubelet/cm/BUILD index 4f043d246f5..6b34a22cad4 100644 --- a/pkg/kubelet/cm/BUILD +++ b/pkg/kubelet/cm/BUILD @@ -36,8 +36,8 @@ go_library( "//pkg/util/runtime:go_default_library", "//pkg/util/sets:go_default_library", "//pkg/util/sysctl:go_default_library", + "//pkg/util/version:go_default_library", "//pkg/util/wait:go_default_library", - "//vendor:github.com/blang/semver", "//vendor:github.com/golang/glog", "//vendor:github.com/opencontainers/runc/libcontainer/cgroups", "//vendor:github.com/opencontainers/runc/libcontainer/cgroups/fs", diff --git a/pkg/kubelet/cm/container_manager_linux.go b/pkg/kubelet/cm/container_manager_linux.go index b12e0e4772d..640dd244cf5 100644 --- a/pkg/kubelet/cm/container_manager_linux.go +++ b/pkg/kubelet/cm/container_manager_linux.go @@ -29,7 +29,6 @@ import ( "sync" "time" - "github.com/blang/semver" "github.com/golang/glog" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fs" @@ -47,6 +46,7 @@ import ( "k8s.io/kubernetes/pkg/util/runtime" "k8s.io/kubernetes/pkg/util/sets" utilsysctl "k8s.io/kubernetes/pkg/util/sysctl" + utilversion "k8s.io/kubernetes/pkg/util/version" "k8s.io/kubernetes/pkg/util/wait" ) @@ -66,7 +66,7 @@ const ( var ( // The docker version in which containerd was introduced. - containerdVersion = semver.MustParse("1.11.0") + containerdVersion = utilversion.MustParseSemantic("1.11.0") ) // A non-user container tracked by the Kubelet. @@ -632,10 +632,10 @@ func getPidsForProcess(name, pidFile string) ([]int, error) { // Temporarily export the function to be used by dockershim. // TODO(yujuhong): Move this function to dockershim once kubelet migrates to // dockershim as the default. -func EnsureDockerInContainer(dockerVersion semver.Version, oomScoreAdj int, manager *fs.Manager) error { +func EnsureDockerInContainer(dockerVersion *utilversion.Version, oomScoreAdj int, manager *fs.Manager) error { type process struct{ name, file string } dockerProcs := []process{{dockerProcessName, dockerPidFile}} - if dockerVersion.GTE(containerdVersion) { + if dockerVersion.AtLeast(containerdVersion) { dockerProcs = append(dockerProcs, process{containerdProcessName, containerdPidFile}) } var errs []error @@ -797,17 +797,16 @@ func isKernelPid(pid int) bool { } // Helper for getting the docker version. -func getDockerVersion(cadvisor cadvisor.Interface) semver.Version { - var fallback semver.Version // Fallback to zero-value by default. +func getDockerVersion(cadvisor cadvisor.Interface) *utilversion.Version { versions, err := cadvisor.VersionInfo() if err != nil { glog.Errorf("Error requesting cAdvisor VersionInfo: %v", err) - return fallback + return utilversion.MustParseSemantic("0.0.0") } - dockerVersion, err := semver.Parse(versions.DockerVersion) + dockerVersion, err := utilversion.ParseSemantic(versions.DockerVersion) if err != nil { glog.Errorf("Error parsing docker version %q: %v", versions.DockerVersion, err) - return fallback + return utilversion.MustParseSemantic("0.0.0") } return dockerVersion } diff --git a/pkg/kubelet/dockershim/cm/BUILD b/pkg/kubelet/dockershim/cm/BUILD index 38e2efdb2b8..35ca865359b 100644 --- a/pkg/kubelet/dockershim/cm/BUILD +++ b/pkg/kubelet/dockershim/cm/BUILD @@ -18,8 +18,8 @@ go_library( "//pkg/kubelet/cm:go_default_library", "//pkg/kubelet/dockertools:go_default_library", "//pkg/kubelet/qos:go_default_library", + "//pkg/util/version:go_default_library", "//pkg/util/wait:go_default_library", - "//vendor:github.com/blang/semver", "//vendor:github.com/golang/glog", "//vendor:github.com/opencontainers/runc/libcontainer/cgroups/fs", "//vendor:github.com/opencontainers/runc/libcontainer/configs", diff --git a/pkg/kubelet/dockershim/cm/container_manager_linux.go b/pkg/kubelet/dockershim/cm/container_manager_linux.go index a2d0f95d96e..8db88445cdf 100644 --- a/pkg/kubelet/dockershim/cm/container_manager_linux.go +++ b/pkg/kubelet/dockershim/cm/container_manager_linux.go @@ -25,13 +25,13 @@ import ( "strconv" "time" - "github.com/blang/semver" "github.com/golang/glog" "github.com/opencontainers/runc/libcontainer/cgroups/fs" "github.com/opencontainers/runc/libcontainer/configs" kubecm "k8s.io/kubernetes/pkg/kubelet/cm" "k8s.io/kubernetes/pkg/kubelet/dockertools" "k8s.io/kubernetes/pkg/kubelet/qos" + utilversion "k8s.io/kubernetes/pkg/util/version" "k8s.io/kubernetes/pkg/util/wait" ) @@ -85,7 +85,7 @@ func (m *containerManager) doWork() { glog.Errorf("Unable to get docker version: %v", err) return } - version, err := semver.Parse(v.Version) + version, err := utilversion.ParseSemantic(v.Version) if err != nil { glog.Errorf("Unable to parse docker version %q: %v", v.Version, err) return diff --git a/pkg/kubelet/dockertools/BUILD b/pkg/kubelet/dockertools/BUILD index f23aa602e03..5b7733427f7 100644 --- a/pkg/kubelet/dockertools/BUILD +++ b/pkg/kubelet/dockertools/BUILD @@ -62,7 +62,7 @@ go_library( "//pkg/util/sets:go_default_library", "//pkg/util/strings:go_default_library", "//pkg/util/term:go_default_library", - "//vendor:github.com/coreos/go-semver/semver", + "//pkg/util/version:go_default_library", "//vendor:github.com/docker/distribution/digest", "//vendor:github.com/docker/distribution/reference", "//vendor:github.com/docker/docker/pkg/jsonmessage", diff --git a/pkg/kubelet/dockertools/docker_manager.go b/pkg/kubelet/dockertools/docker_manager.go index 804f9156e4e..ff8143c5242 100644 --- a/pkg/kubelet/dockertools/docker_manager.go +++ b/pkg/kubelet/dockertools/docker_manager.go @@ -34,7 +34,6 @@ import ( "sync" "time" - "github.com/coreos/go-semver/semver" dockertypes "github.com/docker/engine-api/types" dockercontainer "github.com/docker/engine-api/types/container" dockerstrslice "github.com/docker/engine-api/types/strslice" @@ -73,6 +72,7 @@ import ( "k8s.io/kubernetes/pkg/util/sets" utilstrings "k8s.io/kubernetes/pkg/util/strings" "k8s.io/kubernetes/pkg/util/term" + utilversion "k8s.io/kubernetes/pkg/util/version" ) const ( @@ -1033,37 +1033,9 @@ func getDockerNetworkMode(container *dockertypes.ContainerJSON) string { return "" } -// dockerVersion implements kubecontainer.Version interface by implementing -// Compare() and String() (which is implemented by the underlying semver.Version) -// TODO: this code is the same as rktVersion and may make sense to be moved to -// somewhere shared. -type dockerVersion struct { - *semver.Version -} - // newDockerVersion returns a semantically versioned docker version value -func newDockerVersion(version string) (dockerVersion, error) { - sem, err := semver.NewVersion(version) - return dockerVersion{sem}, err -} - -func (r dockerVersion) String() string { - return r.Version.String() -} - -func (r dockerVersion) Compare(other string) (int, error) { - v, err := newDockerVersion(other) - if err != nil { - return -1, err - } - - if r.LessThan(*v.Version) { - return -1, nil - } - if v.Version.LessThan(*r.Version) { - return 1, nil - } - return 0, nil +func newDockerVersion(version string) (*utilversion.Version, error) { + return utilversion.ParseSemantic(version) } // apiVersion implements kubecontainer.Version interface by implementing diff --git a/pkg/kubelet/dockertools/docker_manager_test.go b/pkg/kubelet/dockertools/docker_manager_test.go index e9ce23115d4..967c48d3aab 100644 --- a/pkg/kubelet/dockertools/docker_manager_test.go +++ b/pkg/kubelet/dockertools/docker_manager_test.go @@ -2117,12 +2117,14 @@ func TestDockerVersionComparison(t *testing.T) { {version: "1.10.4-rc1", compare: -1}, {version: "1.11.1", compare: -1}, {version: "1.11.1-rc4", compare: -1}, - {version: "invalid", compare: -1, err: true}, + {version: "invalid", err: true}, } { testCase := fmt.Sprintf("test case #%d test version %q", i, test.version) res, err := v.Compare(test.version) - assert.Equal(t, test.compare, res, testCase) assert.Equal(t, test.err, err != nil, testCase) + if !test.err { + assert.Equal(t, test.compare, res, testCase) + } } } diff --git a/pkg/kubelet/kuberuntime/BUILD b/pkg/kubelet/kuberuntime/BUILD index eb92fbf766d..9369b2e852f 100644 --- a/pkg/kubelet/kuberuntime/BUILD +++ b/pkg/kubelet/kuberuntime/BUILD @@ -53,7 +53,7 @@ go_library( "//pkg/util/runtime:go_default_library", "//pkg/util/selinux:go_default_library", "//pkg/util/sets:go_default_library", - "//vendor:github.com/coreos/go-semver/semver", + "//pkg/util/version:go_default_library", "//vendor:github.com/docker/docker/pkg/jsonlog", "//vendor:github.com/fsnotify/fsnotify", "//vendor:github.com/golang/glog", diff --git a/pkg/kubelet/kuberuntime/kuberuntime_manager.go b/pkg/kubelet/kuberuntime/kuberuntime_manager.go index 74ca458848d..deead5b69ef 100644 --- a/pkg/kubelet/kuberuntime/kuberuntime_manager.go +++ b/pkg/kubelet/kuberuntime/kuberuntime_manager.go @@ -22,7 +22,6 @@ import ( "os" "time" - "github.com/coreos/go-semver/semver" "github.com/golang/glog" cadvisorapi "github.com/google/cadvisor/info/v1" @@ -43,6 +42,7 @@ import ( kubetypes "k8s.io/kubernetes/pkg/types" "k8s.io/kubernetes/pkg/util/flowcontrol" utilruntime "k8s.io/kubernetes/pkg/util/runtime" + utilversion "k8s.io/kubernetes/pkg/util/version" ) const ( @@ -202,33 +202,8 @@ func (m *kubeGenericRuntimeManager) Type() string { return m.runtimeName } -// runtimeVersion implements kubecontainer.Version interface by implementing -// Compare() and String() -type runtimeVersion struct { - *semver.Version -} - -func newRuntimeVersion(version string) (runtimeVersion, error) { - sem, err := semver.NewVersion(version) - if err != nil { - return runtimeVersion{}, err - } - return runtimeVersion{sem}, nil -} - -func (r runtimeVersion) Compare(other string) (int, error) { - v, err := semver.NewVersion(other) - if err != nil { - return -1, err - } - - if r.LessThan(*v) { - return -1, nil - } - if v.LessThan(*r.Version) { - return 1, nil - } - return 0, nil +func newRuntimeVersion(version string) (*utilversion.Version, error) { + return utilversion.ParseSemantic(version) } func (m *kubeGenericRuntimeManager) getTypedVersion() (*runtimeapi.VersionResponse, error) { diff --git a/pkg/kubelet/rkt/BUILD b/pkg/kubelet/rkt/BUILD index e104faefdeb..3dc5c9f3ad4 100644 --- a/pkg/kubelet/rkt/BUILD +++ b/pkg/kubelet/rkt/BUILD @@ -47,10 +47,10 @@ go_library( "//pkg/util/strings:go_default_library", "//pkg/util/term:go_default_library", "//pkg/util/uuid:go_default_library", + "//pkg/util/version:go_default_library", "//pkg/util/wait:go_default_library", "//vendor:github.com/appc/spec/schema", "//vendor:github.com/appc/spec/schema/types", - "//vendor:github.com/coreos/go-semver/semver", "//vendor:github.com/coreos/go-systemd/dbus", "//vendor:github.com/coreos/go-systemd/unit", "//vendor:github.com/coreos/rkt/api/v1alpha", diff --git a/pkg/kubelet/rkt/version.go b/pkg/kubelet/rkt/version.go index 37468572732..3609bf97b17 100644 --- a/pkg/kubelet/rkt/version.go +++ b/pkg/kubelet/rkt/version.go @@ -20,45 +20,21 @@ import ( "fmt" "sync" - "github.com/coreos/go-semver/semver" rktapi "github.com/coreos/rkt/api/v1alpha" "golang.org/x/net/context" + + utilversion "k8s.io/kubernetes/pkg/util/version" ) type versions struct { sync.RWMutex - binVersion rktVersion - apiVersion rktVersion + binVersion *utilversion.Version + apiVersion *utilversion.Version systemdVersion systemdVersion } -// rktVersion implementes kubecontainer.Version interface by implementing -// Compare() and String() (which is implemented by the underlying semver.Version) -type rktVersion struct { - *semver.Version -} - -func newRktVersion(version string) (rktVersion, error) { - sem, err := semver.NewVersion(version) - if err != nil { - return rktVersion{}, err - } - return rktVersion{sem}, nil -} - -func (r rktVersion) Compare(other string) (int, error) { - v, err := semver.NewVersion(other) - if err != nil { - return -1, err - } - - if r.LessThan(*v) { - return -1, nil - } - if v.LessThan(*r.Version) { - return 1, nil - } - return 0, nil +func newRktVersion(version string) (*utilversion.Version, error) { + return utilversion.ParseSemantic(version) } func (r *Runtime) getVersions() error { diff --git a/pkg/proxy/iptables/BUILD b/pkg/proxy/iptables/BUILD index 0f5df8428ed..b93ca5fc113 100644 --- a/pkg/proxy/iptables/BUILD +++ b/pkg/proxy/iptables/BUILD @@ -25,7 +25,7 @@ go_library( "//pkg/util/sets:go_default_library", "//pkg/util/slice:go_default_library", "//pkg/util/sysctl:go_default_library", - "//vendor:github.com/coreos/go-semver/semver", + "//pkg/util/version:go_default_library", "//vendor:github.com/davecgh/go-spew/spew", "//vendor:github.com/golang/glog", ], diff --git a/pkg/proxy/iptables/proxier.go b/pkg/proxy/iptables/proxier.go index cbb9b8f014d..9bc18bc8a41 100644 --- a/pkg/proxy/iptables/proxier.go +++ b/pkg/proxy/iptables/proxier.go @@ -32,7 +32,6 @@ import ( "sync" "time" - "github.com/coreos/go-semver/semver" "github.com/davecgh/go-spew/spew" "github.com/golang/glog" "k8s.io/kubernetes/pkg/api" @@ -47,6 +46,7 @@ import ( "k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/slice" utilsysctl "k8s.io/kubernetes/pkg/util/sysctl" + utilversion "k8s.io/kubernetes/pkg/util/version" ) const ( @@ -93,20 +93,19 @@ type KernelCompatTester interface { // an error if it fails to get the iptables version without error, in which // case it will also return false. func CanUseIPTablesProxier(iptver IPTablesVersioner, kcompat KernelCompatTester) (bool, error) { - minVersion, err := semver.NewVersion(iptablesMinVersion) + minVersion, err := utilversion.ParseGeneric(iptablesMinVersion) if err != nil { return false, err } - // returns "X.Y.Z" versionString, err := iptver.GetVersion() if err != nil { return false, err } - version, err := semver.NewVersion(versionString) + version, err := utilversion.ParseGeneric(versionString) if err != nil { return false, err } - if version.LessThan(*minVersion) { + if version.LessThan(minVersion) { return false, nil } diff --git a/pkg/registry/generic/registry/BUILD b/pkg/registry/generic/registry/BUILD index bb99ba11556..ff1eee6104d 100644 --- a/pkg/registry/generic/registry/BUILD +++ b/pkg/registry/generic/registry/BUILD @@ -37,7 +37,7 @@ go_library( "//pkg/storage/storagebackend/factory:go_default_library", "//pkg/util/runtime:go_default_library", "//pkg/util/validation/field:go_default_library", - "//pkg/version:go_default_library", + "//pkg/util/version:go_default_library", "//pkg/watch:go_default_library", "//vendor:github.com/golang/glog", "//vendor:golang.org/x/net/context", diff --git a/pkg/registry/generic/registry/store.go b/pkg/registry/generic/registry/store.go index 89758e08252..4659fce7144 100644 --- a/pkg/registry/generic/registry/store.go +++ b/pkg/registry/generic/registry/store.go @@ -39,7 +39,7 @@ import ( "k8s.io/kubernetes/pkg/storage" utilruntime "k8s.io/kubernetes/pkg/util/runtime" "k8s.io/kubernetes/pkg/util/validation/field" - "k8s.io/kubernetes/pkg/version" + utilversion "k8s.io/kubernetes/pkg/util/version" "k8s.io/kubernetes/pkg/watch" "github.com/golang/glog" @@ -235,11 +235,11 @@ func isOldKubectl(userAgent string) bool { if len(subs) != 2 { return false } - kubectlVersion, versionErr := version.Parse(subs[1]) + kubectlVersion, versionErr := utilversion.ParseSemantic(subs[1]) if versionErr != nil { return false } - return kubectlVersion.LT(version.MustParse("v1.4.0")) + return kubectlVersion.LessThan(utilversion.MustParseSemantic("v1.4.0")) } // Create inserts a new item according to the unique key from the object. diff --git a/pkg/util/iptables/BUILD b/pkg/util/iptables/BUILD index 00963243883..be572204ec2 100644 --- a/pkg/util/iptables/BUILD +++ b/pkg/util/iptables/BUILD @@ -20,7 +20,7 @@ go_library( "//pkg/util/dbus:go_default_library", "//pkg/util/exec:go_default_library", "//pkg/util/sets:go_default_library", - "//vendor:github.com/coreos/go-semver/semver", + "//pkg/util/version:go_default_library", "//vendor:github.com/godbus/dbus", "//vendor:github.com/golang/glog", ], diff --git a/pkg/util/iptables/iptables.go b/pkg/util/iptables/iptables.go index b5840a28878..d9917fff19e 100644 --- a/pkg/util/iptables/iptables.go +++ b/pkg/util/iptables/iptables.go @@ -23,12 +23,12 @@ import ( "strings" "sync" - "github.com/coreos/go-semver/semver" godbus "github.com/godbus/dbus" "github.com/golang/glog" utildbus "k8s.io/kubernetes/pkg/util/dbus" utilexec "k8s.io/kubernetes/pkg/util/exec" "k8s.io/kubernetes/pkg/util/sets" + utilversion "k8s.io/kubernetes/pkg/util/version" ) type RulePosition string @@ -40,7 +40,7 @@ const ( // An injectable interface for running iptables commands. Implementations must be goroutine-safe. type Interface interface { - // GetVersion returns the "X.Y.Z" semver string for iptables. + // GetVersion returns the "X.Y.Z" version string for iptables. GetVersion() (string, error) // EnsureChain checks if the specified chain exists and, if not, creates it. If the chain existed, return true. EnsureChain(table Table, chain Chain) (bool, error) @@ -462,45 +462,42 @@ func makeFullArgs(table Table, chain Chain, args ...string) []string { // Checks if iptables has the "-C" flag func getIPTablesHasCheckCommand(vstring string) bool { - minVersion, err := semver.NewVersion(MinCheckVersion) + minVersion, err := utilversion.ParseGeneric(MinCheckVersion) if err != nil { glog.Errorf("MinCheckVersion (%s) is not a valid version string: %v", MinCheckVersion, err) return true } - version, err := semver.NewVersion(vstring) + version, err := utilversion.ParseGeneric(vstring) if err != nil { glog.Errorf("vstring (%s) is not a valid version string: %v", vstring, err) return true } - if version.LessThan(*minVersion) { - return false - } - return true + return version.AtLeast(minVersion) } // Checks if iptables version has a "wait" flag func getIPTablesWaitFlag(vstring string) []string { - version, err := semver.NewVersion(vstring) + version, err := utilversion.ParseGeneric(vstring) if err != nil { glog.Errorf("vstring (%s) is not a valid version string: %v", vstring, err) return nil } - minVersion, err := semver.NewVersion(MinWaitVersion) + minVersion, err := utilversion.ParseGeneric(MinWaitVersion) if err != nil { glog.Errorf("MinWaitVersion (%s) is not a valid version string: %v", MinWaitVersion, err) return nil } - if version.LessThan(*minVersion) { + if version.LessThan(minVersion) { return nil } - minVersion, err = semver.NewVersion(MinWait2Version) + minVersion, err = utilversion.ParseGeneric(MinWait2Version) if err != nil { glog.Errorf("MinWait2Version (%s) is not a valid version string: %v", MinWait2Version, err) return nil } - if version.LessThan(*minVersion) { + if version.LessThan(minVersion) { return []string{"-w"} } else { return []string{"-w2"} @@ -515,7 +512,7 @@ func getIPTablesVersionString(exec utilexec.Interface) (string, error) { if err != nil { return "", err } - versionMatcher := regexp.MustCompile("v([0-9]+\\.[0-9]+\\.[0-9]+)") + versionMatcher := regexp.MustCompile("v([0-9]+(\\.[0-9]+)+)") match := versionMatcher.FindStringSubmatch(string(bytes)) if match == nil { return "", fmt.Errorf("no iptables version found in string: %s", bytes) diff --git a/pkg/util/version/BUILD b/pkg/util/version/BUILD new file mode 100644 index 00000000000..5fadf6dd75a --- /dev/null +++ b/pkg/util/version/BUILD @@ -0,0 +1,26 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", + "go_test", +) + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "version.go", + ], + tags = ["automanaged"], +) + +go_test( + name = "go_default_test", + srcs = ["version_test.go"], + library = "go_default_library", + tags = ["automanaged"], + deps = [], +) diff --git a/pkg/util/version/doc.go b/pkg/util/version/doc.go new file mode 100644 index 00000000000..ebe43152e8e --- /dev/null +++ b/pkg/util/version/doc.go @@ -0,0 +1,18 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package version provides utilities for version number comparisons +package version // import "k8s.io/kubernetes/pkg/util/version" diff --git a/pkg/util/version/version.go b/pkg/util/version/version.go new file mode 100644 index 00000000000..327f2e67f40 --- /dev/null +++ b/pkg/util/version/version.go @@ -0,0 +1,236 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package version + +import ( + "bytes" + "fmt" + "regexp" + "strconv" + "strings" +) + +// Version is an opqaue representation of a version number +type Version struct { + components []uint + semver bool + preRelease string + buildMetadata string +} + +var ( + // versionMatchRE splits a version string into numeric and "extra" parts + versionMatchRE = regexp.MustCompile(`^\s*v?([0-9]+(?:\.[0-9]+)*)(.*)*$`) + // extraMatchRE splits the "extra" part of versionMatchRE into semver pre-release and build metadata; it does not validate the "no leading zeroes" constraint for pre-release + extraMatchRE = regexp.MustCompile(`^(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?\s*$`) +) + +func parse(str string, semver bool) (*Version, error) { + parts := versionMatchRE.FindStringSubmatch(str) + if parts == nil { + return nil, fmt.Errorf("could not parse %q as version", str) + } + numbers, extra := parts[1], parts[2] + + components := strings.Split(numbers, ".") + if (semver && len(components) != 3) || (!semver && len(components) < 2) { + return nil, fmt.Errorf("illegal version string %q", str) + } + + v := &Version{ + components: make([]uint, len(components)), + semver: semver, + } + for i, comp := range components { + if (i == 0 || semver) && strings.HasPrefix(comp, "0") && comp != "0" { + return nil, fmt.Errorf("illegal zero-prefixed version component %q in %q", comp, str) + } + num, err := strconv.ParseUint(comp, 10, 0) + if err != nil { + return nil, fmt.Errorf("illegal non-numeric version component %q in %q: %v", comp, str, err) + } + v.components[i] = uint(num) + } + + if semver && extra != "" { + extraParts := extraMatchRE.FindStringSubmatch(extra) + if extraParts == nil { + return nil, fmt.Errorf("could not parse pre-release/metadata (%s) in version %q", extra, str) + } + v.preRelease, v.buildMetadata = extraParts[1], extraParts[2] + + for _, comp := range strings.Split(v.preRelease, ".") { + if _, err := strconv.ParseUint(comp, 10, 0); err == nil { + if strings.HasPrefix(comp, "0") && comp != "0" { + return nil, fmt.Errorf("illegal zero-prefixed version component %q in %q", comp, str) + } + } + } + } + + return v, nil +} + +// ParseGeneric parses a "generic" version string. The version string must consist of two +// or more dot-separated numeric fields (the first of which can't have leading zeroes), +// followed by arbitrary uninterpreted data (which need not be separated from the final +// numeric field by punctuation). For convenience, leading and trailing whitespace is +// ignored, and the version can be preceded by the letter "v". See also ParseSemantic. +func ParseGeneric(str string) (*Version, error) { + return parse(str, false) +} + +// MustParseGeneric is like ParseGeneric except that it panics on error +func MustParseGeneric(str string) *Version { + v, err := ParseGeneric(str) + if err != nil { + panic(err) + } + return v +} + +// ParseSemantic parses a version string that exactly obeys the syntax and semantics of +// the "Semantic Versioning" specification (http://semver.org/) (although it ignores +// leading and trailing whitespace, and allows the version to be preceded by "v"). For +// version strings that are not guaranteed to obey the Semantic Versioning syntax, use +// ParseGeneric. +func ParseSemantic(str string) (*Version, error) { + return parse(str, true) +} + +// MustParseSemantic is like ParseSemantic except that it panics on error +func MustParseSemantic(str string) *Version { + v, err := ParseSemantic(str) + if err != nil { + panic(err) + } + return v +} + +// BuildMetadata returns the build metadata, if v is a Semantic Version, or "" +func (v *Version) BuildMetadata() string { + return v.buildMetadata +} + +// String converts a Version back to a string; note that for versions parsed with +// ParseGeneric, this will not include the trailing uninterpreted portion of the version +// number. +func (v *Version) String() string { + var buffer bytes.Buffer + + for i, comp := range v.components { + if i > 0 { + buffer.WriteString(".") + } + buffer.WriteString(fmt.Sprintf("%d", comp)) + } + if v.preRelease != "" { + buffer.WriteString("-") + buffer.WriteString(v.preRelease) + } + if v.buildMetadata != "" { + buffer.WriteString("+") + buffer.WriteString(v.buildMetadata) + } + + return buffer.String() +} + +// compareInternal returns -1 if v is less than other, 1 if it is greater than other, or 0 +// if they are equal +func (v *Version) compareInternal(other *Version) int { + for i := range v.components { + switch { + case i >= len(other.components): + if v.components[i] != 0 { + return 1 + } + case other.components[i] < v.components[i]: + return 1 + case other.components[i] > v.components[i]: + return -1 + } + } + + if !v.semver || !other.semver { + return 0 + } + + switch { + case v.preRelease == "" && other.preRelease != "": + return 1 + case v.preRelease != "" && other.preRelease == "": + return -1 + case v.preRelease == other.preRelease: // includes case where both are "" + return 0 + } + + vPR := strings.Split(v.preRelease, ".") + oPR := strings.Split(other.preRelease, ".") + for i := range vPR { + if i >= len(oPR) { + return 1 + } + vNum, err := strconv.ParseUint(vPR[i], 10, 0) + if err == nil { + oNum, err := strconv.ParseUint(oPR[i], 10, 0) + if err == nil { + switch { + case oNum < vNum: + return 1 + case oNum > vNum: + return -1 + default: + continue + } + } + } + if oPR[i] < vPR[i] { + return 1 + } else if oPR[i] > vPR[i] { + return -1 + } + } + + return 0 +} + +// AtLeast tests if a version is at least equal to a given minimum version. If both +// Versions are Semantic Versions, this will use the Semantic Version comparison +// algorithm. Otherwise, it will compare only the numeric components, with non-present +// components being considered "0" (ie, "1.4" is equal to "1.4.0"). +func (v *Version) AtLeast(min *Version) bool { + return v.compareInternal(min) != -1 +} + +// LessThan tests if a version is less than a given version. (It is exactly the opposite +// of AtLeast, for situations where asking "is v too old?" makes more sense than asking +// "is v new enough?".) +func (v *Version) LessThan(other *Version) bool { + return v.compareInternal(other) == -1 +} + +// Compare compares v against a version string (which will be parsed as either Semantic +// or non-Semantic depending on v). On success it returns -1 if v is less than other, 1 if +// it is greater than other, or 0 if they are equal. +func (v *Version) Compare(other string) (int, error) { + ov, err := parse(other, v.semver) + if err != nil { + return 0, err + } + return v.compareInternal(ov), nil +} diff --git a/pkg/util/version/version_test.go b/pkg/util/version/version_test.go new file mode 100644 index 00000000000..555c59b4b75 --- /dev/null +++ b/pkg/util/version/version_test.go @@ -0,0 +1,259 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package version + +import ( + "fmt" + "testing" +) + +type testItem struct { + version string + unparsed string + equalsPrev bool +} + +func testOne(v *Version, item, prev testItem) error { + str := v.String() + if item.unparsed == "" { + if str != item.version { + return fmt.Errorf("bad round-trip: %q -> %q", item.version, str) + } + } else { + if str != item.unparsed { + return fmt.Errorf("bad unparse: %q -> %q, expected %q", item.version, str, item.unparsed) + } + } + + if prev.version != "" { + cmp, err := v.Compare(prev.version) + if err != nil { + return fmt.Errorf("unexpected parse error: %v", err) + } + switch { + case cmp == -1: + return fmt.Errorf("unexpected ordering %q < %q", item.version, prev.version) + case cmp == 0 && !item.equalsPrev: + return fmt.Errorf("unexpected comparison %q == %q", item.version, item.version) + case cmp == 1 && item.equalsPrev: + return fmt.Errorf("unexpected comparison %q != %q", item.version, item.version) + } + } + + return nil +} + +func TestSemanticVersions(t *testing.T) { + tests := []testItem{ + // This is every version string that appears in the 2.0 semver spec, + // sorted in strictly increasing order except as noted. + {version: "0.1.0"}, + {version: "1.0.0-0.3.7"}, + {version: "1.0.0-alpha"}, + {version: "1.0.0-alpha+001", equalsPrev: true}, + {version: "1.0.0-alpha.1"}, + {version: "1.0.0-alpha.beta"}, + {version: "1.0.0-beta"}, + {version: "1.0.0-beta+exp.sha.5114f85", equalsPrev: true}, + {version: "1.0.0-beta.2"}, + {version: "1.0.0-beta.11"}, + {version: "1.0.0-rc.1"}, + {version: "1.0.0-x.7.z.92"}, + {version: "1.0.0"}, + {version: "1.0.0+20130313144700", equalsPrev: true}, + {version: "1.9.0"}, + {version: "1.10.0"}, + {version: "1.11.0"}, + {version: "2.0.0"}, + {version: "2.1.0"}, + {version: "2.1.1"}, + {version: "42.0.0"}, + + // We also allow whitespace and "v" prefix + {version: " 42.0.0", unparsed: "42.0.0", equalsPrev: true}, + {version: "\t42.0.0 ", unparsed: "42.0.0", equalsPrev: true}, + {version: "43.0.0-1", unparsed: "43.0.0-1"}, + {version: "43.0.0-1 ", unparsed: "43.0.0-1", equalsPrev: true}, + {version: "v43.0.0-1", unparsed: "43.0.0-1", equalsPrev: true}, + {version: " v43.0.0", unparsed: "43.0.0"}, + {version: " 43.0.0 ", unparsed: "43.0.0", equalsPrev: true}, + } + + var prev testItem + for _, item := range tests { + v, err := ParseSemantic(item.version) + if err != nil { + t.Errorf("unexpected parse error: %v", err) + continue + } + err = testOne(v, item, prev) + if err != nil { + t.Errorf("%v", err) + } + prev = item + } +} + +func TestBadSemanticVersions(t *testing.T) { + tests := []string{ + // "MUST take the form X.Y.Z" + "1", + "1.2", + "1.2.3.4", + ".2.3", + "1..3", + "1.2.", + "", + "..", + // "where X, Y, and Z are non-negative integers" + "-1.2.3", + "1.-2.3", + "1.2.-3", + "1a.2.3", + "1.2a.3", + "1.2.3a", + "a1.2.3", + "a.b.c", + "1 .2.3", + "1. 2.3", + // "and MUST NOT contain leading zeroes." + "01.2.3", + "1.02.3", + "1.2.03", + // "[pre-release] identifiers MUST comprise only ASCII alphanumerics and hyphen" + "1.2.3-/", + // "[pre-release] identifiers MUST NOT be empty" + "1.2.3-", + "1.2.3-.", + "1.2.3-foo.", + "1.2.3-.foo", + // "Numeric [pre-release] identifiers MUST NOT include leading zeroes" + "1.2.3-01", + // "[build metadata] identifiers MUST comprise only ASCII alphanumerics and hyphen" + "1.2.3+/", + // "[build metadata] identifiers MUST NOT be empty" + "1.2.3+", + "1.2.3+.", + "1.2.3+foo.", + "1.2.3+.foo", + + // whitespace/"v"-prefix checks + "v 1.2.3", + "vv1.2.3", + } + + for i := range tests { + _, err := ParseSemantic(tests[i]) + if err == nil { + t.Errorf("unexpected success parsing invalid semver %q", tests[i]) + } + } +} + +func TestGenericVersions(t *testing.T) { + tests := []testItem{ + // This is all of the strings from TestSemanticVersions, plus some strings + // from TestBadSemanticVersions that should parse as generic versions, + // plus some additional strings. + {version: "0.1.0", unparsed: "0.1.0"}, + {version: "1.0.0-0.3.7", unparsed: "1.0.0"}, + {version: "1.0.0-alpha", unparsed: "1.0.0", equalsPrev: true}, + {version: "1.0.0-alpha+001", unparsed: "1.0.0", equalsPrev: true}, + {version: "1.0.0-alpha.1", unparsed: "1.0.0", equalsPrev: true}, + {version: "1.0.0-alpha.beta", unparsed: "1.0.0", equalsPrev: true}, + {version: "1.0.0.beta", unparsed: "1.0.0", equalsPrev: true}, + {version: "1.0.0-beta+exp.sha.5114f85", unparsed: "1.0.0", equalsPrev: true}, + {version: "1.0.0.beta.2", unparsed: "1.0.0", equalsPrev: true}, + {version: "1.0.0.beta.11", unparsed: "1.0.0", equalsPrev: true}, + {version: "1.0.0.rc.1", unparsed: "1.0.0", equalsPrev: true}, + {version: "1.0.0-x.7.z.92", unparsed: "1.0.0", equalsPrev: true}, + {version: "1.0.0", unparsed: "1.0.0", equalsPrev: true}, + {version: "1.0.0+20130313144700", unparsed: "1.0.0", equalsPrev: true}, + {version: "1.2", unparsed: "1.2"}, + {version: "1.2a.3", unparsed: "1.2", equalsPrev: true}, + {version: "1.2.3", unparsed: "1.2.3"}, + {version: "1.2.3a", unparsed: "1.2.3", equalsPrev: true}, + {version: "1.2.3-foo.", unparsed: "1.2.3", equalsPrev: true}, + {version: "1.2.3-.foo", unparsed: "1.2.3", equalsPrev: true}, + {version: "1.2.3-01", unparsed: "1.2.3", equalsPrev: true}, + {version: "1.2.3+", unparsed: "1.2.3", equalsPrev: true}, + {version: "1.2.3+foo.", unparsed: "1.2.3", equalsPrev: true}, + {version: "1.2.3+.foo", unparsed: "1.2.3", equalsPrev: true}, + {version: "1.02.3", unparsed: "1.2.3", equalsPrev: true}, + {version: "1.2.03", unparsed: "1.2.3", equalsPrev: true}, + {version: "1.2.003", unparsed: "1.2.3", equalsPrev: true}, + {version: "1.2.3.4", unparsed: "1.2.3.4"}, + {version: "1.2.3.4b3", unparsed: "1.2.3.4", equalsPrev: true}, + {version: "1.2.3.4.5", unparsed: "1.2.3.4.5"}, + {version: "1.9.0", unparsed: "1.9.0"}, + {version: "1.10.0", unparsed: "1.10.0"}, + {version: "1.11.0", unparsed: "1.11.0"}, + {version: "2.0.0", unparsed: "2.0.0"}, + {version: "2.1.0", unparsed: "2.1.0"}, + {version: "2.1.1", unparsed: "2.1.1"}, + {version: "42.0.0", unparsed: "42.0.0"}, + {version: " 42.0.0", unparsed: "42.0.0", equalsPrev: true}, + {version: "\t42.0.0 ", unparsed: "42.0.0", equalsPrev: true}, + {version: "42.0.0-1", unparsed: "42.0.0", equalsPrev: true}, + {version: "42.0.0-1 ", unparsed: "42.0.0", equalsPrev: true}, + {version: "v42.0.0-1", unparsed: "42.0.0", equalsPrev: true}, + {version: " v43.0.0", unparsed: "43.0.0"}, + {version: " 43.0.0 ", unparsed: "43.0.0", equalsPrev: true}, + } + + var prev testItem + for _, item := range tests { + v, err := ParseGeneric(item.version) + if err != nil { + t.Errorf("unexpected parse error: %v", err) + continue + } + err = testOne(v, item, prev) + if err != nil { + t.Errorf("%v", err) + } + prev = item + } +} + +func TestBadGenericVersions(t *testing.T) { + tests := []string{ + "1", + "01.2.3", + "-1.2.3", + "1.-2.3", + ".2.3", + "1..3", + "1a.2.3", + "a1.2.3", + "1 .2.3", + "1. 2.3", + "1.bob", + "bob", + "v 1.2.3", + "vv1.2.3", + "", + ".", + } + + for i := range tests { + _, err := ParseGeneric(tests[i]) + if err == nil { + t.Errorf("unexpected success parsing invalid version %q", tests[i]) + } + } +} diff --git a/pkg/version/BUILD b/pkg/version/BUILD index e8620a9bc40..00751c2bff3 100644 --- a/pkg/version/BUILD +++ b/pkg/version/BUILD @@ -5,7 +5,6 @@ licenses(["notice"]) load( "@io_bazel_rules_go//go:def.bzl", "go_library", - "go_test", ) go_library( @@ -13,20 +12,7 @@ go_library( srcs = [ "base.go", "doc.go", - "semver.go", "version.go", ], tags = ["automanaged"], - deps = [ - "//vendor:github.com/blang/semver", - "//vendor:github.com/golang/glog", - ], -) - -go_test( - name = "go_default_test", - srcs = ["semver_test.go"], - library = "go_default_library", - tags = ["automanaged"], - deps = [], ) diff --git a/pkg/version/semver.go b/pkg/version/semver.go deleted file mode 100644 index 1f4067e217b..00000000000 --- a/pkg/version/semver.go +++ /dev/null @@ -1,50 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package version - -import ( - "strings" - "unicode" - - "github.com/blang/semver" - "github.com/golang/glog" -) - -func Parse(gitversion string) (semver.Version, error) { - // optionally trim leading spaces then one v - var seen bool - gitversion = strings.TrimLeftFunc(gitversion, func(ch rune) bool { - if seen { - return false - } - if ch == 'v' { - seen = true - return true - } - return unicode.IsSpace(ch) - }) - - return semver.Make(gitversion) -} - -func MustParse(gitversion string) semver.Version { - v, err := Parse(gitversion) - if err != nil { - glog.Fatalf("failed to parse semver from gitversion %q: %v", gitversion, err) - } - return v -} diff --git a/pkg/version/semver_test.go b/pkg/version/semver_test.go deleted file mode 100644 index 1b17e1758b3..00000000000 --- a/pkg/version/semver_test.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package version - -import "testing" - -func TestParseVersion(t *testing.T) { - cases := []struct { - version string - expectErr bool - }{ - {version: "v1.0.1-alpha"}, - {version: "v0.19.3"}, - {version: "0.19.3"}, - {version: "v1.2.0-alpha.3.1264+0655e65b435106-dirty"}, - {version: "1.2.0-alpha.3.1264+0655e65b435106-dirty"}, - {version: "1.2.0-alpha.3.1264+0655e65b435106-dirty"}, - {version: "1.0.0"}, - {version: "\t v1.0.0"}, - {version: "vv1.0.0", expectErr: true}, - {version: "blah1.0.0", expectErr: true}, - } - - for i, c := range cases { - _, err := Parse(c.version) - if err != nil && !c.expectErr { - t.Errorf("[%v]unexpected error: %v", i, err) - } - if err == nil && c.expectErr { - t.Errorf("[%v]expected error for %s", i, c.version) - } - } -} diff --git a/test/e2e/BUILD b/test/e2e/BUILD index 3c0fa552395..90dafd5616c 100644 --- a/test/e2e/BUILD +++ b/test/e2e/BUILD @@ -175,10 +175,10 @@ go_library( "//pkg/util/sets:go_default_library", "//pkg/util/system:go_default_library", "//pkg/util/uuid:go_default_library", + "//pkg/util/version:go_default_library", "//pkg/util/wait:go_default_library", "//pkg/util/workqueue:go_default_library", "//pkg/util/yaml:go_default_library", - "//pkg/version:go_default_library", "//pkg/volume/util/volumehelper:go_default_library", "//pkg/watch:go_default_library", "//plugin/pkg/admission/serviceaccount:go_default_library", diff --git a/test/e2e/framework/BUILD b/test/e2e/framework/BUILD index 03276d31132..356debc6442 100644 --- a/test/e2e/framework/BUILD +++ b/test/e2e/framework/BUILD @@ -81,14 +81,13 @@ go_library( "//pkg/util/system:go_default_library", "//pkg/util/uuid:go_default_library", "//pkg/util/validation:go_default_library", + "//pkg/util/version:go_default_library", "//pkg/util/wait:go_default_library", - "//pkg/version:go_default_library", "//pkg/watch:go_default_library", "//plugin/pkg/scheduler/algorithm/predicates:go_default_library", "//plugin/pkg/scheduler/schedulercache:go_default_library", "//test/e2e/perftype:go_default_library", "//test/utils:go_default_library", - "//vendor:github.com/blang/semver", "//vendor:github.com/golang/glog", "//vendor:github.com/google/cadvisor/info/v1", "//vendor:github.com/onsi/ginkgo", diff --git a/test/e2e/framework/util.go b/test/e2e/framework/util.go index 7540727613f..dd59c4a7031 100644 --- a/test/e2e/framework/util.go +++ b/test/e2e/framework/util.go @@ -40,7 +40,6 @@ import ( "text/tabwriter" "time" - "github.com/blang/semver" "github.com/golang/glog" "golang.org/x/crypto/ssh" "golang.org/x/net/websocket" @@ -87,8 +86,8 @@ import ( "k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/system" "k8s.io/kubernetes/pkg/util/uuid" + utilversion "k8s.io/kubernetes/pkg/util/version" "k8s.io/kubernetes/pkg/util/wait" - "k8s.io/kubernetes/pkg/version" "k8s.io/kubernetes/pkg/watch" "k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates" "k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache" @@ -234,8 +233,8 @@ func GetPauseImageNameForHostArch() string { // // TODO(ihmccreery): remove once we don't care about v1.0 anymore, (tentatively // in v1.3). -var SubResourcePodProxyVersion = version.MustParse("v1.1.0") -var subResourceServiceAndNodeProxyVersion = version.MustParse("v1.2.0") +var SubResourcePodProxyVersion = utilversion.MustParseSemantic("v1.1.0") +var subResourceServiceAndNodeProxyVersion = utilversion.MustParseSemantic("v1.2.0") func GetServicesProxyRequest(c clientset.Interface, request *restclient.Request) (*restclient.Request, error) { subResourceProxyAvailable, err := ServerVersionGTE(subResourceServiceAndNodeProxyVersion, c.Discovery()) @@ -350,7 +349,7 @@ func NodeOSDistroIs(supportedNodeOsDistros ...string) bool { return false } -func SkipUnlessServerVersionGTE(v semver.Version, c discovery.ServerVersionInterface) { +func SkipUnlessServerVersionGTE(v *utilversion.Version, c discovery.ServerVersionInterface) { gte, err := ServerVersionGTE(v, c) if err != nil { Failf("Failed to get server version: %v", err) @@ -501,7 +500,7 @@ func WaitForPodsSuccess(c clientset.Interface, ns string, successPodLabels map[s return nil } -var ReadyReplicaVersion = version.MustParse("v1.4.0") +var ReadyReplicaVersion = utilversion.MustParseSemantic("v1.4.0") // WaitForPodsRunningReady waits up to timeout to ensure that all pods in // namespace ns are either running and ready, or failed but controlled by a @@ -1624,19 +1623,19 @@ func (r podProxyResponseChecker) CheckAllResponses() (done bool, err error) { // version. // // TODO(18726): This should be incorporated into client.VersionInterface. -func ServerVersionGTE(v semver.Version, c discovery.ServerVersionInterface) (bool, error) { +func ServerVersionGTE(v *utilversion.Version, c discovery.ServerVersionInterface) (bool, error) { serverVersion, err := c.ServerVersion() if err != nil { return false, fmt.Errorf("Unable to get server version: %v", err) } - sv, err := version.Parse(serverVersion.GitVersion) + sv, err := utilversion.ParseSemantic(serverVersion.GitVersion) if err != nil { return false, fmt.Errorf("Unable to parse server version %q: %v", serverVersion.GitVersion, err) } - return sv.GTE(v), nil + return sv.AtLeast(v), nil } -func SkipUnlessKubectlVersionGTE(v semver.Version) { +func SkipUnlessKubectlVersionGTE(v *utilversion.Version) { gte, err := KubectlVersionGTE(v) if err != nil { Failf("Failed to get kubectl version: %v", err) @@ -1648,25 +1647,25 @@ func SkipUnlessKubectlVersionGTE(v semver.Version) { // KubectlVersionGTE returns true if the kubectl version is greater than or // equal to v. -func KubectlVersionGTE(v semver.Version) (bool, error) { +func KubectlVersionGTE(v *utilversion.Version) (bool, error) { kv, err := KubectlVersion() if err != nil { return false, err } - return kv.GTE(v), nil + return kv.AtLeast(v), nil } // KubectlVersion gets the version of kubectl that's currently being used (see // --kubectl-path in e2e.go to use an alternate kubectl). -func KubectlVersion() (semver.Version, error) { +func KubectlVersion() (*utilversion.Version, error) { output := RunKubectlOrDie("version", "--client") matches := gitVersionRegexp.FindStringSubmatch(output) if len(matches) != 2 { - return semver.Version{}, fmt.Errorf("Could not find kubectl version in output %v", output) + return nil, fmt.Errorf("Could not find kubectl version in output %v", output) } // Don't use the full match, as it contains "GitVersion:\"" and a // trailing "\"". Just use the submatch. - return version.Parse(matches[1]) + return utilversion.ParseSemantic(matches[1]) } func PodsResponding(c clientset.Interface, ns, name string, wantName bool, pods *v1.PodList) error { diff --git a/test/e2e/kubectl.go b/test/e2e/kubectl.go index 3a91b65ae04..f318c646c70 100644 --- a/test/e2e/kubectl.go +++ b/test/e2e/kubectl.go @@ -54,8 +54,8 @@ import ( uexec "k8s.io/kubernetes/pkg/util/exec" utilnet "k8s.io/kubernetes/pkg/util/net" "k8s.io/kubernetes/pkg/util/uuid" + utilversion "k8s.io/kubernetes/pkg/util/version" "k8s.io/kubernetes/pkg/util/wait" - "k8s.io/kubernetes/pkg/version" "k8s.io/kubernetes/test/e2e/framework" "k8s.io/kubernetes/test/e2e/generated" testutils "k8s.io/kubernetes/test/utils" @@ -101,39 +101,39 @@ var ( // that rely on extended pod logging options to work on clusters before that. // // TODO(ihmccreery): remove once we don't care about v1.0 anymore, (tentatively in v1.3). - extendedPodLogFilterVersion = version.MustParse("v1.1.0") + extendedPodLogFilterVersion = utilversion.MustParseSemantic("v1.1.0") // NodePorts were made optional in #12831 (v1.1.0) so we don't expect tests that used to // require NodePorts but no longer include them to work on clusters before that. // // TODO(ihmccreery): remove once we don't care about v1.0 anymore, (tentatively in v1.3). - nodePortsOptionalVersion = version.MustParse("v1.1.0") + nodePortsOptionalVersion = utilversion.MustParseSemantic("v1.1.0") // Jobs were introduced in v1.1, so we don't expect tests that rely on jobs to work on // clusters before that. // // TODO(ihmccreery): remove once we don't care about v1.0 anymore, (tentatively in v1.3). - jobsVersion = version.MustParse("v1.1.0") + jobsVersion = utilversion.MustParseSemantic("v1.1.0") // Deployments were introduced by default in v1.2, so we don't expect tests that rely on // deployments to work on clusters before that. // // TODO(ihmccreery): remove once we don't care about v1.1 anymore, (tentatively in v1.4). - deploymentsVersion = version.MustParse("v1.2.0-alpha.7.726") + deploymentsVersion = utilversion.MustParseSemantic("v1.2.0-alpha.7.726") // Pod probe parameters were introduced in #15967 (v1.2) so we don't expect tests that use // these probe parameters to work on clusters before that. // // TODO(ihmccreery): remove once we don't care about v1.1 anymore, (tentatively in v1.4). - podProbeParametersVersion = version.MustParse("v1.2.0-alpha.4") + podProbeParametersVersion = utilversion.MustParseSemantic("v1.2.0-alpha.4") // 'kubectl create quota' was introduced in #28351 (v1.4) so we don't expect tests that use // 'kubectl create quota' to work on kubectl clients before that. - kubectlCreateQuotaVersion = version.MustParse("v1.4.0-alpha.2") + kubectlCreateQuotaVersion = utilversion.MustParseSemantic("v1.4.0-alpha.2") // Returning container command exit codes in kubectl run/exec was introduced in #26541 (v1.4) // so we don't expect tests that verifies return code to work on kubectl clients before that. - kubectlContainerExitCodeVersion = version.MustParse("v1.4.0-alpha.3") + kubectlContainerExitCodeVersion = utilversion.MustParseSemantic("v1.4.0-alpha.3") ) // Stops everything from filePath from namespace ns and checks if everything matching selectors from the given namespace is correctly stopped. diff --git a/test/e2e/portforward.go b/test/e2e/portforward.go index abbf30627d8..f7c3e70e7f8 100644 --- a/test/e2e/portforward.go +++ b/test/e2e/portforward.go @@ -29,8 +29,8 @@ import ( "time" "k8s.io/kubernetes/pkg/api/v1" + utilversion "k8s.io/kubernetes/pkg/util/version" "k8s.io/kubernetes/pkg/util/wait" - "k8s.io/kubernetes/pkg/version" "k8s.io/kubernetes/test/e2e/framework" testutils "k8s.io/kubernetes/test/utils" @@ -44,7 +44,7 @@ const ( // TODO support other ports besides 80 var ( portForwardRegexp = regexp.MustCompile("Forwarding from 127.0.0.1:([0-9]+) -> 80") - portForwardPortToStdOutV = version.MustParse("v1.3.0-alpha.4") + portForwardPortToStdOutV = utilversion.MustParseSemantic("v1.3.0-alpha.4") ) func pfPod(expectedClientData, chunks, chunkSize, chunkIntervalMillis string) *v1.Pod { diff --git a/test/e2e/service_accounts.go b/test/e2e/service_accounts.go index 0be7cd54e8e..31a46399148 100644 --- a/test/e2e/service_accounts.go +++ b/test/e2e/service_accounts.go @@ -24,8 +24,8 @@ import ( "k8s.io/kubernetes/pkg/api/v1" metav1 "k8s.io/kubernetes/pkg/apis/meta/v1" "k8s.io/kubernetes/pkg/util/uuid" + utilversion "k8s.io/kubernetes/pkg/util/version" "k8s.io/kubernetes/pkg/util/wait" - "k8s.io/kubernetes/pkg/version" "k8s.io/kubernetes/plugin/pkg/admission/serviceaccount" "k8s.io/kubernetes/test/e2e/framework" @@ -33,7 +33,7 @@ import ( . "github.com/onsi/gomega" ) -var serviceAccountTokenNamespaceVersion = version.MustParse("v1.2.0") +var serviceAccountTokenNamespaceVersion = utilversion.MustParseSemantic("v1.2.0") var _ = framework.KubeDescribe("ServiceAccounts", func() { f := framework.NewDefaultFramework("svcaccounts") diff --git a/test/test_owners.csv b/test/test_owners.csv index d0b49f260c1..2345aa2afb4 100644 --- a/test/test_owners.csv +++ b/test/test_owners.csv @@ -872,11 +872,11 @@ k8s.io/kubernetes/pkg/util/testing,jlowdermilk,1 k8s.io/kubernetes/pkg/util/threading,roberthbailey,1 k8s.io/kubernetes/pkg/util/validation,Q-Lee,1 k8s.io/kubernetes/pkg/util/validation/field,timstclair,1 +k8s.io/kubernetes/pkg/util/version,danwinship,0 k8s.io/kubernetes/pkg/util/wait,Q-Lee,1 k8s.io/kubernetes/pkg/util/workqueue,mtaufen,1 k8s.io/kubernetes/pkg/util/wsstream,timothysc,1 k8s.io/kubernetes/pkg/util/yaml,rmmh,1 -k8s.io/kubernetes/pkg/version,spxtr,1 k8s.io/kubernetes/pkg/volume,saad-ali,0 k8s.io/kubernetes/pkg/volume/aws_ebs,caesarxuchao,1 k8s.io/kubernetes/pkg/volume/azure_dd,bgrant0607,1