[v10.4.x] Alerting: Fix simplified routing group by override (#86620)

Alerting: Fix simplified routing group by override (#86552)

* Alerting: Fix simplified routing custom group by override

Custom group by overrides for simplified routing were missing required fields
GroupBy and GroupByAll normally set during upstream Route validation.

This fix ensures those missing fields are applied to the generated routes.

* Inline GroupBy and GroupByAll initialization instead of normalize after

(cherry picked from commit 71445002b7)
This commit is contained in:
Matthew Jacobson
2024-04-19 17:23:16 +02:00
committed by GitHub
parent 0ed766d9a1
commit 879edcbc32
3 changed files with 27 additions and 4 deletions
+3 -3
View File
@@ -12,8 +12,8 @@ import (
"github.com/prometheus/common/model"
)
// groupByAll is a special value defined by alertmanager that can be used in a Route's GroupBy field to aggregate by all possible labels.
const groupByAll = "..."
// GroupByAll is a special value defined by alertmanager that can be used in a Route's GroupBy field to aggregate by all possible labels.
const GroupByAll = "..."
type ListNotificationSettingsQuery struct {
OrgID int64
@@ -44,7 +44,7 @@ func (s *NotificationSettings) Validate() error {
if len(s.GroupBy) > 0 {
alertName, folderTitle := false, false
for _, lbl := range s.GroupBy {
if lbl == groupByAll {
if lbl == GroupByAll {
alertName, folderTitle = true, true
break
}
@@ -116,12 +116,16 @@ func generateRouteFromSettings(defaultReceiver string, settings map[data.Fingerp
if err != nil {
return autogeneratedRoute{}, err
}
groupByStr := []string{models.FolderTitleLabel, model.AlertNameLabel}
groupByAll, groupBy := toGroupBy(groupByStr...)
receiverRoute = &definitions.Route{
Receiver: s.Receiver,
ObjectMatchers: definitions.ObjectMatchers{contactMatcher},
Continue: false,
// Since we'll have many rules from different folders using this policy, we ensure it has these necessary groupings.
GroupByStr: []string{models.FolderTitleLabel, model.AlertNameLabel},
GroupByStr: groupByStr,
GroupBy: groupBy,
GroupByAll: groupByAll,
}
receiverRoutes[s.Receiver] = receiverRoute
autoGenRoot.Routes = append(autoGenRoot.Routes, receiverRoute)
@@ -135,12 +139,15 @@ func generateRouteFromSettings(defaultReceiver string, settings map[data.Fingerp
if err != nil {
return autogeneratedRoute{}, err
}
groupByAll, groupBy := toGroupBy(s.GroupBy...)
receiverRoute.Routes = append(receiverRoute.Routes, &definitions.Route{
Receiver: s.Receiver,
ObjectMatchers: definitions.ObjectMatchers{settingMatcher},
Continue: false, // Only a single setting-specific route should match.
GroupByStr: s.GroupBy, // Note: in order to pass validation at least FolderTitleLabel and AlertNameLabel are always included.
GroupBy: groupBy,
GroupByAll: groupByAll,
MuteTimeIntervals: s.MuteTimeIntervals,
GroupWait: s.GroupWait,
GroupInterval: s.GroupInterval,
@@ -153,6 +160,19 @@ func generateRouteFromSettings(defaultReceiver string, settings map[data.Fingerp
}, nil
}
// toGroupBy converts the given label strings to (groupByAll, []model.LabelName) where groupByAll is true if the input
// contains models.GroupByAll. This logic is in accordance with upstream Route.ValidateChild().
func toGroupBy(groupByStr ...string) (groupByAll bool, groupBy []model.LabelName) {
for _, l := range groupByStr {
if l == models.GroupByAll {
return true, nil
} else {
groupBy = append(groupBy, model.LabelName(l))
}
}
return false, groupBy
}
// addToRoute adds this autogenerated route to the given route as the first top-level route under the root.
func (ar *autogeneratedRoute) addToRoute(route *definitions.Route) error {
if route == nil {
@@ -227,6 +227,9 @@ func TestAddAutogenConfig(t *testing.T) {
require.NoError(t, err)
}
// We compare against the upstream normalized route.
require.NoError(t, tt.expRoute.Validate())
cOpt := []cmp.Option{
cmpopts.IgnoreUnexported(definitions.Route{}, labels.Matcher{}),
}