mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
K8s: Refactor standalone apiserver initialization (#81932)
This commit is contained in:
154
pkg/services/apiserver/standalone/factory.go
Normal file
154
pkg/services/apiserver/standalone/factory.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package standalone
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend"
|
||||
"github.com/spf13/pflag"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apis/datasource/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/plugins"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/datasource"
|
||||
"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/services/accesscontrol/actest"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/builder"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
testdatasource "github.com/grafana/grafana/pkg/tsdb/grafana-testdata-datasource"
|
||||
)
|
||||
|
||||
type APIServerFactory interface {
|
||||
// Called before the groups are loaded so any custom command can be registered
|
||||
InitFlags(flags *pflag.FlagSet)
|
||||
|
||||
// Given the flags, what can we produce
|
||||
GetEnabled(runtime []RuntimeConfig) ([]schema.GroupVersion, error)
|
||||
|
||||
// Make an API server for a given group+version
|
||||
MakeAPIServer(gv schema.GroupVersion) (builder.APIGroupBuilder, error)
|
||||
}
|
||||
|
||||
// Zero dependency provider for testing
|
||||
func GetDummyAPIFactory() APIServerFactory {
|
||||
return &DummyAPIFactory{}
|
||||
}
|
||||
|
||||
type DummyAPIFactory struct{}
|
||||
|
||||
func (p *DummyAPIFactory) InitFlags(flags *pflag.FlagSet) {}
|
||||
|
||||
func (p *DummyAPIFactory) GetEnabled(runtime []RuntimeConfig) ([]schema.GroupVersion, error) {
|
||||
gv := []schema.GroupVersion{}
|
||||
for _, cfg := range runtime {
|
||||
if !cfg.Enabled {
|
||||
return nil, fmt.Errorf("only enabled supported now")
|
||||
}
|
||||
if cfg.Group == "all" {
|
||||
return nil, fmt.Errorf("all not yet supported")
|
||||
}
|
||||
gv = append(gv, schema.GroupVersion{Group: cfg.Group, Version: cfg.Version})
|
||||
}
|
||||
return gv, nil
|
||||
}
|
||||
|
||||
func (p *DummyAPIFactory) MakeAPIServer(gv schema.GroupVersion) (builder.APIGroupBuilder, error) {
|
||||
if gv.Version != "v0alpha1" {
|
||||
return nil, fmt.Errorf("only alpha supported now")
|
||||
}
|
||||
|
||||
switch gv.Group {
|
||||
case "example.grafana.app":
|
||||
return example.NewTestingAPIBuilder(), nil
|
||||
|
||||
// Only works with testdata
|
||||
case "query.grafana.app":
|
||||
return query.NewQueryAPIBuilder(
|
||||
featuremgmt.WithFeatures(),
|
||||
runner.NewDummyTestRunner(),
|
||||
runner.NewDummyRegistry(),
|
||||
), nil
|
||||
|
||||
case "featuretoggle.grafana.app":
|
||||
return featuretoggle.NewFeatureFlagAPIBuilder(
|
||||
featuremgmt.WithFeatureManager(setting.FeatureMgmtSettings{}, nil), // none... for now
|
||||
&actest.FakeAccessControl{ExpectedEvaluate: false},
|
||||
), nil
|
||||
|
||||
case "testdata.datasource.grafana.app":
|
||||
return datasource.NewDataSourceAPIBuilder(
|
||||
plugins.JSONData{
|
||||
ID: "grafana-testdata-datasource",
|
||||
},
|
||||
testdatasource.ProvideService(), // the client
|
||||
&pluginDatasourceImpl{
|
||||
startup: v1.Now(),
|
||||
},
|
||||
&pluginDatasourceImpl{}, // stub
|
||||
&actest.FakeAccessControl{ExpectedEvaluate: true},
|
||||
)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unsupported group")
|
||||
}
|
||||
|
||||
// Simple stub for standalone datasource testing
|
||||
type pluginDatasourceImpl struct {
|
||||
startup v1.Time
|
||||
}
|
||||
|
||||
var (
|
||||
_ datasource.PluginDatasourceProvider = (*pluginDatasourceImpl)(nil)
|
||||
)
|
||||
|
||||
// Get implements PluginDatasourceProvider.
|
||||
func (p *pluginDatasourceImpl) Get(ctx context.Context, pluginID string, uid string) (*v0alpha1.DataSourceConnection, error) {
|
||||
all, err := p.List(ctx, pluginID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for idx, v := range all.Items {
|
||||
if v.Name == uid {
|
||||
return &all.Items[idx], nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("not found")
|
||||
}
|
||||
|
||||
// List implements PluginConfigProvider.
|
||||
func (p *pluginDatasourceImpl) List(ctx context.Context, pluginID string) (*v0alpha1.DataSourceConnectionList, error) {
|
||||
info, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &v0alpha1.DataSourceConnectionList{
|
||||
TypeMeta: v0alpha1.GenericConnectionResourceInfo.TypeMeta(),
|
||||
Items: []v0alpha1.DataSourceConnection{
|
||||
{
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: "PD8C576611E62080A",
|
||||
Namespace: info.Value, // the raw namespace value
|
||||
CreationTimestamp: p.startup,
|
||||
},
|
||||
Title: "gdev-testdata",
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// PluginContextForDataSource implements PluginConfigProvider.
|
||||
func (*pluginDatasourceImpl) GetInstanceSettings(ctx context.Context, pluginID, uid string) (*backend.DataSourceInstanceSettings, error) {
|
||||
return &backend.DataSourceInstanceSettings{}, nil
|
||||
}
|
||||
|
||||
// PluginContextWrapper
|
||||
func (*pluginDatasourceImpl) PluginContextForDataSource(ctx context.Context, datasourceSettings *backend.DataSourceInstanceSettings) (backend.PluginContext, error) {
|
||||
return backend.PluginContext{DataSourceInstanceSettings: datasourceSettings}, nil
|
||||
}
|
||||
46
pkg/services/apiserver/standalone/runtime.go
Normal file
46
pkg/services/apiserver/standalone/runtime.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package standalone
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RuntimeConfig struct {
|
||||
Group string
|
||||
Version string
|
||||
Enabled bool
|
||||
}
|
||||
|
||||
func (a RuntimeConfig) 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) ([]RuntimeConfig, error) {
|
||||
if cfg == "" {
|
||||
return nil, fmt.Errorf("missing --runtime-config={apiservers}")
|
||||
}
|
||||
parts := strings.Split(cfg, ",")
|
||||
apis := make([]RuntimeConfig, 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] = RuntimeConfig{
|
||||
Group: part[:idx0],
|
||||
Version: part[idx0+1 : idx1],
|
||||
Enabled: part[idx1+1:] == "true",
|
||||
}
|
||||
}
|
||||
return apis, nil
|
||||
}
|
||||
22
pkg/services/apiserver/standalone/runtime_test.go
Normal file
22
pkg/services/apiserver/standalone/runtime_test.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package standalone
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestReadRuntimeCOnfig(t *testing.T) {
|
||||
out, err := ReadRuntimeConfig("all/all=true,dashboards.grafana.app/v0alpha1=false")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, []RuntimeConfig{
|
||||
{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)
|
||||
}
|
||||
Reference in New Issue
Block a user