fix(folders): use namespace_uid for alert count (#111773)

This commit is contained in:
Jean-Philippe Quéméner
2025-09-29 16:12:34 -05:00
committed by GitHub
parent 37b5b1a03d
commit d0e3e91b03
3 changed files with 93 additions and 3 deletions
+89
View File
@@ -8,6 +8,7 @@ import (
"net/http"
"slices"
"testing"
"time"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/api/meta"
@@ -15,6 +16,10 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"github.com/grafana/grafana/pkg/expr"
apimodels "github.com/grafana/grafana/pkg/services/ngalert/api/tooling/definitions"
"github.com/prometheus/common/model"
folders "github.com/grafana/grafana/apps/folder/pkg/apis/folder/v1beta1"
"github.com/grafana/grafana/pkg/api/dtos"
grafanarest "github.com/grafana/grafana/pkg/apiserver/rest"
@@ -26,6 +31,7 @@ import (
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/setting"
alerting "github.com/grafana/grafana/pkg/tests/api/alerting"
"github.com/grafana/grafana/pkg/tests/apis"
"github.com/grafana/grafana/pkg/tests/testinfra"
"github.com/grafana/grafana/pkg/tests/testsuite"
@@ -223,6 +229,89 @@ func TestIntegrationFoldersApp(t *testing.T) {
})
}
// Validates that folder delete checks alert_rule stats and blocks deletion
func TestIntegrationFolderDeletionBlockedByAlertRules(t *testing.T) {
testutil.SkipIntegrationTestInShortMode(t)
if !db.IsTestDbSQLite() {
t.Skip("test only on sqlite for now")
}
t.Run("should be blocked by alert rules", func(t *testing.T) {
helper := apis.NewK8sTestHelper(t, testinfra.GrafanaOpts{
AppModeProduction: true,
DisableAnonymous: true,
APIServerStorageType: "unified",
UnifiedStorageConfig: map[string]setting.UnifiedStorageConfig{
folders.RESOURCEGROUP: {DualWriterMode: grafanarest.Mode5},
},
EnableFeatureToggles: []string{
featuremgmt.FlagUnifiedStorageSearch,
},
})
client := helper.GetResourceClient(apis.ResourceClientArgs{
User: helper.Org1.Admin,
GVR: gvr,
})
// Create a folder via legacy API so it is visible everywhere.
folderUID := "alertrule-del-test"
legacyPayload := fmt.Sprintf(`{"title": "Folder With Alert Rule", "uid": "%s"}`, folderUID)
legacyCreate := apis.DoRequest(helper, apis.RequestParams{
User: client.Args.User,
Method: http.MethodPost,
Path: "/api/folders",
Body: []byte(legacyPayload),
}, &folder.Folder{})
require.NotNil(t, legacyCreate.Result)
require.Equal(t, folderUID, legacyCreate.Result.UID)
// Create one alert rule in that folder namespace via ruler API.
addr := helper.GetEnv().Server.HTTPServer.Listener.Addr().String()
api := alerting.NewAlertingLegacyAPIClient(addr, "admin", "admin")
// simple always-true rule
forDuration := model.Duration(10 * time.Second)
rule := apimodels.PostableExtendedRuleNode{
ApiRuleNode: &apimodels.ApiRuleNode{For: &forDuration},
GrafanaManagedAlert: &apimodels.PostableGrafanaRule{
Title: "rule-in-folder",
Condition: "A",
Data: []apimodels.AlertQuery{
{
RefID: "A",
DatasourceUID: expr.DatasourceUID,
RelativeTimeRange: apimodels.RelativeTimeRange{
From: apimodels.Duration(600 * time.Second),
To: 0,
},
Model: json.RawMessage(`{"type":"math","expression":"2 + 3 > 1"}`),
},
},
},
}
group := apimodels.PostableRuleGroupConfig{
Name: "arulegroup",
Interval: model.Duration(10 * time.Second),
Rules: []apimodels.PostableExtendedRuleNode{rule},
}
_ = api.PostRulesGroup(t, folderUID, &group, false)
// Attempt to delete the folder via K8s API. This should be blocked by alert rules.
err := client.Resource.Delete(context.Background(), folderUID, metav1.DeleteOptions{})
require.Error(t, err, "expected folder deletion to be blocked when alert rules exist")
// Delete the rule group from ruler.
status, body := api.DeleteRulesGroup(t, folderUID, group.Name, true)
require.Equalf(t, http.StatusAccepted, status, body)
// Now we should be able to delete the folder.
err = client.Resource.Delete(context.Background(), folderUID, metav1.DeleteOptions{})
require.NoError(t, err)
})
}
func doFolderTests(t *testing.T, helper *apis.K8sTestHelper) *apis.K8sTestHelper {
t.Run("Check folder CRUD (just create for now) in legacy API appears in k8s apis", func(t *testing.T) {
client := helper.GetResourceClient(apis.ResourceClientArgs{