to revert: testing fs api in grafana ds

pull/46165/head
Artur Wierzbicki 3 years ago
parent 448fa27620
commit fbf17df21b
  1. 2
      pkg/plugins/manager/manager_integration_test.go
  2. 123
      pkg/tsdb/grafanads/grafana.go
  3. 27
      pkg/tsdb/grafanads/grafana_test.go
  4. 2
      pkg/tsdb/grafanads/testdata/jslib.golden.txt
  5. 28
      pkg/tsdb/grafanads/testdata/list.golden.txt
  6. 2
      public/app/features/dimensions/editors/FolderPickerTab.tsx

@ -87,7 +87,7 @@ func TestPluginManager_int_init(t *testing.T) {
my := mysql.ProvideService(cfg, hcp)
ms := mssql.ProvideService(cfg)
sv2 := searchV2.ProvideService(sqlstore.InitTestDB(t))
graf := grafanads.ProvideService(cfg, sv2)
graf := grafanads.ProvideService(cfg, sv2, nil)
coreRegistry := coreplugin.ProvideCoreRegistry(am, cw, cm, es, grap, idb, lk, otsdb, pr, tmpo, td, pg, my, ms, graf)

@ -3,6 +3,7 @@ package grafanads
import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"path/filepath"
@ -10,8 +11,8 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana-plugin-sdk-go/experimental"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/filestorage"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/searchV2"
@ -31,6 +32,8 @@ const DatasourceID = -1
// Grafana DS command.
const DatasourceUID = "grafana"
const publicFilestorageBackend = "public"
// Make sure Service implements required interfaces.
// This is important to do since otherwise we will only get a
// not implemented error response from plugin at runtime.
@ -40,12 +43,14 @@ var (
logger = log.New("tsdb.grafana")
)
func ProvideService(cfg *setting.Cfg, search searchV2.SearchService) *Service {
return newService(cfg, search)
func ProvideService(cfg *setting.Cfg, search searchV2.SearchService, fs filestorage.FileStorage) *Service {
return newService(cfg, search, fs)
}
func newService(cfg *setting.Cfg, search searchV2.SearchService) *Service {
func newService(cfg *setting.Cfg, search searchV2.SearchService, fs filestorage.FileStorage) *Service {
s := &Service{
fs: fs,
search: search,
staticRootPath: cfg.StaticRootPath,
roots: []string{
"testdata",
@ -55,7 +60,7 @@ func newService(cfg *setting.Cfg, search searchV2.SearchService) *Service {
"maps",
"upload", // does not exist yet
},
search: search,
log: log.New("grafanads"),
}
return s
@ -67,6 +72,8 @@ type Service struct {
staticRootPath string
roots []string
search searchV2.SearchService
fs filestorage.FileStorage
log log.Logger
}
func DataSourceModel(orgId int64) *models.DataSource {
@ -111,22 +118,63 @@ func (s *Service) CheckHealth(_ context.Context, _ *backend.CheckHealthRequest)
}, nil
}
func (s *Service) publicPath(path string) (string, error) {
if strings.Contains(path, "..") {
return "", fmt.Errorf("invalid string")
func (s *Service) getDirectoryFrame(path string, details bool) (*data.Frame, error) {
// Name() string // base name of the file
// Size() int64 // length in bytes for regular files; system-dependent for others
// Mode() FileMode // file mode bits
// ModTime() time.Time // modification time
// IsDir() bool // abbreviation for Mode().IsDir()
ctx := context.Background()
folders, err := s.fs.ListFolders(ctx, path, &filestorage.ListOptions{Recursive: false})
if err != nil {
s.log.Error("failed when listing folders", "path", path, "err", err)
return nil, errors.New("unknown error")
}
ok := false
for _, root := range s.roots {
if strings.HasPrefix(path, root) {
ok = true
break
filesResp, err := s.fs.ListFiles(ctx, path, nil, &filestorage.ListOptions{Recursive: false})
if err != nil {
s.log.Error("failed when listing files", "path", path, "err", err)
return nil, errors.New("unknown error")
}
count := len(filesResp.Files) + len(folders)
names := data.NewFieldFromFieldType(data.FieldTypeString, count)
mtype := data.NewFieldFromFieldType(data.FieldTypeString, count)
size := data.NewFieldFromFieldType(data.FieldTypeInt64, count)
modified := data.NewFieldFromFieldType(data.FieldTypeTime, count)
names.Name = "name"
mtype.Name = "media-type"
size.Name = "size"
size.Config = &data.FieldConfig{
Unit: "bytes",
}
modified.Name = "modified"
for i, f := range filesResp.Files {
names.Set(i, f.Name)
mtype.Set(i, f.MimeType)
if details {
size.Set(i, f.Size)
modified.Set(i, f.Modified)
}
}
if !ok {
return "", fmt.Errorf("bad root path")
for i, f := range folders {
names.Set(i, f.FullPath)
mtype.Set(i, "directory")
}
return filepath.Join(s.staticRootPath, path), nil
frame := data.NewFrame("", names, mtype)
frame.SetMeta(&data.FrameMeta{
PathSeparator: filestorage.Delimiter,
Type: data.FrameTypeDirectoryListing,
})
if details {
frame.Fields = append(frame.Fields, size)
frame.Fields = append(frame.Fields, modified)
}
return frame, nil
}
func (s *Service) doListQuery(query backend.DataQuery) backend.DataResponse {
@ -138,14 +186,23 @@ func (s *Service) doListQuery(query backend.DataQuery) backend.DataResponse {
return response
}
if q.Path == "" {
count := len(s.roots)
path := q.Path
if path == "" {
folders, err := s.fs.ListFolders(context.Background(), publicFilestorageBackend, nil)
if err != nil {
s.log.Error("failed when listing folders", "path", publicFilestorageBackend, "err", err)
response.Error = errors.New("unknown error")
return response
}
count := len(folders)
names := data.NewFieldFromFieldType(data.FieldTypeString, count)
mtype := data.NewFieldFromFieldType(data.FieldTypeString, count)
names.Name = "name"
mtype.Name = "mediaType"
for i, f := range s.roots {
names.Set(i, f)
for i, f := range folders {
names.Set(i, f.FullPath)
s.log.Info("setting full path", "name", f.Name, "path", f.FullPath)
mtype.Set(i, "directory")
}
frame := data.NewFrame("", names, mtype)
@ -154,12 +211,7 @@ func (s *Service) doListQuery(query backend.DataQuery) backend.DataResponse {
})
response.Frames = data.Frames{frame}
} else {
path, err := s.publicPath(q.Path)
if err != nil {
response.Error = err
return response
}
frame, err := experimental.GetDirectoryFrame(path, false)
frame, err := s.getDirectoryFrame(path, false)
if err != nil {
response.Error = err
return response
@ -170,6 +222,24 @@ func (s *Service) doListQuery(query backend.DataQuery) backend.DataResponse {
return response
}
func (s *Service) publicPath(path string) (string, error) {
if strings.Contains(path, "..") {
return "", fmt.Errorf("invalid string")
}
ok := false
for _, root := range s.roots {
if strings.HasPrefix(path, root) {
ok = true
break
}
}
if !ok {
return "", fmt.Errorf("bad root path")
}
return filepath.Join(s.staticRootPath, path), nil
}
func (s *Service) doReadQuery(query backend.DataQuery) backend.DataResponse {
q := &listQueryModel{}
response := backend.DataResponse{}
@ -194,6 +264,7 @@ func (s *Service) doReadQuery(query backend.DataQuery) backend.DataResponse {
// nolint:gosec
fileReader, err := os.Open(path)
if err != nil {
s.log.Error("Failed to read file", "err", err, "path", path)
response.Error = fmt.Errorf("failed to read file")
return response
}

@ -5,11 +5,12 @@ import (
"path"
"testing"
"github.com/grafana/grafana/pkg/services/searchV2"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/experimental"
"github.com/grafana/grafana/pkg/infra/filestorage"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/searchV2"
"github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/require"
)
@ -19,25 +20,35 @@ func asJSON(v interface{}) json.RawMessage {
}
func TestReadFolderListing(t *testing.T) {
ds := newService(&setting.Cfg{StaticRootPath: "../../../public"}, searchV2.NewStubSearchService())
features := featuremgmt.WithFeatures(featuremgmt.FlagFileStoreApi, true)
cfg := &setting.Cfg{StaticRootPath: "./../../../public"}
fs, err := filestorage.ProvideService(features, cfg)
require.NoError(t, err)
ds := newService(&setting.Cfg{StaticRootPath: "../../../public"}, searchV2.NewStubSearchService(), fs)
dr := ds.doListQuery(backend.DataQuery{
QueryType: "x",
JSON: asJSON(listQueryModel{
Path: "testdata",
Path: filestorage.Join("public", "testdata"),
}),
})
err := experimental.CheckGoldenDataResponse(path.Join("testdata", "list.golden.txt"), &dr, true)
err = experimental.CheckGoldenDataResponse(path.Join("testdata", "list.golden.txt"), &dr, true)
require.NoError(t, err)
}
func TestReadCSVFile(t *testing.T) {
ds := newService(&setting.Cfg{StaticRootPath: "../../../public"}, searchV2.NewStubSearchService())
features := featuremgmt.WithFeatures(featuremgmt.FlagFileStoreApi, true)
cfg := &setting.Cfg{StaticRootPath: "./../../../public"}
fs, err := filestorage.ProvideService(features, cfg)
require.NoError(t, err)
ds := newService(&setting.Cfg{StaticRootPath: "../../../public"}, searchV2.NewStubSearchService(), fs)
dr := ds.doReadQuery(backend.DataQuery{
QueryType: "x",
JSON: asJSON(readQueryModel{
Path: "testdata/js_libraries.csv",
}),
})
err := experimental.CheckGoldenDataResponse(path.Join("testdata", "jslib.golden.txt"), &dr, true)
err = experimental.CheckGoldenDataResponse(path.Join("testdata", "jslib.golden.txt"), &dr, true)
require.NoError(t, err)
}

@ -18,4 +18,4 @@ Dimensions: 4 Fields by 6 Rows
====== TEST DATA RESPONSE (arrow base64) ======
FRAME=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
FRAME=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

@ -6,20 +6,20 @@ Frame[0] {
}
Name:
Dimensions: 2 Fields by 7 Rows
+--------------------------+------------------+
| Name: name | Name: media-type |
| Labels: | Labels: |
| Type: []string | Type: []string |
+--------------------------+------------------+
| browser_marketshare.csv | |
| flight_info_by_state.csv | |
| gdp_per_capita.csv | |
| js_libraries.csv | |
| ohlc_dogecoin.csv | |
| population_by_state.csv | |
| weight_height.csv | |
+--------------------------+------------------+
+--------------------------+-------------------------+
| Name: name | Name: media-type |
| Labels: | Labels: |
| Type: []string | Type: []string |
+--------------------------+-------------------------+
| browser_marketshare.csv | text/csv; charset=utf-8 |
| flight_info_by_state.csv | text/csv; charset=utf-8 |
| gdp_per_capita.csv | text/csv; charset=utf-8 |
| js_libraries.csv | text/csv; charset=utf-8 |
| ohlc_dogecoin.csv | text/csv; charset=utf-8 |
| population_by_state.csv | text/csv; charset=utf-8 |
| weight_height.csv | text/csv; charset=utf-8 |
+--------------------------+-------------------------+
====== TEST DATA RESPONSE (arrow base64) ======
FRAME=QVJST1cxAAD/////uAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAKQAAAADAAAATAAAACgAAAAEAAAA0P7//wgAAAAMAAAAAAAAAAAAAAAFAAAAcmVmSWQAAADw/v//CAAAAAwAAAAAAAAAAAAAAAQAAABuYW1lAAAAABD///8IAAAAPAAAADAAAAB7InR5cGUiOiJkaXJlY3RvcnktbGlzdGluZyIsInBhdGhTZXBhcmF0b3IiOiIvIn0AAAAABAAAAG1ldGEAAAAAAgAAAHwAAAAEAAAAnv///xQAAABAAAAAQAAAAAAAAAU8AAAAAQAAAAQAAACM////CAAAABQAAAAKAAAAbWVkaWEtdHlwZQAABAAAAG5hbWUAAAAAAAAAAIj///8KAAAAbWVkaWEtdHlwZQAAAAASABgAFAAAABMADAAAAAgABAASAAAAFAAAAEQAAABIAAAAAAAABUQAAAABAAAADAAAAAgADAAIAAQACAAAAAgAAAAQAAAABAAAAG5hbWUAAAAABAAAAG5hbWUAAAAAAAAAAAQABAAEAAAABAAAAG5hbWUAAAAA/////9gAAAAUAAAAAAAAAAwAFgAUABMADAAEAAwAAADQAAAAAAAAABQAAAAAAAADAwAKABgADAAIAAQACgAAABQAAAB4AAAABwAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAIAAAAAAAAACQAAAAAAAAALAAAAAAAAAAAAAAAAAAAACwAAAAAAAAACAAAAAAAAAA0AAAAAAAAAAAAAAAAAAAAAAAAAACAAAABwAAAAAAAAAAAAAAAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAFwAAAC8AAABBAAAAUQAAAGIAAAB5AAAAigAAAGJyb3dzZXJfbWFya2V0c2hhcmUuY3N2ZmxpZ2h0X2luZm9fYnlfc3RhdGUuY3N2Z2RwX3Blcl9jYXBpdGEuY3N2anNfbGlicmFyaWVzLmNzdm9obGNfZG9nZWNvaW4uY3N2cG9wdWxhdGlvbl9ieV9zdGF0ZS5jc3Z3ZWlnaHRfaGVpZ2h0LmNzdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAwAFAASAAwACAAEAAwAAAAQAAAALAAAADwAAAAAAAMAAQAAAMgBAAAAAAAA4AAAAAAAAADQAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAMAAAACAAEAAoAAAAIAAAApAAAAAMAAABMAAAAKAAAAAQAAADQ/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAPD+//8IAAAADAAAAAAAAAAAAAAABAAAAG5hbWUAAAAAEP///wgAAAA8AAAAMAAAAHsidHlwZSI6ImRpcmVjdG9yeS1saXN0aW5nIiwicGF0aFNlcGFyYXRvciI6Ii8ifQAAAAAEAAAAbWV0YQAAAAACAAAAfAAAAAQAAACe////FAAAAEAAAABAAAAAAAAABTwAAAABAAAABAAAAIz///8IAAAAFAAAAAoAAABtZWRpYS10eXBlAAAEAAAAbmFtZQAAAAAAAAAAiP///woAAABtZWRpYS10eXBlAAAAABIAGAAUAAAAEwAMAAAACAAEABIAAAAUAAAARAAAAEgAAAAAAAAFRAAAAAEAAAAMAAAACAAMAAgABAAIAAAACAAAABAAAAAEAAAAbmFtZQAAAAAEAAAAbmFtZQAAAAAAAAAABAAEAAQAAAAEAAAAbmFtZQAAAADoAQAAQVJST1cx
FRAME=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

@ -73,7 +73,7 @@ export const FolderPickerTab = (props: Props) => {
getDatasourceSrv()
.get('-- Grafana --')
.then((ds) => {
(ds as GrafanaDatasource).listFiles(folder).subscribe({
(ds as GrafanaDatasource).listFiles(`/public/${folder}`).subscribe({
next: (frame) => {
const cards: ResourceItem[] = [];
frame.forEach((item) => {

Loading…
Cancel
Save