mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Storage: refactor readonly support (#52127)
This commit is contained in:
@@ -4,7 +4,8 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/filestorage"
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
@@ -25,9 +26,8 @@ var ErrValidationFailed = errors.New("request validation failed")
|
||||
var ErrFileAlreadyExists = errors.New("file exists")
|
||||
|
||||
const RootPublicStatic = "public-static"
|
||||
const RootResources = "resources"
|
||||
|
||||
const MAX_UPLOAD_SIZE = 3 * 1024 * 1024 // 3MB
|
||||
const MAX_UPLOAD_SIZE = 1 * 1024 * 1024 // 3MB
|
||||
|
||||
type DeleteFolderCmd struct {
|
||||
Path string `json:"path"`
|
||||
@@ -85,11 +85,26 @@ func ProvideService(sql *sqlstore.SQLStore, features featuremgmt.FeatureToggles,
|
||||
setDescription("Access files from the static public files"),
|
||||
}
|
||||
|
||||
// Development dashboards
|
||||
if setting.Env != setting.Prod {
|
||||
devenv := filepath.Join(cfg.StaticRootPath, "..", "devenv")
|
||||
if _, err := os.Stat(devenv); !os.IsNotExist(err) {
|
||||
// path/to/whatever exists
|
||||
s := newDiskStorage("devenv", "Development Environment", &StorageLocalDiskConfig{
|
||||
Path: devenv,
|
||||
Roots: []string{
|
||||
"/dev-dashboards/",
|
||||
},
|
||||
}).setReadOnly(false).setDescription("Explore files within the developer environment directly")
|
||||
globalRoots = append(globalRoots, s)
|
||||
}
|
||||
}
|
||||
|
||||
initializeOrgStorages := func(orgId int64) []storageRuntime {
|
||||
storages := make([]storageRuntime, 0)
|
||||
if features.IsEnabled(featuremgmt.FlagStorageLocalUpload) {
|
||||
storages = append(storages,
|
||||
newSQLStorage(RootResources,
|
||||
newSQLStorage("resources",
|
||||
"Resources",
|
||||
&StorageSQLConfig{orgId: orgId}, sql).
|
||||
setBuiltin(true).
|
||||
@@ -155,22 +170,16 @@ type UploadRequest struct {
|
||||
OverwriteExistingFile bool
|
||||
}
|
||||
|
||||
func storageSupportsMutatingOperations(path string) bool {
|
||||
// TODO: this is temporary - make it rbac-driven
|
||||
return strings.HasPrefix(path, RootResources+"/") || path == RootResources
|
||||
}
|
||||
|
||||
func (s *standardStorageService) Upload(ctx context.Context, user *models.SignedInUser, req *UploadRequest) error {
|
||||
upload, _ := s.tree.getRoot(getOrgId(user), RootResources)
|
||||
upload, storagePath := s.tree.getRoot(getOrgId(user), req.Path)
|
||||
if upload == nil {
|
||||
return ErrUploadFeatureDisabled
|
||||
}
|
||||
|
||||
if !storageSupportsMutatingOperations(req.Path) {
|
||||
if upload.Meta().ReadOnly {
|
||||
return ErrUnsupportedStorage
|
||||
}
|
||||
|
||||
storagePath := strings.TrimPrefix(req.Path, RootResources)
|
||||
validationResult := s.validateUploadRequest(ctx, user, req, storagePath)
|
||||
if !validationResult.ok {
|
||||
grafanaStorageLogger.Warn("file upload validation failed", "filetype", req.MimeType, "path", req.Path, "reason", validationResult.reason)
|
||||
@@ -186,7 +195,7 @@ func (s *standardStorageService) Upload(ctx context.Context, user *models.Signed
|
||||
grafanaStorageLogger.Info("uploading a file", "filetype", req.MimeType, "path", req.Path)
|
||||
|
||||
if !req.OverwriteExistingFile {
|
||||
file, err := upload.Get(ctx, storagePath)
|
||||
file, err := upload.Store().Get(ctx, storagePath)
|
||||
if err != nil {
|
||||
grafanaStorageLogger.Error("failed while checking file existence", "err", err, "path", req.Path)
|
||||
return ErrUploadInternalError
|
||||
@@ -197,7 +206,7 @@ func (s *standardStorageService) Upload(ctx context.Context, user *models.Signed
|
||||
}
|
||||
}
|
||||
|
||||
if err := upload.Upsert(ctx, upsertCommand); err != nil {
|
||||
if err := upload.Store().Upsert(ctx, upsertCommand); err != nil {
|
||||
grafanaStorageLogger.Error("failed while uploading the file", "err", err, "path", req.Path)
|
||||
return ErrUploadInternalError
|
||||
}
|
||||
@@ -206,34 +215,32 @@ func (s *standardStorageService) Upload(ctx context.Context, user *models.Signed
|
||||
}
|
||||
|
||||
func (s *standardStorageService) DeleteFolder(ctx context.Context, user *models.SignedInUser, cmd *DeleteFolderCmd) error {
|
||||
resources, _ := s.tree.getRoot(getOrgId(user), RootResources)
|
||||
if resources == nil {
|
||||
root, storagePath := s.tree.getRoot(getOrgId(user), cmd.Path)
|
||||
if root == nil {
|
||||
return fmt.Errorf("resources storage is not enabled")
|
||||
}
|
||||
|
||||
if !storageSupportsMutatingOperations(cmd.Path) {
|
||||
if root.Meta().ReadOnly {
|
||||
return ErrUnsupportedStorage
|
||||
}
|
||||
|
||||
storagePath := strings.TrimPrefix(cmd.Path, RootResources)
|
||||
if storagePath == "" {
|
||||
storagePath = filestorage.Delimiter
|
||||
}
|
||||
return resources.DeleteFolder(ctx, storagePath, &filestorage.DeleteFolderOptions{Force: true})
|
||||
return root.Store().DeleteFolder(ctx, storagePath, &filestorage.DeleteFolderOptions{Force: true})
|
||||
}
|
||||
|
||||
func (s *standardStorageService) CreateFolder(ctx context.Context, user *models.SignedInUser, cmd *CreateFolderCmd) error {
|
||||
if !storageSupportsMutatingOperations(cmd.Path) {
|
||||
return ErrUnsupportedStorage
|
||||
}
|
||||
|
||||
resources, _ := s.tree.getRoot(getOrgId(user), RootResources)
|
||||
if resources == nil {
|
||||
root, storagePath := s.tree.getRoot(getOrgId(user), cmd.Path)
|
||||
if root == nil {
|
||||
return fmt.Errorf("resources storage is not enabled")
|
||||
}
|
||||
|
||||
storagePath := strings.TrimPrefix(cmd.Path, RootResources)
|
||||
err := resources.CreateFolder(ctx, storagePath)
|
||||
if root.Meta().ReadOnly {
|
||||
return ErrUnsupportedStorage
|
||||
}
|
||||
|
||||
err := root.Store().CreateFolder(ctx, storagePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -241,17 +248,16 @@ func (s *standardStorageService) CreateFolder(ctx context.Context, user *models.
|
||||
}
|
||||
|
||||
func (s *standardStorageService) Delete(ctx context.Context, user *models.SignedInUser, path string) error {
|
||||
if !storageSupportsMutatingOperations(path) {
|
||||
return ErrUnsupportedStorage
|
||||
}
|
||||
|
||||
resources, _ := s.tree.getRoot(getOrgId(user), RootResources)
|
||||
if resources == nil {
|
||||
root, storagePath := s.tree.getRoot(getOrgId(user), path)
|
||||
if root == nil {
|
||||
return fmt.Errorf("resources storage is not enabled")
|
||||
}
|
||||
|
||||
storagePath := strings.TrimPrefix(path, RootResources)
|
||||
err := resources.Delete(ctx, storagePath)
|
||||
if root.Meta().ReadOnly {
|
||||
return ErrUnsupportedStorage
|
||||
}
|
||||
|
||||
err := root.Store().Delete(ctx, storagePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user