diff --git a/api/v1beta1/grafananotificationpolicy_types.go b/api/v1beta1/grafananotificationpolicy_types.go
index f1ec57f9f..6a16c515e 100644
--- a/api/v1beta1/grafananotificationpolicy_types.go
+++ b/api/v1beta1/grafananotificationpolicy_types.go
@@ -29,7 +29,7 @@ type GrafanaNotificationPolicySpec struct {
GrafanaCommonSpec `json:",inline"`
// Routes for alerts to match against
- Route *Route `json:"route"`
+ Route *PartialRoute `json:"route"`
// Whether to enable or disable editing of the notification policy in Grafana UI
// +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable"
@@ -37,10 +37,7 @@ type GrafanaNotificationPolicySpec struct {
Editable *bool `json:"editable,omitempty"`
}
-type Route struct {
- // continue
- Continue bool `json:"continue,omitempty"`
-
+type PartialRoute struct {
// group by
GroupBy []string `json:"group_by,omitempty"`
@@ -50,23 +47,6 @@ type Route struct {
// group wait
GroupWait string `json:"group_wait,omitempty"`
- // match re
- MatchRe models.MatchRegexps `json:"match_re,omitempty"`
-
- // matchers
- Matchers Matchers `json:"matchers,omitempty"`
-
- // mute time intervals
- MuteTimeIntervals []string `json:"mute_time_intervals,omitempty"`
-
- ActiveTimeIntervals []string `json:"active_time_intervals,omitempty"`
-
- // object matchers
- ObjectMatchers models.ObjectMatchers `json:"object_matchers,omitempty"`
-
- // provenance
- Provenance models.Provenance `json:"provenance,omitempty"`
-
// receiver
// +kubebuilder:validation:MinLength=1
Receiver string `json:"receiver"`
@@ -82,6 +62,31 @@ type Route struct {
// +kubebuilder:pruning:PreserveUnknownFields
// +kubebuilder:validation:Schemaless
Routes []*Route `json:"routes,omitempty"`
+
+ // Deprecated: Does nothing
+ Provenance models.Provenance `json:"provenance,omitempty"`
+}
+
+type Route struct {
+ PartialRoute `json:",inline"`
+
+ // continue
+ Continue bool `json:"continue,omitempty"`
+
+ // match re
+ MatchRe models.MatchRegexps `json:"match_re,omitempty"`
+
+ // matchers
+ Matchers Matchers `json:"matchers,omitempty"`
+
+ // object matchers
+ ObjectMatchers models.ObjectMatchers `json:"object_matchers,omitempty"`
+
+ // mute time intervals
+ MuteTimeIntervals []string `json:"mute_time_intervals,omitempty"`
+
+ // active time intervals
+ ActiveTimeIntervals []string `json:"active_time_intervals,omitempty"`
}
type Matcher struct {
@@ -124,7 +129,6 @@ func (r *Route) ToModelRoute() *models.Route {
MuteTimeIntervals: r.MuteTimeIntervals,
ActiveTimeIntervals: r.ActiveTimeIntervals,
ObjectMatchers: r.ObjectMatchers,
- Provenance: r.Provenance,
Receiver: r.Receiver,
RepeatInterval: r.RepeatInterval,
Routes: make([]*models.Route, len(r.Routes)),
@@ -136,15 +140,31 @@ func (r *Route) ToModelRoute() *models.Route {
return out
}
+func (r *PartialRoute) ToModelRoute() *models.Route {
+ out := &models.Route{
+ GroupBy: r.GroupBy,
+ GroupInterval: r.GroupInterval,
+ GroupWait: r.GroupWait,
+ Receiver: r.Receiver,
+ RepeatInterval: r.RepeatInterval,
+ Routes: make([]*models.Route, len(r.Routes)),
+ }
+ for i, v := range r.Routes {
+ out.Routes[i] = v.ToModelRoute()
+ }
+
+ return out
+}
+
// selectorMutuallyExclusive checks if a single route satisfies the mutual exclusivity constraint
// for checking the entire route including nested routes, use IsRouteSelectorMutuallyExclusive
-func (r *Route) selectorMutuallyExclusive() bool {
+func (r *PartialRoute) selectorMutuallyExclusive() bool {
return !(r.RouteSelector != nil && len(r.Routes) > 0) // nolint:staticcheck
}
// IsRouteSelectorMutuallyExclusive returns true when the route and all its sub-routes
// satisfy the constraint of routes and routeSelector being mutually exclusive
-func (r *Route) IsRouteSelectorMutuallyExclusive() bool {
+func (r *PartialRoute) IsRouteSelectorMutuallyExclusive() bool {
if !r.selectorMutuallyExclusive() {
return false
}
@@ -160,7 +180,7 @@ func (r *Route) IsRouteSelectorMutuallyExclusive() bool {
}
// HasRouteSelector checks if the given Route or any of its nested Routes has a RouteSelector
-func (r *Route) HasRouteSelector() bool {
+func (r *PartialRoute) HasRouteSelector() bool {
if r.RouteSelector != nil {
return true
}
diff --git a/api/v1beta1/grafananotificationpolicy_types_test.go b/api/v1beta1/grafananotificationpolicy_types_test.go
index 01abf1ef8..b08272097 100644
--- a/api/v1beta1/grafananotificationpolicy_types_test.go
+++ b/api/v1beta1/grafananotificationpolicy_types_test.go
@@ -38,13 +38,10 @@ func newNotificationPolicy(name string, editable *bool) *GrafanaNotificationPoli
},
},
},
- Route: &Route{
- Continue: false,
- Receiver: "grafana-default-email",
- GroupBy: []string{"group_name", "alert_name"},
- MuteTimeIntervals: []string{},
- ActiveTimeIntervals: []string{},
- Routes: []*Route{},
+ Route: &PartialRoute{
+ Receiver: "grafana-default-email",
+ GroupBy: []string{"group_name", "alert_name"},
+ Routes: []*Route{},
},
},
}
@@ -91,24 +88,24 @@ var _ = Describe("NotificationPolicy type", func() {
func TestIsRouteSelectorMutuallyExclusive(t *testing.T) {
tests := []struct {
name string
- route *Route
+ route *PartialRoute
expected bool
}{
{
name: "Empty route",
- route: &Route{},
+ route: &PartialRoute{},
expected: true,
},
{
name: "Route with only RouteSelector",
- route: &Route{
+ route: &PartialRoute{
RouteSelector: &metav1.LabelSelector{},
},
expected: true,
},
{
name: "Route with only sub-routes",
- route: &Route{
+ route: &PartialRoute{
Routes: []*Route{
{},
{},
@@ -118,7 +115,7 @@ func TestIsRouteSelectorMutuallyExclusive(t *testing.T) {
},
{
name: "Route with both RouteSelector and sub-routes",
- route: &Route{
+ route: &PartialRoute{
RouteSelector: &metav1.LabelSelector{},
Routes: []*Route{
{},
@@ -128,14 +125,18 @@ func TestIsRouteSelectorMutuallyExclusive(t *testing.T) {
},
{
name: "Nested routes with mutual exclusivity",
- route: &Route{
+ route: &PartialRoute{
Routes: []*Route{
{
- RouteSelector: &metav1.LabelSelector{},
+ PartialRoute: PartialRoute{
+ RouteSelector: &metav1.LabelSelector{},
+ },
},
{
- Routes: []*Route{
- {},
+ PartialRoute: PartialRoute{
+ Routes: []*Route{
+ {},
+ },
},
},
},
@@ -144,12 +145,14 @@ func TestIsRouteSelectorMutuallyExclusive(t *testing.T) {
},
{
name: "Nested routes without mutual exclusivity",
- route: &Route{
+ route: &PartialRoute{
Routes: []*Route{
{
- RouteSelector: &metav1.LabelSelector{},
- Routes: []*Route{
- {},
+ PartialRoute: PartialRoute{
+ RouteSelector: &metav1.LabelSelector{},
+ Routes: []*Route{
+ {},
+ },
},
},
},
diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go
index 93c461b8b..0615da086 100644
--- a/api/v1beta1/zz_generated.deepcopy.go
+++ b/api/v1beta1/zz_generated.deepcopy.go
@@ -1585,7 +1585,7 @@ func (in *GrafanaNotificationPolicySpec) DeepCopyInto(out *GrafanaNotificationPo
in.GrafanaCommonSpec.DeepCopyInto(&out.GrafanaCommonSpec)
if in.Route != nil {
in, out := &in.Route, &out.Route
- *out = new(Route)
+ *out = new(PartialRoute)
(*in).DeepCopyInto(*out)
}
if in.Editable != nil {
@@ -2307,6 +2307,42 @@ func (in *OperatorReconcileVars) DeepCopy() *OperatorReconcileVars {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *PartialRoute) DeepCopyInto(out *PartialRoute) {
+ *out = *in
+ if in.GroupBy != nil {
+ in, out := &in.GroupBy, &out.GroupBy
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+ if in.RouteSelector != nil {
+ in, out := &in.RouteSelector, &out.RouteSelector
+ *out = new(metav1.LabelSelector)
+ (*in).DeepCopyInto(*out)
+ }
+ if in.Routes != nil {
+ in, out := &in.Routes, &out.Routes
+ *out = make([]*Route, len(*in))
+ for i := range *in {
+ if (*in)[i] != nil {
+ in, out := &(*in)[i], &(*out)[i]
+ *out = new(Route)
+ (*in).DeepCopyInto(*out)
+ }
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PartialRoute.
+func (in *PartialRoute) DeepCopy() *PartialRoute {
+ if in == nil {
+ return nil
+ }
+ out := new(PartialRoute)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PersistentVolumeClaimV1) DeepCopyInto(out *PersistentVolumeClaimV1) {
*out = *in
@@ -2436,11 +2472,7 @@ func (in *Record) DeepCopy() *Record {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Route) DeepCopyInto(out *Route) {
*out = *in
- if in.GroupBy != nil {
- in, out := &in.GroupBy, &out.GroupBy
- *out = make([]string, len(*in))
- copy(*out, *in)
- }
+ in.PartialRoute.DeepCopyInto(&out.PartialRoute)
if in.MatchRe != nil {
in, out := &in.MatchRe, &out.MatchRe
*out = make(models.MatchRegexps, len(*in))
@@ -2459,16 +2491,6 @@ func (in *Route) DeepCopyInto(out *Route) {
}
}
}
- if in.MuteTimeIntervals != nil {
- in, out := &in.MuteTimeIntervals, &out.MuteTimeIntervals
- *out = make([]string, len(*in))
- copy(*out, *in)
- }
- if in.ActiveTimeIntervals != nil {
- in, out := &in.ActiveTimeIntervals, &out.ActiveTimeIntervals
- *out = make([]string, len(*in))
- copy(*out, *in)
- }
if in.ObjectMatchers != nil {
in, out := &in.ObjectMatchers, &out.ObjectMatchers
*out = make(models.ObjectMatchers, len(*in))
@@ -2480,21 +2502,15 @@ func (in *Route) DeepCopyInto(out *Route) {
}
}
}
- if in.RouteSelector != nil {
- in, out := &in.RouteSelector, &out.RouteSelector
- *out = new(metav1.LabelSelector)
- (*in).DeepCopyInto(*out)
+ if in.MuteTimeIntervals != nil {
+ in, out := &in.MuteTimeIntervals, &out.MuteTimeIntervals
+ *out = make([]string, len(*in))
+ copy(*out, *in)
}
- if in.Routes != nil {
- in, out := &in.Routes, &out.Routes
- *out = make([]*Route, len(*in))
- for i := range *in {
- if (*in)[i] != nil {
- in, out := &(*in)[i], &(*out)[i]
- *out = new(Route)
- (*in).DeepCopyInto(*out)
- }
- }
+ if in.ActiveTimeIntervals != nil {
+ in, out := &in.ActiveTimeIntervals, &out.ActiveTimeIntervals
+ *out = make([]string, len(*in))
+ copy(*out, *in)
}
}
diff --git a/config/crd/bases/grafana.integreatly.org_grafananotificationpolicies.yaml b/config/crd/bases/grafana.integreatly.org_grafananotificationpolicies.yaml
index fe6208cfb..0daa917b0 100644
--- a/config/crd/bases/grafana.integreatly.org_grafananotificationpolicies.yaml
+++ b/config/crd/bases/grafana.integreatly.org_grafananotificationpolicies.yaml
@@ -120,13 +120,6 @@ spec:
route:
description: Routes for alerts to match against
properties:
- active_time_intervals:
- items:
- type: string
- type: array
- continue:
- description: continue
- type: boolean
group_by:
description: group by
items:
@@ -138,50 +131,8 @@ spec:
group_wait:
description: group wait
type: string
- match_re:
- additionalProperties:
- type: string
- description: match re
- type: object
- matchers:
- description: matchers
- items:
- properties:
- isEqual:
- description: is equal
- type: boolean
- isRegex:
- description: is regex
- type: boolean
- name:
- description: name
- type: string
- value:
- description: value
- type: string
- required:
- - isRegex
- - value
- type: object
- type: array
- mute_time_intervals:
- description: mute time intervals
- items:
- type: string
- type: array
- object_matchers:
- description: object matchers
- items:
- description: |-
- ObjectMatcher ObjectMatcher is a matcher that can be used to filter alerts.
-
- swagger:model ObjectMatcher
- items:
- type: string
- type: array
- type: array
provenance:
- description: provenance
+ description: 'Deprecated: Does nothing'
type: string
receiver:
description: receiver
diff --git a/config/crd/bases/grafana.integreatly.org_grafananotificationpolicyroutes.yaml b/config/crd/bases/grafana.integreatly.org_grafananotificationpolicyroutes.yaml
index 1f11c0921..708c2fa3e 100644
--- a/config/crd/bases/grafana.integreatly.org_grafananotificationpolicyroutes.yaml
+++ b/config/crd/bases/grafana.integreatly.org_grafananotificationpolicyroutes.yaml
@@ -44,6 +44,7 @@ spec:
of GrafanaNotificationPolicyRoute
properties:
active_time_intervals:
+ description: active time intervals
items:
type: string
type: array
@@ -104,7 +105,7 @@ spec:
type: array
type: array
provenance:
- description: provenance
+ description: 'Deprecated: Does nothing'
type: string
receiver:
description: receiver
diff --git a/controllers/notificationpolicy_controller.go b/controllers/notificationpolicy_controller.go
index 37b873e1b..04dc8474e 100644
--- a/controllers/notificationpolicy_controller.go
+++ b/controllers/notificationpolicy_controller.go
@@ -215,9 +215,9 @@ func assembleNotificationPolicyRoutes(ctx context.Context, k8sClient client.Clie
// so we can detect loops
visitedChilds := make(map[string]bool)
- var assembleRoute func(*v1beta1.Route) error
+ var assembleRoute func(*v1beta1.PartialRoute) error
- assembleRoute = func(route *v1beta1.Route) error {
+ assembleRoute = func(route *v1beta1.PartialRoute) error {
if route.RouteSelector != nil {
routes, err := getMatchingNotificationPolicyRoutes(ctx, k8sClient, route.RouteSelector, namespace)
if err != nil {
@@ -243,7 +243,7 @@ func assembleNotificationPolicyRoutes(ctx context.Context, k8sClient client.Clie
visitedChilds[key] = true
// Recursively assemble the matched route
- if err := assembleRoute(&matchedRoute.Spec.Route); err != nil {
+ if err := assembleRoute(&matchedRoute.Spec.PartialRoute); err != nil {
return err
}
@@ -254,7 +254,7 @@ func assembleNotificationPolicyRoutes(ctx context.Context, k8sClient client.Clie
} else {
// if no RouteSelector is specified, process inline routes, as they are mutually exclusive
for i, inlineRoute := range route.Routes {
- if err := assembleRoute(inlineRoute); err != nil {
+ if err := assembleRoute(&inlineRoute.PartialRoute); err != nil {
return err
}
@@ -379,7 +379,7 @@ func (r *GrafanaNotificationPolicyReconciler) SetupWithManager(mgr ctrl.Manager)
}()
// check if notification policy route is valid
- if !npr.Spec.Route.IsRouteSelectorMutuallyExclusive() {
+ if !npr.Spec.PartialRoute.IsRouteSelectorMutuallyExclusive() {
setInvalidSpecMutuallyExclusive(&npr.Status.Conditions, npr.Generation)
return nil
}
diff --git a/controllers/notificationpolicy_controller_test.go b/controllers/notificationpolicy_controller_test.go
index 07ef30df6..e386b37bf 100644
--- a/controllers/notificationpolicy_controller_test.go
+++ b/controllers/notificationpolicy_controller_test.go
@@ -56,7 +56,7 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
name: "Simple assembly with one level of routes",
notificationPolicy: &v1beta1.GrafanaNotificationPolicy{
Spec: v1beta1.GrafanaNotificationPolicySpec{
- Route: &v1beta1.Route{
+ Route: &v1beta1.PartialRoute{
Receiver: "default-receiver",
RouteSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"tier": "first"},
@@ -73,7 +73,9 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
},
Spec: v1beta1.GrafanaNotificationPolicyRouteSpec{
Route: v1beta1.Route{
- Receiver: "team-A-receiver",
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "team-A-receiver",
+ },
Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "A", IsEqual: true}},
},
},
@@ -81,14 +83,14 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
},
want: &v1beta1.GrafanaNotificationPolicy{
Spec: v1beta1.GrafanaNotificationPolicySpec{
- Route: &v1beta1.Route{
+ Route: &v1beta1.PartialRoute{
Receiver: "default-receiver",
- Routes: []*v1beta1.Route{
- {
+ Routes: []*v1beta1.Route{{
+ PartialRoute: v1beta1.PartialRoute{
Receiver: "team-A-receiver",
- Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "A", IsEqual: true}},
},
- },
+ Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "A", IsEqual: true}},
+ }},
},
},
},
@@ -104,7 +106,7 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
GrafanaCommonSpec: v1beta1.GrafanaCommonSpec{
AllowCrossNamespaceImport: false,
},
- Route: &v1beta1.Route{
+ Route: &v1beta1.PartialRoute{
Receiver: "default-receiver",
RouteSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"tier": "first"},
@@ -121,8 +123,10 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
},
Spec: v1beta1.GrafanaNotificationPolicyRouteSpec{
Route: v1beta1.Route{
- Receiver: "team-A-receiver",
Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "A", IsEqual: true}},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "team-A-receiver",
+ },
},
},
},
@@ -134,8 +138,10 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
},
Spec: v1beta1.GrafanaNotificationPolicyRouteSpec{
Route: v1beta1.Route{
- Receiver: "team-A-receiver-other-namespace",
Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "A", IsEqual: true}},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "team-A-receiver-other-namespace",
+ },
},
},
},
@@ -145,12 +151,14 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
Namespace: "default",
},
Spec: v1beta1.GrafanaNotificationPolicySpec{
- Route: &v1beta1.Route{
+ Route: &v1beta1.PartialRoute{
Receiver: "default-receiver",
Routes: []*v1beta1.Route{
{
- Receiver: "team-A-receiver",
Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "A", IsEqual: true}},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "team-A-receiver",
+ },
},
},
},
@@ -162,7 +170,7 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
name: "Assembly with nested routes",
notificationPolicy: &v1beta1.GrafanaNotificationPolicy{
Spec: v1beta1.GrafanaNotificationPolicySpec{
- Route: &v1beta1.Route{
+ Route: &v1beta1.PartialRoute{
Receiver: "default-receiver",
RouteSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"tier": "first"},
@@ -179,10 +187,12 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
},
Spec: v1beta1.GrafanaNotificationPolicyRouteSpec{
Route: v1beta1.Route{
- Receiver: "team-A-receiver",
Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "A", IsEqual: true}},
- RouteSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{"tier": "second"},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "team-A-receiver",
+ RouteSelector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"tier": "second"},
+ },
},
},
},
@@ -195,7 +205,9 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
},
Spec: v1beta1.GrafanaNotificationPolicyRouteSpec{
Route: v1beta1.Route{
- Receiver: "team-B-receiver",
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "team-B-receiver",
+ },
Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "B", IsEqual: true}},
},
},
@@ -203,16 +215,20 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
},
want: &v1beta1.GrafanaNotificationPolicy{
Spec: v1beta1.GrafanaNotificationPolicySpec{
- Route: &v1beta1.Route{
+ Route: &v1beta1.PartialRoute{
Receiver: "default-receiver",
Routes: []*v1beta1.Route{
{
- Receiver: "team-A-receiver",
Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "A", IsEqual: true}},
- Routes: []*v1beta1.Route{
- {
- Receiver: "team-B-receiver",
- Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "B", IsEqual: true}},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "team-A-receiver",
+ Routes: []*v1beta1.Route{
+ {
+ Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "B", IsEqual: true}},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "team-B-receiver",
+ },
+ },
},
},
},
@@ -226,21 +242,25 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
name: "Assembly with nested routes and multiple RouteSelectors inside Routes",
notificationPolicy: &v1beta1.GrafanaNotificationPolicy{
Spec: v1beta1.GrafanaNotificationPolicySpec{
- Route: &v1beta1.Route{
+ Route: &v1beta1.PartialRoute{
Receiver: "default-receiver",
Routes: []*v1beta1.Route{
{
- Receiver: "team-A-receiver",
Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "A", IsEqual: true}},
- RouteSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{"tier": "second", "team": "A"},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "team-A-receiver",
+ RouteSelector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"tier": "second", "team": "A"},
+ },
},
},
{
- Receiver: "team-B-receiver",
Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "B", IsEqual: true}},
- RouteSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{"tier": "second", "team": "B"},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "team-B-receiver",
+ RouteSelector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"tier": "second", "team": "B"},
+ },
},
},
},
@@ -256,8 +276,10 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
},
Spec: v1beta1.GrafanaNotificationPolicyRouteSpec{
Route: v1beta1.Route{
- Receiver: "project-X-receiver",
Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("project"), Value: "X", IsEqual: true}},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "project-X-receiver",
+ },
},
},
},
@@ -269,34 +291,44 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
},
Spec: v1beta1.GrafanaNotificationPolicyRouteSpec{
Route: v1beta1.Route{
- Receiver: "project-Y-receiver",
Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("project"), Value: "Y", IsEqual: true}},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "project-Y-receiver",
+ },
},
},
},
},
want: &v1beta1.GrafanaNotificationPolicy{
Spec: v1beta1.GrafanaNotificationPolicySpec{
- Route: &v1beta1.Route{
+ Route: &v1beta1.PartialRoute{
Receiver: "default-receiver",
Routes: []*v1beta1.Route{
{
- Receiver: "team-A-receiver",
Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "A", IsEqual: true}},
- Routes: []*v1beta1.Route{
- {
- Receiver: "project-X-receiver",
- Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("project"), Value: "X", IsEqual: true}},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "team-A-receiver",
+ Routes: []*v1beta1.Route{
+ {
+ Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("project"), Value: "X", IsEqual: true}},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "project-X-receiver",
+ },
+ },
},
},
},
{
- Receiver: "team-B-receiver",
Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "B", IsEqual: true}},
- Routes: []*v1beta1.Route{
- {
- Receiver: "project-Y-receiver",
- Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("project"), Value: "Y", IsEqual: true}},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "team-B-receiver",
+ Routes: []*v1beta1.Route{
+ {
+ Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("project"), Value: "Y", IsEqual: true}},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "project-Y-receiver",
+ },
+ },
},
},
},
@@ -310,7 +342,7 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
name: "Detect loop in routes",
notificationPolicy: &v1beta1.GrafanaNotificationPolicy{
Spec: v1beta1.GrafanaNotificationPolicySpec{
- Route: &v1beta1.Route{
+ Route: &v1beta1.PartialRoute{
Receiver: "default-receiver",
RouteSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{"tier": "first"},
@@ -327,10 +359,12 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
},
Spec: v1beta1.GrafanaNotificationPolicyRouteSpec{
Route: v1beta1.Route{
- Receiver: "team-A-receiver",
Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "A", IsEqual: true}},
- RouteSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{"tier": "second"},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "team-A-receiver",
+ RouteSelector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"tier": "second"},
+ },
},
},
},
@@ -343,10 +377,12 @@ func TestAssembleNotificationPolicyRoutes(t *testing.T) {
},
Spec: v1beta1.GrafanaNotificationPolicyRouteSpec{
Route: v1beta1.Route{
- Receiver: "team-B-receiver",
Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "B", IsEqual: true}},
- RouteSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{"tier": "first"},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "team-B-receiver",
+ RouteSelector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"tier": "first"},
+ },
},
},
},
@@ -394,7 +430,7 @@ var _ = Describe("NotificationPolicy Reconciler: Provoke Conditions", func() {
meta: objectMetaSuspended,
spec: v1beta1.GrafanaNotificationPolicySpec{
GrafanaCommonSpec: commonSpecSuspended,
- Route: &v1beta1.Route{Receiver: "default-receiver"},
+ Route: &v1beta1.PartialRoute{Receiver: "default-receiver"},
},
want: metav1.Condition{
Type: conditionSuspended,
@@ -406,7 +442,7 @@ var _ = Describe("NotificationPolicy Reconciler: Provoke Conditions", func() {
meta: objectMetaNoMatchingInstances,
spec: v1beta1.GrafanaNotificationPolicySpec{
GrafanaCommonSpec: commonSpecNoMatchingInstances,
- Route: &v1beta1.Route{Receiver: "default-receiver"},
+ Route: &v1beta1.PartialRoute{Receiver: "default-receiver"},
},
want: metav1.Condition{
Type: conditionNoMatchingInstance,
@@ -419,7 +455,7 @@ var _ = Describe("NotificationPolicy Reconciler: Provoke Conditions", func() {
meta: objectMetaApplyFailed,
spec: v1beta1.GrafanaNotificationPolicySpec{
GrafanaCommonSpec: commonSpecApplyFailed,
- Route: &v1beta1.Route{Receiver: "default-receiver"},
+ Route: &v1beta1.PartialRoute{Receiver: "default-receiver"},
},
want: metav1.Condition{
Type: conditionNotificationPolicySynchronized,
@@ -432,10 +468,12 @@ var _ = Describe("NotificationPolicy Reconciler: Provoke Conditions", func() {
meta: objectMetaInvalidSpec,
spec: v1beta1.GrafanaNotificationPolicySpec{
GrafanaCommonSpec: commonSpecInvalidSpec,
- Route: &v1beta1.Route{
+ Route: &v1beta1.PartialRoute{
Receiver: "default-receiver",
Routes: []*v1beta1.Route{{
- Receiver: "default-receiver",
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "default-receiver",
+ },
}},
RouteSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{},
@@ -453,7 +491,7 @@ var _ = Describe("NotificationPolicy Reconciler: Provoke Conditions", func() {
meta: objectMetaSynchronized,
spec: v1beta1.GrafanaNotificationPolicySpec{
GrafanaCommonSpec: commonSpecSynchronized,
- Route: &v1beta1.Route{
+ Route: &v1beta1.PartialRoute{
Receiver: "grafana-default-email",
},
},
@@ -492,14 +530,16 @@ var _ = Describe("NotificationPolicy Reconciler: Provoke LoopDetected Condition"
MatchLabels: map[string]string{"loop-detected": "test"},
},
},
- Route: &v1beta1.Route{
+ Route: &v1beta1.PartialRoute{
Receiver: "grafana-default-email",
Routes: []*v1beta1.Route{{
- Receiver: "grafana-default-email",
- Matchers: v1beta1.Matchers{{Name: stringP("team"), Value: "a", IsEqual: true}},
- RouteSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{"team-a": "child"},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "grafana-default-email",
+ RouteSelector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"team-a": "child"},
+ },
},
+ Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "a", IsEqual: true}},
}},
},
},
@@ -512,10 +552,12 @@ var _ = Describe("NotificationPolicy Reconciler: Provoke LoopDetected Condition"
},
Spec: v1beta1.GrafanaNotificationPolicyRouteSpec{
Route: v1beta1.Route{
- Receiver: "grafana-default-email",
- Matchers: v1beta1.Matchers{{Name: stringP("team"), Value: "b", IsEqual: true}},
- RouteSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{"team-b": "child"},
+ Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "b", IsEqual: true}},
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "grafana-default-email",
+ RouteSelector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"team-b": "child"},
+ },
},
},
},
@@ -528,10 +570,12 @@ var _ = Describe("NotificationPolicy Reconciler: Provoke LoopDetected Condition"
},
Spec: v1beta1.GrafanaNotificationPolicyRouteSpec{
Route: v1beta1.Route{
- Receiver: "grafana-default-email",
- Matchers: v1beta1.Matchers{{Name: stringP("team"), Value: "b", IsEqual: true}}, // Also matches team b
- RouteSelector: &metav1.LabelSelector{
- MatchLabels: map[string]string{"team-b": "child"},
+ Matchers: v1beta1.Matchers{&v1beta1.Matcher{Name: stringP("team"), Value: "b", IsEqual: true}}, // Also matches team b
+ PartialRoute: v1beta1.PartialRoute{
+ Receiver: "grafana-default-email",
+ RouteSelector: &metav1.LabelSelector{
+ MatchLabels: map[string]string{"team-b": "child"},
+ },
},
},
},
diff --git a/deploy/helm/grafana-operator/files/crds/grafana.integreatly.org_grafananotificationpolicies.yaml b/deploy/helm/grafana-operator/files/crds/grafana.integreatly.org_grafananotificationpolicies.yaml
index fe6208cfb..0daa917b0 100644
--- a/deploy/helm/grafana-operator/files/crds/grafana.integreatly.org_grafananotificationpolicies.yaml
+++ b/deploy/helm/grafana-operator/files/crds/grafana.integreatly.org_grafananotificationpolicies.yaml
@@ -120,13 +120,6 @@ spec:
route:
description: Routes for alerts to match against
properties:
- active_time_intervals:
- items:
- type: string
- type: array
- continue:
- description: continue
- type: boolean
group_by:
description: group by
items:
@@ -138,50 +131,8 @@ spec:
group_wait:
description: group wait
type: string
- match_re:
- additionalProperties:
- type: string
- description: match re
- type: object
- matchers:
- description: matchers
- items:
- properties:
- isEqual:
- description: is equal
- type: boolean
- isRegex:
- description: is regex
- type: boolean
- name:
- description: name
- type: string
- value:
- description: value
- type: string
- required:
- - isRegex
- - value
- type: object
- type: array
- mute_time_intervals:
- description: mute time intervals
- items:
- type: string
- type: array
- object_matchers:
- description: object matchers
- items:
- description: |-
- ObjectMatcher ObjectMatcher is a matcher that can be used to filter alerts.
-
- swagger:model ObjectMatcher
- items:
- type: string
- type: array
- type: array
provenance:
- description: provenance
+ description: 'Deprecated: Does nothing'
type: string
receiver:
description: receiver
diff --git a/deploy/helm/grafana-operator/files/crds/grafana.integreatly.org_grafananotificationpolicyroutes.yaml b/deploy/helm/grafana-operator/files/crds/grafana.integreatly.org_grafananotificationpolicyroutes.yaml
index 1f11c0921..708c2fa3e 100644
--- a/deploy/helm/grafana-operator/files/crds/grafana.integreatly.org_grafananotificationpolicyroutes.yaml
+++ b/deploy/helm/grafana-operator/files/crds/grafana.integreatly.org_grafananotificationpolicyroutes.yaml
@@ -44,6 +44,7 @@ spec:
of GrafanaNotificationPolicyRoute
properties:
active_time_intervals:
+ description: active time intervals
items:
type: string
type: array
@@ -104,7 +105,7 @@ spec:
type: array
type: array
provenance:
- description: provenance
+ description: 'Deprecated: Does nothing'
type: string
receiver:
description: receiver
diff --git a/deploy/kustomize/base/crds.yaml b/deploy/kustomize/base/crds.yaml
index d5660b3ce..9bb16c9ff 100644
--- a/deploy/kustomize/base/crds.yaml
+++ b/deploy/kustomize/base/crds.yaml
@@ -2637,13 +2637,6 @@ spec:
route:
description: Routes for alerts to match against
properties:
- active_time_intervals:
- items:
- type: string
- type: array
- continue:
- description: continue
- type: boolean
group_by:
description: group by
items:
@@ -2655,50 +2648,8 @@ spec:
group_wait:
description: group wait
type: string
- match_re:
- additionalProperties:
- type: string
- description: match re
- type: object
- matchers:
- description: matchers
- items:
- properties:
- isEqual:
- description: is equal
- type: boolean
- isRegex:
- description: is regex
- type: boolean
- name:
- description: name
- type: string
- value:
- description: value
- type: string
- required:
- - isRegex
- - value
- type: object
- type: array
- mute_time_intervals:
- description: mute time intervals
- items:
- type: string
- type: array
- object_matchers:
- description: object matchers
- items:
- description: |-
- ObjectMatcher ObjectMatcher is a matcher that can be used to filter alerts.
-
- swagger:model ObjectMatcher
- items:
- type: string
- type: array
- type: array
provenance:
- description: provenance
+ description: 'Deprecated: Does nothing'
type: string
receiver:
description: receiver
@@ -2901,6 +2852,7 @@ spec:
of GrafanaNotificationPolicyRoute
properties:
active_time_intervals:
+ description: active time intervals
items:
type: string
type: array
@@ -2961,7 +2913,7 @@ spec:
type: array
type: array
provenance:
- description: provenance
+ description: 'Deprecated: Does nothing'
type: string
receiver:
description: receiver
diff --git a/docs/docs/api.md b/docs/docs/api.md
index b802047b7..1f63a2fe2 100644
--- a/docs/docs/api.md
+++ b/docs/docs/api.md
@@ -5128,20 +5128,6 @@ Routes for alerts to match against
receiver
| Name | -Type | -Description | -Required | -
|---|---|---|---|
| isRegex | -boolean | -
- is regex - |
- true | -
| value | -string | -
- value - |
- true | -
| isEqual | -boolean | -
- is equal - |
- false | -
| name | -string | -
- name - |
- false | -