From c887ef2c9ab96e05c949fdc8c0bac9a145c68a92 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Tue, 14 Nov 2023 12:29:15 -0800 Subject: [PATCH] K8s: Set version info in response (#78083) Co-authored-by: Jeff Levin --- pkg/services/grafana-apiserver/service.go | 54 ++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/pkg/services/grafana-apiserver/service.go b/pkg/services/grafana-apiserver/service.go index 9b06fff2230..8b833a197ba 100644 --- a/pkg/services/grafana-apiserver/service.go +++ b/pkg/services/grafana-apiserver/service.go @@ -6,14 +6,20 @@ import ( "net/http" "net/http/httptest" "path" + goruntime "runtime" + "runtime/debug" "strconv" + "strings" + "time" "github.com/go-logr/logr" "github.com/grafana/dskit/services" + "golang.org/x/mod/semver" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/version" "k8s.io/apiserver/pkg/authorization/authorizer" openapinamer "k8s.io/apiserver/pkg/endpoints/openapi" "k8s.io/apiserver/pkg/endpoints/responsewriter" @@ -261,6 +267,7 @@ func (s *service) start(ctx context.Context) error { } serverConfig.Authorization.Authorizer = s.authorizer + serverConfig.TracerProvider = s.tracing.GetTracerProvider() // Add OpenAPI specs for each group+version defsGetter := getOpenAPIDefinitions(builders) @@ -275,6 +282,10 @@ func (s *service) start(ctx context.Context) error { // Add the custom routes to service discovery serverConfig.OpenAPIV3Config.PostProcessSpec3 = getOpenAPIPostProcessor(builders) + // Set the swagger build versions + serverConfig.OpenAPIConfig.Info.Version = setting.BuildVersion + serverConfig.OpenAPIV3Config.Info.Version = setting.BuildVersion + serverConfig.SkipOpenAPIInstallation = false serverConfig.BuildHandlerChainFunc = func(delegateHandler http.Handler, c *genericapiserver.Config) http.Handler { // Call DefaultBuildHandlerChain on the main entrypoint http.Handler @@ -290,7 +301,22 @@ func (s *service) start(ctx context.Context) error { return genericapiserver.DefaultBuildHandlerChain(requestHandler, c) } - serverConfig.TracerProvider = s.tracing.GetTracerProvider() + k8sVersion, err := getK8sApiserverVersion() + if err != nil { + return err + } + before, after, _ := strings.Cut(setting.BuildVersion, ".") + serverConfig.Version = &version.Info{ + Major: before, + Minor: after, + GoVersion: goruntime.Version(), + Platform: fmt.Sprintf("%s/%s", goruntime.GOOS, goruntime.GOARCH), + Compiler: goruntime.Compiler, + GitTreeState: setting.BuildBranch, + GitCommit: setting.BuildCommit, + BuildDate: time.Unix(setting.BuildStamp, 0).UTC().Format(time.DateTime), + GitVersion: k8sVersion, + } // Create the server server, err := serverConfig.Complete().New("grafana-apiserver", genericapiserver.NewEmptyDelegate()) @@ -403,3 +429,29 @@ type roundTripperFunc struct { func (f *roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { return f.fn(req) } + +// find the k8s version according to build info +func getK8sApiserverVersion() (string, error) { + bi, ok := debug.ReadBuildInfo() + if !ok { + return "", fmt.Errorf("debug.ReadBuildInfo() failed") + } + + for _, dep := range bi.Deps { + if dep.Path == "k8s.io/apiserver" { + if !semver.IsValid(dep.Version) { + return "", fmt.Errorf("invalid semantic version for k8s.io/apiserver") + } + // v0 => v1 + majorVersion := strings.TrimPrefix(semver.Major(dep.Version), "v") + majorInt, err := strconv.Atoi(majorVersion) + if err != nil { + return "", fmt.Errorf("could not convert majorVersion to int. majorVersion: %s", majorVersion) + } + newMajor := fmt.Sprintf("v%d", majorInt+1) + return strings.Replace(dep.Version, semver.Major(dep.Version), newMajor, 1), nil + } + } + + return "", fmt.Errorf("could not find k8s.io/apiserver in build info") +}