APIServer: Move shared code to a utility/helper function (#80261)

This commit is contained in:
Ryan McKinley 2024-01-10 07:30:16 -08:00 committed by GitHub
parent 4f832c4c69
commit ee7daeb2a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 113 additions and 134 deletions

View File

@ -4,11 +4,13 @@ import (
"os"
"path"
"github.com/grafana/grafana/pkg/aggregator"
"github.com/grafana/grafana/pkg/services/grafana-apiserver/utils"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog/v2"
"github.com/grafana/grafana/pkg/aggregator"
grafanaapiserver "github.com/grafana/grafana/pkg/services/grafana-apiserver"
"github.com/grafana/grafana/pkg/services/grafana-apiserver/utils"
"github.com/spf13/cobra"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/options"
@ -56,7 +58,7 @@ func newCommandStartExampleAPIServer(o *APIServerOptions, stopCh <-chan struct{}
// Register standard k8s flags with the command line
o.RecommendedOptions = options.NewRecommendedOptions(
defaultEtcdPathPrefix,
Codecs.LegacyCodec(), // the codec is passed to etcd and not used
grafanaapiserver.Codecs.LegacyCodec(), // the codec is passed to etcd and not used
)
o.RecommendedOptions.AddFlags(cmd.Flags())
@ -111,20 +113,10 @@ func run(serverOptions *aggregator.AggregatorServerOptions) error {
}
// Install the API Group+version
for _, b := range serverOptions.Builders {
g, err := b.GetAPIGroupInfo(Scheme, Codecs, config.GenericConfig.RESTOptionsGetter)
if err != nil {
klog.Errorf("Error getting group info for prerequisite API group: %s", err)
return err
}
if g == nil || len(g.PrioritizedVersions) < 1 {
continue
}
err = aggregator.GenericAPIServer.InstallAPIGroup(g)
if err != nil {
klog.Errorf("Error installing prerequisite API groups for aggregator: %s", err)
return err
}
err = grafanaapiserver.InstallAPIs(aggregator.GenericAPIServer, config.GenericConfig.RESTOptionsGetter, serverOptions.Builders)
if err != nil {
klog.Errorf("Error installing apis: %s", err)
return err
}
if err := clientcmd.WriteToFile(

View File

@ -6,22 +6,15 @@ import (
"net"
"path"
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"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
openapinamer "k8s.io/apiserver/pkg/endpoints/openapi"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/options"
"k8s.io/apiserver/pkg/util/openapi"
"k8s.io/client-go/tools/clientcmd"
netutils "k8s.io/utils/net"
"github.com/grafana/grafana/pkg/services/grafana-apiserver/utils"
"github.com/grafana/grafana/pkg/registry/apis/example"
grafanaAPIServer "github.com/grafana/grafana/pkg/services/grafana-apiserver"
"github.com/grafana/grafana/pkg/services/grafana-apiserver/utils"
)
const (
@ -29,26 +22,6 @@ const (
dataPath = "data/grafana-apiserver" // same as grafana core
)
var (
Scheme = runtime.NewScheme()
Codecs = serializer.NewCodecFactory(Scheme)
)
func init() {
unversionedVersion := schema.GroupVersion{Group: "", Version: "v1"}
unversionedTypes := []runtime.Object{
&metav1.Status{},
&metav1.WatchEvent{},
&metav1.APIVersions{},
&metav1.APIGroupList{},
&metav1.APIGroup{},
&metav1.APIResourceList{},
}
// we need to add the options to empty v1
metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Group: "", Version: "v1"})
Scheme.AddUnversionedTypes(unversionedVersion, unversionedTypes...)
}
// APIServerOptions contains the state for the apiserver
type APIServerOptions struct {
builders []grafanaAPIServer.APIGroupBuilder
@ -84,7 +57,7 @@ func (o *APIServerOptions) LoadAPIGroupBuilders(args []string) error {
// Install schemas
for _, b := range o.builders {
if err := b.InstallSchema(Scheme); err != nil {
if err := b.InstallSchema(grafanaAPIServer.Scheme); err != nil {
return err
}
}
@ -160,7 +133,7 @@ func (o *APIServerOptions) Config() (*genericapiserver.RecommendedConfig, error)
o.RecommendedOptions.CoreAPI = nil
}
serverConfig := genericapiserver.NewRecommendedConfig(Codecs)
serverConfig := genericapiserver.NewRecommendedConfig(grafanaAPIServer.Codecs)
if o.RecommendedOptions.CoreAPI == nil {
if err := o.ModifiedApplyTo(serverConfig); err != nil {
@ -176,16 +149,8 @@ func (o *APIServerOptions) Config() (*genericapiserver.RecommendedConfig, error)
serverConfig.DisabledPostStartHooks = serverConfig.DisabledPostStartHooks.Insert("priority-and-fairness-config-consumer")
// Add OpenAPI specs for each group+version
defsGetter := grafanaAPIServer.GetOpenAPIDefinitions(o.builders)
serverConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(
openapi.GetOpenAPIDefinitionsWithoutDisabledFeatures(defsGetter),
openapinamer.NewDefinitionNamer(Scheme))
serverConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config(
openapi.GetOpenAPIDefinitionsWithoutDisabledFeatures(defsGetter),
openapinamer.NewDefinitionNamer(Scheme))
return serverConfig, nil
err := grafanaAPIServer.SetupConfig(serverConfig, o.builders)
return serverConfig, err
}
// Validate validates APIServerOptions
@ -212,18 +177,9 @@ func (o *APIServerOptions) RunAPIServer(config *genericapiserver.RecommendedConf
}
// Install the API Group+version
for _, b := range o.builders {
g, err := b.GetAPIGroupInfo(Scheme, Codecs, completedConfig.RESTOptionsGetter)
if err != nil {
return err
}
if g == nil || len(g.PrioritizedVersions) < 1 {
continue
}
err = server.InstallAPIGroup(g)
if err != nil {
return err
}
err = grafanaAPIServer.InstallAPIs(server, config.RESTOptionsGetter, o.builders)
if err != nil {
return err
}
// write the local config to disk

View File

@ -25,7 +25,7 @@ type APIGroupBuilder interface {
// Build the group+version behavior
GetAPIGroupInfo(
scheme *runtime.Scheme,
codecs serializer.CodecFactory, // pointer?
codecs serializer.CodecFactory,
optsGetter generic.RESTOptionsGetter,
) (*genericapiserver.APIGroupInfo, error)

View File

@ -0,0 +1,89 @@
package grafanaapiserver
import (
"fmt"
"net/http"
goruntime "runtime"
"strings"
"time"
"k8s.io/apimachinery/pkg/version"
openapinamer "k8s.io/apiserver/pkg/endpoints/openapi"
"k8s.io/apiserver/pkg/registry/generic"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/util/openapi"
"k8s.io/client-go/kubernetes/scheme"
"github.com/grafana/grafana/pkg/setting"
)
func SetupConfig(serverConfig *genericapiserver.RecommendedConfig, builders []APIGroupBuilder) error {
defsGetter := GetOpenAPIDefinitions(builders)
serverConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(
openapi.GetOpenAPIDefinitionsWithoutDisabledFeatures(defsGetter),
openapinamer.NewDefinitionNamer(Scheme, scheme.Scheme))
serverConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config(
openapi.GetOpenAPIDefinitionsWithoutDisabledFeatures(defsGetter),
openapinamer.NewDefinitionNamer(Scheme, scheme.Scheme))
// Add the custom routes to service discovery
serverConfig.OpenAPIV3Config.PostProcessSpec = 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
// See https://github.com/kubernetes/apiserver/blob/v0.28.0/pkg/server/config.go#L906
// DefaultBuildHandlerChain provides many things, notably CORS, HSTS, cache-control, authz and latency tracking
requestHandler, err := getAPIHandler(
delegateHandler,
c.LoopbackClientConfig,
builders)
if err != nil {
panic(fmt.Sprintf("could not build handler chain func: %s", err.Error()))
}
return genericapiserver.DefaultBuildHandlerChain(requestHandler, c)
}
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,
}
return nil
}
func InstallAPIs(server *genericapiserver.GenericAPIServer,
optsGetter generic.RESTOptionsGetter,
builders []APIGroupBuilder,
) error {
for _, b := range builders {
g, err := b.GetAPIGroupInfo(Scheme, Codecs, optsGetter)
if err != nil {
return err
}
if g == nil || len(g.PrioritizedVersions) < 1 {
continue
}
err = server.InstallAPIGroup(g)
if err != nil {
return err
}
}
return nil
}

View File

@ -16,7 +16,7 @@ type requestHandler struct {
router *mux.Router
}
func GetAPIHandler(delegateHandler http.Handler, restConfig *restclient.Config, builders []APIGroupBuilder) (http.Handler, error) {
func getAPIHandler(delegateHandler http.Handler, restConfig *restclient.Config, builders []APIGroupBuilder) (http.Handler, error) {
useful := false // only true if any routes exist anywhere
router := mux.NewRouter()
@ -120,7 +120,7 @@ func (h *methodNotAllowedHandler) ServeHTTP(w http.ResponseWriter, req *http.Req
// Modify the the OpenAPI spec to include the additional routes.
// Currently this requires: https://github.com/kubernetes/kube-openapi/pull/420
// In future k8s release, the hook will use Config3 rather than the same hook for both v2 and v3
func GetOpenAPIPostProcessor(builders []APIGroupBuilder) func(*spec3.OpenAPI) (*spec3.OpenAPI, error) {
func getOpenAPIPostProcessor(builders []APIGroupBuilder) func(*spec3.OpenAPI) (*spec3.OpenAPI, error) {
return func(s *spec3.OpenAPI) (*spec3.OpenAPI, error) {
if s.Paths == nil {
return s, nil

View File

@ -6,11 +6,9 @@ import (
"net/http"
"net/http/httptest"
"path"
goruntime "runtime"
"runtime/debug"
"strconv"
"strings"
"time"
"github.com/go-logr/logr"
"github.com/grafana/dskit/services"
@ -21,13 +19,9 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/version"
openapinamer "k8s.io/apiserver/pkg/endpoints/openapi"
"k8s.io/apiserver/pkg/endpoints/responsewriter"
genericapiserver "k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/options"
"k8s.io/apiserver/pkg/util/openapi"
"k8s.io/client-go/kubernetes/scheme"
clientrest "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/component-base/logs"
@ -325,53 +319,10 @@ func (s *service) start(ctx context.Context) error {
serverConfig.TracerProvider = s.tracing.GetTracerProvider()
// Add OpenAPI specs for each group+version
defsGetter := GetOpenAPIDefinitions(builders)
serverConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(
openapi.GetOpenAPIDefinitionsWithoutDisabledFeatures(defsGetter),
openapinamer.NewDefinitionNamer(Scheme, scheme.Scheme))
serverConfig.OpenAPIV3Config = genericapiserver.DefaultOpenAPIV3Config(
openapi.GetOpenAPIDefinitionsWithoutDisabledFeatures(defsGetter),
openapinamer.NewDefinitionNamer(Scheme, scheme.Scheme))
// Add the custom routes to service discovery
serverConfig.OpenAPIV3Config.PostProcessSpec = 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
// See https://github.com/kubernetes/apiserver/blob/v0.28.0/pkg/server/config.go#L906
// DefaultBuildHandlerChain provides many things, notably CORS, HSTS, cache-control, authz and latency tracking
requestHandler, err := GetAPIHandler(
delegateHandler,
c.LoopbackClientConfig,
builders)
if err != nil {
panic(fmt.Sprintf("could not build handler chain func: %s", err.Error()))
}
return genericapiserver.DefaultBuildHandlerChain(requestHandler, c)
}
k8sVersion, err := getK8sApiserverVersion()
err := SetupConfig(serverConfig, builders)
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())
@ -380,18 +331,9 @@ func (s *service) start(ctx context.Context) error {
}
// Install the API Group+version
for _, b := range builders {
g, err := b.GetAPIGroupInfo(Scheme, Codecs, serverConfig.RESTOptionsGetter)
if err != nil {
return err
}
if g == nil || len(g.PrioritizedVersions) < 1 {
continue
}
err = server.InstallAPIGroup(g)
if err != nil {
return err
}
err = InstallAPIs(server, serverConfig.RESTOptionsGetter, builders)
if err != nil {
return err
}
// Used by the proxy wrapper registered in ProvideService