Skip to content

Commit a0780e2

Browse files
authored
Merge pull request kubesphere#3338 from junotx/ca
custom alerting tuning
2 parents 166dd4f + bac3d66 commit a0780e2

File tree

5 files changed

+261
-89
lines changed

5 files changed

+261
-89
lines changed

pkg/api/alerting/v2alpha1/types.go

+82-17
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ limitations under the License.
1717
package v2alpha1
1818

1919
import (
20-
"regexp"
20+
"context"
2121
"sort"
2222
"strconv"
2323
"strings"
@@ -26,21 +26,27 @@ import (
2626
"github.com/emicklei/go-restful"
2727
"github.com/pkg/errors"
2828
prommodel "github.com/prometheus/common/model"
29+
"github.com/prometheus/prometheus/pkg/timestamp"
2930
"github.com/prometheus/prometheus/promql/parser"
31+
"github.com/prometheus/prometheus/template"
3032
utilerrors "k8s.io/apimachinery/pkg/util/errors"
3133
)
3234

3335
const (
3436
RuleLevelCluster RuleLevel = "cluster"
3537
RuleLevelNamespace RuleLevel = "namespace"
38+
39+
AnnotationKeyRuleUpdateTime = "rule_update_time"
3640
)
3741

3842
var (
3943
ErrThanosRulerNotEnabled = errors.New("The request operation to custom alerting rule could not be done because thanos ruler is not enabled")
4044
ErrAlertingRuleNotFound = errors.New("The alerting rule was not found")
4145
ErrAlertingRuleAlreadyExists = errors.New("The alerting rule already exists")
46+
ErrAlertingAPIV2NotEnabled = errors.New("The alerting v2 API is not enabled")
4247

43-
ruleLabelNameMatcher = regexp.MustCompile(`[a-zA-Z_][a-zA-Z0-9_]*`)
48+
templateTestData = template.AlertTemplateData(map[string]string{}, map[string]string{}, 0)
49+
templateTestTextPrefix = "{{$labels := .Labels}}{{$externalLabels := .ExternalLabels}}{{$value := .Value}}"
4450
)
4551

4652
type RuleLevel string
@@ -65,7 +71,10 @@ func (r *PostableAlertingRule) Validate() error {
6571
if r.Name == "" {
6672
errs = append(errs, errors.New("name can not be empty"))
6773
}
68-
if _, err := parser.ParseExpr(r.Query); err != nil {
74+
75+
if r.Query == "" {
76+
errs = append(errs, errors.New("query can not be empty"))
77+
} else if _, err := parser.ParseExpr(r.Query); err != nil {
6978
errs = append(errs, errors.Wrapf(err, "query is invalid: %s", r.Query))
7079
}
7180
if r.Duration != "" {
@@ -74,12 +83,42 @@ func (r *PostableAlertingRule) Validate() error {
7483
}
7584
}
7685

86+
parseTest := func(text string) error {
87+
tmpl := template.NewTemplateExpander(
88+
context.TODO(),
89+
templateTestTextPrefix+text,
90+
"__alert_"+r.Name,
91+
templateTestData,
92+
prommodel.Time(timestamp.FromTime(time.Now())),
93+
nil,
94+
nil,
95+
)
96+
return tmpl.ParseTest()
97+
}
98+
7799
if len(r.Labels) > 0 {
78-
for name, _ := range r.Labels {
79-
if !ruleLabelNameMatcher.MatchString(name) || strings.HasPrefix(name, "__") {
100+
for name, v := range r.Labels {
101+
if !prommodel.LabelName(name).IsValid() || strings.HasPrefix(name, "__") {
80102
errs = append(errs, errors.Errorf(
81103
"label name (%s) is not valid. The name must match [a-zA-Z_][a-zA-Z0-9_]* and has not the __ prefix (label names with this prefix are for internal use)", name))
82104
}
105+
if !prommodel.LabelValue(v).IsValid() {
106+
errs = append(errs, errors.Errorf("invalid label value: %s", v))
107+
}
108+
if err := parseTest(v); err != nil {
109+
errs = append(errs, errors.Errorf("invalid label value: %s", v))
110+
}
111+
}
112+
}
113+
114+
if len(r.Annotations) > 0 {
115+
for name, v := range r.Annotations {
116+
if !prommodel.LabelName(name).IsValid() {
117+
errs = append(errs, errors.Errorf("invalid annotation name: %s", v))
118+
}
119+
if err := parseTest(v); err != nil {
120+
errs = append(errs, errors.Errorf("invalid annotation value: %s", v))
121+
}
83122
}
84123
}
85124

@@ -126,7 +165,7 @@ type AlertingRuleQueryParams struct {
126165
LabelEqualFilters map[string]string
127166
LabelContainFilters map[string]string
128167

129-
Offset int
168+
PageNum int
130169
Limit int
131170
SortField string
132171
SortType string
@@ -180,10 +219,22 @@ func AlertingRuleIdCompare(leftId, rightId string) bool {
180219
}
181220

182221
func (q *AlertingRuleQueryParams) Sort(rules []*GettableAlertingRule) {
183-
idCompare := func(left, right *GettableAlertingRule) bool {
222+
baseCompare := func(left, right *GettableAlertingRule) bool {
223+
var leftUpdateTime, rightUpdateTime string
224+
if len(left.Annotations) > 0 {
225+
leftUpdateTime = left.Annotations[AnnotationKeyRuleUpdateTime]
226+
}
227+
if len(right.Annotations) > 0 {
228+
rightUpdateTime = right.Annotations[AnnotationKeyRuleUpdateTime]
229+
}
230+
231+
if leftUpdateTime != rightUpdateTime {
232+
return leftUpdateTime > rightUpdateTime
233+
}
234+
184235
return AlertingRuleIdCompare(left.Id, right.Id)
185236
}
186-
var compare = idCompare
237+
var compare = baseCompare
187238
if q != nil {
188239
reverse := q.SortType == "desc"
189240
switch q.SortField {
@@ -195,7 +246,7 @@ func (q *AlertingRuleQueryParams) Sort(rules []*GettableAlertingRule) {
195246
}
196247
return c < 0
197248
}
198-
return idCompare(left, right)
249+
return baseCompare(left, right)
199250
}
200251
case "lastEvaluation":
201252
compare = func(left, right *GettableAlertingRule) bool {
@@ -213,7 +264,7 @@ func (q *AlertingRuleQueryParams) Sort(rules []*GettableAlertingRule) {
213264
return left.LastEvaluation.Before(*right.LastEvaluation)
214265
}
215266
}
216-
return idCompare(left, right)
267+
return baseCompare(left, right)
217268
}
218269
case "evaluationTime":
219270
compare = func(left, right *GettableAlertingRule) bool {
@@ -223,7 +274,7 @@ func (q *AlertingRuleQueryParams) Sort(rules []*GettableAlertingRule) {
223274
}
224275
return left.EvaluationDurationSeconds < right.EvaluationDurationSeconds
225276
}
226-
return idCompare(left, right)
277+
return baseCompare(left, right)
227278
}
228279
}
229280
}
@@ -235,7 +286,7 @@ func (q *AlertingRuleQueryParams) Sort(rules []*GettableAlertingRule) {
235286
func (q *AlertingRuleQueryParams) Sub(rules []*GettableAlertingRule) []*GettableAlertingRule {
236287
start, stop := 0, 10
237288
if q != nil {
238-
start, stop = q.Offset, q.Offset+q.Limit
289+
start, stop = (q.PageNum-1)*q.Limit, q.PageNum*q.Limit
239290
}
240291
total := len(rules)
241292
if start < total {
@@ -252,8 +303,8 @@ type AlertQueryParams struct {
252303
LabelEqualFilters map[string]string
253304
LabelContainFilters map[string]string
254305

255-
Offset int
256-
Limit int
306+
PageNum int
307+
Limit int
257308
}
258309

259310
func (q *AlertQueryParams) Filter(alerts []*Alert) []*Alert {
@@ -312,7 +363,7 @@ func (q *AlertQueryParams) Sort(alerts []*Alert) {
312363
func (q *AlertQueryParams) Sub(alerts []*Alert) []*Alert {
313364
start, stop := 0, 10
314365
if q != nil {
315-
start, stop = q.Offset, q.Offset+q.Limit
366+
start, stop = (q.PageNum-1)*q.Limit, q.PageNum*q.Limit
316367
}
317368
total := len(alerts)
318369
if start < total {
@@ -333,7 +384,14 @@ func ParseAlertingRuleQueryParams(req *restful.Request) (*AlertingRuleQueryParam
333384
q.NameContainFilter = req.QueryParameter("name")
334385
q.State = req.QueryParameter("state")
335386
q.Health = req.QueryParameter("health")
336-
q.Offset, _ = strconv.Atoi(req.QueryParameter("offset"))
387+
q.PageNum, err = strconv.Atoi(req.QueryParameter("page"))
388+
if err != nil {
389+
q.PageNum = 1
390+
err = nil
391+
}
392+
if q.PageNum <= 0 {
393+
q.PageNum = 1
394+
}
337395
q.Limit, err = strconv.Atoi(req.QueryParameter("limit"))
338396
if err != nil {
339397
q.Limit = 10
@@ -352,7 +410,14 @@ func ParseAlertQueryParams(req *restful.Request) (*AlertQueryParams, error) {
352410
)
353411

354412
q.State = req.QueryParameter("state")
355-
q.Offset, _ = strconv.Atoi(req.QueryParameter("offset"))
413+
q.PageNum, err = strconv.Atoi(req.QueryParameter("page"))
414+
if err != nil {
415+
q.PageNum = 1
416+
err = nil
417+
}
418+
if q.PageNum <= 0 {
419+
q.PageNum = 1
420+
}
356421
q.Limit, err = strconv.Atoi(req.QueryParameter("limit"))
357422
if err != nil {
358423
q.Limit = 10

pkg/kapis/alerting/v2alpha1/register.go

+25-11
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,24 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa
4141
promResourceClient promresourcesclient.Interface, ruleClient alerting.RuleClient,
4242
option *alerting.Options) error {
4343

44-
handler := newHandler(informers, promResourceClient, ruleClient, option)
45-
4644
ws := runtime.NewWebService(GroupVersion)
4745

46+
if informers == nil || promResourceClient == nil || ruleClient == nil || option == nil {
47+
h := func(req *restful.Request, resp *restful.Response) {
48+
ksapi.HandleBadRequest(resp, nil, alertingv2alpha1.ErrAlertingAPIV2NotEnabled)
49+
return
50+
}
51+
ws.Route(ws.GET("/{path:*}").To(h).Returns(http.StatusOK, ksapi.StatusOK, nil))
52+
ws.Route(ws.PUT("/{path:*}").To(h).Returns(http.StatusOK, ksapi.StatusOK, nil))
53+
ws.Route(ws.POST("/{path:*}").To(h).Returns(http.StatusOK, ksapi.StatusOK, nil))
54+
ws.Route(ws.DELETE("/{path:*}").To(h).Returns(http.StatusOK, ksapi.StatusOK, nil))
55+
ws.Route(ws.PATCH("/{path:*}").To(h).Returns(http.StatusOK, ksapi.StatusOK, nil))
56+
container.Add(ws)
57+
return nil
58+
}
59+
60+
handler := newHandler(informers, promResourceClient, ruleClient, option)
61+
4862
ws.Route(ws.GET("/rules").
4963
To(handler.handleListCustomAlertingRules).
5064
Doc("list the cluster-level custom alerting rules").
@@ -54,7 +68,7 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa
5468
Param(ws.QueryParameter("label_filters", "label filters, concatenating multiple filters with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").DataFormat("key=%s,key~%s")).
5569
Param(ws.QueryParameter("sort_field", "sort field, one of `name`, `lastEvaluation`, `evaluationTime`")).
5670
Param(ws.QueryParameter("sort_type", "sort type, one of `asc`, `desc`")).
57-
Param(ws.QueryParameter("offset", "offset of the result set").DataType("integer").DefaultValue("0")).
71+
Param(ws.QueryParameter("page", "page of the result set").DataType("integer").DefaultValue("1")).
5872
Param(ws.QueryParameter("limit", "limit size of the result set").DataType("integer").DefaultValue("10")).
5973
Returns(http.StatusOK, ksapi.StatusOK, alertingv2alpha1.GettableAlertingRuleList{}).
6074
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
@@ -64,7 +78,7 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa
6478
Doc("list the alerts of the cluster-level custom alerting rules").
6579
Param(ws.QueryParameter("state", "state, one of `firing`, `pending`, `inactive`")).
6680
Param(ws.QueryParameter("label_filters", "label filters, concatenating multiple filters with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").DataFormat("key=%s,key~%s")).
67-
Param(ws.QueryParameter("offset", "offset of the result set").DataType("integer").DefaultValue("0")).
81+
Param(ws.QueryParameter("page", "page of the result set").DataType("integer").DefaultValue("1")).
6882
Param(ws.QueryParameter("limit", "limit size of the result set").DataType("integer").DefaultValue("10")).
6983
Returns(http.StatusOK, ksapi.StatusOK, alertingv2alpha1.AlertList{}).
7084
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
@@ -78,7 +92,7 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa
7892
ws.Route(ws.GET("/rules/{rule_name}/alerts").
7993
To(handler.handleListCustomRuleAlerts).
8094
Doc("list the alerts of the cluster-level custom alerting rule with the specified name").
81-
Returns(http.StatusOK, ksapi.StatusOK, []alertingv2alpha1.Alert{}).
95+
Returns(http.StatusOK, ksapi.StatusOK, alertingv2alpha1.AlertList{}).
8296
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
8397

8498
ws.Route(ws.POST("/rules").
@@ -110,7 +124,7 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa
110124
Param(ws.QueryParameter("label_filters", "label filters, concatenating multiple filters with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").DataFormat("key=%s,key~%s")).
111125
Param(ws.QueryParameter("sort_field", "sort field, one of `name`, `lastEvaluation`, `evaluationTime`")).
112126
Param(ws.QueryParameter("sort_type", "sort type, one of `asc`, `desc`")).
113-
Param(ws.QueryParameter("offset", "offset of the result set").DataType("integer").DefaultValue("0")).
127+
Param(ws.QueryParameter("page", "page of the result set").DataType("integer").DefaultValue("1")).
114128
Param(ws.QueryParameter("limit", "limit size of the result set").DataType("integer").DefaultValue("10")).
115129
Returns(http.StatusOK, ksapi.StatusOK, alertingv2alpha1.GettableAlertingRuleList{}).
116130
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
@@ -120,7 +134,7 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa
120134
Doc("list the alerts of the custom alerting rules in the specified namespace.").
121135
Param(ws.QueryParameter("state", "state, one of `firing`, `pending`, `inactive`")).
122136
Param(ws.QueryParameter("label_filters", "label filters, concatenating multiple filters with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").DataFormat("key=%s,key~%s")).
123-
Param(ws.QueryParameter("offset", "offset of the result set").DataType("integer").DefaultValue("0")).
137+
Param(ws.QueryParameter("page", "page of the result set").DataType("integer").DefaultValue("1")).
124138
Param(ws.QueryParameter("limit", "limit size of the result set").DataType("integer").DefaultValue("10")).
125139
Returns(http.StatusOK, ksapi.StatusOK, alertingv2alpha1.AlertList{}).
126140
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
@@ -134,7 +148,7 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa
134148
ws.Route(ws.GET("/namespaces/{namespace}/rules/{rule_name}/alerts").
135149
To(handler.handleListCustomRuleAlerts).
136150
Doc("get the alerts of the custom alerting rule with the specified name in the specified namespace").
137-
Returns(http.StatusOK, ksapi.StatusOK, []alertingv2alpha1.Alert{}).
151+
Returns(http.StatusOK, ksapi.StatusOK, alertingv2alpha1.AlertList{}).
138152
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
139153

140154
ws.Route(ws.POST("/namespaces/{namespace}/rules").
@@ -166,7 +180,7 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa
166180
Param(ws.QueryParameter("label_filters", "label filters, concatenating multiple filters with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").DataFormat("key=%s,key~%s")).
167181
Param(ws.QueryParameter("sort_field", "sort field, one of `name`, `lastEvaluation`, `evaluationTime`")).
168182
Param(ws.QueryParameter("sort_type", "sort type, one of `asc`, `desc`")).
169-
Param(ws.QueryParameter("offset", "offset of the result set").DataType("integer").DefaultValue("0")).
183+
Param(ws.QueryParameter("page", "page of the result set").DataType("integer").DefaultValue("1")).
170184
Param(ws.QueryParameter("limit", "limit size of the result set").DataType("integer").DefaultValue("10")).
171185
Returns(http.StatusOK, ksapi.StatusOK, alertingv2alpha1.GettableAlertingRuleList{}).
172186
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
@@ -176,7 +190,7 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa
176190
Doc("list the alerts of the builtin(non-custom) rules").
177191
Param(ws.QueryParameter("state", "state, one of `firing`, `pending`, `inactive`")).
178192
Param(ws.QueryParameter("label_filters", "label filters, concatenating multiple filters with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a").DataFormat("key=%s,key~%s")).
179-
Param(ws.QueryParameter("offset", "offset of the result set").DataType("integer").DefaultValue("0")).
193+
Param(ws.QueryParameter("page", "page of the result set").DataType("integer").DefaultValue("1")).
180194
Param(ws.QueryParameter("limit", "limit size of the result set").DataType("integer").DefaultValue("10")).
181195
Returns(http.StatusOK, ksapi.StatusOK, alertingv2alpha1.AlertList{}).
182196
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
@@ -190,7 +204,7 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa
190204
ws.Route(ws.GET("/builtin/rules/{rule_id}/alerts").
191205
To(handler.handleListBuiltinRuleAlerts).
192206
Doc("list the alerts of the builtin(non-custom) alerting rule with the specified id").
193-
Returns(http.StatusOK, ksapi.StatusOK, []alertingv2alpha1.Alert{}).
207+
Returns(http.StatusOK, ksapi.StatusOK, alertingv2alpha1.AlertList{}).
194208
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
195209

196210
container.Add(ws)

0 commit comments

Comments
 (0)