Skip to content
Open
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
23 changes: 23 additions & 0 deletions internal/manager/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ package manager
import (
"context"
"crypto/tls"
"fmt"
"os"
"strings"

"github.com/go-logr/logr"
networkingv1beta1 "k8s.io/api/networking/v1beta1"
Expand Down Expand Up @@ -333,6 +335,7 @@ func checkK8sVersion(mgr ctrl.Manager, logger logr.Logger) {
logger.Info("failed to parse server version", "error", err)
return
}
currentVersion = releaseVersion(currentVersion)

if !currentVersion.AtLeast(minV) {
logger.Info("WARNING: Kubernetes cluster version does not meet minimum requirement",
Expand All @@ -341,3 +344,23 @@ func checkK8sVersion(mgr ctrl.Manager, logger logr.Logger) {
)
}
}

// releaseVersion drops a distribution suffix so it does not read as a
// prerelease. Managed clusters report versions like v1.31.0-eks-a737599 or
// v1.32.1-gke.1000000, and semver sorts a prerelease below the same release,
// so an EKS cluster running exactly the minimum would otherwise be reported as
// too old. Only alpha/beta/rc are real prereleases; anything else is a vendor
// tag and does not make the cluster older than its release.
func releaseVersion(v *version.Version) *version.Version {
pre := v.PreRelease()
if pre == "" {
return v
}
for _, prefix := range []string{"alpha", "beta", "rc"} {
if strings.HasPrefix(pre, prefix) {
return v
}
}
// WithPreRelease("") is a no-op, so rebuild from the release components.
return version.MustParseSemantic(fmt.Sprintf("%d.%d.%d", v.Major(), v.Minor(), v.Patch()))
}
59 changes: 59 additions & 0 deletions internal/manager/run_version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 manager

import (
"testing"

"k8s.io/apimachinery/pkg/util/version"
)

func TestReleaseVersionAtLeast(t *testing.T) {
minV := version.MustParseSemantic("1.31.0")

for _, tc := range []struct {
gitVersion string
wantAtLeast bool
}{
// Managed distributions tag the release; that is not a prerelease.
{"v1.31.0-eks-a737599", true},
{"v1.31.0-gke.1000000", true},
{"v1.31.0+rke2r1", true},
{"v1.30.5-eks-a737599", false},

// Real prereleases of the minimum still sort below it.
{"v1.31.0-alpha.1", false},
{"v1.31.0-beta.0", false},
{"v1.31.0-rc.1", false},

{"v1.31.0", true},
{"v1.32.1", true},
{"v1.30.0", false},
} {
t.Run(tc.gitVersion, func(t *testing.T) {
parsed, err := version.ParseSemantic(tc.gitVersion)
if err != nil {
t.Fatalf("parsing %q: %v", tc.gitVersion, err)
}
if got := releaseVersion(parsed).AtLeast(minV); got != tc.wantAtLeast {
t.Errorf("releaseVersion(%q).AtLeast(%s) = %v, want %v",
tc.gitVersion, minV, got, tc.wantAtLeast)
}
})
}
}
Loading