The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/registry/apis/scope/register.go

224 lines
7.0 KiB

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
}