K8s/Permissions: Enable a grant-permissions annotation action to set default permissions (#102527)
* create permissions * add key * lint * structure as a delayed callback * legacy API hook * merge main * wired up * and folders * watch repos * missing return statement * Set the correct permissions * add TestAfterCreatePermissionCreator * do not add perms on folder create * fix tests * add annotation on create * lint * lint * ensure we set permissions when the FT is disabled * remove custom folder_storage * fix lint * change default * lint * lint * fix: annotation * ensure permissions are added on folder legacy * remove folderstorage again * fix tests * add FT * undo change to folder * dashboard on create * remove annotation for folder * fix tests * fix prepare after rebase * fix tests * fix tests * fix tests * lint * address comments * add test for prepareObjectForStorage * add again skipIfMode as per comment --------- Co-authored-by: Georges Chaudy <chaudyg@gmail.com>
This commit is contained in:
co-authored by
Georges Chaudy
parent
ceed824378
commit
af8a70bbab
@@ -10,7 +10,6 @@ import (
|
||||
"k8s.io/apiserver/pkg/registry/generic/registry"
|
||||
"k8s.io/apiserver/pkg/registry/rest"
|
||||
|
||||
"github.com/grafana/grafana/pkg/apimachinery/identity"
|
||||
"github.com/grafana/grafana/pkg/apimachinery/utils"
|
||||
grafanaregistry "github.com/grafana/grafana/pkg/apiserver/registry/generic"
|
||||
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
|
||||
@@ -19,7 +18,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/apistore"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
type DashboardStorage struct {
|
||||
@@ -27,7 +25,7 @@ type DashboardStorage struct {
|
||||
DashboardService dashboards.DashboardService
|
||||
}
|
||||
|
||||
func (s *DashboardStorage) NewStore(dash utils.ResourceInfo, scheme *runtime.Scheme, defaultOptsGetter generic.RESTOptionsGetter, reg prometheus.Registerer) (grafanarest.Storage, error) {
|
||||
func (s *DashboardStorage) NewStore(dash utils.ResourceInfo, scheme *runtime.Scheme, defaultOptsGetter generic.RESTOptionsGetter, reg prometheus.Registerer, permissions dashboards.PermissionsRegistrationService) (grafanarest.Storage, error) {
|
||||
server, err := resource.NewResourceServer(resource.ResourceServerOptions{
|
||||
Backend: s.Access,
|
||||
Reg: reg,
|
||||
@@ -47,6 +45,7 @@ func (s *DashboardStorage) NewStore(dash utils.ResourceInfo, scheme *runtime.Sch
|
||||
optsGetter.RegisterOptions(dash.GroupResource(), apistore.StorageOptions{
|
||||
EnableFolderSupport: true,
|
||||
RequireDeprecatedInternalID: true,
|
||||
Permissions: permissions.SetDefaultPermissionsAfterCreate,
|
||||
})
|
||||
|
||||
store, err := grafanaregistry.NewRegistryStore(scheme, dash, optsGetter)
|
||||
@@ -65,15 +64,7 @@ type storeWrapper struct {
|
||||
func (s *storeWrapper) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
|
||||
ctx = legacy.WithLegacyAccess(ctx)
|
||||
|
||||
meta, err := utils.MetaAccessor(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
managerProperties, managerPresent := meta.GetManagerProperties()
|
||||
isProvisioned := managerPresent && managerProperties.Kind != utils.ManagerKindUnknown
|
||||
|
||||
obj, err = s.Store.Create(ctx, obj, createValidation, options)
|
||||
obj, err := s.Store.Create(ctx, obj, createValidation, options)
|
||||
access := legacy.GetLegacyAccess(ctx)
|
||||
if access != nil && access.DashboardID > 0 {
|
||||
meta, _ := utils.MetaAccessor(obj)
|
||||
@@ -82,10 +73,9 @@ func (s *storeWrapper) Create(ctx context.Context, obj runtime.Object, createVal
|
||||
meta.SetDeprecatedInternalID(access.DashboardID) //nolint:staticcheck
|
||||
}
|
||||
}
|
||||
|
||||
meta, metaErr := utils.MetaAccessor(obj)
|
||||
if metaErr == nil {
|
||||
// Reconstruc the same UID as done at the storage level
|
||||
// Reconstruct the same UID as done at the storage level
|
||||
// https://github.com/grafana/grafana/blob/a84e96fba29c3a1bb384fdbad1c9c658cc79ec8f/pkg/registry/apis/dashboard/legacy/sql_dashboards.go#L287
|
||||
// This is necessary because the UID generated during the creation via legacy storage is actually never stored in the database
|
||||
// and the one returned here is wrong.
|
||||
@@ -100,31 +90,6 @@ func (s *storeWrapper) Create(ctx context.Context, obj runtime.Object, createVal
|
||||
return obj, metaErr
|
||||
}
|
||||
|
||||
unstructuredMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(obj)
|
||||
if err != nil {
|
||||
return obj, err
|
||||
}
|
||||
unstructuredObj := &unstructured.Unstructured{Object: unstructuredMap}
|
||||
|
||||
user, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return obj, err
|
||||
}
|
||||
|
||||
legacyDashboard, err := s.DashboardService.UnstructuredToLegacyDashboard(ctx, unstructuredObj, user.GetOrgID())
|
||||
if err != nil {
|
||||
return obj, err
|
||||
}
|
||||
|
||||
// We only need these two parameters for SetDefaultPermissions
|
||||
dto := &dashboards.SaveDashboardDTO{
|
||||
User: user,
|
||||
OrgID: user.GetOrgID(),
|
||||
}
|
||||
|
||||
// Temporary approach to set default permissions until we have a proper method in place via k8s
|
||||
s.DashboardService.SetDefaultPermissions(ctx, dto, legacyDashboard, isProvisioned)
|
||||
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -74,6 +74,7 @@ type DashboardsAPIBuilder struct {
|
||||
legacy *DashboardStorage
|
||||
unified resource.ResourceClient
|
||||
dashboardProvisioningService dashboards.DashboardProvisioningService
|
||||
dashboardPermissions dashboards.PermissionsRegistrationService
|
||||
scheme *runtime.Scheme
|
||||
search *SearchHandler
|
||||
dashStore dashboards.Store
|
||||
@@ -94,6 +95,7 @@ func RegisterAPIService(
|
||||
apiregistration builder.APIRegistrar,
|
||||
dashboardService dashboards.DashboardService,
|
||||
provisioningDashboardService dashboards.DashboardProvisioningService,
|
||||
dashboardPermissions dashboards.PermissionsRegistrationService,
|
||||
accessControl accesscontrol.AccessControl,
|
||||
provisioning provisioning.ProvisioningService,
|
||||
dashStore dashboards.Store,
|
||||
@@ -116,6 +118,7 @@ func RegisterAPIService(
|
||||
log: log.New("grafana-apiserver.dashboards"),
|
||||
|
||||
dashboardService: dashboardService,
|
||||
dashboardPermissions: dashboardPermissions,
|
||||
features: features,
|
||||
accessControl: accessControl,
|
||||
unified: unified,
|
||||
@@ -389,6 +392,9 @@ func (b *DashboardsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver
|
||||
storageOpts := apistore.StorageOptions{
|
||||
EnableFolderSupport: true,
|
||||
RequireDeprecatedInternalID: true,
|
||||
|
||||
// Sets default root permissions
|
||||
Permissions: b.dashboardPermissions.SetDefaultPermissionsAfterCreate,
|
||||
}
|
||||
|
||||
// Split dashboards when they are large
|
||||
@@ -468,7 +474,7 @@ func (b *DashboardsAPIBuilder) storageForVersion(
|
||||
storage := map[string]rest.Storage{}
|
||||
apiGroupInfo.VersionedResourcesStorageMap[dashboards.GroupVersion().Version] = storage
|
||||
|
||||
legacyStore, err := b.legacy.NewStore(dashboards, opts.Scheme, opts.OptsGetter, b.reg)
|
||||
legacyStore, err := b.legacy.NewStore(dashboards, opts.Scheme, opts.OptsGetter, b.reg, b.dashboardPermissions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user