mirror of https://github.com/grafana/grafana.git
				
				
				
			
		
			
	
	
		
			162 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
		
		
			
		
	
	
			162 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
| 
								 | 
							
								package query
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"context"
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									"k8s.io/apimachinery/pkg/apis/meta/internalversion"
							 | 
						||
| 
								 | 
							
									metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
							 | 
						||
| 
								 | 
							
									"k8s.io/apimachinery/pkg/runtime"
							 | 
						||
| 
								 | 
							
									"k8s.io/apiserver/pkg/endpoints/request"
							 | 
						||
| 
								 | 
							
									"k8s.io/apiserver/pkg/registry/rest"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									authlib "github.com/grafana/authlib/types"
							 | 
						||
| 
								 | 
							
									"github.com/grafana/grafana/pkg/apimachinery/utils"
							 | 
						||
| 
								 | 
							
									queryV0 "github.com/grafana/grafana/pkg/apis/query/v0alpha1"
							 | 
						||
| 
								 | 
							
									gapiutil "github.com/grafana/grafana/pkg/services/apiserver/utils"
							 | 
						||
| 
								 | 
							
									"github.com/grafana/grafana/pkg/services/datasources"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var (
							 | 
						||
| 
								 | 
							
									_ rest.Scoper               = (*connectionAccess)(nil)
							 | 
						||
| 
								 | 
							
									_ rest.SingularNameProvider = (*connectionAccess)(nil)
							 | 
						||
| 
								 | 
							
									_ rest.Getter               = (*connectionAccess)(nil)
							 | 
						||
| 
								 | 
							
									_ rest.Lister               = (*connectionAccess)(nil)
							 | 
						||
| 
								 | 
							
									_ rest.Storage              = (*connectionAccess)(nil)
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Get all datasource connections -- this will be backed by search or duplicated resource in unified storage
							 | 
						||
| 
								 | 
							
								type DataSourceConnectionProvider interface {
							 | 
						||
| 
								 | 
							
									// Get gets a specific datasource (that the user in context can see)
							 | 
						||
| 
								 | 
							
									// The name is {group}:{name}, see /pkg/apis/query/v0alpha1/connection.go#L34
							 | 
						||
| 
								 | 
							
									GetConnection(ctx context.Context, namespace string, name string) (*queryV0.DataSourceConnection, error)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// List lists all data sources the user in context can see
							 | 
						||
| 
								 | 
							
									ListConnections(ctx context.Context, namespace string) (*queryV0.DataSourceConnectionList, error)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type connectionAccess struct {
							 | 
						||
| 
								 | 
							
									tableConverter rest.TableConvertor
							 | 
						||
| 
								 | 
							
									connections    DataSourceConnectionProvider
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (s *connectionAccess) New() runtime.Object {
							 | 
						||
| 
								 | 
							
									return queryV0.ConnectionResourceInfo.NewFunc()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (s *connectionAccess) Destroy() {}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (s *connectionAccess) NamespaceScoped() bool {
							 | 
						||
| 
								 | 
							
									return true
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (s *connectionAccess) GetSingularName() string {
							 | 
						||
| 
								 | 
							
									return queryV0.ConnectionResourceInfo.GetSingularName()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (s *connectionAccess) ShortNames() []string {
							 | 
						||
| 
								 | 
							
									return queryV0.ConnectionResourceInfo.GetShortNames()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (s *connectionAccess) NewList() runtime.Object {
							 | 
						||
| 
								 | 
							
									return queryV0.ConnectionResourceInfo.NewListFunc()
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (s *connectionAccess) ConvertToTable(ctx context.Context, object runtime.Object, tableOptions runtime.Object) (*metav1.Table, error) {
							 | 
						||
| 
								 | 
							
									if s.tableConverter == nil {
							 | 
						||
| 
								 | 
							
										s.tableConverter = queryV0.ConnectionResourceInfo.TableConverter()
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return s.tableConverter.ConvertToTable(ctx, object, tableOptions)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (s *connectionAccess) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) {
							 | 
						||
| 
								 | 
							
									return s.connections.GetConnection(ctx, request.NamespaceValue(ctx), name)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (s *connectionAccess) List(ctx context.Context, options *internalversion.ListOptions) (runtime.Object, error) {
							 | 
						||
| 
								 | 
							
									return s.connections.ListConnections(ctx, request.NamespaceValue(ctx))
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type connectionsProvider struct {
							 | 
						||
| 
								 | 
							
									dsService datasources.DataSourceService
							 | 
						||
| 
								 | 
							
									registry  queryV0.DataSourceApiServerRegistry
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var (
							 | 
						||
| 
								 | 
							
									_ DataSourceConnectionProvider = (*connectionsProvider)(nil)
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (q *connectionsProvider) GetConnection(ctx context.Context, namespace string, name string) (*queryV0.DataSourceConnection, error) {
							 | 
						||
| 
								 | 
							
									info, err := authlib.ParseNamespace(namespace)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									ds, err := q.dsService.GetDataSource(ctx, &datasources.GetDataSourceQuery{
							 | 
						||
| 
								 | 
							
										UID:   name,
							 | 
						||
| 
								 | 
							
										OrgID: info.OrgID,
							 | 
						||
| 
								 | 
							
									})
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// TODO... access control?
							 | 
						||
| 
								 | 
							
									return q.asConnection(ds, namespace)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (q *connectionsProvider) ListConnections(ctx context.Context, namespace string) (*queryV0.DataSourceConnectionList, error) {
							 | 
						||
| 
								 | 
							
									ns, err := authlib.ParseNamespace(namespace)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									dss, err := q.dsService.GetDataSources(ctx, &datasources.GetDataSourcesQuery{
							 | 
						||
| 
								 | 
							
										OrgID:           ns.OrgID,
							 | 
						||
| 
								 | 
							
										DataSourceLimit: 10000,
							 | 
						||
| 
								 | 
							
									})
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, err
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									result := &queryV0.DataSourceConnectionList{
							 | 
						||
| 
								 | 
							
										Items: []queryV0.DataSourceConnection{},
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									for _, ds := range dss {
							 | 
						||
| 
								 | 
							
										v, err := q.asConnection(ds, namespace)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											return nil, err
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										result.Items = append(result.Items, *v)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return result, nil
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (q *connectionsProvider) asConnection(ds *datasources.DataSource, ns string) (v *queryV0.DataSourceConnection, err error) {
							 | 
						||
| 
								 | 
							
									gv, err := q.registry.GetDatasourceGroupVersion(ds.Type)
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										return nil, fmt.Errorf("datasource type %q does not map to an apiserver %w", ds.Type, err)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									v = &queryV0.DataSourceConnection{
							 | 
						||
| 
								 | 
							
										ObjectMeta: metav1.ObjectMeta{
							 | 
						||
| 
								 | 
							
											Name:              queryV0.DataSourceConnectionName(gv.Group, ds.UID),
							 | 
						||
| 
								 | 
							
											Namespace:         ns,
							 | 
						||
| 
								 | 
							
											CreationTimestamp: metav1.NewTime(ds.Created),
							 | 
						||
| 
								 | 
							
											ResourceVersion:   fmt.Sprintf("%d", ds.Updated.UnixMilli()),
							 | 
						||
| 
								 | 
							
											Generation:        int64(ds.Version),
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
										Title: ds.Name,
							 | 
						||
| 
								 | 
							
										Datasource: queryV0.DataSourceConnectionRef{
							 | 
						||
| 
								 | 
							
											Group:   gv.Group,
							 | 
						||
| 
								 | 
							
											Version: gv.Version,
							 | 
						||
| 
								 | 
							
											Name:    ds.UID,
							 | 
						||
| 
								 | 
							
										},
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									v.UID = gapiutil.CalculateClusterWideUID(v) // UID is unique across all groups
							 | 
						||
| 
								 | 
							
									if !ds.Updated.IsZero() {
							 | 
						||
| 
								 | 
							
										meta, err := utils.MetaAccessor(v)
							 | 
						||
| 
								 | 
							
										if err != nil {
							 | 
						||
| 
								 | 
							
											meta.SetUpdatedTimestamp(&ds.Updated)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return v, err
							 | 
						||
| 
								 | 
							
								}
							 |