K8s: Refactor standalone apiserver initialization (#81932)
This commit is contained in:
@@ -1,22 +1,28 @@
|
||||
package apiserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/apiserver/pkg/server/options"
|
||||
"k8s.io/component-base/cli"
|
||||
|
||||
"github.com/grafana/grafana/pkg/server"
|
||||
grafanaapiserver "github.com/grafana/grafana/pkg/services/apiserver"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/standalone"
|
||||
)
|
||||
|
||||
func newCommandStartExampleAPIServer(o *APIServerOptions, stopCh <-chan struct{}) *cobra.Command {
|
||||
devAcknowledgementNotice := "The apiserver command is in heavy development. The entire setup is subject to change without notice"
|
||||
runtimeConfig := ""
|
||||
|
||||
factory, err := server.InitializeAPIServerFactory()
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
o.factory = factory
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "apiserver [api group(s)]",
|
||||
Short: "Run the grafana apiserver",
|
||||
@@ -24,7 +30,11 @@ func newCommandStartExampleAPIServer(o *APIServerOptions, stopCh <-chan struct{}
|
||||
devAcknowledgementNotice,
|
||||
Example: "grafana apiserver example.grafana.app",
|
||||
RunE: func(c *cobra.Command, args []string) error {
|
||||
apis, err := readRuntimeConfig(runtimeConfig)
|
||||
runtime, err := standalone.ReadRuntimeConfig(runtimeConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
apis, err := o.factory.GetEnabled(runtime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -52,6 +62,7 @@ func newCommandStartExampleAPIServer(o *APIServerOptions, stopCh <-chan struct{}
|
||||
}
|
||||
|
||||
cmd.Flags().StringVar(&runtimeConfig, "runtime-config", "", "A set of key=value pairs that enable or disable built-in APIs.")
|
||||
o.factory.InitFlags(cmd.Flags())
|
||||
|
||||
// Register standard k8s flags with the command line
|
||||
o.RecommendedOptions = options.NewRecommendedOptions(
|
||||
@@ -71,43 +82,3 @@ func RunCLI() int {
|
||||
|
||||
return cli.Run(cmd)
|
||||
}
|
||||
|
||||
type apiConfig struct {
|
||||
group string
|
||||
version string
|
||||
enabled bool
|
||||
}
|
||||
|
||||
func (a apiConfig) String() string {
|
||||
return fmt.Sprintf("%s/%s=%v", a.group, a.version, a.enabled)
|
||||
}
|
||||
|
||||
// Supported options are:
|
||||
//
|
||||
// <group>/<version>=true|false for a specific API group and version (e.g. dashboards.grafana.app/v0alpha1=true)
|
||||
// api/all=true|false controls all API versions
|
||||
// api/ga=true|false controls all API versions of the form v[0-9]+
|
||||
// api/beta=true|false controls all API versions of the form v[0-9]+beta[0-9]+
|
||||
// api/alpha=true|false controls all API versions of the form v[0-9]+alpha[0-9]+`)
|
||||
//
|
||||
// See: https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/
|
||||
func readRuntimeConfig(cfg string) ([]apiConfig, error) {
|
||||
if cfg == "" {
|
||||
return nil, fmt.Errorf("missing --runtime-config={apiservers}")
|
||||
}
|
||||
parts := strings.Split(cfg, ",")
|
||||
apis := make([]apiConfig, len(parts))
|
||||
for i, part := range parts {
|
||||
idx0 := strings.Index(part, "/")
|
||||
idx1 := strings.LastIndex(part, "=")
|
||||
if idx1 < idx0 || idx0 < 0 {
|
||||
return nil, fmt.Errorf("expected values in the form: group/version=true")
|
||||
}
|
||||
apis[i] = apiConfig{
|
||||
group: part[:idx0],
|
||||
version: part[idx0+1 : idx1],
|
||||
enabled: part[idx1+1:] == "true",
|
||||
}
|
||||
}
|
||||
return apis, nil
|
||||
}
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package apiserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAdminAPIEndpoint(t *testing.T) {
|
||||
out, err := readRuntimeConfig("all/all=true,dashboards.grafana.app/v0alpha1=false")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []apiConfig{
|
||||
{group: "all", version: "all", enabled: true},
|
||||
{group: "dashboards.grafana.app", version: "v0alpha1", enabled: false},
|
||||
}, out)
|
||||
require.Equal(t, "all/all=true", fmt.Sprintf("%v", out[0]))
|
||||
|
||||
// Empty is an error
|
||||
_, err = readRuntimeConfig("")
|
||||
require.Error(t, err)
|
||||
}
|
||||
@@ -6,23 +6,17 @@ import (
|
||||
"net"
|
||||
"path"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/apiserver/pkg/server/options"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
netutils "k8s.io/utils/net"
|
||||
|
||||
"github.com/grafana/grafana/pkg/registry/apis/example"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/featuretoggle"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/query"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/query/runner"
|
||||
"github.com/grafana/grafana/pkg/server"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
|
||||
grafanaAPIServer "github.com/grafana/grafana/pkg/services/apiserver"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/builder"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/standalone"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/utils"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -32,6 +26,7 @@ const (
|
||||
|
||||
// APIServerOptions contains the state for the apiserver
|
||||
type APIServerOptions struct {
|
||||
factory standalone.APIServerFactory
|
||||
builders []builder.APIGroupBuilder
|
||||
RecommendedOptions *options.RecommendedOptions
|
||||
AlternateDNS []string
|
||||
@@ -47,40 +42,14 @@ func newAPIServerOptions(out, errOut io.Writer) *APIServerOptions {
|
||||
}
|
||||
}
|
||||
|
||||
func (o *APIServerOptions) loadAPIGroupBuilders(runtime []apiConfig) error {
|
||||
func (o *APIServerOptions) loadAPIGroupBuilders(apis []schema.GroupVersion) error {
|
||||
o.builders = []builder.APIGroupBuilder{}
|
||||
for _, gv := range runtime {
|
||||
if !gv.enabled {
|
||||
return fmt.Errorf("disabling apis is not yet supported")
|
||||
}
|
||||
switch gv.group {
|
||||
case "all":
|
||||
return fmt.Errorf("managing all APIs is not yet supported")
|
||||
case "example.grafana.app":
|
||||
o.builders = append(o.builders, example.NewTestingAPIBuilder())
|
||||
// Only works with testdata
|
||||
case "query.grafana.app":
|
||||
o.builders = append(o.builders, query.NewQueryAPIBuilder(
|
||||
featuremgmt.WithFeatures(),
|
||||
runner.NewDummyTestRunner(),
|
||||
runner.NewDummyRegistry(),
|
||||
))
|
||||
case "featuretoggle.grafana.app":
|
||||
o.builders = append(o.builders,
|
||||
featuretoggle.NewFeatureFlagAPIBuilder(
|
||||
featuremgmt.WithFeatureManager(setting.FeatureMgmtSettings{}, nil), // none... for now
|
||||
&actest.FakeAccessControl{ExpectedEvaluate: false},
|
||||
),
|
||||
)
|
||||
case "testdata.datasource.grafana.app":
|
||||
ds, err := server.InitializeDataSourceAPIServer(gv.group)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.builders = append(o.builders, ds)
|
||||
default:
|
||||
return fmt.Errorf("unsupported runtime-config: %v", gv)
|
||||
for _, gv := range apis {
|
||||
api, err := o.factory.MakeAPIServer(gv)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
o.builders = append(o.builders, api)
|
||||
}
|
||||
|
||||
if len(o.builders) < 1 {
|
||||
|
||||
Reference in New Issue
Block a user