From a3094ccbe6f9f134da29aedf4d6d87a9a97bf463 Mon Sep 17 00:00:00 2001 From: yongruilin Date: Thu, 6 Feb 2025 16:11:12 -0800 Subject: [PATCH 1/2] feat: extend version information with more detailed version fields - Add new version fields to version.Info struct: * EmulationMajor and EmulationMinor to track emulated version * MinCompatibilityMajor and MinCompatibilityMinor for compatibility tracking - Update related code to populate and use these new fields - Improve version information documentation and OpenAPI generation - Modify version routes and documentation to reflect new version information structure --- api/openapi-spec/swagger.json | 22 +++- api/openapi-spec/v3/version_openapi.json | 22 +++- pkg/controlplane/instance_test.go | 6 + pkg/generated/openapi/zz_generated.openapi.go | 42 ++++++- .../generated/openapi/zz_generated.openapi.go | 42 ++++++- .../apimachinery/pkg/util/version/version.go | 6 +- .../k8s.io/apimachinery/pkg/version/doc.go | 2 +- .../k8s.io/apimachinery/pkg/version/types.go | 28 +++-- .../src/k8s.io/apiserver/pkg/server/config.go | 2 +- .../pkg/server/options/serving_test.go | 12 +- .../apiserver/pkg/server/routes/version.go | 6 +- .../apiserver/openapi/zz_generated.openapi.go | 42 ++++++- .../component-base/compatibility/version.go | 27 +++++ .../compatibility/version_test.go | 114 ++++++++++++++++++ .../k8s.io/component-base/version/version.go | 2 + .../generated/openapi/zz_generated.openapi.go | 42 ++++++- .../generated/openapi/zz_generated.openapi.go | 42 ++++++- test/integration/client/client_test.go | 6 + 18 files changed, 410 insertions(+), 55 deletions(-) diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 384067bd5cc..f97f2b8c2ff 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -19474,6 +19474,14 @@ "compiler": { "type": "string" }, + "emulationMajor": { + "description": "EmulationMajor is the major version of the emulation version", + "type": "string" + }, + "emulationMinor": { + "description": "EmulationMinor is the minor version of the emulation version", + "type": "string" + }, "gitCommit": { "type": "string" }, @@ -19487,9 +19495,19 @@ "type": "string" }, "major": { + "description": "Major is the major version of the binary version", + "type": "string" + }, + "minCompatibilityMajor": { + "description": "MinCompatibilityMajor is the major version of the minimum compatibility version", + "type": "string" + }, + "minCompatibilityMinor": { + "description": "MinCompatibilityMinor is the minor version of the minimum compatibility version", "type": "string" }, "minor": { + "description": "Minor is the minor version of the binary version", "type": "string" }, "platform": { @@ -85995,8 +86013,8 @@ "consumes": [ "application/json" ], - "description": "get the code version", - "operationId": "getCodeVersion", + "description": "get the version information for this server", + "operationId": "getVersion", "produces": [ "application/json" ], diff --git a/api/openapi-spec/v3/version_openapi.json b/api/openapi-spec/v3/version_openapi.json index fd78d07722f..a1d51fb1d3b 100644 --- a/api/openapi-spec/v3/version_openapi.json +++ b/api/openapi-spec/v3/version_openapi.json @@ -12,6 +12,14 @@ "default": "", "type": "string" }, + "emulationMajor": { + "description": "EmulationMajor is the major version of the emulation version", + "type": "string" + }, + "emulationMinor": { + "description": "EmulationMinor is the minor version of the emulation version", + "type": "string" + }, "gitCommit": { "default": "", "type": "string" @@ -30,10 +38,20 @@ }, "major": { "default": "", + "description": "Major is the major version of the binary version", + "type": "string" + }, + "minCompatibilityMajor": { + "description": "MinCompatibilityMajor is the major version of the minimum compatibility version", + "type": "string" + }, + "minCompatibilityMinor": { + "description": "MinCompatibilityMinor is the minor version of the minimum compatibility version", "type": "string" }, "minor": { "default": "", + "description": "Minor is the minor version of the binary version", "type": "string" }, "platform": { @@ -72,8 +90,8 @@ "paths": { "/version/": { "get": { - "description": "get the code version", - "operationId": "getCodeVersion", + "description": "get the version information for this server", + "operationId": "getVersion", "responses": { "200": { "content": { diff --git a/pkg/controlplane/instance_test.go b/pkg/controlplane/instance_test.go index 81437588298..7c84959a1c8 100644 --- a/pkg/controlplane/instance_test.go +++ b/pkg/controlplane/instance_test.go @@ -243,8 +243,14 @@ func TestVersion(t *testing.T) { } expectedInfo := utilversion.Get() kubeVersion := compatibility.DefaultKubeEffectiveVersionForTest().BinaryVersion() + emulationVersion := compatibility.DefaultKubeEffectiveVersionForTest().EmulationVersion() + minCompatibilityVersion := compatibility.DefaultKubeEffectiveVersionForTest().MinCompatibilityVersion() expectedInfo.Major = fmt.Sprintf("%d", kubeVersion.Major()) expectedInfo.Minor = fmt.Sprintf("%d", kubeVersion.Minor()) + expectedInfo.EmulationMajor = fmt.Sprintf("%d", emulationVersion.Major()) + expectedInfo.EmulationMinor = fmt.Sprintf("%d", emulationVersion.Minor()) + expectedInfo.MinCompatibilityMajor = fmt.Sprintf("%d", minCompatibilityVersion.Major()) + expectedInfo.MinCompatibilityMinor = fmt.Sprintf("%d", minCompatibilityVersion.Minor()) if !reflect.DeepEqual(expectedInfo, info) { t.Errorf("Expected %#v, Got %#v", expectedInfo, info) diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 17a71439d69..f126dc6c73a 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -58457,16 +58457,46 @@ func schema_k8sio_apimachinery_pkg_version_Info(ref common.ReferenceCallback) co Properties: map[string]spec.Schema{ "major": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Major is the major version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", }, }, "minor": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Minor is the minor version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMajor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMajor is the major version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMinor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMinor is the minor version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMajor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMajor is the major version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMinor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMinor is the minor version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", }, }, "gitVersion": { diff --git a/staging/src/k8s.io/apiextensions-apiserver/pkg/generated/openapi/zz_generated.openapi.go b/staging/src/k8s.io/apiextensions-apiserver/pkg/generated/openapi/zz_generated.openapi.go index 0d7157096e8..1b9dc5905ad 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/pkg/generated/openapi/zz_generated.openapi.go +++ b/staging/src/k8s.io/apiextensions-apiserver/pkg/generated/openapi/zz_generated.openapi.go @@ -6599,16 +6599,46 @@ func schema_k8sio_apimachinery_pkg_version_Info(ref common.ReferenceCallback) co Properties: map[string]spec.Schema{ "major": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Major is the major version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", }, }, "minor": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Minor is the minor version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMajor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMajor is the major version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMinor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMinor is the minor version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMajor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMajor is the major version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMinor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMinor is the minor version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", }, }, "gitVersion": { diff --git a/staging/src/k8s.io/apimachinery/pkg/util/version/version.go b/staging/src/k8s.io/apimachinery/pkg/util/version/version.go index b7812ff2d15..ef18472cc44 100644 --- a/staging/src/k8s.io/apimachinery/pkg/util/version/version.go +++ b/staging/src/k8s.io/apimachinery/pkg/util/version/version.go @@ -468,15 +468,15 @@ func (v *Version) Info() *apimachineryversion.Info { return nil } // in case info is empty, or the major and minor in info is different from the actual major and minor - v.info.Major = itoa(v.Major()) - v.info.Minor = itoa(v.Minor()) + v.info.Major = Itoa(v.Major()) + v.info.Minor = Itoa(v.Minor()) if v.info.GitVersion == "" { v.info.GitVersion = v.String() } return &v.info } -func itoa(i uint) string { +func Itoa(i uint) string { if i == 0 { return "" } diff --git a/staging/src/k8s.io/apimachinery/pkg/version/doc.go b/staging/src/k8s.io/apimachinery/pkg/version/doc.go index e64ad36ed25..5f446a4f4af 100644 --- a/staging/src/k8s.io/apimachinery/pkg/version/doc.go +++ b/staging/src/k8s.io/apimachinery/pkg/version/doc.go @@ -16,5 +16,5 @@ limitations under the License. // +k8s:openapi-gen=true -// Package version supplies the type for version information collected at build time. +// Package version supplies the type for version information. package version diff --git a/staging/src/k8s.io/apimachinery/pkg/version/types.go b/staging/src/k8s.io/apimachinery/pkg/version/types.go index 72727b503b7..6a18f9e91d7 100644 --- a/staging/src/k8s.io/apimachinery/pkg/version/types.go +++ b/staging/src/k8s.io/apimachinery/pkg/version/types.go @@ -20,15 +20,25 @@ package version // TODO: Add []string of api versions supported? It's still unclear // how we'll want to distribute that information. type Info struct { - Major string `json:"major"` - Minor string `json:"minor"` - GitVersion string `json:"gitVersion"` - GitCommit string `json:"gitCommit"` - GitTreeState string `json:"gitTreeState"` - BuildDate string `json:"buildDate"` - GoVersion string `json:"goVersion"` - Compiler string `json:"compiler"` - Platform string `json:"platform"` + // Major is the major version of the binary version + Major string `json:"major"` + // Minor is the minor version of the binary version + Minor string `json:"minor"` + // EmulationMajor is the major version of the emulation version + EmulationMajor string `json:"emulationMajor,omitempty"` + // EmulationMinor is the minor version of the emulation version + EmulationMinor string `json:"emulationMinor,omitempty"` + // MinCompatibilityMajor is the major version of the minimum compatibility version + MinCompatibilityMajor string `json:"minCompatibilityMajor,omitempty"` + // MinCompatibilityMinor is the minor version of the minimum compatibility version + MinCompatibilityMinor string `json:"minCompatibilityMinor,omitempty"` + GitVersion string `json:"gitVersion"` + GitCommit string `json:"gitCommit"` + GitTreeState string `json:"gitTreeState"` + BuildDate string `json:"buildDate"` + GoVersion string `json:"goVersion"` + Compiler string `json:"compiler"` + Platform string `json:"platform"` } // String returns info as a human-friendly version string. diff --git a/staging/src/k8s.io/apiserver/pkg/server/config.go b/staging/src/k8s.io/apiserver/pkg/server/config.go index 9e9bf4e3d20..cc778e3fd74 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/config.go +++ b/staging/src/k8s.io/apiserver/pkg/server/config.go @@ -1108,7 +1108,7 @@ func installAPI(name string, s *GenericAPIServer, c *Config) { } } - routes.Version{Version: c.EffectiveVersion.BinaryVersion().Info()}.Install(s.Handler.GoRestfulContainer) + routes.Version{Version: c.EffectiveVersion.Info()}.Install(s.Handler.GoRestfulContainer) if c.EnableDiscovery { if c.FeatureGate.Enabled(genericfeatures.AggregatedDiscoveryEndpoint) { diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go b/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go index 898996837be..b8d0574980b 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go @@ -372,7 +372,7 @@ func TestServerRunWithSNI(t *testing.T) { t.Fatalf("failed to connect with loopback client: %v", err) } if expected := &v; !reflect.DeepEqual(got, expected) { - t.Errorf("loopback client didn't get correct version info: expected=%v got=%v", expected, got) + t.Errorf("loopback client didn't get correct version info: expected=%v got=%v", *expected, *got) } select { @@ -463,9 +463,13 @@ func certSignature(cert tls.Certificate) (string, error) { func fakeVersion() version.Info { return version.Info{ - Major: "42", - Minor: "42", - GitVersion: "42.42", + Major: "42", + Minor: "42", + EmulationMajor: "42", + EmulationMinor: "42", + MinCompatibilityMajor: "42", + MinCompatibilityMinor: "41", + GitVersion: "42.42", } } diff --git a/staging/src/k8s.io/apiserver/pkg/server/routes/version.go b/staging/src/k8s.io/apiserver/pkg/server/routes/version.go index d2235f2ee6e..1a9dc583d9a 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/routes/version.go +++ b/staging/src/k8s.io/apiserver/pkg/server/routes/version.go @@ -39,11 +39,11 @@ func (v Version) Install(c *restful.Container) { // Set up a service to return the git code version. versionWS := new(restful.WebService) versionWS.Path("/version") - versionWS.Doc("git code version from which this is built") + versionWS.Doc("get the version information for this server.") versionWS.Route( versionWS.GET("/").To(v.handleVersion). - Doc("get the code version"). - Operation("getCodeVersion"). + Doc("get the version information for this server"). + Operation("getVersion"). Produces(restful.MIME_JSON). Consumes(restful.MIME_JSON). Writes(version.Info{})) diff --git a/staging/src/k8s.io/code-generator/examples/apiserver/openapi/zz_generated.openapi.go b/staging/src/k8s.io/code-generator/examples/apiserver/openapi/zz_generated.openapi.go index 4885fb073ec..36cc9892434 100644 --- a/staging/src/k8s.io/code-generator/examples/apiserver/openapi/zz_generated.openapi.go +++ b/staging/src/k8s.io/code-generator/examples/apiserver/openapi/zz_generated.openapi.go @@ -2625,16 +2625,46 @@ func schema_k8sio_apimachinery_pkg_version_Info(ref common.ReferenceCallback) co Properties: map[string]spec.Schema{ "major": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Major is the major version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", }, }, "minor": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Minor is the minor version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMajor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMajor is the major version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMinor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMinor is the minor version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMajor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMajor is the major version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMinor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMinor is the minor version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", }, }, "gitVersion": { diff --git a/staging/src/k8s.io/component-base/compatibility/version.go b/staging/src/k8s.io/component-base/compatibility/version.go index 1230e8774ef..2c6be2fc192 100644 --- a/staging/src/k8s.io/component-base/compatibility/version.go +++ b/staging/src/k8s.io/component-base/compatibility/version.go @@ -21,6 +21,7 @@ import ( "sync/atomic" "k8s.io/apimachinery/pkg/util/version" + apimachineryversion "k8s.io/apimachinery/pkg/version" baseversion "k8s.io/component-base/version" ) @@ -42,6 +43,9 @@ type EffectiveVersion interface { // AllowedMinCompatibilityVersionRange returns the string of the allowed range of min compatibility version. // Used only for docs/help. AllowedMinCompatibilityVersionRange() string + + // Info returns the version information of a component. + Info() *apimachineryversion.Info } type MutableEffectiveVersion interface { @@ -173,6 +177,29 @@ func (m *effectiveVersion) Validate() []error { return errs } +// Info returns the version information of a component. +// If the binary version is nil, it returns nil. +func (m *effectiveVersion) Info() *apimachineryversion.Info { + binVer := m.BinaryVersion() + if binVer == nil { + return nil + } + + info := binVer.Info() + + if ev := m.EmulationVersion(); ev != nil { + info.EmulationMajor = version.Itoa(ev.Major()) + info.EmulationMinor = version.Itoa(ev.Minor()) + } + + if mcv := m.MinCompatibilityVersion(); mcv != nil { + info.MinCompatibilityMajor = version.Itoa(mcv.Major()) + info.MinCompatibilityMinor = version.Itoa(mcv.Minor()) + } + + return info +} + // NewEffectiveVersion creates a MutableEffectiveVersion from the binaryVersion. // If useDefaultBuildBinaryVersion is true, the call of BinaryVersion() will always return the current binary version. // NewEffectiveVersion(binaryVersion, true) should only be used if the binary version is dynamic. diff --git a/staging/src/k8s.io/component-base/compatibility/version_test.go b/staging/src/k8s.io/component-base/compatibility/version_test.go index ce25a13b7a0..877ea76e3de 100644 --- a/staging/src/k8s.io/component-base/compatibility/version_test.go +++ b/staging/src/k8s.io/component-base/compatibility/version_test.go @@ -17,9 +17,11 @@ limitations under the License. package compatibility import ( + "reflect" "testing" "k8s.io/apimachinery/pkg/util/version" + apimachineryversion "k8s.io/apimachinery/pkg/version" ) func TestValidate(t *testing.T) { @@ -146,3 +148,115 @@ func TestSetEmulationVersion(t *testing.T) { }) } } + +func TestInfo(t *testing.T) { + tests := []struct { + name string + binaryVersion string + emulationVersion string + minCompatibilityVersion string + expectedInfo *apimachineryversion.Info + }{ + { + name: "normal case", + binaryVersion: "v1.34.0", + emulationVersion: "v1.32.0", + minCompatibilityVersion: "v1.31.0", + expectedInfo: &apimachineryversion.Info{ + Major: "1", + Minor: "34", + EmulationMajor: "1", + EmulationMinor: "32", + MinCompatibilityMajor: "1", + MinCompatibilityMinor: "31", + GitVersion: "1.34.0", + }, + }, + { + name: "default min compatibility version is emulation version - 1", + binaryVersion: "v1.34.0", + emulationVersion: "v1.32.0", + // minCompatibilityVersion not set, should default to v1.31.0 + expectedInfo: &apimachineryversion.Info{ + Major: "1", + Minor: "34", + EmulationMajor: "1", + EmulationMinor: "32", + MinCompatibilityMajor: "1", + MinCompatibilityMinor: "31", + GitVersion: "1.34.0", + }, + }, + { + name: "emulation version same as binary version", + binaryVersion: "v1.34.0", + emulationVersion: "v1.34.0", + // minCompatibilityVersion not set, should default to v1.33.0 + expectedInfo: &apimachineryversion.Info{ + Major: "1", + Minor: "34", + EmulationMajor: "1", + EmulationMinor: "34", + MinCompatibilityMajor: "1", + MinCompatibilityMinor: "33", + GitVersion: "1.34.0", + }, + }, + { + name: "empty binary version", + binaryVersion: "", + expectedInfo: nil, + }, + { + name: "with pre-release and build metadata", + binaryVersion: "v1.34.0-alpha.1+abc123", + emulationVersion: "v1.32.0", + // minCompatibilityVersion not set, should default to v1.31.0 + expectedInfo: &apimachineryversion.Info{ + Major: "1", + Minor: "34", + EmulationMajor: "1", + EmulationMinor: "32", + MinCompatibilityMajor: "1", + MinCompatibilityMinor: "31", + GitVersion: "1.34.0-alpha.1+abc123", + }, + }, + { + name: "override default min compatibility version", + binaryVersion: "v1.34.0", + emulationVersion: "v1.32.0", + minCompatibilityVersion: "v1.32.0", // explicitly set to same as emulation version + expectedInfo: &apimachineryversion.Info{ + Major: "1", + Minor: "34", + EmulationMajor: "1", + EmulationMinor: "32", + MinCompatibilityMajor: "1", + MinCompatibilityMinor: "32", + GitVersion: "1.34.0", + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + var effective MutableEffectiveVersion + if test.binaryVersion == "" { + effective = &effectiveVersion{} + } else { + effective = NewEffectiveVersionFromString(test.binaryVersion, "", "") + if test.emulationVersion != "" { + effective.SetEmulationVersion(version.MustParse(test.emulationVersion)) + } + if test.minCompatibilityVersion != "" { + effective.SetMinCompatibilityVersion(version.MustParse(test.minCompatibilityVersion)) + } + } + info := effective.Info() + if !reflect.DeepEqual(test.expectedInfo, info) { + t.Errorf("Expected %#v, Got %#v", test.expectedInfo, *info) + } + }) + } +} diff --git a/staging/src/k8s.io/component-base/version/version.go b/staging/src/k8s.io/component-base/version/version.go index 1d268d4c680..c71ccf1969e 100644 --- a/staging/src/k8s.io/component-base/version/version.go +++ b/staging/src/k8s.io/component-base/version/version.go @@ -25,6 +25,8 @@ import ( // Get returns the overall codebase version. It's for detecting // what code a binary was built from. +// The caller should use BinaryMajor and BinaryMinor to determine +// the binary version. The Major and Minor fields are still set by git version for backwards compatibility. func Get() apimachineryversion.Info { // These variables typically come from -ldflags settings and in // their absence fallback to the settings in ./base.go diff --git a/staging/src/k8s.io/kube-aggregator/pkg/generated/openapi/zz_generated.openapi.go b/staging/src/k8s.io/kube-aggregator/pkg/generated/openapi/zz_generated.openapi.go index 2a2e10d4a87..44fd7107ac4 100644 --- a/staging/src/k8s.io/kube-aggregator/pkg/generated/openapi/zz_generated.openapi.go +++ b/staging/src/k8s.io/kube-aggregator/pkg/generated/openapi/zz_generated.openapi.go @@ -2625,16 +2625,46 @@ func schema_k8sio_apimachinery_pkg_version_Info(ref common.ReferenceCallback) co Properties: map[string]spec.Schema{ "major": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Major is the major version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", }, }, "minor": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Minor is the minor version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMajor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMajor is the major version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMinor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMinor is the minor version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMajor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMajor is the major version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMinor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMinor is the minor version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", }, }, "gitVersion": { diff --git a/staging/src/k8s.io/sample-apiserver/pkg/generated/openapi/zz_generated.openapi.go b/staging/src/k8s.io/sample-apiserver/pkg/generated/openapi/zz_generated.openapi.go index 02f706e9449..0b54d941c59 100644 --- a/staging/src/k8s.io/sample-apiserver/pkg/generated/openapi/zz_generated.openapi.go +++ b/staging/src/k8s.io/sample-apiserver/pkg/generated/openapi/zz_generated.openapi.go @@ -2623,16 +2623,46 @@ func schema_k8sio_apimachinery_pkg_version_Info(ref common.ReferenceCallback) co Properties: map[string]spec.Schema{ "major": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Major is the major version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", }, }, "minor": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Minor is the minor version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMajor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMajor is the major version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMinor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMinor is the minor version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMajor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMajor is the major version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMinor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMinor is the minor version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", }, }, "gitVersion": { diff --git a/test/integration/client/client_test.go b/test/integration/client/client_test.go index 3314b631c46..eeb18ce4bcc 100644 --- a/test/integration/client/client_test.go +++ b/test/integration/client/client_test.go @@ -85,8 +85,14 @@ func TestClient(t *testing.T) { } expectedInfo := utilversion.Get() kubeVersion := compatibility.DefaultKubeEffectiveVersionForTest().BinaryVersion() + emulationVersion := compatibility.DefaultKubeEffectiveVersionForTest().EmulationVersion() + minCompatibilityVersion := compatibility.DefaultKubeEffectiveVersionForTest().MinCompatibilityVersion() expectedInfo.Major = fmt.Sprintf("%d", kubeVersion.Major()) expectedInfo.Minor = fmt.Sprintf("%d", kubeVersion.Minor()) + expectedInfo.EmulationMajor = fmt.Sprintf("%d", emulationVersion.Major()) + expectedInfo.EmulationMinor = fmt.Sprintf("%d", emulationVersion.Minor()) + expectedInfo.MinCompatibilityMajor = fmt.Sprintf("%d", minCompatibilityVersion.Major()) + expectedInfo.MinCompatibilityMinor = fmt.Sprintf("%d", minCompatibilityVersion.Minor()) if e, a := expectedInfo, *info; !reflect.DeepEqual(e, a) { t.Errorf("expected %#v, got %#v", e, a) From 14934b481ef6522d6c1003ded19002ea45abe5d1 Mon Sep 17 00:00:00 2001 From: yongruilin Date: Wed, 5 Mar 2025 23:55:08 +0000 Subject: [PATCH 2/2] refactor: detach Info from apimachinery util version - Remove `info` field from `Version` struct - Modify `WithInfo` and `Info` methods to be deprecated - Update version information retrieval to use base version info - Simplify version information generation in compatibility tests - Remove unnecessary version info passing in build and test scenarios --- api/openapi-spec/swagger.json | 2 +- api/openapi-spec/v3/version_openapi.json | 2 +- .../apimachinery/pkg/util/version/version.go | 16 +-- .../pkg/server/options/serving_test.go | 27 ++-- .../apiserver/pkg/server/routes/version.go | 2 +- .../pkg/util/compatibility/version.go | 4 +- .../component-base/compatibility/version.go | 11 +- .../compatibility/version_test.go | 135 ++++++++++-------- 8 files changed, 106 insertions(+), 93 deletions(-) diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index f97f2b8c2ff..af8de61dae4 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -86014,7 +86014,7 @@ "application/json" ], "description": "get the version information for this server", - "operationId": "getVersion", + "operationId": "getCodeVersion", "produces": [ "application/json" ], diff --git a/api/openapi-spec/v3/version_openapi.json b/api/openapi-spec/v3/version_openapi.json index a1d51fb1d3b..f2b33c3dc6a 100644 --- a/api/openapi-spec/v3/version_openapi.json +++ b/api/openapi-spec/v3/version_openapi.json @@ -91,7 +91,7 @@ "/version/": { "get": { "description": "get the version information for this server", - "operationId": "getVersion", + "operationId": "getCodeVersion", "responses": { "200": { "content": { diff --git a/staging/src/k8s.io/apimachinery/pkg/util/version/version.go b/staging/src/k8s.io/apimachinery/pkg/util/version/version.go index ef18472cc44..72c0769e6cd 100644 --- a/staging/src/k8s.io/apimachinery/pkg/util/version/version.go +++ b/staging/src/k8s.io/apimachinery/pkg/util/version/version.go @@ -33,7 +33,6 @@ type Version struct { semver bool preRelease string buildMetadata string - info apimachineryversion.Info } var ( @@ -456,24 +455,25 @@ func (v *Version) Compare(other string) (int, error) { return v.compareInternal(ov), nil } -// WithInfo returns copy of the version object with requested info +// WithInfo returns copy of the version object. +// Deprecated: The Info field has been removed from the Version struct. This method no longer modifies the Version object. func (v *Version) WithInfo(info apimachineryversion.Info) *Version { result := *v - result.info = info return &result } +// Info returns the version information of a component. +// Deprecated: Use Info() from effective version instead. func (v *Version) Info() *apimachineryversion.Info { if v == nil { return nil } // in case info is empty, or the major and minor in info is different from the actual major and minor - v.info.Major = Itoa(v.Major()) - v.info.Minor = Itoa(v.Minor()) - if v.info.GitVersion == "" { - v.info.GitVersion = v.String() + return &apimachineryversion.Info{ + Major: Itoa(v.Major()), + Minor: Itoa(v.Minor()), + GitVersion: v.String(), } - return &v.info } func Itoa(i uint) string { diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go b/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go index b8d0574980b..21b2abf7d4c 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/serving_test.go @@ -47,6 +47,7 @@ import ( restclient "k8s.io/client-go/rest" cliflag "k8s.io/component-base/cli/flag" basecompatibility "k8s.io/component-base/compatibility" + baseversion "k8s.io/component-base/version" "k8s.io/klog/v2/ktesting" netutils "k8s.io/utils/net" ) @@ -277,9 +278,8 @@ func TestServerRunWithSNI(t *testing.T) { // launch server config := setUp(t) - v := fakeVersion() - config.EffectiveVersion = basecompatibility.NewEffectiveVersionFromString(v.String(), "", "") - + info := fakeVersionInfo() + config.EffectiveVersion = basecompatibility.NewEffectiveVersionFromString(fmt.Sprintf("%s.%s", info.Major, info.Minor), "", "") config.EnableIndex = true secureOptions := (&SecureServingOptions{ BindAddress: netutils.ParseIPSloppy("127.0.0.1"), @@ -371,7 +371,7 @@ func TestServerRunWithSNI(t *testing.T) { if err != nil { t.Fatalf("failed to connect with loopback client: %v", err) } - if expected := &v; !reflect.DeepEqual(got, expected) { + if expected := &info; !reflect.DeepEqual(got, expected) { t.Errorf("loopback client didn't get correct version info: expected=%v got=%v", *expected, *got) } @@ -461,16 +461,15 @@ func certSignature(cert tls.Certificate) (string, error) { return x509CertSignature(x509Certs[0]), nil } -func fakeVersion() version.Info { - return version.Info{ - Major: "42", - Minor: "42", - EmulationMajor: "42", - EmulationMinor: "42", - MinCompatibilityMajor: "42", - MinCompatibilityMinor: "41", - GitVersion: "42.42", - } +func fakeVersionInfo() version.Info { + baseVer := baseversion.Get() + baseVer.Major = "42" + baseVer.Minor = "42" + baseVer.EmulationMajor = "42" + baseVer.EmulationMinor = "42" + baseVer.MinCompatibilityMajor = "42" + baseVer.MinCompatibilityMinor = "41" + return baseVer } // generateSelfSignedCertKey creates a self-signed certificate and key for the given host. diff --git a/staging/src/k8s.io/apiserver/pkg/server/routes/version.go b/staging/src/k8s.io/apiserver/pkg/server/routes/version.go index 1a9dc583d9a..3e72f18efac 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/routes/version.go +++ b/staging/src/k8s.io/apiserver/pkg/server/routes/version.go @@ -43,7 +43,7 @@ func (v Version) Install(c *restful.Container) { versionWS.Route( versionWS.GET("/").To(v.handleVersion). Doc("get the version information for this server"). - Operation("getVersion"). + Operation("getCodeVersion"). Produces(restful.MIME_JSON). Consumes(restful.MIME_JSON). Writes(version.Info{})) diff --git a/staging/src/k8s.io/apiserver/pkg/util/compatibility/version.go b/staging/src/k8s.io/apiserver/pkg/util/compatibility/version.go index 9ceaf3de65d..2c829d5c147 100644 --- a/staging/src/k8s.io/apiserver/pkg/util/compatibility/version.go +++ b/staging/src/k8s.io/apiserver/pkg/util/compatibility/version.go @@ -55,11 +55,11 @@ func kubeEffectiveVersionFloors(binaryVersion *version.Version) *version.Version // We do not enforce the N-3..N emulation version range in tests so that the tests would not automatically fail when there is a version bump. // Only used in tests. func DefaultKubeEffectiveVersionForTest() basecompatibility.MutableEffectiveVersion { - binaryVersion := version.MustParse(baseversion.DefaultKubeBinaryVersion).WithInfo(baseversion.Get()) + binaryVersion := version.MustParse(baseversion.DefaultKubeBinaryVersion) return basecompatibility.NewEffectiveVersion(binaryVersion, false, version.MustParse("0.0"), version.MustParse("0.0")) } func defaultBuildBinaryVersion() *version.Version { verInfo := baseversion.Get() - return version.MustParse(verInfo.String()).WithInfo(verInfo) + return version.MustParse(verInfo.String()) } diff --git a/staging/src/k8s.io/component-base/compatibility/version.go b/staging/src/k8s.io/component-base/compatibility/version.go index 2c6be2fc192..29e33ce37a9 100644 --- a/staging/src/k8s.io/component-base/compatibility/version.go +++ b/staging/src/k8s.io/component-base/compatibility/version.go @@ -185,7 +185,12 @@ func (m *effectiveVersion) Info() *apimachineryversion.Info { return nil } - info := binVer.Info() + info := baseversion.Get() + info.Major = version.Itoa(binVer.Major()) + info.Minor = version.Itoa(binVer.Minor()) + if info.GitVersion == "" { + info.GitVersion = binVer.String() + } if ev := m.EmulationVersion(); ev != nil { info.EmulationMajor = version.Itoa(ev.Major()) @@ -197,7 +202,7 @@ func (m *effectiveVersion) Info() *apimachineryversion.Info { info.MinCompatibilityMinor = version.Itoa(mcv.Minor()) } - return info + return &info } // NewEffectiveVersion creates a MutableEffectiveVersion from the binaryVersion. @@ -236,5 +241,5 @@ func NewEffectiveVersionFromString(binaryVer, emulationVerFloor, minCompatibilit func defaultBuildBinaryVersion() *version.Version { verInfo := baseversion.Get() - return version.MustParse(verInfo.String()).WithInfo(verInfo) + return version.MustParse(verInfo.String()) } diff --git a/staging/src/k8s.io/component-base/compatibility/version_test.go b/staging/src/k8s.io/component-base/compatibility/version_test.go index 877ea76e3de..e7042778f86 100644 --- a/staging/src/k8s.io/component-base/compatibility/version_test.go +++ b/staging/src/k8s.io/component-base/compatibility/version_test.go @@ -17,11 +17,9 @@ limitations under the License. package compatibility import ( - "reflect" "testing" "k8s.io/apimachinery/pkg/util/version" - apimachineryversion "k8s.io/apimachinery/pkg/version" ) func TestValidate(t *testing.T) { @@ -151,91 +149,80 @@ func TestSetEmulationVersion(t *testing.T) { func TestInfo(t *testing.T) { tests := []struct { - name string - binaryVersion string - emulationVersion string - minCompatibilityVersion string - expectedInfo *apimachineryversion.Info + name string + binaryVersion string + emulationVersion string + minCompatibilityVersion string + expectedMajor string + expectedMinor string + expectedEmulationMajor string + expectedEmulationMinor string + expectedMinCompatibilityMajor string + expectedMinCompatibilityMinor string }{ { - name: "normal case", - binaryVersion: "v1.34.0", - emulationVersion: "v1.32.0", - minCompatibilityVersion: "v1.31.0", - expectedInfo: &apimachineryversion.Info{ - Major: "1", - Minor: "34", - EmulationMajor: "1", - EmulationMinor: "32", - MinCompatibilityMajor: "1", - MinCompatibilityMinor: "31", - GitVersion: "1.34.0", - }, + name: "normal case", + binaryVersion: "v1.34.0", + emulationVersion: "v1.32.0", + minCompatibilityVersion: "v1.31.0", + expectedMajor: "1", + expectedMinor: "34", + expectedEmulationMajor: "1", + expectedEmulationMinor: "32", + expectedMinCompatibilityMajor: "1", + expectedMinCompatibilityMinor: "31", }, { name: "default min compatibility version is emulation version - 1", binaryVersion: "v1.34.0", emulationVersion: "v1.32.0", // minCompatibilityVersion not set, should default to v1.31.0 - expectedInfo: &apimachineryversion.Info{ - Major: "1", - Minor: "34", - EmulationMajor: "1", - EmulationMinor: "32", - MinCompatibilityMajor: "1", - MinCompatibilityMinor: "31", - GitVersion: "1.34.0", - }, + expectedMajor: "1", + expectedMinor: "34", + expectedEmulationMajor: "1", + expectedEmulationMinor: "32", + expectedMinCompatibilityMajor: "1", + expectedMinCompatibilityMinor: "31", }, { name: "emulation version same as binary version", binaryVersion: "v1.34.0", emulationVersion: "v1.34.0", // minCompatibilityVersion not set, should default to v1.33.0 - expectedInfo: &apimachineryversion.Info{ - Major: "1", - Minor: "34", - EmulationMajor: "1", - EmulationMinor: "34", - MinCompatibilityMajor: "1", - MinCompatibilityMinor: "33", - GitVersion: "1.34.0", - }, + expectedMajor: "1", + expectedMinor: "34", + expectedEmulationMajor: "1", + expectedEmulationMinor: "34", + expectedMinCompatibilityMajor: "1", + expectedMinCompatibilityMinor: "33", }, { name: "empty binary version", binaryVersion: "", - expectedInfo: nil, }, { name: "with pre-release and build metadata", binaryVersion: "v1.34.0-alpha.1+abc123", emulationVersion: "v1.32.0", // minCompatibilityVersion not set, should default to v1.31.0 - expectedInfo: &apimachineryversion.Info{ - Major: "1", - Minor: "34", - EmulationMajor: "1", - EmulationMinor: "32", - MinCompatibilityMajor: "1", - MinCompatibilityMinor: "31", - GitVersion: "1.34.0-alpha.1+abc123", - }, + expectedMajor: "1", + expectedMinor: "34", + expectedEmulationMajor: "1", + expectedEmulationMinor: "32", + expectedMinCompatibilityMajor: "1", + expectedMinCompatibilityMinor: "31", }, { - name: "override default min compatibility version", - binaryVersion: "v1.34.0", - emulationVersion: "v1.32.0", - minCompatibilityVersion: "v1.32.0", // explicitly set to same as emulation version - expectedInfo: &apimachineryversion.Info{ - Major: "1", - Minor: "34", - EmulationMajor: "1", - EmulationMinor: "32", - MinCompatibilityMajor: "1", - MinCompatibilityMinor: "32", - GitVersion: "1.34.0", - }, + name: "override default min compatibility version", + binaryVersion: "v1.34.0", + emulationVersion: "v1.32.0", + minCompatibilityVersion: "v1.32.0", // explicitly set to same as emulation version + expectedMajor: "1", + expectedMinor: "34", + expectedEmulationMajor: "1", + expectedEmulationMinor: "32", + expectedMinCompatibilityMajor: "1", + expectedMinCompatibilityMinor: "32", }, } @@ -254,8 +241,30 @@ func TestInfo(t *testing.T) { } } info := effective.Info() - if !reflect.DeepEqual(test.expectedInfo, info) { - t.Errorf("Expected %#v, Got %#v", test.expectedInfo, *info) + if info == nil { + if test.expectedMajor != "" { + t.Fatalf("expected info, got nil") + } + return + } + + if info.Major != test.expectedMajor { + t.Errorf("expected major %s, got %s", test.expectedMajor, info.Major) + } + if info.Minor != test.expectedMinor { + t.Errorf("expected minor %s, got %s", test.expectedMinor, info.Minor) + } + if info.EmulationMajor != test.expectedEmulationMajor { + t.Errorf("expected emulation major %s, got %s", test.expectedEmulationMajor, info.EmulationMajor) + } + if info.EmulationMinor != test.expectedEmulationMinor { + t.Errorf("expected emulation minor %s, got %s", test.expectedEmulationMinor, info.EmulationMinor) + } + if info.MinCompatibilityMajor != test.expectedMinCompatibilityMajor { + t.Errorf("expected min compatibility major %s, got %s", test.expectedMinCompatibilityMajor, info.MinCompatibilityMajor) + } + if info.MinCompatibilityMinor != test.expectedMinCompatibilityMinor { + t.Errorf("expected min compatibility minor %s, got %s", test.expectedMinCompatibilityMinor, info.MinCompatibilityMinor) } }) }