Alerting: Allow disabling provenance in the Prometheus conversion API (#101573)
When creating Grafana-managed alerts from Prometheus rule definitions with mimirtool or cortextool, the rules are marked as "provisioned" and are not editable in the Grafana UI. This PR allows changing this by providing an extra header: --extra-header="X-Disable-Provenance=true". When provenance is disabled, we do not keep the original rule definition in YAML, so it is impossible to read it back using the Prometheus conversion API (mimirtool/cortextool). This is intentional because if we did keep it and the rule was later changed in the UI, its Prometheus YAML definition would no longer reflect the latest version of the alert rule, as it would be unchanged.
This commit is contained in:
@@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user