backend/datasources: move datasources models into the datasources service package (#51267)

* backend/datasources: move datasources models into the datasources service pkg
This commit is contained in:
Kristin Laemmert
2022-06-27 12:23:15 -04:00
committed by GitHub
parent 78c012df65
commit 945f015770
77 changed files with 728 additions and 660 deletions
+15 -14
View File
@@ -5,6 +5,7 @@ import (
"net/http"
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana/pkg/infra/httpclient"
"github.com/grafana/grafana/pkg/models"
)
@@ -12,51 +13,51 @@ import (
// DataSourceService interface for interacting with datasources.
type DataSourceService interface {
// GetDataSource gets a datasource.
GetDataSource(ctx context.Context, query *models.GetDataSourceQuery) error
GetDataSource(ctx context.Context, query *GetDataSourceQuery) error
// GetDataSources gets datasources.
GetDataSources(ctx context.Context, query *models.GetDataSourcesQuery) error
GetDataSources(ctx context.Context, query *GetDataSourcesQuery) error
// GetDataSourcesByType gets datasources by type.
GetDataSourcesByType(ctx context.Context, query *models.GetDataSourcesByTypeQuery) error
GetDataSourcesByType(ctx context.Context, query *GetDataSourcesByTypeQuery) error
// AddDataSource adds a new datasource.
AddDataSource(ctx context.Context, cmd *models.AddDataSourceCommand) error
AddDataSource(ctx context.Context, cmd *AddDataSourceCommand) error
// DeleteDataSource deletes an existing datasource.
DeleteDataSource(ctx context.Context, cmd *models.DeleteDataSourceCommand) error
DeleteDataSource(ctx context.Context, cmd *DeleteDataSourceCommand) error
// UpdateDataSource updates an existing datasource.
UpdateDataSource(ctx context.Context, cmd *models.UpdateDataSourceCommand) error
UpdateDataSource(ctx context.Context, cmd *UpdateDataSourceCommand) error
// GetDefaultDataSource gets the default datasource.
GetDefaultDataSource(ctx context.Context, query *models.GetDefaultDataSourceQuery) error
GetDefaultDataSource(ctx context.Context, query *GetDefaultDataSourceQuery) error
// GetHTTPTransport gets a datasource specific HTTP transport.
GetHTTPTransport(ctx context.Context, ds *models.DataSource, provider httpclient.Provider, customMiddlewares ...sdkhttpclient.Middleware) (http.RoundTripper, error)
GetHTTPTransport(ctx context.Context, ds *DataSource, provider httpclient.Provider, customMiddlewares ...sdkhttpclient.Middleware) (http.RoundTripper, error)
// DecryptedValues decrypts the encrypted secureJSONData of the provided datasource and
// returns the decrypted values.
DecryptedValues(ctx context.Context, ds *models.DataSource) (map[string]string, error)
DecryptedValues(ctx context.Context, ds *DataSource) (map[string]string, error)
// DecryptedValue decrypts the encrypted datasource secureJSONData identified by key
// and returns the decrypted value.
DecryptedValue(ctx context.Context, ds *models.DataSource, key string) (string, bool, error)
DecryptedValue(ctx context.Context, ds *DataSource, key string) (string, bool, error)
// DecryptedBasicAuthPassword decrypts the encrypted datasource basic authentication
// password and returns the decrypted value.
DecryptedBasicAuthPassword(ctx context.Context, ds *models.DataSource) (string, error)
DecryptedBasicAuthPassword(ctx context.Context, ds *DataSource) (string, error)
// DecryptedPassword decrypts the encrypted datasource password and returns the
// decrypted value.
DecryptedPassword(ctx context.Context, ds *models.DataSource) (string, error)
DecryptedPassword(ctx context.Context, ds *DataSource) (string, error)
}
// CacheService interface for retrieving a cached datasource.
type CacheService interface {
// GetDatasource gets a datasource identified by datasource numeric identifier.
GetDatasource(ctx context.Context, datasourceID int64, user *models.SignedInUser, skipCache bool) (*models.DataSource, error)
GetDatasource(ctx context.Context, datasourceID int64, user *models.SignedInUser, skipCache bool) (*DataSource, error)
// GetDatasourceByUID gets a datasource identified by datasource unique identifier (UID).
GetDatasourceByUID(ctx context.Context, datasourceUID string, user *models.SignedInUser, skipCache bool) (*models.DataSource, error)
GetDatasourceByUID(ctx context.Context, datasourceUID string, user *models.SignedInUser, skipCache bool) (*DataSource, error)
}
+13
View File
@@ -0,0 +1,13 @@
package datasources
import "errors"
var (
ErrDataSourceNotFound = errors.New("data source not found")
ErrDataSourceNameExists = errors.New("data source with the same name already exists")
ErrDataSourceUidExists = errors.New("data source with the same uid already exists")
ErrDataSourceUpdatingOldVersion = errors.New("trying to update old version of datasource")
ErrDataSourceAccessDenied = errors.New("data source access denied")
ErrDataSourceFailedGenerateUniqueUid = errors.New("failed to generate unique datasource ID")
ErrDataSourceIdentifierNotSet = errors.New("unique identifier and org id are needed to be able to get or delete a datasource")
)
@@ -8,25 +8,25 @@ import (
)
type FakeCacheService struct {
DataSources []*models.DataSource
DataSources []*datasources.DataSource
}
var _ datasources.CacheService = &FakeCacheService{}
func (c *FakeCacheService) GetDatasource(ctx context.Context, datasourceID int64, user *models.SignedInUser, skipCache bool) (*models.DataSource, error) {
func (c *FakeCacheService) GetDatasource(ctx context.Context, datasourceID int64, user *models.SignedInUser, skipCache bool) (*datasources.DataSource, error) {
for _, datasource := range c.DataSources {
if datasource.Id == datasourceID {
return datasource, nil
}
}
return nil, models.ErrDataSourceNotFound
return nil, datasources.ErrDataSourceNotFound
}
func (c *FakeCacheService) GetDatasourceByUID(ctx context.Context, datasourceUID string, user *models.SignedInUser, skipCache bool) (*models.DataSource, error) {
func (c *FakeCacheService) GetDatasourceByUID(ctx context.Context, datasourceUID string, user *models.SignedInUser, skipCache bool) (*datasources.DataSource, error) {
for _, datasource := range c.DataSources {
if datasource.Uid == datasourceUID {
return datasource, nil
}
}
return nil, models.ErrDataSourceNotFound
return nil, datasources.ErrDataSourceNotFound
}
@@ -5,19 +5,19 @@ import (
"net/http"
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana/pkg/infra/httpclient"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/datasources"
)
type FakeDataSourceService struct {
lastId int64
DataSources []*models.DataSource
DataSources []*datasources.DataSource
}
var _ datasources.DataSourceService = &FakeDataSourceService{}
func (s *FakeDataSourceService) GetDataSource(ctx context.Context, query *models.GetDataSourceQuery) error {
func (s *FakeDataSourceService) GetDataSource(ctx context.Context, query *datasources.GetDataSourceQuery) error {
for _, datasource := range s.DataSources {
idMatch := query.Id != 0 && query.Id == datasource.Id
uidMatch := query.Uid != "" && query.Uid == datasource.Uid
@@ -28,10 +28,10 @@ func (s *FakeDataSourceService) GetDataSource(ctx context.Context, query *models
return nil
}
}
return models.ErrDataSourceNotFound
return datasources.ErrDataSourceNotFound
}
func (s *FakeDataSourceService) GetDataSources(ctx context.Context, query *models.GetDataSourcesQuery) error {
func (s *FakeDataSourceService) GetDataSources(ctx context.Context, query *datasources.GetDataSourcesQuery) error {
for _, datasource := range s.DataSources {
orgMatch := query.OrgId != 0 && query.OrgId == datasource.OrgId
if orgMatch {
@@ -41,7 +41,7 @@ func (s *FakeDataSourceService) GetDataSources(ctx context.Context, query *model
return nil
}
func (s *FakeDataSourceService) GetDataSourcesByType(ctx context.Context, query *models.GetDataSourcesByTypeQuery) error {
func (s *FakeDataSourceService) GetDataSourcesByType(ctx context.Context, query *datasources.GetDataSourcesByTypeQuery) error {
for _, datasource := range s.DataSources {
typeMatch := query.Type != "" && query.Type == datasource.Type
if typeMatch {
@@ -51,11 +51,11 @@ func (s *FakeDataSourceService) GetDataSourcesByType(ctx context.Context, query
return nil
}
func (s *FakeDataSourceService) AddDataSource(ctx context.Context, cmd *models.AddDataSourceCommand) error {
func (s *FakeDataSourceService) AddDataSource(ctx context.Context, cmd *datasources.AddDataSourceCommand) error {
if s.lastId == 0 {
s.lastId = int64(len(s.DataSources) - 1)
}
cmd.Result = &models.DataSource{
cmd.Result = &datasources.DataSource{
Id: s.lastId + 1,
Name: cmd.Name,
Type: cmd.Type,
@@ -66,7 +66,7 @@ func (s *FakeDataSourceService) AddDataSource(ctx context.Context, cmd *models.A
return nil
}
func (s *FakeDataSourceService) DeleteDataSource(ctx context.Context, cmd *models.DeleteDataSourceCommand) error {
func (s *FakeDataSourceService) DeleteDataSource(ctx context.Context, cmd *datasources.DeleteDataSourceCommand) error {
for i, datasource := range s.DataSources {
idMatch := cmd.ID != 0 && cmd.ID == datasource.Id
uidMatch := cmd.UID != "" && cmd.UID == datasource.Uid
@@ -76,10 +76,10 @@ func (s *FakeDataSourceService) DeleteDataSource(ctx context.Context, cmd *model
return nil
}
}
return models.ErrDataSourceNotFound
return datasources.ErrDataSourceNotFound
}
func (s *FakeDataSourceService) UpdateDataSource(ctx context.Context, cmd *models.UpdateDataSourceCommand) error {
func (s *FakeDataSourceService) UpdateDataSource(ctx context.Context, cmd *datasources.UpdateDataSourceCommand) error {
for _, datasource := range s.DataSources {
idMatch := cmd.Id != 0 && cmd.Id == datasource.Id
uidMatch := cmd.Uid != "" && cmd.Uid == datasource.Uid
@@ -91,14 +91,14 @@ func (s *FakeDataSourceService) UpdateDataSource(ctx context.Context, cmd *model
return nil
}
}
return models.ErrDataSourceNotFound
return datasources.ErrDataSourceNotFound
}
func (s *FakeDataSourceService) GetDefaultDataSource(ctx context.Context, query *models.GetDefaultDataSourceQuery) error {
func (s *FakeDataSourceService) GetDefaultDataSource(ctx context.Context, query *datasources.GetDefaultDataSourceQuery) error {
return nil
}
func (s *FakeDataSourceService) GetHTTPTransport(ctx context.Context, ds *models.DataSource, provider httpclient.Provider, customMiddlewares ...sdkhttpclient.Middleware) (http.RoundTripper, error) {
func (s *FakeDataSourceService) GetHTTPTransport(ctx context.Context, ds *datasources.DataSource, provider httpclient.Provider, customMiddlewares ...sdkhttpclient.Middleware) (http.RoundTripper, error) {
rt, err := provider.GetTransport(sdkhttpclient.Options{})
if err != nil {
return nil, err
@@ -106,19 +106,19 @@ func (s *FakeDataSourceService) GetHTTPTransport(ctx context.Context, ds *models
return rt, nil
}
func (s *FakeDataSourceService) DecryptedValues(ctx context.Context, ds *models.DataSource) (map[string]string, error) {
func (s *FakeDataSourceService) DecryptedValues(ctx context.Context, ds *datasources.DataSource) (map[string]string, error) {
values := make(map[string]string)
return values, nil
}
func (s *FakeDataSourceService) DecryptedValue(ctx context.Context, ds *models.DataSource, key string) (string, bool, error) {
func (s *FakeDataSourceService) DecryptedValue(ctx context.Context, ds *datasources.DataSource, key string) (string, bool, error) {
return "", false, nil
}
func (s *FakeDataSourceService) DecryptedBasicAuthPassword(ctx context.Context, ds *models.DataSource) (string, error) {
func (s *FakeDataSourceService) DecryptedBasicAuthPassword(ctx context.Context, ds *datasources.DataSource) (string, error) {
return "", nil
}
func (s *FakeDataSourceService) DecryptedPassword(ctx context.Context, ds *models.DataSource) (string, error) {
func (s *FakeDataSourceService) DecryptedPassword(ctx context.Context, ds *datasources.DataSource) (string, error) {
return "", nil
}
+215
View File
@@ -0,0 +1,215 @@
package datasources
import (
"time"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
)
const (
DS_GRAPHITE = "graphite"
DS_INFLUXDB = "influxdb"
DS_INFLUXDB_08 = "influxdb_08"
DS_ES = "elasticsearch"
DS_PROMETHEUS = "prometheus"
DS_ALERTMANAGER = "alertmanager"
DS_JAEGER = "jaeger"
DS_LOKI = "loki"
DS_OPENTSDB = "opentsdb"
DS_TEMPO = "tempo"
DS_ZIPKIN = "zipkin"
DS_MYSQL = "mysql"
DS_POSTGRES = "postgres"
DS_MSSQL = "mssql"
DS_ACCESS_DIRECT = "direct"
DS_ACCESS_PROXY = "proxy"
DS_ES_OPEN_DISTRO = "grafana-es-open-distro-datasource"
DS_ES_OPENSEARCH = "grafana-opensearch-datasource"
)
type DsAccess string
type DataSource struct {
Id int64 `json:"id"`
OrgId int64 `json:"orgId"`
Version int `json:"version"`
Name string `json:"name"`
Type string `json:"type"`
Access DsAccess `json:"access"`
Url string `json:"url"`
// swagger:ignore
Password string `json:"-"`
User string `json:"user"`
Database string `json:"database"`
BasicAuth bool `json:"basicAuth"`
BasicAuthUser string `json:"basicAuthUser"`
// swagger:ignore
BasicAuthPassword string `json:"-"`
WithCredentials bool `json:"withCredentials"`
IsDefault bool `json:"isDefault"`
JsonData *simplejson.Json `json:"jsonData"`
SecureJsonData map[string][]byte `json:"secureJsonData"`
ReadOnly bool `json:"readOnly"`
Uid string `json:"uid"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
}
// AllowedCookies parses the jsondata.keepCookies and returns a list of
// allowed cookies, otherwise an empty list.
func (ds DataSource) AllowedCookies() []string {
if ds.JsonData != nil {
if keepCookies := ds.JsonData.Get("keepCookies"); keepCookies != nil {
return keepCookies.MustStringArray()
}
}
return []string{}
}
// Specific error type for grpc secrets management so that we can show more detailed plugin errors to users
type ErrDatasourceSecretsPluginUserFriendly struct {
Err string
}
func (e ErrDatasourceSecretsPluginUserFriendly) Error() string {
return e.Err
}
// ----------------------
// COMMANDS
// Also acts as api DTO
type AddDataSourceCommand struct {
Name string `json:"name" binding:"Required"`
Type string `json:"type" binding:"Required"`
Access DsAccess `json:"access" binding:"Required"`
Url string `json:"url"`
Database string `json:"database"`
User string `json:"user"`
BasicAuth bool `json:"basicAuth"`
BasicAuthUser string `json:"basicAuthUser"`
WithCredentials bool `json:"withCredentials"`
IsDefault bool `json:"isDefault"`
JsonData *simplejson.Json `json:"jsonData"`
SecureJsonData map[string]string `json:"secureJsonData"`
Uid string `json:"uid"`
OrgId int64 `json:"-"`
UserId int64 `json:"-"`
ReadOnly bool `json:"-"`
EncryptedSecureJsonData map[string][]byte `json:"-"`
UpdateSecretFn UpdateSecretFn `json:"-"`
Result *DataSource `json:"-"`
}
// Also acts as api DTO
type UpdateDataSourceCommand struct {
Name string `json:"name" binding:"Required"`
Type string `json:"type" binding:"Required"`
Access DsAccess `json:"access" binding:"Required"`
Url string `json:"url"`
User string `json:"user"`
Database string `json:"database"`
BasicAuth bool `json:"basicAuth"`
BasicAuthUser string `json:"basicAuthUser"`
WithCredentials bool `json:"withCredentials"`
IsDefault bool `json:"isDefault"`
JsonData *simplejson.Json `json:"jsonData"`
SecureJsonData map[string]string `json:"secureJsonData"`
Version int `json:"version"`
Uid string `json:"uid"`
OrgId int64 `json:"-"`
Id int64 `json:"-"`
ReadOnly bool `json:"-"`
EncryptedSecureJsonData map[string][]byte `json:"-"`
UpdateSecretFn UpdateSecretFn `json:"-"`
Result *DataSource `json:"-"`
}
// DeleteDataSourceCommand will delete a DataSource based on OrgID as well as the UID (preferred), ID, or Name.
// At least one of the UID, ID, or Name properties must be set in addition to OrgID.
type DeleteDataSourceCommand struct {
ID int64
UID string
Name string
OrgID int64
DeletedDatasourcesCount int64
UpdateSecretFn UpdateSecretFn
}
// Function for updating secrets along with datasources, to ensure atomicity
type UpdateSecretFn func() error
// ---------------------
// QUERIES
type GetDataSourcesQuery struct {
OrgId int64
DataSourceLimit int
User *models.SignedInUser
Result []*DataSource
}
type GetDataSourcesByTypeQuery struct {
Type string
Result []*DataSource
}
type GetDefaultDataSourceQuery struct {
OrgId int64
User *models.SignedInUser
Result *DataSource
}
// GetDataSourceQuery will get a DataSource based on OrgID as well as the UID (preferred), ID, or Name.
// At least one of the UID, ID, or Name properties must be set in addition to OrgID.
type GetDataSourceQuery struct {
Id int64
Uid string
Name string
OrgId int64
Result *DataSource
}
// ---------------------
// Permissions
// ---------------------
// Datasource permission
// Description:
// * `0` - No Access
// * `1` - Query
// Enum: 0,1
// swagger:model
type DsPermissionType int
const (
DsPermissionNoAccess DsPermissionType = iota
DsPermissionQuery
)
func (p DsPermissionType) String() string {
names := map[int]string{
int(DsPermissionQuery): "Query",
int(DsPermissionNoAccess): "No Access",
}
return names[int(p)]
}
type DatasourcesPermissionFilterQuery struct {
User *models.SignedInUser
Datasources []*DataSource
Result []*DataSource
}
@@ -4,17 +4,17 @@ import (
"context"
"errors"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/datasources"
)
var ErrNotImplemented = errors.New("not implemented")
type DatasourcePermissionsService interface {
FilterDatasourcesBasedOnQueryPermissions(ctx context.Context, cmd *models.DatasourcesPermissionFilterQuery) error
FilterDatasourcesBasedOnQueryPermissions(ctx context.Context, cmd *datasources.DatasourcesPermissionFilterQuery) error
}
// dummy method
func (hs *OSSDatasourcePermissionsService) FilterDatasourcesBasedOnQueryPermissions(ctx context.Context, cmd *models.DatasourcesPermissionFilterQuery) error {
func (hs *OSSDatasourcePermissionsService) FilterDatasourcesBasedOnQueryPermissions(ctx context.Context, cmd *datasources.DatasourcesPermissionFilterQuery) error {
return ErrNotImplemented
}
@@ -3,15 +3,15 @@ package permissions
import (
"context"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/datasources"
)
type mockDatasourcePermissionService struct {
DsResult []*models.DataSource
DsResult []*datasources.DataSource
ErrResult error
}
func (m *mockDatasourcePermissionService) FilterDatasourcesBasedOnQueryPermissions(ctx context.Context, cmd *models.DatasourcesPermissionFilterQuery) error {
func (m *mockDatasourcePermissionService) FilterDatasourcesBasedOnQueryPermissions(ctx context.Context, cmd *datasources.DatasourcesPermissionFilterQuery) error {
cmd.Result = m.DsResult
return m.ErrResult
}
@@ -8,6 +8,7 @@ import (
"github.com/grafana/grafana/pkg/infra/localcache"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/sqlstore"
)
@@ -30,12 +31,12 @@ func (dc *CacheServiceImpl) GetDatasource(
datasourceID int64,
user *models.SignedInUser,
skipCache bool,
) (*models.DataSource, error) {
) (*datasources.DataSource, error) {
cacheKey := idKey(datasourceID)
if !skipCache {
if cached, found := dc.CacheService.Get(cacheKey); found {
ds := cached.(*models.DataSource)
ds := cached.(*datasources.DataSource)
if ds.OrgId == user.OrgId {
return ds, nil
}
@@ -44,7 +45,7 @@ func (dc *CacheServiceImpl) GetDatasource(
dc.logger.Debug("Querying for data source via SQL store", "id", datasourceID, "orgId", user.OrgId)
query := &models.GetDataSourceQuery{Id: datasourceID, OrgId: user.OrgId}
query := &datasources.GetDataSourceQuery{Id: datasourceID, OrgId: user.OrgId}
err := dc.SQLStore.GetDataSource(ctx, query)
if err != nil {
return nil, err
@@ -64,7 +65,7 @@ func (dc *CacheServiceImpl) GetDatasourceByUID(
datasourceUID string,
user *models.SignedInUser,
skipCache bool,
) (*models.DataSource, error) {
) (*datasources.DataSource, error) {
if datasourceUID == "" {
return nil, fmt.Errorf("can not get data source by uid, uid is empty")
}
@@ -75,7 +76,7 @@ func (dc *CacheServiceImpl) GetDatasourceByUID(
if !skipCache {
if cached, found := dc.CacheService.Get(uidCacheKey); found {
ds := cached.(*models.DataSource)
ds := cached.(*datasources.DataSource)
if ds.OrgId == user.OrgId {
return ds, nil
}
@@ -83,7 +84,7 @@ func (dc *CacheServiceImpl) GetDatasourceByUID(
}
dc.logger.Debug("Querying for data source via SQL store", "uid", datasourceUID, "orgId", user.OrgId)
query := &models.GetDataSourceQuery{Uid: datasourceUID, OrgId: user.OrgId}
query := &datasources.GetDataSourceQuery{Uid: datasourceUID, OrgId: user.OrgId}
err := dc.SQLStore.GetDataSource(ctx, query)
if err != nil {
return nil, err
@@ -15,7 +15,6 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/httpclient"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt"
@@ -73,7 +72,7 @@ func ProvideService(
// DataSourceRetriever interface for retrieving a datasource.
type DataSourceRetriever interface {
// GetDataSource gets a datasource.
GetDataSource(ctx context.Context, query *models.GetDataSourceQuery) error
GetDataSource(ctx context.Context, query *datasources.GetDataSourceQuery) error
}
const secretType = "datasource"
@@ -92,7 +91,7 @@ func NewNameScopeResolver(db DataSourceRetriever) (string, accesscontrol.ScopeAt
return nil, accesscontrol.ErrInvalidScope
}
query := models.GetDataSourceQuery{Name: dsName, OrgId: orgID}
query := datasources.GetDataSourceQuery{Name: dsName, OrgId: orgID}
if err := db.GetDataSource(ctx, &query); err != nil {
return nil, err
}
@@ -120,7 +119,7 @@ func NewIDScopeResolver(db DataSourceRetriever) (string, accesscontrol.ScopeAttr
return nil, accesscontrol.ErrInvalidScope
}
query := models.GetDataSourceQuery{Id: dsID, OrgId: orgID}
query := datasources.GetDataSourceQuery{Id: dsID, OrgId: orgID}
if err := db.GetDataSource(ctx, &query); err != nil {
return nil, err
}
@@ -129,19 +128,19 @@ func NewIDScopeResolver(db DataSourceRetriever) (string, accesscontrol.ScopeAttr
})
}
func (s *Service) GetDataSource(ctx context.Context, query *models.GetDataSourceQuery) error {
func (s *Service) GetDataSource(ctx context.Context, query *datasources.GetDataSourceQuery) error {
return s.SQLStore.GetDataSource(ctx, query)
}
func (s *Service) GetDataSources(ctx context.Context, query *models.GetDataSourcesQuery) error {
func (s *Service) GetDataSources(ctx context.Context, query *datasources.GetDataSourcesQuery) error {
return s.SQLStore.GetDataSources(ctx, query)
}
func (s *Service) GetDataSourcesByType(ctx context.Context, query *models.GetDataSourcesByTypeQuery) error {
func (s *Service) GetDataSourcesByType(ctx context.Context, query *datasources.GetDataSourcesByTypeQuery) error {
return s.SQLStore.GetDataSourcesByType(ctx, query)
}
func (s *Service) AddDataSource(ctx context.Context, cmd *models.AddDataSourceCommand) error {
func (s *Service) AddDataSource(ctx context.Context, cmd *datasources.AddDataSourceCommand) error {
return s.SQLStore.InTransaction(ctx, func(ctx context.Context) error {
var err error
// this is here for backwards compatibility
@@ -185,7 +184,7 @@ func (s *Service) AddDataSource(ctx context.Context, cmd *models.AddDataSourceCo
})
}
func (s *Service) DeleteDataSource(ctx context.Context, cmd *models.DeleteDataSourceCommand) error {
func (s *Service) DeleteDataSource(ctx context.Context, cmd *datasources.DeleteDataSourceCommand) error {
return s.SQLStore.InTransaction(ctx, func(ctx context.Context) error {
cmd.UpdateSecretFn = func() error {
return s.SecretsStore.Del(ctx, cmd.OrgID, cmd.Name, secretType)
@@ -195,11 +194,11 @@ func (s *Service) DeleteDataSource(ctx context.Context, cmd *models.DeleteDataSo
})
}
func (s *Service) UpdateDataSource(ctx context.Context, cmd *models.UpdateDataSourceCommand) error {
func (s *Service) UpdateDataSource(ctx context.Context, cmd *datasources.UpdateDataSourceCommand) error {
return s.SQLStore.InTransaction(ctx, func(ctx context.Context) error {
var err error
query := &models.GetDataSourceQuery{
query := &datasources.GetDataSourceQuery{
Id: cmd.Id,
OrgId: cmd.OrgId,
}
@@ -234,11 +233,11 @@ func (s *Service) UpdateDataSource(ctx context.Context, cmd *models.UpdateDataSo
})
}
func (s *Service) GetDefaultDataSource(ctx context.Context, query *models.GetDefaultDataSourceQuery) error {
func (s *Service) GetDefaultDataSource(ctx context.Context, query *datasources.GetDefaultDataSourceQuery) error {
return s.SQLStore.GetDefaultDataSource(ctx, query)
}
func (s *Service) GetHTTPClient(ctx context.Context, ds *models.DataSource, provider httpclient.Provider) (*http.Client, error) {
func (s *Service) GetHTTPClient(ctx context.Context, ds *datasources.DataSource, provider httpclient.Provider) (*http.Client, error) {
transport, err := s.GetHTTPTransport(ctx, ds, provider)
if err != nil {
return nil, err
@@ -250,7 +249,7 @@ func (s *Service) GetHTTPClient(ctx context.Context, ds *models.DataSource, prov
}, nil
}
func (s *Service) GetHTTPTransport(ctx context.Context, ds *models.DataSource, provider httpclient.Provider,
func (s *Service) GetHTTPTransport(ctx context.Context, ds *datasources.DataSource, provider httpclient.Provider,
customMiddlewares ...sdkhttpclient.Middleware) (http.RoundTripper, error) {
s.ptc.Lock()
defer s.ptc.Unlock()
@@ -279,7 +278,7 @@ func (s *Service) GetHTTPTransport(ctx context.Context, ds *models.DataSource, p
return rt, nil
}
func (s *Service) GetTLSConfig(ctx context.Context, ds *models.DataSource, httpClientProvider httpclient.Provider) (*tls.Config, error) {
func (s *Service) GetTLSConfig(ctx context.Context, ds *datasources.DataSource, httpClientProvider httpclient.Provider) (*tls.Config, error) {
opts, err := s.httpClientOptions(ctx, ds)
if err != nil {
return nil, err
@@ -287,7 +286,7 @@ func (s *Service) GetTLSConfig(ctx context.Context, ds *models.DataSource, httpC
return httpClientProvider.GetTLSConfig(*opts)
}
func (s *Service) DecryptedValues(ctx context.Context, ds *models.DataSource) (map[string]string, error) {
func (s *Service) DecryptedValues(ctx context.Context, ds *datasources.DataSource) (map[string]string, error) {
decryptedValues := make(map[string]string)
secret, exist, err := s.SecretsStore.Get(ctx, ds.OrgId, ds.Name, secretType)
if err != nil {
@@ -308,7 +307,7 @@ func (s *Service) DecryptedValues(ctx context.Context, ds *models.DataSource) (m
return decryptedValues, nil
}
func (s *Service) MigrateSecrets(ctx context.Context, ds *models.DataSource) (map[string]string, error) {
func (s *Service) MigrateSecrets(ctx context.Context, ds *datasources.DataSource) (map[string]string, error) {
secureJsonData := make(map[string]string)
for k, v := range ds.SecureJsonData {
decrypted, err := s.SecretsService.Decrypt(ctx, v)
@@ -327,7 +326,7 @@ func (s *Service) MigrateSecrets(ctx context.Context, ds *models.DataSource) (ma
return secureJsonData, err
}
func (s *Service) DecryptedValue(ctx context.Context, ds *models.DataSource, key string) (string, bool, error) {
func (s *Service) DecryptedValue(ctx context.Context, ds *datasources.DataSource, key string) (string, bool, error) {
values, err := s.DecryptedValues(ctx, ds)
if err != nil {
return "", false, err
@@ -336,7 +335,7 @@ func (s *Service) DecryptedValue(ctx context.Context, ds *models.DataSource, key
return value, exists, nil
}
func (s *Service) DecryptedBasicAuthPassword(ctx context.Context, ds *models.DataSource) (string, error) {
func (s *Service) DecryptedBasicAuthPassword(ctx context.Context, ds *datasources.DataSource) (string, error) {
value, ok, err := s.DecryptedValue(ctx, ds, "basicAuthPassword")
if ok {
return value, nil
@@ -345,7 +344,7 @@ func (s *Service) DecryptedBasicAuthPassword(ctx context.Context, ds *models.Dat
return "", err
}
func (s *Service) DecryptedPassword(ctx context.Context, ds *models.DataSource) (string, error) {
func (s *Service) DecryptedPassword(ctx context.Context, ds *datasources.DataSource) (string, error) {
value, ok, err := s.DecryptedValue(ctx, ds, "password")
if ok {
return value, nil
@@ -354,7 +353,7 @@ func (s *Service) DecryptedPassword(ctx context.Context, ds *models.DataSource)
return "", err
}
func (s *Service) httpClientOptions(ctx context.Context, ds *models.DataSource) (*sdkhttpclient.Options, error) {
func (s *Service) httpClientOptions(ctx context.Context, ds *datasources.DataSource) (*sdkhttpclient.Options, error) {
tlsOptions, err := s.dsTLSOptions(ctx, ds)
if err != nil {
return nil, err
@@ -442,7 +441,7 @@ func (s *Service) httpClientOptions(ctx context.Context, ds *models.DataSource)
return opts, nil
}
func (s *Service) dsTLSOptions(ctx context.Context, ds *models.DataSource) (sdkhttpclient.TLSOptions, error) {
func (s *Service) dsTLSOptions(ctx context.Context, ds *datasources.DataSource) (sdkhttpclient.TLSOptions, error) {
var tlsSkipVerify, tlsClientAuth, tlsAuthWithCACert bool
var serverName string
@@ -491,7 +490,7 @@ func (s *Service) dsTLSOptions(ctx context.Context, ds *models.DataSource) (sdkh
return opts, nil
}
func (s *Service) getTimeout(ds *models.DataSource) time.Duration {
func (s *Service) getTimeout(ds *datasources.DataSource) time.Duration {
timeout := 0
if ds.JsonData != nil {
timeout = ds.JsonData.Get("timeout").MustInt()
@@ -540,16 +539,16 @@ func (s *Service) getCustomHeaders(jsonData *simplejson.Json, decryptedValues ma
func awsServiceNamespace(dsType string) string {
switch dsType {
case models.DS_ES, models.DS_ES_OPEN_DISTRO, models.DS_ES_OPENSEARCH:
case datasources.DS_ES, datasources.DS_ES_OPEN_DISTRO, datasources.DS_ES_OPENSEARCH:
return "es"
case models.DS_PROMETHEUS, models.DS_ALERTMANAGER:
case datasources.DS_PROMETHEUS, datasources.DS_ALERTMANAGER:
return "aps"
default:
panic(fmt.Sprintf("Unsupported datasource %q", dsType))
}
}
func (s *Service) fillWithSecureJSONData(ctx context.Context, cmd *models.UpdateDataSourceCommand, ds *models.DataSource) error {
func (s *Service) fillWithSecureJSONData(ctx context.Context, cmd *datasources.UpdateDataSourceCommand, ds *datasources.DataSource) error {
decrypted, err := s.DecryptedValues(ctx, ds)
if err != nil {
return err
@@ -10,27 +10,27 @@ import (
"time"
sdkhttpclient "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
"github.com/grafana/grafana/pkg/services/secrets"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/httpclient"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
acmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/secrets"
"github.com/grafana/grafana/pkg/services/secrets/fakes"
"github.com/grafana/grafana/pkg/services/secrets/kvstore"
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
"github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type dataSourceMockRetriever struct {
res []*models.DataSource
res []*datasources.DataSource
}
func (d *dataSourceMockRetriever) GetDataSource(ctx context.Context, query *models.GetDataSourceQuery) error {
func (d *dataSourceMockRetriever) GetDataSource(ctx context.Context, query *datasources.GetDataSourceQuery) error {
for _, datasource := range d.res {
idMatch := query.Id != 0 && query.Id == datasource.Id
uidMatch := query.Uid != "" && query.Uid == datasource.Uid
@@ -41,11 +41,11 @@ func (d *dataSourceMockRetriever) GetDataSource(ctx context.Context, query *mode
return nil
}
}
return models.ErrDataSourceNotFound
return datasources.ErrDataSourceNotFound
}
func TestService_NameScopeResolver(t *testing.T) {
retriever := &dataSourceMockRetriever{[]*models.DataSource{
retriever := &dataSourceMockRetriever{[]*datasources.DataSource{
{Name: "test-datasource", Uid: "1"},
{Name: "*", Uid: "2"},
{Name: ":/*", Uid: "3"},
@@ -88,7 +88,7 @@ func TestService_NameScopeResolver(t *testing.T) {
desc: "unknown datasource",
given: "datasources:name:unknown-datasource",
want: "",
wantErr: models.ErrDataSourceNotFound,
wantErr: datasources.ErrDataSourceNotFound,
},
{
desc: "malformed scope",
@@ -122,7 +122,7 @@ func TestService_NameScopeResolver(t *testing.T) {
}
func TestService_IDScopeResolver(t *testing.T) {
retriever := &dataSourceMockRetriever{[]*models.DataSource{
retriever := &dataSourceMockRetriever{[]*datasources.DataSource{
{Id: 1, Uid: "NnftN9Lnz"},
}}
@@ -189,7 +189,7 @@ func TestService_GetHttpTransport(t *testing.T) {
},
})
ds := models.DataSource{
ds := datasources.DataSource{
Id: 1,
Url: "http://k8s:8001",
Type: "Kubernetes",
@@ -233,7 +233,7 @@ func TestService_GetHttpTransport(t *testing.T) {
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
dsService := ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
ds := models.DataSource{
ds := datasources.DataSource{
Id: 1,
Url: "http://k8s:8001",
Type: "Kubernetes",
@@ -281,7 +281,7 @@ func TestService_GetHttpTransport(t *testing.T) {
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
dsService := ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
ds := models.DataSource{
ds := datasources.DataSource{
Id: 1,
OrgId: 1,
Name: "kubernetes",
@@ -326,7 +326,7 @@ func TestService_GetHttpTransport(t *testing.T) {
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
dsService := ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
ds := models.DataSource{
ds := datasources.DataSource{
Id: 1,
OrgId: 1,
Name: "kubernetes",
@@ -368,7 +368,7 @@ func TestService_GetHttpTransport(t *testing.T) {
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
dsService := ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
ds := models.DataSource{
ds := datasources.DataSource{
Id: 1,
Url: "http://k8s:8001",
Type: "Kubernetes",
@@ -400,7 +400,7 @@ func TestService_GetHttpTransport(t *testing.T) {
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
dsService := ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
ds := models.DataSource{
ds := datasources.DataSource{
Id: 1,
OrgId: 1,
Name: "kubernetes",
@@ -466,7 +466,7 @@ func TestService_GetHttpTransport(t *testing.T) {
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
dsService := ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
ds := models.DataSource{
ds := datasources.DataSource{
Id: 1,
Url: "http://k8s:8001",
Type: "Kubernetes",
@@ -500,8 +500,8 @@ func TestService_GetHttpTransport(t *testing.T) {
secretsService := secretsManager.SetupTestService(t, fakes.NewFakeSecretsStore())
dsService := ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
ds := models.DataSource{
Type: models.DS_ES,
ds := datasources.DataSource{
Type: datasources.DS_ES,
JsonData: sjson,
}
@@ -537,7 +537,7 @@ func TestService_getTimeout(t *testing.T) {
dsService := ProvideService(nil, secretsService, secretsStore, cfg, featuremgmt.WithFeatures(), acmock.New(), acmock.NewMockedPermissionsService())
for _, tc := range testCases {
ds := &models.DataSource{
ds := &datasources.DataSource{
JsonData: tc.jsonData,
}
assert.Equal(t, tc.expectedTimeout, dsService.getTimeout(ds))
@@ -546,7 +546,7 @@ func TestService_getTimeout(t *testing.T) {
func TestService_GetDecryptedValues(t *testing.T) {
t.Run("should migrate and retrieve values from secure json data", func(t *testing.T) {
ds := &models.DataSource{
ds := &datasources.DataSource{
Id: 1,
Url: "https://api.example.com",
Type: "prometheus",
@@ -571,7 +571,7 @@ func TestService_GetDecryptedValues(t *testing.T) {
})
t.Run("should retrieve values from secret store", func(t *testing.T) {
ds := &models.DataSource{
ds := &datasources.DataSource{
Id: 1,
Url: "https://api.example.com",
Type: "prometheus",
+16
View File
@@ -0,0 +1,16 @@
package datasources
import (
"context"
)
// Store is the interface for the datasource Service's storage.
type Store interface {
GetDataSource(context.Context, *GetDataSourceQuery) error
GetDataSources(context.Context, *GetDataSourcesQuery) error
GetDataSourcesByType(context.Context, *GetDataSourcesByTypeQuery) error
GetDefaultDataSource(context.Context, *GetDefaultDataSourceQuery) error
DeleteDataSource(context.Context, *DeleteDataSourceCommand) error
AddDataSource(context.Context, *AddDataSourceCommand) error
UpdateDataSource(context.Context, *UpdateDataSourceCommand) error
}