Merge remote-tracking branch 'origin/main' into grafana-git-ui-sync

This commit is contained in:
Ryan McKinley
2025-03-11 22:35:05 +03:00
8 changed files with 466 additions and 20 deletions
@@ -188,11 +188,12 @@ func (srv *ConvertPrometheusSrv) RouteConvertPrometheusDeleteNamespace(c *contex
}
logger.Info("Deleting all Prometheus-imported rule groups", "folder_uid", namespace.UID, "folder_title", namespaceTitle)
provenance := getProvenance(c)
filterOpts := &provisioning.FilterOptions{
NamespaceUIDs: []string{namespace.UID},
ImportedPrometheusRule: util.Pointer(true),
}
err = srv.alertRuleService.DeleteRuleGroups(c.Req.Context(), c.SignedInUser, models.ProvenanceConvertedPrometheus, filterOpts)
err = srv.alertRuleService.DeleteRuleGroups(c.Req.Context(), c.SignedInUser, provenance, filterOpts)
if errors.Is(err, models.ErrAlertRuleGroupNotFound) {
return response.Empty(http.StatusNotFound)
}
@@ -218,7 +219,8 @@ func (srv *ConvertPrometheusSrv) RouteConvertPrometheusDeleteRuleGroup(c *contex
}
logger.Info("Deleting Prometheus-imported rule group", "folder_uid", folder.UID, "folder_title", namespaceTitle, "group", group)
err = srv.alertRuleService.DeleteRuleGroup(c.Req.Context(), c.SignedInUser, folder.UID, group, models.ProvenanceConvertedPrometheus)
provenance := getProvenance(c)
err = srv.alertRuleService.DeleteRuleGroup(c.Req.Context(), c.SignedInUser, folder.UID, group, provenance)
if errors.Is(err, models.ErrAlertRuleGroupNotFound) {
return response.Empty(http.StatusNotFound)
}
@@ -352,13 +354,21 @@ func (srv *ConvertPrometheusSrv) RouteConvertPrometheusPostRuleGroup(c *contextm
return errorToResponse(err)
}
group, err := srv.convertToGrafanaRuleGroup(c, ds, ns.UID, promGroup, logger)
provenance := getProvenance(c)
// If the provenance is not ConvertedPrometheus, we don't keep the original rule definition.
// This is because the rules can be modified through the UI, which may break compatibility
// with the Prometheus format. We only preserve the original rule definition
// to ensure we can return them in this API in Prometheus format.
keepOriginalRuleDefinition := provenance == models.ProvenanceConvertedPrometheus
group, err := srv.convertToGrafanaRuleGroup(c, ds, ns.UID, promGroup, keepOriginalRuleDefinition, logger)
if err != nil {
logger.Error("Failed to convert Prometheus rules to Grafana rules", "error", err)
return errorToResponse(err)
}
err = srv.alertRuleService.ReplaceRuleGroup(c.Req.Context(), c.SignedInUser, *group, models.ProvenanceConvertedPrometheus)
err = srv.alertRuleService.ReplaceRuleGroup(c.Req.Context(), c.SignedInUser, *group, provenance)
if err != nil {
logger.Error("Failed to replace rule group", "error", err)
return errorToResponse(err)
@@ -387,7 +397,14 @@ func (srv *ConvertPrometheusSrv) getOrCreateNamespace(c *contextmodel.ReqContext
return ns, nil
}
func (srv *ConvertPrometheusSrv) convertToGrafanaRuleGroup(c *contextmodel.ReqContext, ds *datasources.DataSource, namespaceUID string, promGroup apimodels.PrometheusRuleGroup, logger log.Logger) (*models.AlertRuleGroup, error) {
func (srv *ConvertPrometheusSrv) convertToGrafanaRuleGroup(
c *contextmodel.ReqContext,
ds *datasources.DataSource,
namespaceUID string,
promGroup apimodels.PrometheusRuleGroup,
keepOriginalRuleDefinition bool,
logger log.Logger,
) (*models.AlertRuleGroup, error) {
logger.Info("Converting Prometheus rules to Grafana rules", "rules", len(promGroup.Rules), "folder_uid", namespaceUID, "datasource_uid", ds.UID, "datasource_type", ds.Type)
rules := make([]prom.PrometheusRule, len(promGroup.Rules))
@@ -429,6 +446,7 @@ func (srv *ConvertPrometheusSrv) convertToGrafanaRuleGroup(c *contextmodel.ReqCo
AlertRules: prom.RulesConfig{
IsPaused: pauseAlertRules,
},
KeepOriginalRuleDefinition: util.Pointer(keepOriginalRuleDefinition),
},
)
if err != nil {
@@ -537,3 +555,13 @@ func promGroupHasRecordingRules(promGroup apimodels.PrometheusRuleGroup) bool {
}
return false
}
// getProvenance determines the provenance value to use for rules created via the Prometheus conversion API.
// If the X-Disable-Provenance header is present in the request, returns ProvenanceNone,
// otherwise returns ProvenanceConvertedPrometheus.
func getProvenance(ctx *contextmodel.ReqContext) models.Provenance {
if _, disabled := ctx.Req.Header[disableProvenanceHeaderName]; disabled {
return models.ProvenanceNone
}
return models.ProvenanceConvertedPrometheus
}
@@ -144,6 +144,11 @@ func TestRouteConvertPrometheusPostRuleGroup(t *testing.T) {
promDefinition, err := r.PrometheusRuleDefinition()
require.NoError(t, err)
require.Equal(t, expectedDef, promDefinition)
// Verify provenance was set to ProvenanceConvertedPrometheus
prov, err := provenanceStore.GetProvenance(context.Background(), r, 1)
require.NoError(t, err)
require.Equal(t, models.ProvenanceConvertedPrometheus, prov)
}
})
@@ -341,6 +346,41 @@ func TestRouteConvertPrometheusPostRuleGroup(t *testing.T) {
})
}
})
t.Run("with disable provenance header should use ProvenanceNone", func(t *testing.T) {
provenanceStore := fakes.NewFakeProvisioningStore()
srv, _, ruleStore, folderService := createConvertPrometheusSrv(t, withProvenanceStore(provenanceStore))
// Create a folder in the root
fldr := randFolder()
fldr.ParentUID = ""
folderService.ExpectedFolder = fldr
folderService.ExpectedFolders = []*folder.Folder{fldr}
ruleStore.Folders[1] = append(ruleStore.Folders[1], fldr)
// Create request with the X-Disable-Provenance header
rc := createRequestCtx()
rc.Req.Header.Set("X-Disable-Provenance", "true")
response := srv.RouteConvertPrometheusPostRuleGroup(rc, fldr.Title, simpleGroup)
require.Equal(t, http.StatusAccepted, response.Status())
// Get the created rules
rules, err := ruleStore.ListAlertRules(context.Background(), &models.ListAlertRulesQuery{
OrgID: 1,
})
require.NoError(t, err)
require.Len(t, rules, 2)
// Verify provenance was set to ProvenanceNone
for _, r := range rules {
prov, err := provenanceStore.GetProvenance(context.Background(), r, 1)
require.NoError(t, err)
require.Equal(t, models.ProvenanceNone, prov, "Provenance should be ProvenanceNone when X-Disable-Provenance header is set")
// Prometheus rule definition should not be saved when provenance is disabled
require.Nil(t, r.Metadata.PrometheusStyleRule)
}
})
}
func TestRouteConvertPrometheusGetRuleGroup(t *testing.T) {
@@ -743,6 +783,29 @@ func TestRouteConvertPrometheusDeleteNamespace(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, remaining)
})
t.Run("with disable provenance header should still be able to delete rules", func(t *testing.T) {
provenanceStore := fakes.NewFakeProvisioningStore()
srv, ruleStore, fldr, rule := initNamespace("prometheus definition", withProvenanceStore(provenanceStore))
// Mark the rule as provisioned with API provenance
err := provenanceStore.SetProvenance(context.Background(), rule, 1, models.ProvenanceConvertedPrometheus)
require.NoError(t, err)
rc := createRequestCtx()
rc.Req.Header.Set("X-Disable-Provenance", "true")
response := srv.RouteConvertPrometheusDeleteNamespace(rc, fldr.Title)
require.Equal(t, http.StatusAccepted, response.Status())
// Verify the rule was deleted
remaining, err := ruleStore.GetAlertRuleByUID(context.Background(), &models.GetAlertRuleByUIDQuery{
UID: rule.UID,
OrgID: rule.OrgID,
})
require.Error(t, err)
require.Nil(t, remaining)
})
})
}
@@ -854,6 +917,29 @@ func TestRouteConvertPrometheusDeleteRuleGroup(t *testing.T) {
require.NoError(t, err)
require.NotNil(t, remaining)
})
t.Run("with disable provenance header should still be able to delete rules", func(t *testing.T) {
provenanceStore := fakes.NewFakeProvisioningStore()
srv, ruleStore, fldr, rule := initGroup("", groupName, withProvenanceStore(provenanceStore))
// Mark the rule as provisioned with API provenance
err := provenanceStore.SetProvenance(context.Background(), rule, 1, models.ProvenanceConvertedPrometheus)
require.NoError(t, err)
rc := createRequestCtx()
rc.Req.Header.Set("X-Disable-Provenance", "true")
response := srv.RouteConvertPrometheusDeleteRuleGroup(rc, fldr.Title, groupName)
require.Equal(t, http.StatusAccepted, response.Status())
// Verify the rule was deleted
remaining, err := ruleStore.GetAlertRuleByUID(context.Background(), &models.GetAlertRuleByUIDQuery{
UID: rule.UID,
OrgID: rule.OrgID,
})
require.Error(t, err)
require.Nil(t, remaining)
})
})
}
@@ -995,3 +1081,32 @@ func TestGetWorkingFolderUID(t *testing.T) {
require.Equal(t, specifiedFolderUID, folderUID)
})
}
func TestGetProvenance(t *testing.T) {
t.Run("should return ProvenanceConvertedPrometheus when header is not present", func(t *testing.T) {
rc := createRequestCtx()
// Ensure the header is not present
rc.Req.Header.Del(disableProvenanceHeaderName)
provenance := getProvenance(rc)
require.Equal(t, models.ProvenanceConvertedPrometheus, provenance)
})
t.Run("should return ProvenanceNone when header is present", func(t *testing.T) {
rc := createRequestCtx()
// Set the disable provenance header
rc.Req.Header.Set(disableProvenanceHeaderName, "true")
provenance := getProvenance(rc)
require.Equal(t, models.ProvenanceNone, provenance)
})
t.Run("should return ProvenanceNone when header is present with any value", func(t *testing.T) {
rc := createRequestCtx()
// Set the disable provenance header with an empty value
rc.Req.Header.Set(disableProvenanceHeaderName, "")
provenance := getProvenance(rc)
require.Equal(t, models.ProvenanceNone, provenance)
})
}
+20 -12
View File
@@ -37,8 +37,12 @@ type Config struct {
EvaluationOffset *time.Duration
ExecErrState models.ExecutionErrorState
NoDataState models.NoDataState
RecordingRules RulesConfig
AlertRules RulesConfig
// KeepOriginalRuleDefinition indicates whether the original Prometheus rule definition
// if saved to the alert rule metadata. If not, then it will not be possible to convert
// the alert rule back to Prometheus format.
KeepOriginalRuleDefinition *bool
RecordingRules RulesConfig
AlertRules RulesConfig
}
// RulesConfig contains configuration that applies to either recording or alerting rules.
@@ -51,10 +55,11 @@ var (
defaultEvaluationOffset = 0 * time.Minute
defaultConfig = Config{
FromTimeRange: &defaultTimeRange,
EvaluationOffset: &defaultEvaluationOffset,
ExecErrState: models.ErrorErrState,
NoDataState: models.OK,
FromTimeRange: &defaultTimeRange,
EvaluationOffset: &defaultEvaluationOffset,
ExecErrState: models.ErrorErrState,
NoDataState: models.OK,
KeepOriginalRuleDefinition: util.Pointer(true),
}
)
@@ -87,7 +92,9 @@ func NewConverter(cfg Config) (*Converter, error) {
if cfg.NoDataState == "" {
cfg.NoDataState = defaultConfig.NoDataState
}
if cfg.KeepOriginalRuleDefinition == nil {
cfg.KeepOriginalRuleDefinition = defaultConfig.KeepOriginalRuleDefinition
}
if cfg.DatasourceType != datasources.DS_PROMETHEUS && cfg.DatasourceType != datasources.DS_LOKI {
return nil, fmt.Errorf("invalid datasource type: %s", cfg.DatasourceType)
}
@@ -233,11 +240,12 @@ func (p *Converter) convertRule(orgID int64, namespaceUID string, promGroup Prom
RuleGroup: promGroup.Name,
IsPaused: isPaused,
Record: record,
Metadata: models.AlertRuleMetadata{
PrometheusStyleRule: &models.PrometheusStyleRule{
OriginalRuleDefinition: string(originalRuleDefinition),
},
},
}
if p.cfg.KeepOriginalRuleDefinition != nil && *p.cfg.KeepOriginalRuleDefinition {
result.Metadata.PrometheusStyleRule = &models.PrometheusStyleRule{
OriginalRuleDefinition: string(originalRuleDefinition),
}
}
return result, nil
+68
View File
@@ -618,3 +618,71 @@ func TestPrometheusRulesToGrafana_UID(t *testing.T) {
})
})
}
func TestPrometheusRulesToGrafana_KeepOriginalRuleDefinition(t *testing.T) {
orgID := int64(1)
namespace := "namespace"
promGroup := PrometheusRuleGroup{
Name: "test-group",
Rules: []PrometheusRule{
{
Alert: "test-alert",
Expr: "up == 0",
},
},
}
testCases := []struct {
name string
keepOriginalRuleDefinition *bool
expectDefinition bool
}{
{
name: "keep original rule definition is true",
keepOriginalRuleDefinition: util.Pointer(true),
expectDefinition: true,
},
{
name: "keep original rule definition is false",
keepOriginalRuleDefinition: util.Pointer(false),
expectDefinition: false,
},
{
name: "keep original rule definition is nil (should use default)",
keepOriginalRuleDefinition: nil,
expectDefinition: true,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
cfg := Config{
DatasourceUID: "datasource-uid",
DatasourceType: datasources.DS_PROMETHEUS,
DefaultInterval: 1 * time.Minute,
KeepOriginalRuleDefinition: tc.keepOriginalRuleDefinition,
}
converter, err := NewConverter(cfg)
require.NoError(t, err)
// Convert the Prometheus rule to Grafana
grafanaGroup, err := converter.PrometheusRulesToGrafana(orgID, namespace, promGroup)
require.NoError(t, err)
require.Len(t, grafanaGroup.Rules, 1)
if tc.expectDefinition {
originalRuleDefinition, err := yaml.Marshal(promGroup.Rules[0])
require.NoError(t, err)
require.Equal(
t,
string(originalRuleDefinition),
grafanaGroup.Rules[0].Metadata.PrometheusStyleRule.OriginalRuleDefinition,
)
} else {
require.Nil(t, grafanaGroup.Rules[0].Metadata.PrometheusStyleRule)
}
})
}
}
@@ -674,6 +674,42 @@ func TestAlertRuleService(t *testing.T) {
to: models.ProvenanceNone,
errNil: false,
},
{
name: "should be able to update from provenance none to 'converted prometheus'",
from: models.ProvenanceNone,
to: models.ProvenanceConvertedPrometheus,
errNil: true,
},
{
name: "should be able to update from provenance 'converted prometheus' to none",
from: models.ProvenanceConvertedPrometheus,
to: models.ProvenanceNone,
errNil: true,
},
{
name: "should not be able to update from provenance 'converted prometheus' to api",
from: models.ProvenanceConvertedPrometheus,
to: models.ProvenanceAPI,
errNil: false,
},
{
name: "should not be able to update from provenance 'converted prometheus' to file",
from: models.ProvenanceConvertedPrometheus,
to: models.ProvenanceFile,
errNil: false,
},
{
name: "should not be able to update from provenance api to 'converted prometheus'",
from: models.ProvenanceAPI,
to: models.ProvenanceConvertedPrometheus,
errNil: false,
},
{
name: "should not be able to update from provenance file to 'converted prometheus'",
from: models.ProvenanceFile,
to: models.ProvenanceConvertedPrometheus,
errNil: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
@@ -7,9 +7,23 @@ import (
// CanUpdateProvenanceInRuleGroup checks if a provenance can be updated for a rule group and its alerts.
// ReplaceRuleGroup function intends to replace an entire rule group: inserting, updating, and removing rules.
func CanUpdateProvenanceInRuleGroup(storedProvenance, provenance models.Provenance) bool {
return storedProvenance == provenance ||
storedProvenance == models.ProvenanceNone ||
(storedProvenance == models.ProvenanceAPI && provenance == models.ProvenanceNone)
// Same provenance is always allowed
if storedProvenance == provenance {
return true
}
// Can always update stored ProvenanceNone
if storedProvenance == models.ProvenanceNone {
return true
}
// Can reset to ProvenanceNone from specific provenances
if provenance == models.ProvenanceNone {
return storedProvenance == models.ProvenanceAPI ||
storedProvenance == models.ProvenanceConvertedPrometheus
}
return false
}
type ProvenanceStatusTransitionValidator = func(from, to models.Provenance) error
@@ -15,6 +15,7 @@ func TestValidateProvenanceRelaxed(t *testing.T) {
models.ProvenanceNone,
models.ProvenanceAPI,
models.ProvenanceFile,
models.ProvenanceConvertedPrometheus,
models.Provenance(fmt.Sprintf("random-%s", util.GenerateShortUID())),
}
t.Run("all transitions from 'none' are allowed", func(t *testing.T) {
@@ -49,3 +50,62 @@ func TestValidateProvenanceRelaxed(t *testing.T) {
}
})
}
func TestCanUpdateProvenanceInRuleGroup(t *testing.T) {
all := []models.Provenance{
models.ProvenanceNone,
models.ProvenanceAPI,
models.ProvenanceFile,
models.ProvenanceConvertedPrometheus,
models.Provenance(fmt.Sprintf("random-%s", util.GenerateShortUID())),
}
t.Run("same provenance transitions are allowed", func(t *testing.T) {
for _, provenance := range all {
assert.True(t, CanUpdateProvenanceInRuleGroup(provenance, provenance))
}
})
t.Run("all transitions from 'none' are allowed", func(t *testing.T) {
for _, provenance := range all {
assert.True(t, CanUpdateProvenanceInRuleGroup(models.ProvenanceNone, provenance))
}
})
t.Run("only specific provenances can transition to 'none'", func(t *testing.T) {
allowed := []models.Provenance{
models.ProvenanceAPI,
models.ProvenanceConvertedPrometheus,
}
for _, from := range allowed {
assert.True(t, CanUpdateProvenanceInRuleGroup(from, models.ProvenanceNone),
"transition %s -> 'none' should be allowed", from)
}
notAllowed := []models.Provenance{
models.ProvenanceFile,
models.Provenance(fmt.Sprintf("random-%s", util.GenerateShortUID())),
}
for _, from := range notAllowed {
assert.False(t, CanUpdateProvenanceInRuleGroup(from, models.ProvenanceNone),
"transition %s -> 'none' should not be allowed", from)
}
})
t.Run("transitions between different provenances are not allowed", func(t *testing.T) {
for _, from := range all {
if from == models.ProvenanceNone {
continue // always allowed
}
for _, to := range all {
if from == to || to == models.ProvenanceNone {
continue // always allowed
}
assert.False(t, CanUpdateProvenanceInRuleGroup(from, to),
"transition %s -> '%s' should not be allowed", from, to)
}
}
})
}
@@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/expr"
"github.com/grafana/grafana/pkg/services/datasources"
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/org"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/tests/testinfra"
@@ -603,6 +604,122 @@ func TestIntegrationConvertPrometheusEndpoints_FolderUIDHeader(t *testing.T) {
})
}
func TestIntegrationConvertPrometheusEndpoints_Provenance(t *testing.T) {
runTest := func(t *testing.T, enableLokiPaths bool) {
testinfra.SQLiteIntegrationTest(t)
// Setup Grafana and its Database
dir, gpath := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
DisableLegacyAlerting: true,
EnableUnifiedAlerting: true,
DisableAnonymous: true,
AppModeProduction: true,
EnableFeatureToggles: []string{"alertingConversionAPI", "grafanaManagedRecordingRulesDatasources", "grafanaManagedRecordingRules"},
EnableRecordingRules: true,
})
grafanaListedAddr, env := testinfra.StartGrafanaEnv(t, dir, gpath)
// Create admin user
createUser(t, env.SQLStore, env.Cfg, user.CreateUserCommand{
DefaultOrgRole: string(org.RoleAdmin),
Password: "password",
Login: "admin",
})
adminClient := newAlertingApiClient(grafanaListedAddr, "admin", "password")
adminClient.prometheusConversionUseLokiPaths = enableLokiPaths
ds := adminClient.CreateDatasource(t, datasources.DS_PROMETHEUS)
t.Run("default provenance is ProvenanceConvertedPrometheus", func(t *testing.T) {
namespace := "test-namespace-provenance-" + util.GenerateShortUID()
// We have to create a folder to get its UID to use in the ruler API later to fetch the rule group.
namespaceUID := util.GenerateShortUID()
adminClient.CreateFolder(t, namespaceUID, namespace)
adminClient.ConvertPrometheusPostRuleGroup(t, namespace, ds.Body.Datasource.UID, promGroup1, nil)
// Get the rule group using the ruler API and check its provenance
ruleGroup, status := adminClient.GetRulesGroup(t, namespaceUID, promGroup1.Name)
require.Equal(t, http.StatusAccepted, status)
for _, rule := range ruleGroup.Rules {
require.Equal(t, apimodels.Provenance(models.ProvenanceConvertedPrometheus), rule.GrafanaManagedAlert.Provenance)
}
})
t.Run("with disable provenance header should use ProvenanceNone", func(t *testing.T) {
namespace := "test-namespace-provenance-" + util.GenerateShortUID()
// We have to create a folder to get its UID to use in the ruler API later to fetch the rule group.
namespaceUID := util.GenerateShortUID()
adminClient.CreateFolder(t, namespaceUID, namespace)
// Create rule group with the X-Disable-Provenance header
headers := map[string]string{
"X-Disable-Provenance": "true",
}
adminClient.ConvertPrometheusPostRuleGroup(t, namespace, ds.Body.Datasource.UID, promGroup1, headers)
// Get the rule group using the ruler API and check its provenance
ruleGroup, status := adminClient.GetRulesGroup(t, namespaceUID, promGroup1.Name)
require.Equal(t, http.StatusAccepted, status)
for _, rule := range ruleGroup.Rules {
require.Equal(t, apimodels.Provenance(models.ProvenanceNone), rule.GrafanaManagedAlert.Provenance)
}
})
t.Run("can delete rule groups with X-Disable-Provenance header", func(t *testing.T) {
namespace := "test-namespace-delete-provenance-" + util.GenerateShortUID()
namespaceUID := util.GenerateShortUID()
adminClient.CreateFolder(t, namespaceUID, namespace)
// Create a rule group
adminClient.ConvertPrometheusPostRuleGroup(t, namespace, ds.Body.Datasource.UID, promGroup1, nil)
// Now try to delete with X-Disable-Provenance header
// This should succeed
headers := map[string]string{
"X-Disable-Provenance": "true",
}
adminClient.ConvertPrometheusDeleteRuleGroup(t, namespace, promGroup1.Name, headers)
// Verify the rule group is gone
_, status, _ := adminClient.GetRulesGroupWithStatus(t, namespaceUID, promGroup1.Name)
require.Equal(t, http.StatusNotFound, status)
})
t.Run("can delete namespaces with X-Disable-Provenance header", func(t *testing.T) {
namespace := "test-namespace-delete-ns-provenance-" + util.GenerateShortUID()
namespaceUID := util.GenerateShortUID()
adminClient.CreateFolder(t, namespaceUID, namespace)
// Create a rule group with provenance=ProvenanceConvertedPrometheus
adminClient.ConvertPrometheusPostRuleGroup(t, namespace, ds.Body.Datasource.UID, promGroup1, nil)
// Now delete with X-Disable-Provenance header
// This should succeed
headers := map[string]string{
"X-Disable-Provenance": "true",
}
adminClient.ConvertPrometheusDeleteNamespace(t, namespace, headers)
// Verify the namespace has no rule groups
namespaces := adminClient.ConvertPrometheusGetAllRules(t, nil)
_, exists := namespaces[namespace]
require.False(t, exists)
})
}
t.Run("with the mimirtool paths", func(t *testing.T) {
runTest(t, false)
})
t.Run("with the cortextool Loki paths", func(t *testing.T) {
runTest(t, true)
})
}
func TestIntegrationConvertPrometheusEndpoints_Delete(t *testing.T) {
runTest := func(t *testing.T, enableLokiPaths bool) {
testinfra.SQLiteIntegrationTest(t)