Kubectl: check version skew (#127365)
Signed-off-by: Omer Aplatony <omerap12@gmail.com> Kubernetes-commit: 35307319740a3a52cf4632c24b7f99d675537bdf
This commit is contained in:
parent
4afda566a9
commit
5ff92a69e3
|
@ -18,10 +18,10 @@ package version
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/version"
|
||||
apimachineryversion "k8s.io/apimachinery/pkg/version"
|
||||
"math"
|
||||
)
|
||||
|
||||
// supportedMinorVersionSkew is the maximum supported difference between the client and server minor versions.
|
||||
|
@ -29,26 +29,26 @@ import (
|
|||
// and server versions 1.18, 1.19, and 1.20 would be within the supported version skew for client version 1.19.
|
||||
const supportedMinorVersionSkew = 1
|
||||
|
||||
// printVersionSkewWarning prints a warning message if the difference between the client and version is greater than
|
||||
// getVersionSkewWarning returns a warning message if the difference between the client and version is greater than
|
||||
// the supported version skew.
|
||||
func printVersionSkewWarning(w io.Writer, clientVersion, serverVersion apimachineryversion.Info) error {
|
||||
func getVersionSkewWarning(clientVersion, serverVersion apimachineryversion.Info) (string, error) {
|
||||
parsedClientVersion, err := version.ParseSemantic(clientVersion.GitVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", fmt.Errorf("client version error: %w", err)
|
||||
}
|
||||
|
||||
parsedServerVersion, err := version.ParseSemantic(serverVersion.GitVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
return "", fmt.Errorf("server version error: %w", err)
|
||||
}
|
||||
|
||||
majorVersionDifference := math.Abs(float64(parsedClientVersion.Major()) - float64(parsedServerVersion.Major()))
|
||||
minorVersionDifference := math.Abs(float64(parsedClientVersion.Minor()) - float64(parsedServerVersion.Minor()))
|
||||
|
||||
if majorVersionDifference > 0 || minorVersionDifference > supportedMinorVersionSkew {
|
||||
fmt.Fprintf(w, "WARNING: version difference between client (%d.%d) and server (%d.%d) exceeds the supported minor version skew of +/-%d\n",
|
||||
warningMessage := fmt.Sprintf("version difference between client (%d.%d) and server (%d.%d) exceeds the supported minor version skew of +/-%d",
|
||||
parsedClientVersion.Major(), parsedClientVersion.Minor(), parsedServerVersion.Major(), parsedServerVersion.Minor(), supportedMinorVersionSkew)
|
||||
return warningMessage, nil
|
||||
}
|
||||
|
||||
return nil
|
||||
return "", nil
|
||||
}
|
||||
|
|
|
@ -17,14 +17,12 @@ limitations under the License.
|
|||
package version
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
apimachineryversion "k8s.io/apimachinery/pkg/version"
|
||||
"testing"
|
||||
|
||||
apimachineryversion "k8s.io/apimachinery/pkg/version"
|
||||
)
|
||||
|
||||
func TestPrintVersionSkewWarning(t *testing.T) {
|
||||
output := &bytes.Buffer{}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
clientVersion apimachineryversion.Info
|
||||
|
@ -82,14 +80,15 @@ func TestPrintVersionSkewWarning(t *testing.T) {
|
|||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
output.Reset()
|
||||
warningMessage, err := getVersionSkewWarning(tc.clientVersion, tc.serverVersion)
|
||||
if err != nil {
|
||||
t.Errorf("error: %s", err)
|
||||
}
|
||||
|
||||
printVersionSkewWarning(output, tc.clientVersion, tc.serverVersion)
|
||||
|
||||
if tc.isWarningExpected && output.Len() == 0 {
|
||||
t.Error("warning was expected, but not written to the output")
|
||||
} else if !tc.isWarningExpected && output.Len() > 0 {
|
||||
t.Errorf("warning was not expected, but was written to the output: %s", output.String())
|
||||
if tc.isWarningExpected && warningMessage == "" {
|
||||
t.Error("warning was expected")
|
||||
} else if !tc.isWarningExpected && warningMessage != "" {
|
||||
t.Errorf("warning was not expected. but got %s", warningMessage)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -55,6 +55,7 @@ var (
|
|||
type Options struct {
|
||||
ClientOnly bool
|
||||
Output string
|
||||
WarningsAsErrors bool
|
||||
|
||||
args []string
|
||||
|
||||
|
@ -93,6 +94,9 @@ func NewCmdVersion(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cob
|
|||
// Complete completes all the required options
|
||||
func (o *Options) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
var err error
|
||||
|
||||
o.WarningsAsErrors = cmd.Flags().Lookup("warnings-as-errors").Value.String() == "true"
|
||||
|
||||
if o.ClientOnly {
|
||||
return nil
|
||||
}
|
||||
|
@ -162,11 +166,17 @@ func (o *Options) Run() error {
|
|||
}
|
||||
|
||||
if versionInfo.ServerVersion != nil {
|
||||
if err := printVersionSkewWarning(o.ErrOut, *versionInfo.ClientVersion, *versionInfo.ServerVersion); err != nil {
|
||||
warningMessage, err := getVersionSkewWarning(*versionInfo.ClientVersion, *versionInfo.ServerVersion)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if warningMessage != "" {
|
||||
if o.WarningsAsErrors {
|
||||
return errors.New(warningMessage)
|
||||
}
|
||||
fmt.Fprintf(o.ErrOut, "Warning: %s\n", warningMessage) //nolint:errcheck
|
||||
}
|
||||
}
|
||||
|
||||
return serverErr
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,6 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/cli-runtime/pkg/genericiooptions"
|
||||
|
||||
cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
|
||||
|
@ -32,13 +30,18 @@ func TestNewCmdVersionClientVersion(t *testing.T) {
|
|||
defer tf.Cleanup()
|
||||
streams, _, buf, _ := genericiooptions.NewTestIOStreams()
|
||||
o := NewOptions(streams)
|
||||
if err := o.Complete(tf, &cobra.Command{}, nil); err != nil {
|
||||
|
||||
cmd := NewCmdVersion(tf, streams)
|
||||
cmd.Flags().Bool("warnings-as-errors", false, "")
|
||||
|
||||
if err := o.Complete(tf, cmd, nil); err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
if err := o.Validate(); err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
if err := o.Complete(tf, &cobra.Command{}, []string{"extraParameter0"}); err != nil {
|
||||
|
||||
if err := o.Complete(tf, cmd, []string{"extraParameter0"}); err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
if err := o.Validate(); !strings.Contains(err.Error(), "extra arguments") {
|
||||
|
|
Loading…
Reference in New Issue