Nested Folders: Support getting of nested folder in folder service wh… (#58597)

* Nested Folders: Support getting of nested folder in folder service when feature flag is set

* Fix lint

* Fix some tests

* Fix ngalert test

* ngalert fix

* Fix API tests

* Fix some tests and lint

* Fix lint 2

* Fix library elements and panels

* Add access control to get folder

* Cleanup and minor test change
This commit is contained in:
idafurjes
2022-11-11 14:28:24 +01:00
committed by GitHub
parent 88a829e103
commit 080ea88af7
39 changed files with 372 additions and 420 deletions

View File

@@ -14,6 +14,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/folder"
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/ngalert/eval"
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
@@ -181,7 +182,7 @@ func (srv PrometheusSrv) RouteGetRuleStatuses(c *models.ReqContext) response.Res
return response.JSON(http.StatusOK, ruleResponse)
}
func (srv PrometheusSrv) toRuleGroup(groupName string, folder *models.Folder, rules []*ngmodels.AlertRule, labelOptions []ngmodels.LabelOption) *apimodels.RuleGroup {
func (srv PrometheusSrv) toRuleGroup(groupName string, folder *folder.Folder, rules []*ngmodels.AlertRule, labelOptions []ngmodels.LabelOption) *apimodels.RuleGroup {
newGroup := &apimodels.RuleGroup{
Name: groupName,
File: folder.Title, // file is what Prometheus uses for provisioning, we replace it with namespace.

View File

@@ -83,7 +83,7 @@ func (srv RulerSrv) RouteDeleteAlertRules(c *models.ReqContext, namespaceTitle s
unauthz, provisioned := false, false
q := ngmodels.ListAlertRulesQuery{
OrgID: c.SignedInUser.OrgID,
NamespaceUIDs: []string{namespace.Uid},
NamespaceUIDs: []string{namespace.UID},
RuleGroup: ruleGroup,
}
if err = srv.store.ListAlertRules(ctx, &q); err != nil {
@@ -163,7 +163,7 @@ func (srv RulerSrv) RouteGetNamespaceRulesConfig(c *models.ReqContext, namespace
q := ngmodels.ListAlertRulesQuery{
OrgID: c.SignedInUser.OrgID,
NamespaceUIDs: []string{namespace.Uid},
NamespaceUIDs: []string{namespace.UID},
}
if err := srv.store.ListAlertRules(c.Req.Context(), &q); err != nil {
return ErrResp(http.StatusInternalServerError, err, "failed to update rule group")
@@ -189,7 +189,7 @@ func (srv RulerSrv) RouteGetNamespaceRulesConfig(c *models.ReqContext, namespace
if !authorizeAccessToRuleGroup(rules, hasAccess) {
continue
}
result[namespaceTitle] = append(result[namespaceTitle], toGettableRuleGroupConfig(groupName, rules, namespace.Id, provenanceRecords))
result[namespaceTitle] = append(result[namespaceTitle], toGettableRuleGroupConfig(groupName, rules, namespace.ID, provenanceRecords))
}
return response.JSON(http.StatusAccepted, result)
@@ -205,7 +205,7 @@ func (srv RulerSrv) RouteGetRulesGroupConfig(c *models.ReqContext, namespaceTitl
q := ngmodels.ListAlertRulesQuery{
OrgID: c.SignedInUser.OrgID,
NamespaceUIDs: []string{namespace.Uid},
NamespaceUIDs: []string{namespace.UID},
RuleGroup: ruleGroup,
}
if err := srv.store.ListAlertRules(c.Req.Context(), &q); err != nil {
@@ -226,7 +226,7 @@ func (srv RulerSrv) RouteGetRulesGroupConfig(c *models.ReqContext, namespaceTitl
}
result := apimodels.RuleGroupConfigResponse{
GettableRuleGroupConfig: toGettableRuleGroupConfig(ruleGroup, q.Result, namespace.Id, provenanceRecords),
GettableRuleGroupConfig: toGettableRuleGroupConfig(ruleGroup, q.Result, namespace.ID, provenanceRecords),
}
return response.JSON(http.StatusAccepted, result)
}
@@ -296,7 +296,7 @@ func (srv RulerSrv) RouteGetRulesConfig(c *models.ReqContext) response.Response
continue
}
namespace := folder.Title
result[namespace] = append(result[namespace], toGettableRuleGroupConfig(groupKey.RuleGroup, rules, folder.Id, provenanceRecords))
result[namespace] = append(result[namespace], toGettableRuleGroupConfig(groupKey.RuleGroup, rules, folder.ID, provenanceRecords))
}
return response.JSON(http.StatusOK, result)
}
@@ -316,7 +316,7 @@ func (srv RulerSrv) RoutePostNameRulesConfig(c *models.ReqContext, ruleGroupConf
groupKey := ngmodels.AlertRuleGroupKey{
OrgID: c.SignedInUser.OrgID,
NamespaceUID: namespace.Uid,
NamespaceUID: namespace.UID,
RuleGroup: ruleGroupConfig.Name,
}

View File

@@ -18,6 +18,7 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol"
acMock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
"github.com/grafana/grafana/pkg/services/datasources"
"github.com/grafana/grafana/pkg/services/folder"
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/provisioning"
@@ -382,7 +383,7 @@ func TestRouteGetNamespaceRulesConfig(t *testing.T) {
ruleStore := fakes.NewRuleStore(t)
ruleStore.Folders[orgID] = append(ruleStore.Folders[orgID], folder)
groupKey := models.GenerateGroupKey(orgID)
groupKey.NamespaceUID = folder.Uid
groupKey.NamespaceUID = folder.UID
expectedRules := models.GenerateAlertRules(rand.Intn(5)+5, models.AlertRuleGen(withGroupKey(groupKey), models.WithUniqueGroupIndex()))
ruleStore.PutRule(context.Background(), expectedRules...)
@@ -426,12 +427,12 @@ func TestRouteGetRulesConfig(t *testing.T) {
ruleStore := fakes.NewRuleStore(t)
folder1 := randFolder()
folder2 := randFolder()
ruleStore.Folders[orgID] = []*models2.Folder{folder1, folder2}
ruleStore.Folders[orgID] = []*folder.Folder{folder1, folder2}
group1Key := models.GenerateGroupKey(orgID)
group1Key.NamespaceUID = folder1.Uid
group1Key.NamespaceUID = folder1.UID
group2Key := models.GenerateGroupKey(orgID)
group2Key.NamespaceUID = folder2.Uid
group2Key.NamespaceUID = folder2.UID
group1 := models.GenerateAlertRules(rand.Intn(4)+2, models.AlertRuleGen(withGroupKey(group1Key)))
group2 := models.GenerateAlertRules(rand.Intn(4)+2, models.AlertRuleGen(withGroupKey(group2Key)))
@@ -464,7 +465,7 @@ func TestRouteGetRulesConfig(t *testing.T) {
ruleStore := fakes.NewRuleStore(t)
ruleStore.Folders[orgID] = append(ruleStore.Folders[orgID], folder)
groupKey := models.GenerateGroupKey(orgID)
groupKey.NamespaceUID = folder.Uid
groupKey.NamespaceUID = folder.UID
expectedRules := models.GenerateAlertRules(rand.Intn(5)+5, models.AlertRuleGen(withGroupKey(groupKey), models.WithUniqueGroupIndex()))
ruleStore.PutRule(context.Background(), expectedRules...)
@@ -509,7 +510,7 @@ func TestRouteGetRulesGroupConfig(t *testing.T) {
ruleStore := fakes.NewRuleStore(t)
ruleStore.Folders[orgID] = append(ruleStore.Folders[orgID], folder)
groupKey := models.GenerateGroupKey(orgID)
groupKey.NamespaceUID = folder.Uid
groupKey.NamespaceUID = folder.UID
expectedRules := models.GenerateAlertRules(rand.Intn(4)+2, models.AlertRuleGen(withGroupKey(groupKey)))
ruleStore.PutRule(context.Background(), expectedRules...)
@@ -544,7 +545,7 @@ func TestRouteGetRulesGroupConfig(t *testing.T) {
ruleStore := fakes.NewRuleStore(t)
ruleStore.Folders[orgID] = append(ruleStore.Folders[orgID], folder)
groupKey := models.GenerateGroupKey(orgID)
groupKey.NamespaceUID = folder.Uid
groupKey.NamespaceUID = folder.UID
expectedRules := models.GenerateAlertRules(rand.Intn(5)+5, models.AlertRuleGen(withGroupKey(groupKey), models.WithUniqueGroupIndex()))
ruleStore.PutRule(context.Background(), expectedRules...)
@@ -699,9 +700,9 @@ func withGroup(groupName string) func(rule *models.AlertRule) {
}
}
func withNamespace(namespace *models2.Folder) func(rule *models.AlertRule) {
func withNamespace(namespace *folder.Folder) func(rule *models.AlertRule) {
return func(rule *models.AlertRule) {
rule.NamespaceUID = namespace.Uid
rule.NamespaceUID = namespace.UID
}
}

View File

@@ -5,7 +5,7 @@ import (
"fmt"
"time"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/folder"
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/store"
@@ -18,7 +18,7 @@ func validateRuleNode(
groupName string,
interval time.Duration,
orgId int64,
namespace *models.Folder,
namespace *folder.Folder,
conditionValidator func(ngmodels.Condition) error,
cfg *setting.UnifiedAlertingSettings) (*ngmodels.AlertRule, error) {
intervalSeconds, err := validateInterval(cfg, interval)
@@ -93,7 +93,7 @@ func validateRuleNode(
Data: ruleNode.GrafanaManagedAlert.Data,
UID: ruleNode.GrafanaManagedAlert.UID,
IntervalSeconds: intervalSeconds,
NamespaceUID: namespace.Uid,
NamespaceUID: namespace.UID,
RuleGroup: groupName,
NoDataState: noDataState,
ExecErrState: errorState,
@@ -152,7 +152,7 @@ func validateForInterval(ruleNode *apimodels.PostableExtendedRuleNode) (time.Dur
func validateRuleGroup(
ruleGroupConfig *apimodels.PostableRuleGroupConfig,
orgId int64,
namespace *models.Folder,
namespace *folder.Folder,
conditionValidator func(ngmodels.Condition) error,
cfg *setting.UnifiedAlertingSettings) ([]*ngmodels.AlertRule, error) {
if ruleGroupConfig.Name == "" {

View File

@@ -11,7 +11,7 @@ import (
"github.com/stretchr/testify/require"
"golang.org/x/exp/rand"
models2 "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/folder"
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/ngalert/store"
@@ -83,18 +83,18 @@ func validGroup(cfg *setting.UnifiedAlertingSettings, rules ...apimodels.Postabl
}
}
func randFolder() *models2.Folder {
return &models2.Folder{
Id: rand.Int63(),
Uid: util.GenerateShortUID(),
Title: "TEST-FOLDER-" + util.GenerateShortUID(),
Url: "",
Version: 0,
Created: time.Time{},
Updated: time.Time{},
UpdatedBy: 0,
CreatedBy: 0,
HasACL: false,
func randFolder() *folder.Folder {
return &folder.Folder{
ID: rand.Int63(),
UID: util.GenerateShortUID(),
Title: "TEST-FOLDER-" + util.GenerateShortUID(),
// URL: "",
// Version: 0,
Created: time.Time{},
Updated: time.Time{},
// UpdatedBy: 0,
// CreatedBy: 0,
// HasACL: false,
}
}
@@ -235,7 +235,7 @@ func TestValidateRuleNode_NoUID(t *testing.T) {
require.Equal(t, int64(interval.Seconds()), alert.IntervalSeconds)
require.Equal(t, int64(0), alert.Version)
require.Equal(t, api.GrafanaManagedAlert.UID, alert.UID)
require.Equal(t, folder.Uid, alert.NamespaceUID)
require.Equal(t, folder.UID, alert.NamespaceUID)
require.Nil(t, alert.DashboardUID)
require.Nil(t, alert.PanelID)
require.Equal(t, name, alert.RuleGroup)

View File

@@ -3,15 +3,15 @@ package api
import (
"context"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/folder"
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
"github.com/grafana/grafana/pkg/services/user"
)
// RuleStore is the interface for persisting alert rules and instances
type RuleStore interface {
GetUserVisibleNamespaces(context.Context, int64, *user.SignedInUser) (map[string]*models.Folder, error)
GetNamespaceByTitle(context.Context, string, int64, *user.SignedInUser, bool) (*models.Folder, error)
GetUserVisibleNamespaces(context.Context, int64, *user.SignedInUser) (map[string]*folder.Folder, error)
GetNamespaceByTitle(context.Context, string, int64, *user.SignedInUser, bool) (*folder.Folder, error)
GetAlertRulesGroupByRuleUID(ctx context.Context, query *ngmodels.GetAlertRulesGroupByRuleUIDQuery) error
ListAlertRules(ctx context.Context, query *ngmodels.ListAlertRulesQuery) error