Folders: Split legacy out of folder.Service (and remove folder.FolderStore) (#110734)
This commit is contained in:
@@ -47,7 +47,6 @@ import (
|
||||
dashsvc "github.com/grafana/grafana/pkg/services/dashboards/service"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/librarypanels"
|
||||
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
||||
"github.com/grafana/grafana/pkg/services/provisioning"
|
||||
@@ -89,7 +88,6 @@ type DashboardsAPIBuilder struct {
|
||||
scheme *runtime.Scheme
|
||||
search *SearchHandler
|
||||
dashStore dashboards.Store
|
||||
folderStore folder.FolderStore
|
||||
QuotaService quota.Service
|
||||
ProvisioningService provisioning.ProvisioningService
|
||||
cfg *setting.Cfg
|
||||
@@ -125,7 +123,6 @@ func RegisterAPIService(
|
||||
dual dualwrite.Service,
|
||||
sorter sort.Service,
|
||||
quotaService quota.Service,
|
||||
folderStore folder.FolderStore,
|
||||
libraryPanelSvc librarypanels.Service,
|
||||
restConfigProvider apiserver.RestConfigProvider,
|
||||
userService user.Service,
|
||||
@@ -149,7 +146,6 @@ func RegisterAPIService(
|
||||
dashboardProvisioningService: provisioningDashboardService,
|
||||
search: NewSearchHandler(tracing, dual, legacyDashboardSearcher, unified, features),
|
||||
dashStore: dashStore,
|
||||
folderStore: folderStore,
|
||||
QuotaService: quotaService,
|
||||
ProvisioningService: provisioning,
|
||||
cfg: cfg,
|
||||
|
||||
@@ -31,7 +31,7 @@ var (
|
||||
)
|
||||
|
||||
type legacyStorage struct {
|
||||
service folder.Service
|
||||
service folder.LegacyService
|
||||
namespacer request.NamespaceMapper
|
||||
tableConverter rest.TableConvertor
|
||||
}
|
||||
@@ -243,6 +243,7 @@ func (s *legacyStorage) Update(ctx context.Context,
|
||||
return nil, created, fmt.Errorf("expected old object to be a folder also")
|
||||
}
|
||||
|
||||
changed := false
|
||||
mOld, _ := utils.MetaAccessor(old)
|
||||
mNew, _ := utils.MetaAccessor(f)
|
||||
oldParent := mOld.GetFolder()
|
||||
@@ -257,9 +258,9 @@ func (s *legacyStorage) Update(ctx context.Context,
|
||||
if err != nil {
|
||||
return nil, created, err
|
||||
}
|
||||
changed = true
|
||||
}
|
||||
|
||||
changed := false
|
||||
cmd := &folder.UpdateFolderCommand{
|
||||
SignedInUser: user,
|
||||
UID: name,
|
||||
|
||||
@@ -17,17 +17,16 @@ import (
|
||||
"k8s.io/kube-openapi/pkg/common"
|
||||
"k8s.io/kube-openapi/pkg/spec3"
|
||||
|
||||
"github.com/grafana/grafana/apps/iam/pkg/reconcilers"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana"
|
||||
|
||||
authlib "github.com/grafana/authlib/types"
|
||||
folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
|
||||
"github.com/grafana/grafana/apps/iam/pkg/reconcilers"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic"
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/builder"
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/services/authz/zanzana"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -48,7 +47,7 @@ var errNoResource = errors.New("resource name is required")
|
||||
type FolderAPIBuilder struct {
|
||||
features featuremgmt.FeatureToggles
|
||||
namespacer request.NamespaceMapper
|
||||
folderSvc folder.Service
|
||||
folderSvc folder.LegacyService
|
||||
folderPermissionsSvc accesscontrol.FolderPermissionsService
|
||||
acService accesscontrol.Service
|
||||
ac accesscontrol.AccessControl
|
||||
@@ -66,7 +65,7 @@ type FolderAPIBuilder struct {
|
||||
func RegisterAPIService(cfg *setting.Cfg,
|
||||
features featuremgmt.FeatureToggles,
|
||||
apiregistration builder.APIRegistrar,
|
||||
folderSvc folder.Service,
|
||||
folderSvc folder.LegacyService,
|
||||
folderPermissionsSvc accesscontrol.FolderPermissionsService,
|
||||
accessControl accesscontrol.AccessControl,
|
||||
acService accesscontrol.Service,
|
||||
@@ -190,13 +189,13 @@ func (b *FolderAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.API
|
||||
}
|
||||
storage[resourceInfo.StoragePath()] = folderStore
|
||||
|
||||
b.parents = newParentsGetter(folderStore, folderValidationRules.maxDepth) // used for validation
|
||||
b.parents = newParentsGetter(folderStore, folder.MaxNestedFolderDepth) // used for validation
|
||||
storage[resourceInfo.StoragePath("parents")] = &subParentsREST{
|
||||
getter: folderStore,
|
||||
parents: b.parents,
|
||||
}
|
||||
storage[resourceInfo.StoragePath("counts")] = &subCountREST{searcher: b.searcher}
|
||||
storage[resourceInfo.StoragePath("access")] = &subAccessREST{b.folderSvc, b.ac}
|
||||
storage[resourceInfo.StoragePath("access")] = &subAccessREST{folderStore, b.ac}
|
||||
|
||||
// Adds a path to return children of a given folder
|
||||
storage[resourceInfo.StoragePath("children")] = &subChildrenREST{
|
||||
@@ -226,12 +225,6 @@ func (b *FolderAPIBuilder) GetAuthorizer() authorizer.Authorizer {
|
||||
return b.authorizer
|
||||
}
|
||||
|
||||
var folderValidationRules = struct {
|
||||
maxDepth int
|
||||
}{
|
||||
maxDepth: 5, // why different than folder.MaxNestedFolderDepth?? (4)
|
||||
}
|
||||
|
||||
func (b *FolderAPIBuilder) Mutate(ctx context.Context, a admission.Attributes, _ admission.ObjectInterfaces) error {
|
||||
verb := a.GetOperation()
|
||||
if verb == admission.Create || verb == admission.Update {
|
||||
@@ -259,7 +252,7 @@ func (b *FolderAPIBuilder) Validate(ctx context.Context, a admission.Attributes,
|
||||
|
||||
switch a.GetOperation() {
|
||||
case admission.Create:
|
||||
return validateOnCreate(ctx, f, b.parents, folderValidationRules.maxDepth)
|
||||
return validateOnCreate(ctx, f, b.parents, folder.MaxNestedFolderDepth)
|
||||
case admission.Delete:
|
||||
return validateOnDelete(ctx, f, b.searcher)
|
||||
case admission.Update:
|
||||
@@ -267,7 +260,7 @@ func (b *FolderAPIBuilder) Validate(ctx context.Context, a admission.Attributes,
|
||||
if !ok {
|
||||
return fmt.Errorf("obj is not folders.Folder")
|
||||
}
|
||||
return validateOnUpdate(ctx, f, old, b.storage, b.parents, folderValidationRules.maxDepth)
|
||||
return validateOnUpdate(ctx, f, old, b.storage, b.parents, folder.MaxNestedFolderDepth)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,8 +4,7 @@ import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
|
||||
@@ -16,8 +15,8 @@ import (
|
||||
)
|
||||
|
||||
type subAccessREST struct {
|
||||
service folder.Service
|
||||
ac accesscontrol.AccessControl
|
||||
getter rest.Getter
|
||||
ac accesscontrol.AccessControl
|
||||
}
|
||||
|
||||
var _ = rest.Connecter(&subAccessREST{})
|
||||
@@ -47,36 +46,28 @@ func (r *subAccessREST) NewConnectOptions() (runtime.Object, bool, string) {
|
||||
}
|
||||
|
||||
func (r *subAccessREST) Connect(ctx context.Context, name string, opts runtime.Object, responder rest.Responder) (http.Handler, error) {
|
||||
ns, err := request.NamespaceInfoFrom(ctx, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
user, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Can view is managed here (and in the Authorizer)
|
||||
f, err := r.service.Get(ctx, &folder.GetFolderQuery{
|
||||
UID: &name,
|
||||
OrgID: ns.OrgID,
|
||||
SignedInUser: user,
|
||||
})
|
||||
// Must be able to get the resource
|
||||
_, err = r.getter.Get(ctx, name, &v1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
access := &folders.FolderAccessInfo{}
|
||||
canEditEvaluator := accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, dashboards.ScopeFoldersProvider.GetResourceScopeUID(f.UID))
|
||||
canEditEvaluator := accesscontrol.EvalPermission(dashboards.ActionFoldersWrite, dashboards.ScopeFoldersProvider.GetResourceScopeUID(name))
|
||||
access.CanEdit, _ = r.ac.Evaluate(ctx, user, canEditEvaluator)
|
||||
access.CanSave = access.CanEdit
|
||||
canAdminEvaluator := accesscontrol.EvalAll(
|
||||
accesscontrol.EvalPermission(dashboards.ActionFoldersPermissionsRead, dashboards.ScopeFoldersProvider.GetResourceScopeUID(f.UID)),
|
||||
accesscontrol.EvalPermission(dashboards.ActionFoldersPermissionsWrite, dashboards.ScopeFoldersProvider.GetResourceScopeUID(f.UID)),
|
||||
accesscontrol.EvalPermission(dashboards.ActionFoldersPermissionsRead, dashboards.ScopeFoldersProvider.GetResourceScopeUID(name)),
|
||||
accesscontrol.EvalPermission(dashboards.ActionFoldersPermissionsWrite, dashboards.ScopeFoldersProvider.GetResourceScopeUID(name)),
|
||||
)
|
||||
access.CanAdmin, _ = r.ac.Evaluate(ctx, user, canAdminEvaluator)
|
||||
canDeleteEvaluator := accesscontrol.EvalPermission(dashboards.ActionFoldersDelete, dashboards.ScopeFoldersProvider.GetResourceScopeUID(f.UID))
|
||||
canDeleteEvaluator := accesscontrol.EvalPermission(dashboards.ActionFoldersDelete, dashboards.ScopeFoldersProvider.GetResourceScopeUID(name))
|
||||
access.CanDelete, _ = r.ac.Evaluate(ctx, user, canDeleteEvaluator)
|
||||
responder.Object(http.StatusOK, access)
|
||||
}), nil
|
||||
|
||||
Reference in New Issue
Block a user