scopes: moves scopes to enterprise (#100746)
Signed-off-by: bergquist <carl.bergquist@gmail.com>
This commit is contained in:
@@ -13,7 +13,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/query"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/scope"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/userstorage"
|
||||
)
|
||||
|
||||
@@ -31,7 +30,6 @@ func ProvideRegistryServiceSink(
|
||||
_ *datasource.DataSourceAPIBuilder,
|
||||
_ *folders.FolderAPIBuilder,
|
||||
_ *iam.IdentityAccessManagementAPIBuilder,
|
||||
_ *scope.ScopeAPIBuilder,
|
||||
_ *query.QueryAPIBuilder,
|
||||
_ *notifications.NotificationsAPIBuilder,
|
||||
_ *userstorage.UserStorageAPIBuilder,
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
package scope
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
|
||||
scope "github.com/grafana/grafana/pkg/apis/scope/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
)
|
||||
|
||||
var logger = log.New("find-scopenode")
|
||||
|
||||
type findREST struct {
|
||||
scopeNodeStorage *storage
|
||||
}
|
||||
|
||||
var (
|
||||
_ rest.Storage = (*findREST)(nil)
|
||||
_ rest.SingularNameProvider = (*findREST)(nil)
|
||||
_ rest.Connecter = (*findREST)(nil)
|
||||
_ rest.Scoper = (*findREST)(nil)
|
||||
_ rest.StorageMetadata = (*findREST)(nil)
|
||||
)
|
||||
|
||||
func (r *findREST) New() runtime.Object {
|
||||
// This is added as the "ResponseType" regarless what ProducesObject() says :)
|
||||
return &scope.FindScopeNodeChildrenResults{}
|
||||
}
|
||||
|
||||
func (r *findREST) Destroy() {}
|
||||
|
||||
func (r *findREST) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *findREST) GetSingularName() string {
|
||||
return "FindScopeNodeChildrenResults" // Used for the
|
||||
}
|
||||
|
||||
func (r *findREST) ProducesMIMETypes(verb string) []string {
|
||||
return []string{"application/json"} // and parquet!
|
||||
}
|
||||
|
||||
func (r *findREST) ProducesObject(verb string) interface{} {
|
||||
return &scope.FindScopeNodeChildrenResults{}
|
||||
}
|
||||
|
||||
func (r *findREST) ConnectMethods() []string {
|
||||
return []string{"GET"}
|
||||
}
|
||||
|
||||
func (r *findREST) NewConnectOptions() (runtime.Object, bool, string) {
|
||||
return nil, false, "" // true means you can use the trailing path as a variable
|
||||
}
|
||||
|
||||
func (r *findREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
|
||||
// See: /pkg/services/apiserver/builder/helper.go#L34
|
||||
// The name is set with a rewriter hack
|
||||
if name != "name" {
|
||||
return nil, errors.NewNotFound(schema.GroupResource{}, name)
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
parent := req.URL.Query().Get("parent")
|
||||
query := req.URL.Query().Get("query")
|
||||
results := &scope.FindScopeNodeChildrenResults{}
|
||||
|
||||
raw, err := r.scopeNodeStorage.List(ctx, &internalversion.ListOptions{
|
||||
Limit: 10000,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
responder.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
all, ok := raw.(*scope.ScopeNodeList)
|
||||
|
||||
if !ok {
|
||||
responder.Error(fmt.Errorf("expected ScopeNodeList"))
|
||||
return
|
||||
}
|
||||
|
||||
for _, item := range all.Items {
|
||||
filterAndAppendItem(item, parent, query, results)
|
||||
}
|
||||
|
||||
logger.FromContext(req.Context()).Debug("find scopenode", "raw", len(all.Items), "filtered", len(results.Items))
|
||||
|
||||
responder.Object(200, results)
|
||||
}), nil
|
||||
}
|
||||
|
||||
func filterAndAppendItem(item scope.ScopeNode, parent string, query string, results *scope.FindScopeNodeChildrenResults) {
|
||||
if parent != item.Spec.ParentName {
|
||||
return // Someday this will have an index in raw storage on parentName
|
||||
}
|
||||
|
||||
// skip if query is passed and title doesn't contain the query.
|
||||
if query != "" && !strings.Contains(item.Spec.Title, query) {
|
||||
return
|
||||
}
|
||||
|
||||
results.Items = append(results.Items, item)
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package scope
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
scope "github.com/grafana/grafana/pkg/apis/scope/v0alpha1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/internalversion"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
)
|
||||
|
||||
type findScopeDashboardsREST struct {
|
||||
scopeDashboardStorage *storage
|
||||
}
|
||||
|
||||
var (
|
||||
_ rest.Storage = (*findScopeDashboardsREST)(nil)
|
||||
_ rest.SingularNameProvider = (*findScopeDashboardsREST)(nil)
|
||||
_ rest.Connecter = (*findScopeDashboardsREST)(nil)
|
||||
_ rest.Scoper = (*findScopeDashboardsREST)(nil)
|
||||
_ rest.StorageMetadata = (*findScopeDashboardsREST)(nil)
|
||||
)
|
||||
|
||||
func (f *findScopeDashboardsREST) New() runtime.Object {
|
||||
return &scope.FindScopeDashboardBindingsResults{}
|
||||
}
|
||||
|
||||
func (f *findScopeDashboardsREST) Destroy() {}
|
||||
|
||||
func (f *findScopeDashboardsREST) NamespaceScoped() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *findScopeDashboardsREST) GetSingularName() string {
|
||||
return "FindScopeDashboardsResult" // not sure if this is actually used, but it is required to exist
|
||||
}
|
||||
|
||||
func (f *findScopeDashboardsREST) ProducesMIMETypes(verb string) []string {
|
||||
return []string{"application/json"} // and parquet!
|
||||
}
|
||||
|
||||
func (f *findScopeDashboardsREST) ProducesObject(verb string) interface{} {
|
||||
return &scope.FindScopeDashboardBindingsResults{}
|
||||
}
|
||||
|
||||
func (f *findScopeDashboardsREST) ConnectMethods() []string {
|
||||
return []string{"GET"}
|
||||
}
|
||||
|
||||
func (f *findScopeDashboardsREST) NewConnectOptions() (runtime.Object, bool, string) {
|
||||
return nil, false, "" // true means you can use the trailing path as a variable
|
||||
}
|
||||
|
||||
func (f *findScopeDashboardsREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
|
||||
// See: /pkg/services/apiserver/builder/helper.go#L34
|
||||
// The name is set with a rewriter hack
|
||||
if name != "name" {
|
||||
return nil, errors.NewNotFound(schema.GroupResource{}, name)
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
raw, err := f.scopeDashboardStorage.List(ctx, &internalversion.ListOptions{
|
||||
Limit: 10000,
|
||||
})
|
||||
if err != nil {
|
||||
w.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
all, ok := raw.(*scope.ScopeDashboardBindingList)
|
||||
if !ok {
|
||||
w.WriteHeader(500)
|
||||
return
|
||||
}
|
||||
|
||||
scopes := req.URL.Query()["scope"]
|
||||
results := &scope.FindScopeDashboardBindingsResults{
|
||||
Message: fmt.Sprintf("Find: %s", scopes),
|
||||
Items: make([]scope.ScopeDashboardBinding, 0),
|
||||
}
|
||||
|
||||
// we can improve the performance by calling .List once per scope if they are index by labels.
|
||||
// The API stays the same thou.
|
||||
for _, item := range all.Items {
|
||||
for _, s := range scopes {
|
||||
if item.Spec.Scope == s {
|
||||
results.Items = append(results.Items, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sort the dashboard lists based on dashboard title.
|
||||
slices.SortFunc(results.Items, func(i, j scope.ScopeDashboardBinding) int {
|
||||
return strings.Compare(i.Status.DashboardTitle, j.Status.DashboardTitle)
|
||||
})
|
||||
|
||||
logger.FromContext(req.Context()).Debug("find scopedashboardbinding", "raw", len(all.Items), "filtered", len(results.Items), "scopeQueryParams", strings.Join(scopes, ","))
|
||||
|
||||
responder.Object(200, results)
|
||||
}), nil
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package scope
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
scope "github.com/grafana/grafana/pkg/apis/scope/v0alpha1"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFilterAndAppendItem(t *testing.T) {
|
||||
tcs := []struct {
|
||||
Description string
|
||||
|
||||
ParentName string
|
||||
Title string
|
||||
|
||||
QueryParam string
|
||||
ParentParam string
|
||||
|
||||
ExpectedMatches int
|
||||
}{
|
||||
{
|
||||
Description: "Matching parent without query param",
|
||||
ParentName: "ParentNumberOne",
|
||||
Title: "item",
|
||||
QueryParam: "",
|
||||
ParentParam: "ParentNumberOne",
|
||||
ExpectedMatches: 1,
|
||||
},
|
||||
{
|
||||
Description: "Not matching parent",
|
||||
ParentName: "ParentNumberOne",
|
||||
Title: "itemOne",
|
||||
QueryParam: "itemTwo",
|
||||
ParentParam: "ParentNumberTwo",
|
||||
ExpectedMatches: 0,
|
||||
},
|
||||
{
|
||||
Description: "Matching parent and query param",
|
||||
ParentName: "ParentNumberOne",
|
||||
Title: "itemOne",
|
||||
QueryParam: "itemOne",
|
||||
ParentParam: "ParentNumberOne",
|
||||
ExpectedMatches: 1,
|
||||
},
|
||||
{
|
||||
Description: "matching parent but not matching query param",
|
||||
ParentName: "ParentNumberOne",
|
||||
Title: "itemOne",
|
||||
QueryParam: "itemTwo",
|
||||
ParentParam: "ParentNumberOne",
|
||||
ExpectedMatches: 0,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
results := &scope.FindScopeNodeChildrenResults{}
|
||||
item := scope.ScopeNode{
|
||||
Spec: scope.ScopeNodeSpec{
|
||||
ParentName: tc.ParentName,
|
||||
Title: tc.Title,
|
||||
Description: "item description",
|
||||
NodeType: "item type",
|
||||
LinkType: "item link type",
|
||||
LinkID: "item link ID",
|
||||
},
|
||||
}
|
||||
filterAndAppendItem(item, tc.ParentParam, tc.QueryParam, results)
|
||||
require.Equal(t, len(results.Items), tc.ExpectedMatches, tc.Description)
|
||||
}
|
||||
}
|
||||
@@ -1,224 +0,0 @@
|
||||
package scope
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
genericapiserver "k8s.io/apiserver/pkg/server"
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
||||
|
||||
scope "github.com/grafana/grafana/pkg/apis/scope/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/builder"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
)
|
||||
|
||||
var _ builder.APIGroupBuilder = (*ScopeAPIBuilder)(nil)
|
||||
|
||||
// This is used just so wire has something unique to return
|
||||
type ScopeAPIBuilder struct{}
|
||||
|
||||
func NewScopeAPIBuilder() *ScopeAPIBuilder {
|
||||
return &ScopeAPIBuilder{}
|
||||
}
|
||||
|
||||
func RegisterAPIService(features featuremgmt.FeatureToggles, apiregistration builder.APIRegistrar, reg prometheus.Registerer) *ScopeAPIBuilder {
|
||||
if !featuremgmt.AnyEnabled(features,
|
||||
featuremgmt.FlagScopeApi,
|
||||
featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs) {
|
||||
return nil // skip registration unless opting into experimental apis
|
||||
}
|
||||
builder := NewScopeAPIBuilder()
|
||||
apiregistration.RegisterAPI(builder)
|
||||
return builder
|
||||
}
|
||||
|
||||
func (b *ScopeAPIBuilder) GetAuthorizer() authorizer.Authorizer {
|
||||
return nil // default authorizer is fine
|
||||
}
|
||||
|
||||
func (b *ScopeAPIBuilder) GetGroupVersion() schema.GroupVersion {
|
||||
return scope.SchemeGroupVersion
|
||||
}
|
||||
|
||||
func (b *ScopeAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
|
||||
err := scope.AddToScheme(scheme)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = scheme.AddFieldLabelConversionFunc(
|
||||
scope.ScopeResourceInfo.GroupVersionKind(),
|
||||
func(label, value string) (string, string, error) {
|
||||
fieldSet := SelectableScopeFields(&scope.Scope{})
|
||||
for key := range fieldSet {
|
||||
if label == key {
|
||||
return label, value, nil
|
||||
}
|
||||
}
|
||||
return "", "", fmt.Errorf("field label not supported for %s: %s", scope.ScopeResourceInfo.GroupVersionKind(), label)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = scheme.AddFieldLabelConversionFunc(
|
||||
scope.ScopeDashboardBindingResourceInfo.GroupVersionKind(),
|
||||
func(label, value string) (string, string, error) {
|
||||
fieldSet := SelectableScopeDashboardBindingFields(&scope.ScopeDashboardBinding{})
|
||||
for key := range fieldSet {
|
||||
if label == key {
|
||||
return label, value, nil
|
||||
}
|
||||
}
|
||||
return "", "", fmt.Errorf("field label not supported for %s: %s", scope.ScopeDashboardBindingResourceInfo.GroupVersionKind(), label)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = scheme.AddFieldLabelConversionFunc(
|
||||
scope.ScopeNodeResourceInfo.GroupVersionKind(),
|
||||
func(label, value string) (string, string, error) {
|
||||
fieldSet := SelectableScopeNodeFields(&scope.ScopeNode{})
|
||||
for key := range fieldSet {
|
||||
if label == key {
|
||||
return label, value, nil
|
||||
}
|
||||
}
|
||||
return "", "", fmt.Errorf("field label not supported for %s: %s", scope.ScopeNodeResourceInfo.GroupVersionKind(), label)
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// This is required for --server-side apply
|
||||
err = scope.AddKnownTypes(scope.InternalGroupVersion, scheme)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Only one version right now
|
||||
return scheme.SetVersionPriority(scope.SchemeGroupVersion)
|
||||
}
|
||||
|
||||
func (b *ScopeAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, opts builder.APIGroupOptions) error {
|
||||
scheme := opts.Scheme
|
||||
optsGetter := opts.OptsGetter
|
||||
|
||||
scopeResourceInfo := scope.ScopeResourceInfo
|
||||
scopeDashboardResourceInfo := scope.ScopeDashboardBindingResourceInfo
|
||||
scopeNodeResourceInfo := scope.ScopeNodeResourceInfo
|
||||
|
||||
storage := map[string]rest.Storage{}
|
||||
|
||||
scopeStorage, err := newScopeStorage(scheme, optsGetter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
storage[scopeResourceInfo.StoragePath()] = scopeStorage
|
||||
|
||||
scopeDashboardStorage, scopedDashboardStatusStorage, err := newScopeDashboardBindingStorage(scheme, optsGetter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
storage[scopeDashboardResourceInfo.StoragePath()] = scopeDashboardStorage
|
||||
storage[scopeDashboardResourceInfo.StoragePath()+"/status"] = scopedDashboardStatusStorage
|
||||
|
||||
scopeNodeStorage, err := newScopeNodeStorage(scheme, optsGetter)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
storage[scopeNodeResourceInfo.StoragePath()] = scopeNodeStorage
|
||||
|
||||
// Adds a rest.Connector
|
||||
// NOTE! the server has a hardcoded rewrite filter that fills in a name
|
||||
// so the standard k8s plumbing continues to work
|
||||
storage["scope_node_children"] = &findREST{scopeNodeStorage: scopeNodeStorage}
|
||||
|
||||
// Adds a rest.Connector
|
||||
// NOTE! the server has a hardcoded rewrite filter that fills in a name
|
||||
// so the standard k8s plumbing continues to work
|
||||
storage["scope_dashboard_bindings"] = &findScopeDashboardsREST{scopeDashboardStorage: scopeDashboardStorage}
|
||||
|
||||
apiGroupInfo.VersionedResourcesStorageMap[scope.VERSION] = storage
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *ScopeAPIBuilder) GetOpenAPIDefinitions() common.GetOpenAPIDefinitions {
|
||||
return scope.GetOpenAPIDefinitions
|
||||
}
|
||||
|
||||
func (b *ScopeAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.OpenAPI, error) {
|
||||
// The plugin description
|
||||
oas.Info.Description = "Grafana scopes"
|
||||
|
||||
// The root api URL
|
||||
root := "/apis/" + b.GetGroupVersion().String() + "/"
|
||||
|
||||
// Add query parameters to the rest.Connector
|
||||
sub := oas.Paths.Paths[root+"namespaces/{namespace}/scope_node_children/{name}"]
|
||||
if sub != nil && sub.Get != nil {
|
||||
sub.Parameters = []*spec3.Parameter{
|
||||
{
|
||||
ParameterProps: spec3.ParameterProps{
|
||||
Name: "namespace",
|
||||
In: "path",
|
||||
Description: "object name and auth scope, such as for teams and projects",
|
||||
Example: "default",
|
||||
Required: true,
|
||||
Schema: spec.StringProperty().UniqueValues(),
|
||||
},
|
||||
},
|
||||
}
|
||||
sub.Get.Description = "Navigate the scopes tree"
|
||||
sub.Get.Parameters = []*spec3.Parameter{
|
||||
{
|
||||
ParameterProps: spec3.ParameterProps{
|
||||
Name: "parent",
|
||||
In: "query",
|
||||
Description: "The parent scope node",
|
||||
},
|
||||
},
|
||||
}
|
||||
delete(oas.Paths.Paths, root+"namespaces/{namespace}/scope_node_children/{name}")
|
||||
oas.Paths.Paths[root+"namespaces/{namespace}/find/scope_node_children"] = sub
|
||||
}
|
||||
|
||||
findDashboardPath := oas.Paths.Paths[root+"namespaces/{namespace}/scope_dashboard_bindings/{name}"]
|
||||
if findDashboardPath != nil && sub.Get != nil {
|
||||
sub.Parameters = []*spec3.Parameter{
|
||||
{
|
||||
ParameterProps: spec3.ParameterProps{
|
||||
Name: "namespace",
|
||||
In: "path",
|
||||
Description: "object name and auth scope, such as for teams and projects",
|
||||
Example: "default",
|
||||
Required: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
findDashboardPath.Get.Description = "find scope dashboard bindings that match any of the given scopes."
|
||||
findDashboardPath.Get.Parameters = []*spec3.Parameter{
|
||||
{
|
||||
ParameterProps: spec3.ParameterProps{
|
||||
Name: "scope",
|
||||
In: "query",
|
||||
Description: "A scope name (id) to match against, this parameter may be repeated",
|
||||
},
|
||||
},
|
||||
}
|
||||
delete(oas.Paths.Paths, root+"namespaces/{namespace}/scope_dashboard_bindings/{name}")
|
||||
oas.Paths.Paths[root+"namespaces/{namespace}/find/scope_dashboard_bindings"] = findDashboardPath
|
||||
}
|
||||
|
||||
return oas, nil
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
package scope
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/registry/generic"
|
||||
genericregistry "k8s.io/apiserver/pkg/registry/generic/registry"
|
||||
apistore "k8s.io/apiserver/pkg/storage"
|
||||
|
||||
scope "github.com/grafana/grafana/pkg/apis/scope/v0alpha1"
|
||||
grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic"
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
)
|
||||
|
||||
var _ grafanarest.Storage = (*storage)(nil)
|
||||
|
||||
type storage struct {
|
||||
*genericregistry.Store
|
||||
}
|
||||
|
||||
func newScopeStorage(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) (*storage, error) {
|
||||
resourceInfo := scope.ScopeResourceInfo
|
||||
strategy := grafanaregistry.NewStrategy(scheme, resourceInfo.GroupVersion())
|
||||
store := &genericregistry.Store{
|
||||
NewFunc: resourceInfo.NewFunc,
|
||||
NewListFunc: resourceInfo.NewListFunc,
|
||||
KeyRootFunc: grafanaregistry.KeyRootFunc(resourceInfo.GroupResource()),
|
||||
KeyFunc: grafanaregistry.NamespaceKeyFunc(resourceInfo.GroupResource()),
|
||||
PredicateFunc: Matcher,
|
||||
DefaultQualifiedResource: resourceInfo.GroupResource(),
|
||||
SingularQualifiedResource: resourceInfo.SingularGroupResource(),
|
||||
TableConvertor: resourceInfo.TableConverter(),
|
||||
CreateStrategy: strategy,
|
||||
UpdateStrategy: strategy,
|
||||
DeleteStrategy: strategy,
|
||||
}
|
||||
options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: GetAttrs}
|
||||
if err := store.CompleteWithOptions(options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &storage{Store: store}, nil
|
||||
}
|
||||
|
||||
func newScopeDashboardBindingStorage(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) (*storage, *grafanaregistry.StatusREST, error) {
|
||||
resourceInfo := scope.ScopeDashboardBindingResourceInfo
|
||||
strategy := grafanaregistry.NewStrategy(scheme, resourceInfo.GroupVersion())
|
||||
|
||||
store := &genericregistry.Store{
|
||||
NewFunc: resourceInfo.NewFunc,
|
||||
NewListFunc: resourceInfo.NewListFunc,
|
||||
KeyRootFunc: grafanaregistry.KeyRootFunc(resourceInfo.GroupResource()),
|
||||
KeyFunc: grafanaregistry.NamespaceKeyFunc(resourceInfo.GroupResource()),
|
||||
PredicateFunc: Matcher,
|
||||
DefaultQualifiedResource: resourceInfo.GroupResource(),
|
||||
SingularQualifiedResource: resourceInfo.SingularGroupResource(),
|
||||
TableConvertor: resourceInfo.TableConverter(),
|
||||
CreateStrategy: strategy,
|
||||
UpdateStrategy: strategy,
|
||||
DeleteStrategy: strategy,
|
||||
}
|
||||
options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: GetAttrs}
|
||||
if err := store.CompleteWithOptions(options); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
statusStrategy := grafanaregistry.NewStatusStrategy(scheme, resourceInfo.GroupVersion())
|
||||
statusREST := grafanaregistry.NewStatusREST(store, statusStrategy)
|
||||
return &storage{Store: store}, statusREST, nil
|
||||
}
|
||||
|
||||
func newScopeNodeStorage(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) (*storage, error) {
|
||||
resourceInfo := scope.ScopeNodeResourceInfo
|
||||
strategy := grafanaregistry.NewStrategy(scheme, resourceInfo.GroupVersion())
|
||||
|
||||
store := &genericregistry.Store{
|
||||
NewFunc: resourceInfo.NewFunc,
|
||||
NewListFunc: resourceInfo.NewListFunc,
|
||||
KeyRootFunc: grafanaregistry.KeyRootFunc(resourceInfo.GroupResource()),
|
||||
KeyFunc: grafanaregistry.NamespaceKeyFunc(resourceInfo.GroupResource()),
|
||||
PredicateFunc: Matcher,
|
||||
DefaultQualifiedResource: resourceInfo.GroupResource(),
|
||||
SingularQualifiedResource: resourceInfo.SingularGroupResource(),
|
||||
TableConvertor: resourceInfo.TableConverter(),
|
||||
CreateStrategy: strategy,
|
||||
UpdateStrategy: strategy,
|
||||
DeleteStrategy: strategy,
|
||||
}
|
||||
options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: GetAttrs}
|
||||
if err := store.CompleteWithOptions(options); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &storage{Store: store}, nil
|
||||
}
|
||||
|
||||
func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
|
||||
if s, ok := obj.(*scope.Scope); ok {
|
||||
return labels.Set(s.Labels), SelectableScopeFields(s), nil
|
||||
}
|
||||
if s, ok := obj.(*scope.ScopeDashboardBinding); ok {
|
||||
return labels.Set(s.Labels), SelectableScopeDashboardBindingFields(s), nil
|
||||
}
|
||||
if s, ok := obj.(*scope.ScopeNode); ok {
|
||||
return labels.Set(s.Labels), SelectableScopeNodeFields(s), nil
|
||||
}
|
||||
return nil, nil, fmt.Errorf("not a scope or ScopeDashboardBinding object")
|
||||
}
|
||||
|
||||
// Matcher returns a generic.SelectionPredicate that matches on label and field selectors.
|
||||
func Matcher(label labels.Selector, field fields.Selector) apistore.SelectionPredicate {
|
||||
return apistore.SelectionPredicate{
|
||||
Label: label,
|
||||
Field: field,
|
||||
GetAttrs: GetAttrs,
|
||||
}
|
||||
}
|
||||
|
||||
func SelectableScopeFields(obj *scope.Scope) fields.Set {
|
||||
return generic.MergeFieldsSets(generic.ObjectMetaFieldsSet(&obj.ObjectMeta, false), fields.Set{
|
||||
"spec.title": obj.Spec.Title,
|
||||
})
|
||||
}
|
||||
|
||||
func SelectableScopeDashboardBindingFields(obj *scope.ScopeDashboardBinding) fields.Set {
|
||||
return generic.MergeFieldsSets(generic.ObjectMetaFieldsSet(&obj.ObjectMeta, false), fields.Set{
|
||||
"spec.scope": obj.Spec.Scope,
|
||||
})
|
||||
}
|
||||
|
||||
func SelectableScopeNodeFields(obj *scope.ScopeNode) fields.Set {
|
||||
parentName := ""
|
||||
|
||||
if obj != nil {
|
||||
parentName = obj.Spec.ParentName
|
||||
}
|
||||
|
||||
return generic.MergeFieldsSets(generic.ObjectMetaFieldsSet(&obj.ObjectMeta, false), fields.Set{
|
||||
"spec.parentName": parentName,
|
||||
})
|
||||
}
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/registry/apis/iam"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/provisioning"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/query"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/scope"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/service"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/userstorage"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/plugincontext"
|
||||
@@ -42,7 +41,6 @@ var WireSet = wire.NewSet(
|
||||
provisioning.RegisterAPIService,
|
||||
service.RegisterAPIService,
|
||||
query.RegisterAPIService,
|
||||
scope.RegisterAPIService,
|
||||
notifications.RegisterAPIService,
|
||||
userstorage.RegisterAPIService,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user