mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 17:30:00 +00:00
move common logic of highestSupportedVersion to util package
Signed-off-by: TommyStarK <thomasmilox@gmail.com>
This commit is contained in:
parent
988094878e
commit
42356bfbb3
@ -61,47 +61,6 @@ func (h *RegistrationHandler) RegisterPlugin(pluginName string, endpoint string,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the highest supported version.
|
|
||||||
func highestSupportedVersion(versions []string) (*utilversion.Version, error) {
|
|
||||||
if len(versions) == 0 {
|
|
||||||
return nil, errors.New(log("DRA plugin reporting empty array for supported versions"))
|
|
||||||
}
|
|
||||||
|
|
||||||
var highestSupportedVersion *utilversion.Version
|
|
||||||
|
|
||||||
var theErr error
|
|
||||||
|
|
||||||
for i := len(versions) - 1; i >= 0; i-- {
|
|
||||||
currentHighestVer, err := utilversion.ParseGeneric(versions[i])
|
|
||||||
if err != nil {
|
|
||||||
theErr = err
|
|
||||||
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if currentHighestVer.Major() > 1 {
|
|
||||||
// DRA currently only has version 1.x
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if highestSupportedVersion == nil || highestSupportedVersion.LessThan(currentHighestVer) {
|
|
||||||
highestSupportedVersion = currentHighestVer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if highestSupportedVersion == nil {
|
|
||||||
return nil, fmt.Errorf(
|
|
||||||
"could not find a highest supported version from versions (%v) reported by this plugin: %+v",
|
|
||||||
versions, theErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if highestSupportedVersion.Major() != 1 {
|
|
||||||
return nil, fmt.Errorf("highest supported version reported by plugin is %v, must be v1.x", highestSupportedVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
return highestSupportedVersion, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *RegistrationHandler) validateVersions(
|
func (h *RegistrationHandler) validateVersions(
|
||||||
callerName string,
|
callerName string,
|
||||||
pluginName string,
|
pluginName string,
|
||||||
@ -118,7 +77,7 @@ func (h *RegistrationHandler) validateVersions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate version
|
// Validate version
|
||||||
newPluginHighestVersion, err := highestSupportedVersion(versions)
|
newPluginHighestVersion, err := utilversion.HighestSupportedVersion(versions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(
|
return nil, errors.New(
|
||||||
log(
|
log(
|
||||||
|
@ -157,7 +157,12 @@ func (h *RegistrationHandler) validateVersions(callerName, pluginName string, en
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Validate version
|
// Validate version
|
||||||
newDriverHighestVersion, err := highestSupportedVersion(versions)
|
// CSI currently only has version 0.x and 1.x (see https://github.com/container-storage-interface/spec/releases).
|
||||||
|
// Therefore any driver claiming version 2.x+ is ignored as an unsupported versions.
|
||||||
|
// Future 1.x versions of CSI are supposed to be backwards compatible so this version of Kubernetes will work with any 1.x driver
|
||||||
|
// (or 0.x), but it may not work with 2.x drivers (because 2.x does not have to be backwards compatible with 1.x).
|
||||||
|
// CSI v0.x is no longer supported as of Kubernetes v1.17 in accordance with deprecation policy set out in Kubernetes v1.13.
|
||||||
|
newDriverHighestVersion, err := utilversion.HighestSupportedVersion(versions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(log("%s for CSI driver %q failed. None of the versions specified %q are supported. err=%v", callerName, pluginName, versions, err))
|
return nil, errors.New(log("%s for CSI driver %q failed. None of the versions specified %q are supported. err=%v", callerName, pluginName, versions, err))
|
||||||
}
|
}
|
||||||
@ -858,44 +863,6 @@ func unregisterDriver(driverName string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the highest supported version
|
|
||||||
func highestSupportedVersion(versions []string) (*utilversion.Version, error) {
|
|
||||||
if len(versions) == 0 {
|
|
||||||
return nil, errors.New(log("CSI driver reporting empty array for supported versions"))
|
|
||||||
}
|
|
||||||
|
|
||||||
var highestSupportedVersion *utilversion.Version
|
|
||||||
var theErr error
|
|
||||||
for i := len(versions) - 1; i >= 0; i-- {
|
|
||||||
currentHighestVer, err := utilversion.ParseGeneric(versions[i])
|
|
||||||
if err != nil {
|
|
||||||
theErr = err
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if currentHighestVer.Major() > 1 {
|
|
||||||
// CSI currently only has version 0.x and 1.x (see https://github.com/container-storage-interface/spec/releases).
|
|
||||||
// Therefore any driver claiming version 2.x+ is ignored as an unsupported versions.
|
|
||||||
// Future 1.x versions of CSI are supposed to be backwards compatible so this version of Kubernetes will work with any 1.x driver
|
|
||||||
// (or 0.x), but it may not work with 2.x drivers (because 2.x does not have to be backwards compatible with 1.x).
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if highestSupportedVersion == nil || highestSupportedVersion.LessThan(currentHighestVer) {
|
|
||||||
highestSupportedVersion = currentHighestVer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if highestSupportedVersion == nil {
|
|
||||||
return nil, fmt.Errorf("could not find a highest supported version from versions (%v) reported by this driver: %v", versions, theErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if highestSupportedVersion.Major() != 1 {
|
|
||||||
// CSI v0.x is no longer supported as of Kubernetes v1.17 in
|
|
||||||
// accordance with deprecation policy set out in Kubernetes v1.13
|
|
||||||
return nil, fmt.Errorf("highest supported version reported by driver is %v, must be v1.x", highestSupportedVersion)
|
|
||||||
}
|
|
||||||
return highestSupportedVersion, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// waitForAPIServerForever waits forever to get a CSINode instance as a proxy
|
// waitForAPIServerForever waits forever to get a CSINode instance as a proxy
|
||||||
// for a healthy APIServer
|
// for a healthy APIServer
|
||||||
func waitForAPIServerForever(client clientset.Interface, nodeName types.NodeName) error {
|
func waitForAPIServerForever(client clientset.Interface, nodeName types.NodeName) error {
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
storage "k8s.io/api/storage/v1"
|
storage "k8s.io/api/storage/v1"
|
||||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
utilversion "k8s.io/apimachinery/pkg/util/version"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||||
"k8s.io/client-go/informers"
|
"k8s.io/client-go/informers"
|
||||||
@ -142,7 +143,7 @@ func newTestPluginWithVolumeHost(t *testing.T, client *fakeclient.Clientset, hos
|
|||||||
}
|
}
|
||||||
|
|
||||||
func registerFakePlugin(pluginName, endpoint string, versions []string, t *testing.T) {
|
func registerFakePlugin(pluginName, endpoint string, versions []string, t *testing.T) {
|
||||||
highestSupportedVersions, err := highestSupportedVersion(versions)
|
highestSupportedVersions, err := utilversion.HighestSupportedVersion(versions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error parsing versions (%v) for pluginName %q endpoint %q: %#v", versions, pluginName, endpoint, err)
|
t.Fatalf("unexpected error parsing versions (%v) for pluginName %q endpoint %q: %#v", versions, pluginName, endpoint, err)
|
||||||
}
|
}
|
||||||
@ -1411,7 +1412,7 @@ func TestValidatePluginExistingDriver(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
// Arrange & Act
|
// Arrange & Act
|
||||||
highestSupportedVersions1, err := highestSupportedVersion(tc.versions1)
|
highestSupportedVersions1, err := utilversion.HighestSupportedVersion(tc.versions1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error parsing version for testcase: %#v: %v", tc, err)
|
t.Fatalf("unexpected error parsing version for testcase: %#v: %v", tc, err)
|
||||||
}
|
}
|
||||||
@ -1434,109 +1435,3 @@ func TestValidatePluginExistingDriver(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHighestSupportedVersion(t *testing.T) {
|
|
||||||
testCases := []struct {
|
|
||||||
versions []string
|
|
||||||
expectedHighestSupportedVersion string
|
|
||||||
shouldFail bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
versions: []string{"v1.0.0"},
|
|
||||||
expectedHighestSupportedVersion: "1.0.0",
|
|
||||||
shouldFail: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
versions: []string{"0.3.0"},
|
|
||||||
shouldFail: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
versions: []string{"0.2.0"},
|
|
||||||
shouldFail: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
versions: []string{"1.0.0"},
|
|
||||||
expectedHighestSupportedVersion: "1.0.0",
|
|
||||||
shouldFail: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
versions: []string{"v0.3.0"},
|
|
||||||
shouldFail: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
versions: []string{"0.2.0"},
|
|
||||||
shouldFail: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
versions: []string{"0.2.0", "v0.3.0"},
|
|
||||||
shouldFail: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
versions: []string{"0.2.0", "v1.0.0"},
|
|
||||||
expectedHighestSupportedVersion: "1.0.0",
|
|
||||||
shouldFail: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
versions: []string{"0.2.0", "v1.2.3"},
|
|
||||||
expectedHighestSupportedVersion: "1.2.3",
|
|
||||||
shouldFail: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
versions: []string{"v1.2.3", "v0.3.0"},
|
|
||||||
expectedHighestSupportedVersion: "1.2.3",
|
|
||||||
shouldFail: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
versions: []string{"v1.2.3", "v0.3.0", "2.0.1"},
|
|
||||||
expectedHighestSupportedVersion: "1.2.3",
|
|
||||||
shouldFail: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
versions: []string{"v1.2.3", "4.9.12", "v0.3.0", "2.0.1"},
|
|
||||||
expectedHighestSupportedVersion: "1.2.3",
|
|
||||||
shouldFail: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
versions: []string{"4.9.12", "2.0.1"},
|
|
||||||
expectedHighestSupportedVersion: "",
|
|
||||||
shouldFail: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
versions: []string{"v1.2.3", "boo", "v0.3.0", "2.0.1"},
|
|
||||||
expectedHighestSupportedVersion: "1.2.3",
|
|
||||||
shouldFail: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
versions: []string{},
|
|
||||||
expectedHighestSupportedVersion: "",
|
|
||||||
shouldFail: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
versions: []string{"var", "boo", "foo"},
|
|
||||||
expectedHighestSupportedVersion: "",
|
|
||||||
shouldFail: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
// Arrange & Act
|
|
||||||
actual, err := highestSupportedVersion(tc.versions)
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
if tc.shouldFail && err == nil {
|
|
||||||
t.Fatalf("expecting highestSupportedVersion to fail, but got nil error for testcase: %#v", tc)
|
|
||||||
}
|
|
||||||
if !tc.shouldFail && err != nil {
|
|
||||||
t.Fatalf("unexpected error during ValidatePlugin for testcase: %#v\r\n err:%v", tc, err)
|
|
||||||
}
|
|
||||||
if tc.expectedHighestSupportedVersion != "" {
|
|
||||||
result, err := actual.Compare(tc.expectedHighestSupportedVersion)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("comparison failed with %v for testcase %#v", err, tc)
|
|
||||||
}
|
|
||||||
if result != 0 {
|
|
||||||
t.Fatalf("expectedHighestSupportedVersion %v, but got %v for tc: %#v", tc.expectedHighestSupportedVersion, actual, tc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -18,6 +18,7 @@ package version
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -85,6 +86,47 @@ func parse(str string, semver bool) (*Version, error) {
|
|||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HighestSupportedVersion returns the highest supported version
|
||||||
|
// This function assumes that the highest supported version must be v1.x.
|
||||||
|
func HighestSupportedVersion(versions []string) (*Version, error) {
|
||||||
|
if len(versions) == 0 {
|
||||||
|
return nil, errors.New("empty array for supported versions")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
highestSupportedVersion *Version
|
||||||
|
theErr error
|
||||||
|
)
|
||||||
|
|
||||||
|
for i := len(versions) - 1; i >= 0; i-- {
|
||||||
|
currentHighestVer, err := ParseGeneric(versions[i])
|
||||||
|
if err != nil {
|
||||||
|
theErr = err
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentHighestVer.Major() > 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if highestSupportedVersion == nil || highestSupportedVersion.LessThan(currentHighestVer) {
|
||||||
|
highestSupportedVersion = currentHighestVer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if highestSupportedVersion == nil {
|
||||||
|
return nil, fmt.Errorf(
|
||||||
|
"could not find a highest supported version from versions (%v) reported: %+v",
|
||||||
|
versions, theErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if highestSupportedVersion.Major() != 1 {
|
||||||
|
return nil, fmt.Errorf("highest supported version reported is %v, must be v1.x", highestSupportedVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
return highestSupportedVersion, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ParseGeneric parses a "generic" version string. The version string must consist of two
|
// 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),
|
// 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
|
// followed by arbitrary uninterpreted data (which need not be separated from the final
|
||||||
|
@ -346,3 +346,109 @@ func TestComponents(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHighestSupportedVersion(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
versions []string
|
||||||
|
expectedHighestSupportedVersion string
|
||||||
|
shouldFail bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
versions: []string{"v1.0.0"},
|
||||||
|
expectedHighestSupportedVersion: "1.0.0",
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versions: []string{"0.3.0"},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versions: []string{"0.2.0"},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versions: []string{"1.0.0"},
|
||||||
|
expectedHighestSupportedVersion: "1.0.0",
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versions: []string{"v0.3.0"},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versions: []string{"v0.2.0"},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versions: []string{"0.2.0", "v0.3.0"},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versions: []string{"0.2.0", "v1.0.0"},
|
||||||
|
expectedHighestSupportedVersion: "1.0.0",
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versions: []string{"0.2.0", "v1.2.3"},
|
||||||
|
expectedHighestSupportedVersion: "1.2.3",
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versions: []string{"v1.2.3", "v0.3.0"},
|
||||||
|
expectedHighestSupportedVersion: "1.2.3",
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versions: []string{"v1.2.3", "v0.3.0", "2.0.1"},
|
||||||
|
expectedHighestSupportedVersion: "1.2.3",
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versions: []string{"v1.2.3", "4.9.12", "v0.3.0", "2.0.1"},
|
||||||
|
expectedHighestSupportedVersion: "1.2.3",
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versions: []string{"4.9.12", "2.0.1"},
|
||||||
|
expectedHighestSupportedVersion: "",
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versions: []string{"v1.2.3", "boo", "v0.3.0", "2.0.1"},
|
||||||
|
expectedHighestSupportedVersion: "1.2.3",
|
||||||
|
shouldFail: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versions: []string{},
|
||||||
|
expectedHighestSupportedVersion: "",
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
versions: []string{"var", "boo", "foo"},
|
||||||
|
expectedHighestSupportedVersion: "",
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
// Arrange & Act
|
||||||
|
actual, err := HighestSupportedVersion(tc.versions)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
if tc.shouldFail && err == nil {
|
||||||
|
t.Fatalf("expecting highestSupportedVersion to fail, but got nil error for testcase: %#v", tc)
|
||||||
|
}
|
||||||
|
if !tc.shouldFail && err != nil {
|
||||||
|
t.Fatalf("unexpected error during ValidatePlugin for testcase: %#v\r\n err:%v", tc, err)
|
||||||
|
}
|
||||||
|
if tc.expectedHighestSupportedVersion != "" {
|
||||||
|
result, err := actual.Compare(tc.expectedHighestSupportedVersion)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("comparison failed with %v for testcase %#v", err, tc)
|
||||||
|
}
|
||||||
|
if result != 0 {
|
||||||
|
t.Fatalf("expectedHighestSupportedVersion %v, but got %v for tc: %#v", tc.expectedHighestSupportedVersion, actual, tc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user