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) my := mysql.ProvideService(cfg, hcp)
ms := mssql.ProvideService(cfg) ms := mssql.ProvideService(cfg)
sv2 := searchV2.ProvideService(sqlstore.InitTestDB(t)) 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) 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 ( import (
"context" "context"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"os" "os"
"path/filepath" "path/filepath"
@ -10,8 +11,8 @@ import (
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/data" "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/components/simplejson"
"github.com/grafana/grafana/pkg/infra/filestorage"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/searchV2" "github.com/grafana/grafana/pkg/services/searchV2"
@ -31,6 +32,8 @@ const DatasourceID = -1
// Grafana DS command. // Grafana DS command.
const DatasourceUID = "grafana" const DatasourceUID = "grafana"
const publicFilestorageBackend = "public"
// Make sure Service implements required interfaces. // Make sure Service implements required interfaces.
// This is important to do since otherwise we will only get a // This is important to do since otherwise we will only get a
// not implemented error response from plugin at runtime. // not implemented error response from plugin at runtime.
@ -40,12 +43,14 @@ var (
logger = log.New("tsdb.grafana") logger = log.New("tsdb.grafana")
) )
func ProvideService(cfg *setting.Cfg, search searchV2.SearchService) *Service { func ProvideService(cfg *setting.Cfg, search searchV2.SearchService, fs filestorage.FileStorage) *Service {
return newService(cfg, search) 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{ s := &Service{
fs: fs,
search: search,
staticRootPath: cfg.StaticRootPath, staticRootPath: cfg.StaticRootPath,
roots: []string{ roots: []string{
"testdata", "testdata",
@ -55,7 +60,7 @@ func newService(cfg *setting.Cfg, search searchV2.SearchService) *Service {
"maps", "maps",
"upload", // does not exist yet "upload", // does not exist yet
}, },
search: search, log: log.New("grafanads"),
} }
return s return s
@ -67,6 +72,8 @@ type Service struct {
staticRootPath string staticRootPath string
roots []string roots []string
search searchV2.SearchService search searchV2.SearchService
fs filestorage.FileStorage
log log.Logger
} }
func DataSourceModel(orgId int64) *models.DataSource { func DataSourceModel(orgId int64) *models.DataSource {
@ -111,22 +118,63 @@ func (s *Service) CheckHealth(_ context.Context, _ *backend.CheckHealthRequest)
}, nil }, nil
} }
func (s *Service) publicPath(path string) (string, error) { func (s *Service) getDirectoryFrame(path string, details bool) (*data.Frame, error) {
if strings.Contains(path, "..") { // Name() string // base name of the file
return "", fmt.Errorf("invalid string") // 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 filesResp, err := s.fs.ListFiles(ctx, path, nil, &filestorage.ListOptions{Recursive: false})
for _, root := range s.roots { if err != nil {
if strings.HasPrefix(path, root) { s.log.Error("failed when listing files", "path", path, "err", err)
ok = true return nil, errors.New("unknown error")
break }
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 { func (s *Service) doListQuery(query backend.DataQuery) backend.DataResponse {
@ -138,14 +186,23 @@ func (s *Service) doListQuery(query backend.DataQuery) backend.DataResponse {
return response return response
} }
if q.Path == "" { path := q.Path
count := len(s.roots) 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) names := data.NewFieldFromFieldType(data.FieldTypeString, count)
mtype := data.NewFieldFromFieldType(data.FieldTypeString, count) mtype := data.NewFieldFromFieldType(data.FieldTypeString, count)
names.Name = "name" names.Name = "name"
mtype.Name = "mediaType" mtype.Name = "mediaType"
for i, f := range s.roots { for i, f := range folders {
names.Set(i, f) names.Set(i, f.FullPath)
s.log.Info("setting full path", "name", f.Name, "path", f.FullPath)
mtype.Set(i, "directory") mtype.Set(i, "directory")
} }
frame := data.NewFrame("", names, mtype) frame := data.NewFrame("", names, mtype)
@ -154,12 +211,7 @@ func (s *Service) doListQuery(query backend.DataQuery) backend.DataResponse {
}) })
response.Frames = data.Frames{frame} response.Frames = data.Frames{frame}
} else { } else {
path, err := s.publicPath(q.Path) frame, err := s.getDirectoryFrame(path, false)
if err != nil {
response.Error = err
return response
}
frame, err := experimental.GetDirectoryFrame(path, false)
if err != nil { if err != nil {
response.Error = err response.Error = err
return response return response
@ -170,6 +222,24 @@ func (s *Service) doListQuery(query backend.DataQuery) backend.DataResponse {
return response 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 { func (s *Service) doReadQuery(query backend.DataQuery) backend.DataResponse {
q := &listQueryModel{} q := &listQueryModel{}
response := backend.DataResponse{} response := backend.DataResponse{}
@ -194,6 +264,7 @@ func (s *Service) doReadQuery(query backend.DataQuery) backend.DataResponse {
// nolint:gosec // nolint:gosec
fileReader, err := os.Open(path) fileReader, err := os.Open(path)
if err != nil { if err != nil {
s.log.Error("Failed to read file", "err", err, "path", path)
response.Error = fmt.Errorf("failed to read file") response.Error = fmt.Errorf("failed to read file")
return response return response
} }

@ -5,11 +5,12 @@ import (
"path" "path"
"testing" "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/backend"
"github.com/grafana/grafana-plugin-sdk-go/experimental" "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" "github.com/stretchr/testify/require"
) )
@ -19,25 +20,35 @@ func asJSON(v interface{}) json.RawMessage {
} }
func TestReadFolderListing(t *testing.T) { 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{ dr := ds.doListQuery(backend.DataQuery{
QueryType: "x", QueryType: "x",
JSON: asJSON(listQueryModel{ 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) require.NoError(t, err)
} }
func TestReadCSVFile(t *testing.T) { 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{ dr := ds.doReadQuery(backend.DataQuery{
QueryType: "x", QueryType: "x",
JSON: asJSON(readQueryModel{ JSON: asJSON(readQueryModel{
Path: "testdata/js_libraries.csv", 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) require.NoError(t, err)
} }

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

@ -6,20 +6,20 @@ Frame[0] {
} }
Name: Name:
Dimensions: 2 Fields by 7 Rows Dimensions: 2 Fields by 7 Rows
+--------------------------+------------------+ +--------------------------+-------------------------+
| Name: name | Name: media-type | | Name: name | Name: media-type |
| Labels: | Labels: | | Labels: | Labels: |
| Type: []string | Type: []string | | Type: []string | Type: []string |
+--------------------------+------------------+ +--------------------------+-------------------------+
| browser_marketshare.csv | | | browser_marketshare.csv | text/csv; charset=utf-8 |
| flight_info_by_state.csv | | | flight_info_by_state.csv | text/csv; charset=utf-8 |
| gdp_per_capita.csv | | | gdp_per_capita.csv | text/csv; charset=utf-8 |
| js_libraries.csv | | | js_libraries.csv | text/csv; charset=utf-8 |
| ohlc_dogecoin.csv | | | ohlc_dogecoin.csv | text/csv; charset=utf-8 |
| population_by_state.csv | | | population_by_state.csv | text/csv; charset=utf-8 |
| weight_height.csv | | | weight_height.csv | text/csv; charset=utf-8 |
+--------------------------+------------------+ +--------------------------+-------------------------+
====== TEST DATA RESPONSE (arrow base64) ====== ====== 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() getDatasourceSrv()
.get('-- Grafana --') .get('-- Grafana --')
.then((ds) => { .then((ds) => {
(ds as GrafanaDatasource).listFiles(folder).subscribe({ (ds as GrafanaDatasource).listFiles(`/public/${folder}`).subscribe({
next: (frame) => { next: (frame) => {
const cards: ResourceItem[] = []; const cards: ResourceItem[] = [];
frame.forEach((item) => { frame.forEach((item) => {

Loading…
Cancel
Save