Datasources: Add service function to get by group, name, and namespace (#113066)

This commit is contained in:
Stephanie Hingtgen
2025-10-28 16:43:03 +00:00
committed by GitHub
parent 147ff4279b
commit 6a3dfacc95
6 changed files with 111 additions and 0 deletions
+3
View File
@@ -15,6 +15,9 @@ type DataSourceService interface {
// GetDataSource gets a datasource.
GetDataSource(ctx context.Context, query *GetDataSourceQuery) (*DataSource, error)
// GetDataSourceInNamespace gets a datasource by namespace, name (datasource uid), and group (datasource type).
GetDataSourceInNamespace(ctx context.Context, namespace, name, group string) (*DataSource, error)
// GetDataSources gets datasources.
GetDataSources(ctx context.Context, query *GetDataSourcesQuery) ([]*DataSource, error)
@@ -4,6 +4,7 @@ import (
"context"
"net/http"
"github.com/grafana/authlib/types"
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana/pkg/infra/httpclient"
@@ -30,6 +31,19 @@ func (s *FakeDataSourceService) GetDataSource(ctx context.Context, query *dataso
return nil, datasources.ErrDataSourceNotFound
}
func (s *FakeDataSourceService) GetDataSourceInNamespace(ctx context.Context, namespace, name, group string) (*datasources.DataSource, error) {
ns, err := types.ParseNamespace(namespace)
if err != nil {
return nil, err
}
for _, dataSource := range s.DataSources {
if name == dataSource.UID && ns.OrgID == dataSource.OrgID && group == dataSource.Type {
return dataSource, nil
}
}
return nil, datasources.ErrDataSourceNotFound
}
func (s *FakeDataSourceService) GetDataSources(ctx context.Context, query *datasources.GetDataSourcesQuery) ([]*datasources.DataSource, error) {
var dataSources []*datasources.DataSource
for _, datasource := range s.DataSources {
@@ -117,6 +117,8 @@ func (s *Service) Usage(ctx context.Context, scopeParams *quota.ScopeParameters)
type DataSourceRetriever interface {
// GetDataSource gets a datasource.
GetDataSource(ctx context.Context, query *datasources.GetDataSourceQuery) (*datasources.DataSource, error)
// GetDataSourceInNamespace gets a datasource by namespace, name (datasource uid), and group (datasource type).
GetDataSourceInNamespace(ctx context.Context, namespace, name, group string) (*datasources.DataSource, error)
}
// NewNameScopeResolver provides an ScopeAttributeResolver able to
@@ -176,6 +178,10 @@ func (s *Service) GetDataSource(ctx context.Context, query *datasources.GetDataS
return s.SQLStore.GetDataSource(ctx, query)
}
func (s *Service) GetDataSourceInNamespace(ctx context.Context, namespace, name, group string) (*datasources.DataSource, error) {
return s.SQLStore.GetDataSourceInNamespace(ctx, namespace, name, group)
}
func (s *Service) GetDataSources(ctx context.Context, query *datasources.GetDataSourcesQuery) ([]*datasources.DataSource, error) {
return s.SQLStore.GetDataSources(ctx, query)
}
@@ -17,6 +17,7 @@ import (
"github.com/stretchr/testify/require"
"gopkg.in/ini.v1"
"github.com/grafana/authlib/types"
"github.com/grafana/grafana-plugin-sdk-go/backend"
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana/pkg/components/simplejson"
@@ -63,6 +64,19 @@ func (d *dataSourceMockRetriever) GetDataSource(ctx context.Context, query *data
return nil, datasources.ErrDataSourceNotFound
}
func (d *dataSourceMockRetriever) GetDataSourceInNamespace(ctx context.Context, namespace, name, group string) (*datasources.DataSource, error) {
ns, err := types.ParseNamespace(namespace)
if err != nil {
return nil, err
}
for _, dataSource := range d.res {
if name == dataSource.UID && ns.OrgID == dataSource.OrgID && group == dataSource.Type {
return dataSource, nil
}
}
return nil, datasources.ErrDataSourceNotFound
}
func TestIntegrationService_AddDataSource(t *testing.T) {
testutil.SkipIntegrationTestInShortMode(t)
+37
View File
@@ -7,6 +7,7 @@ import (
"strings"
"time"
"github.com/grafana/authlib/types"
"github.com/grafana/grafana/pkg/util/xorm"
"github.com/grafana/grafana/pkg/components/simplejson"
@@ -24,6 +25,7 @@ import (
// Store is the interface for the datasource Service's storage.
type Store interface {
GetDataSource(context.Context, *datasources.GetDataSourceQuery) (*datasources.DataSource, error)
GetDataSourceInNamespace(context.Context, string, string, string) (*datasources.DataSource, error)
GetDataSources(context.Context, *datasources.GetDataSourcesQuery) ([]*datasources.DataSource, error)
GetDataSourcesByType(context.Context, *datasources.GetDataSourcesByTypeQuery) ([]*datasources.DataSource, error)
DeleteDataSource(context.Context, *datasources.DeleteDataSourceCommand) error
@@ -90,6 +92,41 @@ func (ss *SqlStore) getDataSource(_ context.Context, query *datasources.GetDataS
return datasource, nil
}
func (ss *SqlStore) GetDataSourceInNamespace(ctx context.Context, namespace, name, group string) (*datasources.DataSource, error) {
var (
dataSource *datasources.DataSource
err error
)
ns, err := types.ParseNamespace(namespace)
if err != nil {
return nil, err
}
return dataSource, ss.db.WithDbSession(ctx, func(sess *db.Session) error {
dataSource, err = ss.getDataSourceInGroup(ctx, ns.OrgID, name, group, sess)
return err
})
}
func (ss *SqlStore) getDataSourceInGroup(_ context.Context, orgID int64, name, group string, sess *db.Session) (*datasources.DataSource, error) {
datasource := &datasources.DataSource{
OrgID: orgID,
Type: group,
UID: name,
}
has, err := sess.Get(datasource)
if err != nil {
ss.logger.Error("Failed getting data source", "err", err, "name", name, "orgId", orgID, "group", group)
return nil, err
} else if !has {
ss.logger.Debug("Data source not found", "name", name, "orgId", orgID, "group", group)
return nil, datasources.ErrDataSourceNotFound
}
return datasource, nil
}
func (ss *SqlStore) GetDataSources(ctx context.Context, query *datasources.GetDataSourcesQuery) ([]*datasources.DataSource, error) {
var (
sess *xorm.Session
@@ -407,6 +407,43 @@ func TestIntegrationDataAccess(t *testing.T) {
})
})
t.Run("GetDataSourceInGroup", func(t *testing.T) {
t.Run("Only returns datasource of specified type", func(t *testing.T) {
db := db.InitTestDB(t)
ss := SqlStore{db: db, logger: log.NewNopLogger()}
ds, err := ss.AddDataSource(context.Background(), &datasources.AddDataSourceCommand{
OrgID: 10,
Name: "Elasticsearch",
Type: datasources.DS_ES,
Access: datasources.DS_ACCESS_DIRECT,
URL: "http://test",
Database: "site",
ReadOnly: true,
})
require.NoError(t, err)
ds2, err := ss.AddDataSource(context.Background(), &datasources.AddDataSourceCommand{
OrgID: 10,
Name: "Graphite",
Type: datasources.DS_GRAPHITE,
Access: datasources.DS_ACCESS_DIRECT,
URL: "http://test",
Database: "site",
ReadOnly: true,
})
require.NoError(t, err)
dataSource, err := ss.GetDataSourceInNamespace(context.Background(), "org-10", ds.UID, datasources.DS_ES)
require.NoError(t, err)
require.Equal(t, ds.UID, dataSource.UID)
_, err = ss.GetDataSourceInNamespace(context.Background(), "org-10", ds2.UID, datasources.DS_ES)
require.Error(t, err)
require.IsType(t, datasources.ErrDataSourceNotFound, err)
})
})
t.Run("GetDataSourcesByType", func(t *testing.T) {
t.Run("Only returns datasources of specified type", func(t *testing.T) {
db := db.InitTestDB(t)