未验证 提交 88eb1af4 编写于 作者: K KubeSphere CI Bot 提交者: GitHub

Merge pull request #3409 from junotx/ca

add alerting rule bulk api
......@@ -18,6 +18,7 @@ package v2alpha1
import (
"context"
"regexp"
"sort"
"strconv"
"strings"
......@@ -47,6 +48,8 @@ var (
templateTestData = template.AlertTemplateData(map[string]string{}, map[string]string{}, 0)
templateTestTextPrefix = "{{$labels := .Labels}}{{$externalLabels := .ExternalLabels}}{{$value := .Value}}"
ruleNameMatcher = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$`)
)
type RuleLevel string
......@@ -70,6 +73,10 @@ func (r *PostableAlertingRule) Validate() error {
if r.Name == "" {
errs = append(errs, errors.New("name can not be empty"))
} else {
if !ruleNameMatcher.MatchString(r.Name) {
errs = append(errs, errors.New("rule name must match regular expression ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"))
}
}
if r.Query == "" {
......@@ -442,3 +449,80 @@ func parseLabelFilters(req *restful.Request) (map[string]string, map[string]stri
}
return labelEqualFilters, labelContainFilters
}
const (
ErrBadData ErrorType = "bad_data"
ErrDuplicateName ErrorType = "duplicate_name"
ErrNotFound ErrorType = "not_found"
ErrServer ErrorType = "server_error"
StatusSuccess Status = "success"
StatusError Status = "error"
ResultCreated Result = "created"
ResultUpdated Result = "updated"
ResultDeleted Result = "deleted"
)
type Status string
type ErrorType string
type Result string
type BulkResponse struct {
Errors bool `json:"errors" description:"If true, one or more operations in the bulk request don't complete successfully"`
Items []*BulkItemResponse `json:"items" description:"It contains the result of each operation in the bulk request"`
}
// MakeBulkResponse tidies the internal items and sets the errors
func (br *BulkResponse) MakeBulkResponse() *BulkResponse {
var (
items []*BulkItemResponse
itemMap = make(map[string]*BulkItemResponse)
)
for i, item := range br.Items {
if item.Status == StatusError {
br.Errors = true
}
pitem, ok := itemMap[item.RuleName]
if !ok || (pitem.Status == StatusSuccess || item.Status == StatusError) {
itemMap[item.RuleName] = br.Items[i]
}
}
for k := range itemMap {
item := itemMap[k]
if item.Error != nil {
item.ErrorStr = item.Error.Error()
}
items = append(items, itemMap[k])
}
br.Items = items
return br
}
type BulkItemResponse struct {
RuleName string `json:"ruleName,omitempty"`
Status Status `json:"status,omitempty" description:"It may be success or error"`
Result Result `json:"result,omitempty" description:"It may be created, updated or deleted, and only for successful operations"`
ErrorType ErrorType `json:"errorType,omitempty" description:"It may be bad_data, duplicate_name, not_found or server_error, and only for failed operations"`
Error error `json:"-"`
ErrorStr string `json:"error,omitempty" description:"It is only returned for failed operations"`
}
func NewBulkItemSuccessResponse(ruleName string, result Result) *BulkItemResponse {
return &BulkItemResponse{
RuleName: ruleName,
Status: StatusSuccess,
Result: result,
}
}
func NewBulkItemErrorServerResponse(ruleName string, err error) *BulkItemResponse {
return &BulkItemResponse{
RuleName: ruleName,
Status: StatusError,
ErrorType: ErrServer,
Error: err,
}
}
......@@ -283,3 +283,45 @@ func (h *handler) handleListBuiltinRuleAlerts(req *restful.Request, resp *restfu
resp.WriteEntity(alerts)
}
func (h *handler) handleCreateOrUpdateCustomAlertingRules(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
var rules []*v2alpha1.PostableAlertingRule
if err := req.ReadEntity(&rules); err != nil {
klog.Error(err)
ksapi.HandleBadRequest(resp, nil, err)
return
}
bulkResp, err := h.operator.CreateOrUpdateCustomAlertingRules(req.Request.Context(), namespace, rules)
if err != nil {
klog.Error(err)
switch {
case err == v2alpha1.ErrThanosRulerNotEnabled:
ksapi.HandleBadRequest(resp, nil, err)
default:
ksapi.HandleInternalError(resp, nil, err)
}
return
}
resp.WriteEntity(bulkResp)
}
func (h *handler) handleDeleteCustomAlertingRules(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
names := req.QueryParameters("name")
bulkResp, err := h.operator.DeleteCustomAlertingRules(req.Request.Context(), namespace, names)
if err != nil {
klog.Error(err)
switch {
case err == v2alpha1.ErrThanosRulerNotEnabled:
ksapi.HandleBadRequest(resp, nil, err)
default:
ksapi.HandleInternalError(resp, nil, err)
}
return
}
resp.WriteEntity(bulkResp)
}
......@@ -102,6 +102,20 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa
Returns(http.StatusOK, ksapi.StatusOK, nil).
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
ws.Route(ws.DELETE("/rules").
To(handler.handleDeleteCustomAlertingRules).
Doc("delete multiple cluster-level custom alerting rules").
Param(ws.QueryParameter("name", "rule name").CollectionFormat(restful.CollectionFormatMulti).AllowMultiple(true)).
Returns(http.StatusOK, ksapi.StatusOK, alertingv2alpha1.BulkResponse{}).
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
ws.Route(ws.POST("/bulkrules").
To(handler.handleCreateOrUpdateCustomAlertingRules).
Doc("create or update cluster-level custom alerting rules in bulk").
Reads([]alertingv2alpha1.PostableAlertingRule{}).
Returns(http.StatusOK, ksapi.StatusOK, alertingv2alpha1.BulkResponse{}).
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
ws.Route(ws.PUT("/rules/{rule_name}").
To(handler.handleUpdateCustomAlertingRule).
Doc("update the cluster-level custom alerting rule with the specified name").
......@@ -151,6 +165,13 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa
Returns(http.StatusOK, ksapi.StatusOK, alertingv2alpha1.AlertList{}).
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
ws.Route(ws.DELETE("/namespaces/{namespace}/rules").
To(handler.handleDeleteCustomAlertingRules).
Doc("delete multiple custom alerting rules in the specified namespace").
Param(ws.QueryParameter("name", "rule name").CollectionFormat(restful.CollectionFormatMulti).AllowMultiple(true)).
Returns(http.StatusOK, ksapi.StatusOK, alertingv2alpha1.BulkResponse{}).
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
ws.Route(ws.POST("/namespaces/{namespace}/rules").
To(handler.handleCreateCustomAlertingRule).
Doc("create a custom alerting rule in the specified namespace").
......@@ -158,6 +179,13 @@ func AddToContainer(container *restful.Container, informers informers.InformerFa
Returns(http.StatusOK, ksapi.StatusOK, "").
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
ws.Route(ws.POST("/namespaces/{namespace}/bulkrules").
To(handler.handleCreateOrUpdateCustomAlertingRules).
Doc("create or update custom alerting rules in bulk in the specified namespace").
Reads([]alertingv2alpha1.PostableAlertingRule{}).
Returns(http.StatusOK, ksapi.StatusOK, alertingv2alpha1.BulkResponse{}).
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
ws.Route(ws.PUT("/namespaces/{namespace}/rules/{rule_name}").
To(handler.handleUpdateCustomAlertingRule).
Doc("update the custom alerting rule with the specified name in the specified namespace").
......
......@@ -22,14 +22,9 @@ import (
)
const (
rulerNamespace = constants.KubeSphereMonitoringNamespace
customRuleGroupDefault = "alerting.custom.defaults"
customRuleResourceLabelKeyLevel = "custom-alerting-rule-level"
)
rulerNamespace = constants.KubeSphereMonitoringNamespace
var (
maxSecretSize = corev1.MaxSecretSize
maxConfigMapDataSize = int(float64(maxSecretSize) * 0.45)
customRuleResourceLabelKeyLevel = "custom-alerting-rule-level"
)
// Operator contains all operations to alerting rules. The operations may involve manipulations of prometheusrule
......@@ -57,6 +52,11 @@ type Operator interface {
// DeleteCustomAlertingRule deletes the custom alerting rule with the given name.
DeleteCustomAlertingRule(ctx context.Context, namespace, ruleName string) error
// CreateOrUpdateCustomAlertingRules creates or updates custom alerting rules in bulk.
CreateOrUpdateCustomAlertingRules(ctx context.Context, namespace string, rs []*v2alpha1.PostableAlertingRule) (*v2alpha1.BulkResponse, error)
// DeleteCustomAlertingRules deletes a batch of custom alerting rules.
DeleteCustomAlertingRules(ctx context.Context, namespace string, ruleNames []string) (*v2alpha1.BulkResponse, error)
// ListBuiltinAlertingRules lists the builtin(non-custom) alerting rules
ListBuiltinAlertingRules(ctx context.Context,
queryParams *v2alpha1.AlertingRuleQueryParams) (*v2alpha1.GettableAlertingRuleList, error)
......@@ -241,40 +241,6 @@ func (o *operator) ListBuiltinRuleAlerts(ctx context.Context, ruleId string) (*v
}, nil
}
func (o *operator) ListClusterAlertingRules(ctx context.Context, customFlag string,
queryParams *v2alpha1.AlertingRuleQueryParams) (*v2alpha1.GettableAlertingRuleList, error) {
namespace := rulerNamespace
ruleNamespace, err := o.namespaceInformer.Lister().Get(namespace)
if err != nil {
return nil, err
}
alertingRules, err := o.listCustomAlertingRules(ctx, ruleNamespace, v2alpha1.RuleLevelCluster)
if err != nil {
return nil, err
}
return pageAlertingRules(alertingRules, queryParams), nil
}
func (o *operator) ListClusterRulesAlerts(ctx context.Context,
queryParams *v2alpha1.AlertQueryParams) (*v2alpha1.AlertList, error) {
namespace := rulerNamespace
ruleNamespace, err := o.namespaceInformer.Lister().Get(namespace)
if err != nil {
return nil, err
}
alertingRules, err := o.listCustomAlertingRules(ctx, ruleNamespace, v2alpha1.RuleLevelCluster)
if err != nil {
return nil, err
}
return pageAlerts(alertingRules, queryParams), nil
}
func (o *operator) listCustomAlertingRules(ctx context.Context, ruleNamespace *corev1.Namespace,
level v2alpha1.RuleLevel) ([]*v2alpha1.GettableAlertingRule, error) {
......@@ -292,6 +258,10 @@ func (o *operator) listCustomAlertingRules(ctx context.Context, ruleNamespace *c
return nil, err
}
if len(resourceRulesMap) == 0 {
return nil, nil
}
ruleGroups, err := o.ruleClient.ThanosRules(ctx)
if err != nil {
return nil, err
......@@ -473,8 +443,20 @@ func (o *operator) CreateCustomAlertingRule(ctx context.Context, namespace strin
setRuleUpdateTime(rule, time.Now())
return ruler.AddAlertingRule(ctx, ruleNamespace, extraRuleResourceSelector,
customRuleGroupDefault, parseToPrometheusRule(rule), ruleResourceLabels)
respItems, err := ruler.AddAlertingRules(ctx, ruleNamespace, extraRuleResourceSelector,
ruleResourceLabels, &rules.RuleWithGroup{Rule: *parseToPrometheusRule(rule)})
if err != nil {
return err
}
for _, item := range respItems {
if item.Status == v2alpha1.StatusError {
if item.ErrorType == v2alpha1.ErrNotFound {
return v2alpha1.ErrAlertingRuleNotFound
}
return item.Error
}
}
return nil
}
func (o *operator) UpdateCustomAlertingRule(ctx context.Context, namespace, name string,
......@@ -526,8 +508,21 @@ func (o *operator) UpdateCustomAlertingRule(ctx context.Context, namespace, name
setRuleUpdateTime(rule, time.Now())
return ruler.UpdateAlertingRule(ctx, ruleNamespace, extraRuleResourceSelector,
resourceRule.Group, parseToPrometheusRule(rule), ruleResourceLabels)
respItems, err := ruler.UpdateAlertingRules(ctx, ruleNamespace, extraRuleResourceSelector, ruleResourceLabels,
&rules.ResourceRuleItem{ResourceName: resourceRule.ResourceName,
RuleWithGroup: rules.RuleWithGroup{Group: resourceRule.Group, Rule: *parseToPrometheusRule(rule)}})
if err != nil {
return err
}
for _, item := range respItems {
if item.Status == v2alpha1.StatusError {
if item.ErrorType == v2alpha1.ErrNotFound {
return v2alpha1.ErrAlertingRuleNotFound
}
return item.Error
}
}
return nil
}
func (o *operator) DeleteCustomAlertingRule(ctx context.Context, namespace, name string) error {
......@@ -555,15 +550,254 @@ func (o *operator) DeleteCustomAlertingRule(ctx context.Context, namespace, name
}
extraRuleResourceSelector := labels.SelectorFromSet(labels.Set{customRuleResourceLabelKeyLevel: string(level)})
resourceRule, err := o.resourceRuleCache.GetRule(ruler, ruleNamespace, extraRuleResourceSelector, name)
resourceRules, err := o.resourceRuleCache.GetRuleByIdOrName(ruler, ruleNamespace, extraRuleResourceSelector, name)
if err != nil {
return err
}
if resourceRule == nil {
if len(resourceRules) == 0 {
return v2alpha1.ErrAlertingRuleNotFound
}
return ruler.DeleteAlertingRule(ctx, ruleNamespace, extraRuleResourceSelector, resourceRule.Group, name)
respItems, err := ruler.DeleteAlertingRules(ctx, ruleNamespace, resourceRules...)
if err != nil {
return err
}
for _, item := range respItems {
if item.Status == v2alpha1.StatusError {
if item.ErrorType == v2alpha1.ErrNotFound {
return v2alpha1.ErrAlertingRuleNotFound
}
return item.Error
}
}
return nil
}
func (o *operator) CreateOrUpdateCustomAlertingRules(ctx context.Context, namespace string,
rs []*v2alpha1.PostableAlertingRule) (*v2alpha1.BulkResponse, error) {
if l := len(rs); l == 0 {
return &v2alpha1.BulkResponse{}, nil
}
ruler, err := o.getThanosRuler()
if err != nil {
return nil, err
}
if ruler == nil {
return nil, v2alpha1.ErrThanosRulerNotEnabled
}
var (
level v2alpha1.RuleLevel
ruleResourceLabels = make(map[string]string)
)
for k, v := range o.thanosRuleResourceLabels {
ruleResourceLabels[k] = v
}
if namespace == "" {
namespace = rulerNamespace
level = v2alpha1.RuleLevelCluster
} else {
level = v2alpha1.RuleLevelNamespace
}
ruleResourceLabels[customRuleResourceLabelKeyLevel] = string(level)
ruleNamespace, err := o.namespaceInformer.Lister().Get(namespace)
if err != nil {
return nil, err
}
extraRuleResourceSelector := labels.SelectorFromSet(labels.Set{customRuleResourceLabelKeyLevel: string(level)})
resourceRulesMap, err := o.resourceRuleCache.ListRules(ruler, ruleNamespace, extraRuleResourceSelector)
if err != nil {
return nil, err
}
exists := make(map[string][]*rules.ResourceRuleItem)
for _, c := range resourceRulesMap {
for n, items := range c.NameRules {
exists[n] = append(exists[n], items...)
}
}
// check all the rules
var (
br = &v2alpha1.BulkResponse{}
nameSet = make(map[string]struct{})
invalids = make(map[string]struct{})
)
for i := range rs {
var (
r = rs[i]
name = r.Name
)
if _, ok := nameSet[name]; ok {
br.Items = append(br.Items, &v2alpha1.BulkItemResponse{
RuleName: name,
Status: v2alpha1.StatusError,
ErrorType: v2alpha1.ErrDuplicateName,
Error: errors.Errorf("There is more than one rule named %s in the bulk request", name),
})
invalids[name] = struct{}{}
continue
} else {
nameSet[name] = struct{}{}
}
if err := r.Validate(); err != nil {
br.Items = append(br.Items, &v2alpha1.BulkItemResponse{
RuleName: name,
Status: v2alpha1.StatusError,
ErrorType: v2alpha1.ErrBadData,
Error: err,
})
invalids[name] = struct{}{}
continue
}
if level == v2alpha1.RuleLevelNamespace {
expr, err := rules.InjectExprNamespaceLabel(r.Query, namespace)
if err != nil {
br.Items = append(br.Items, v2alpha1.NewBulkItemErrorServerResponse(name, err))
invalids[name] = struct{}{}
continue
}
r.Query = expr
}
}
if len(nameSet) == len(invalids) {
return br.MakeBulkResponse(), nil
}
// Confirm whether the rules should be added or updated. For each rule that is committed,
// it will be added if the rule does not exist, or updated otherwise.
// If there are rules with the same name in the existing rules to update, the first will be
// updated but the others will be deleted
var (
addRules []*rules.RuleWithGroup
updRules []*rules.ResourceRuleItem
delRules []*rules.ResourceRuleItem // duplicate rules that need to deleted in other resources
updateTime = time.Now()
)
for i := range rs {
r := rs[i]
if _, ok := invalids[r.Name]; ok {
continue
}
setRuleUpdateTime(r, updateTime)
if items, ok := exists[r.Name]; ok && len(items) > 0 {
item := items[0]
updRules = append(updRules, &rules.ResourceRuleItem{
ResourceName: item.ResourceName,
RuleWithGroup: rules.RuleWithGroup{Group: item.Group, Rule: *parseToPrometheusRule(r)}})
if len(items) > 1 {
for j := 1; j < len(items); j++ {
if items[j].ResourceName != item.ResourceName {
delRules = append(delRules, items[j])
}
}
}
} else {
addRules = append(addRules, &rules.RuleWithGroup{Rule: *parseToPrometheusRule(r)})
}
}
// add rules
if len(addRules) > 0 {
resps, err := ruler.AddAlertingRules(ctx, ruleNamespace, extraRuleResourceSelector, ruleResourceLabels, addRules...)
if err == nil {
br.Items = append(br.Items, resps...)
} else {
for _, rule := range addRules {
br.Items = append(br.Items, v2alpha1.NewBulkItemErrorServerResponse(rule.Alert, err))
}
}
}
// update existing rules
if len(updRules) > 0 {
resps, err := ruler.UpdateAlertingRules(ctx, ruleNamespace, extraRuleResourceSelector, ruleResourceLabels, updRules...)
if err == nil {
br.Items = append(br.Items, resps...)
} else {
for _, rule := range updRules {
br.Items = append(br.Items, v2alpha1.NewBulkItemErrorServerResponse(rule.Alert, err))
}
}
}
// delete possible duplicate rules
if len(delRules) > 0 {
_, err := ruler.DeleteAlertingRules(ctx, ruleNamespace, delRules...)
if err != nil {
for _, rule := range delRules {
br.Items = append(br.Items, v2alpha1.NewBulkItemErrorServerResponse(rule.Alert, err))
}
}
}
return br.MakeBulkResponse(), nil
}
func (o *operator) DeleteCustomAlertingRules(ctx context.Context, namespace string,
names []string) (*v2alpha1.BulkResponse, error) {
if l := len(names); l == 0 {
return &v2alpha1.BulkResponse{}, nil
}
ruler, err := o.getThanosRuler()
if err != nil {
return nil, err
}
if ruler == nil {
return nil, v2alpha1.ErrThanosRulerNotEnabled
}
var (
level v2alpha1.RuleLevel
)
if namespace == "" {
namespace = rulerNamespace
level = v2alpha1.RuleLevelCluster
} else {
level = v2alpha1.RuleLevelNamespace
}
ruleNamespace, err := o.namespaceInformer.Lister().Get(namespace)
if err != nil {
return nil, err
}
extraRuleResourceSelector := labels.SelectorFromSet(labels.Set{customRuleResourceLabelKeyLevel: string(level)})
resourceRulesMap, err := o.resourceRuleCache.ListRules(ruler, ruleNamespace, extraRuleResourceSelector)
if err != nil {
return nil, err
}
exists := make(map[string][]*rules.ResourceRuleItem)
for _, c := range resourceRulesMap {
for n, items := range c.NameRules {
exists[n] = append(exists[n], items...)
}
}
br := &v2alpha1.BulkResponse{}
var ruleItems []*rules.ResourceRuleItem
for _, n := range names {
if items, ok := exists[n]; ok {
ruleItems = append(ruleItems, items...)
} else {
br.Items = append(br.Items, &v2alpha1.BulkItemResponse{
RuleName: n,
Status: v2alpha1.StatusError,
ErrorType: v2alpha1.ErrNotFound,
})
}
}
respItems, err := ruler.DeleteAlertingRules(ctx, ruleNamespace, ruleItems...)
if err != nil {
return nil, err
}
br.Items = append(br.Items, respItems...)
return br.MakeBulkResponse(), nil
}
// getPrometheusRuler gets the cluster-in prometheus
......@@ -603,6 +837,9 @@ func (o *operator) getThanosRuler() (rules.Ruler, error) {
}
func parseToPrometheusRule(rule *v2alpha1.PostableAlertingRule) *promresourcesv1.Rule {
if _, ok := rule.Labels[rules.LabelKeyAlertType]; !ok {
rule.Labels[rules.LabelKeyAlertType] = rules.LabelValueAlertType
}
return &promresourcesv1.Rule{
Alert: rule.Name,
Expr: intstr.FromString(rule.Query),
......
......@@ -107,6 +107,24 @@ func (c *RuleCache) getResourceRuleCaches(ruler Ruler, ruleNamespace *corev1.Nam
func (c *RuleCache) GetRule(ruler Ruler, ruleNamespace *corev1.Namespace,
extraRuleResourceSelector labels.Selector, idOrName string) (*ResourceRuleItem, error) {
rules, err := c.GetRuleByIdOrName(ruler, ruleNamespace, extraRuleResourceSelector, idOrName)
if err != nil {
return nil, err
}
if l := len(rules); l == 0 {
return nil, nil
} else if l > 1 {
// guarantees the stability of the get operations.
sort.Slice(rules, func(i, j int) bool {
return v2alpha1.AlertingRuleIdCompare(rules[i].Id, rules[j].Id)
})
}
return rules[0], nil
}
func (c *RuleCache) GetRuleByIdOrName(ruler Ruler, ruleNamespace *corev1.Namespace,
extraRuleResourceSelector labels.Selector, idOrName string) ([]*ResourceRuleItem, error) {
caches, err := c.getResourceRuleCaches(ruler, ruleNamespace, extraRuleResourceSelector)
if err != nil {
return nil, err
......@@ -121,9 +139,11 @@ func (c *RuleCache) GetRule(ruler Ruler, ruleNamespace *corev1.Namespace,
for rn, rc := range caches {
if rule, ok := rc.IdRules[idOrName]; ok {
rules = append(rules, &ResourceRuleItem{
Group: rule.Group,
Id: rule.Id,
Rule: rule.Rule.DeepCopy(),
RuleWithGroup: RuleWithGroup{
Group: rule.Group,
Id: rule.Id,
Rule: *rule.Rule.DeepCopy(),
},
ResourceName: rn,
})
}
......@@ -133,9 +153,11 @@ func (c *RuleCache) GetRule(ruler Ruler, ruleNamespace *corev1.Namespace,
if nrules, ok := rc.NameRules[idOrName]; ok {
for _, nrule := range nrules {
rules = append(rules, &ResourceRuleItem{
Group: nrule.Group,
Id: nrule.Id,
Rule: nrule.Rule.DeepCopy(),
RuleWithGroup: RuleWithGroup{
Group: nrule.Group,
Id: nrule.Id,
Rule: *nrule.Rule.DeepCopy(),
},
ResourceName: rn,
})
}
......@@ -145,15 +167,7 @@ func (c *RuleCache) GetRule(ruler Ruler, ruleNamespace *corev1.Namespace,
return nil, errors.New("unsupported ruler type")
}
if l := len(rules); l == 0 {
return nil, nil
} else if l > 1 {
// guarantees the stability of the get operations.
sort.Slice(rules, func(i, j int) bool {
return v2alpha1.AlertingRuleIdCompare(rules[i].Id, rules[j].Id)
})
}
return rules[0], nil
return rules, err
}
func (c *RuleCache) ListRules(ruler Ruler, ruleNamespace *corev1.Namespace,
......@@ -178,9 +192,11 @@ func (c *RuleCache) ListRules(ruler Ruler, ruleNamespace *corev1.Namespace,
for _, rule := range rules {
rrs.GroupSet[rule.Group] = struct{}{}
rr := &ResourceRuleItem{
Group: rule.Group,
Id: rule.Id,
Rule: rule.Rule.DeepCopy(),
RuleWithGroup: RuleWithGroup{
Group: rule.Group,
Id: rule.Id,
Rule: *rule.Rule.DeepCopy(),
},
ResourceName: rn,
}
rrs.IdRules[rr.Id] = rr
......
......@@ -13,9 +13,7 @@ type ResourceRuleCollection struct {
type ResourceRuleItem struct {
ResourceName string
Group string
Id string
Rule *promresourcesv1.Rule
RuleWithGroup
}
type ResourceRule struct {
......@@ -29,3 +27,9 @@ type ResourceRuleChunk struct {
Custom bool
ResourceRulesMap map[string]*ResourceRuleCollection
}
type RuleWithGroup struct {
Group string
Id string
promresourcesv1.Rule
}
此差异已折叠。
......@@ -28,6 +28,9 @@ const (
LabelKeyThanosRulerReplica = "thanos_ruler_replica"
LabelKeyPrometheusReplica = "prometheus_replica"
LabelKeyAlertType = "alerttype"
LabelValueAlertType = "metric"
)
func FormatExpr(expr string) (string, error) {
......@@ -208,7 +211,7 @@ func GetAlertingRulesStatus(ruleNamespace string, ruleChunk *ResourceRuleChunk,
func GetAlertingRuleStatus(ruleNamespace string, rule *ResourceRule, epRuleGroups []*alerting.RuleGroup,
extLabels func() map[string]string) (*v2alpha1.GettableAlertingRule, error) {
if rule == nil || rule.Rule == nil {
if rule == nil || rule.Alert == "" {
return nil, nil
}
......@@ -257,7 +260,7 @@ func GetAlertingRuleStatus(ruleNamespace string, rule *ResourceRule, epRuleGroup
func getAlertingRuleStatus(resRule *ResourceRuleItem, epRule *alerting.AlertingRule,
custom bool, level v2alpha1.RuleLevel) *v2alpha1.GettableAlertingRule {
if resRule == nil || resRule.Rule == nil {
if resRule == nil || resRule.Alert == "" {
return nil
}
......
package rules
import (
"kubesphere.io/kubesphere/pkg/simple/client/alerting"
"testing"
"github.com/google/go-cmp/cmp"
......@@ -9,6 +8,7 @@ import (
"github.com/prometheus/prometheus/rules"
"k8s.io/apimachinery/pkg/util/intstr"
"kubesphere.io/kubesphere/pkg/api/alerting/v2alpha1"
"kubesphere.io/kubesphere/pkg/simple/client/alerting"
)
func TestGetAlertingRulesStatus(t *testing.T) {
......@@ -31,15 +31,17 @@ func TestGetAlertingRulesStatus(t *testing.T) {
NameRules: map[string][]*ResourceRuleItem{
"ca7f09e76954e67c": []*ResourceRuleItem{{
ResourceName: "custom-alerting-rule-jqbgn",
Group: "alerting.custom.defaults",
Id: "ca7f09e76954e67c",
Rule: &promresourcesv1.Rule{
Alert: "TestCPUUsageHigh",
Expr: intstr.FromString(`namespace:workload_cpu_usage:sum{namespace="test"} > 1`),
For: "1m",
Annotations: map[string]string{
"alias": "The alias is here",
"description": "The description is here",
RuleWithGroup: RuleWithGroup{
Group: "alerting.custom.defaults",
Id: "ca7f09e76954e67c",
Rule: promresourcesv1.Rule{
Alert: "TestCPUUsageHigh",
Expr: intstr.FromString(`namespace:workload_cpu_usage:sum{namespace="test"} > 1`),
For: "1m",
Annotations: map[string]string{
"alias": "The alias is here",
"description": "The description is here",
},
},
},
}},
......
......@@ -22,7 +22,6 @@ import (
"flag"
"fmt"
"io/ioutil"
"kubesphere.io/kubesphere/pkg/version"
"log"
"github.com/emicklei/go-restful"
......@@ -32,6 +31,7 @@ import (
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"
"github.com/pkg/errors"
promfake "github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/fake"
urlruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/apiserver/runtime"
......@@ -53,10 +53,12 @@ import (
tenantv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/tenant/v1alpha2"
terminalv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/terminal/v1alpha2"
"kubesphere.io/kubesphere/pkg/models/iam/group"
"kubesphere.io/kubesphere/pkg/simple/client/alerting"
fakedevops "kubesphere.io/kubesphere/pkg/simple/client/devops/fake"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
fakes3 "kubesphere.io/kubesphere/pkg/simple/client/s3/fake"
"kubesphere.io/kubesphere/pkg/version"
)
var output string
......@@ -129,7 +131,9 @@ func generateSwaggerJson() []byte {
urlruntime.Must(terminalv1alpha2.AddToContainer(container, clientsets.Kubernetes(), nil))
urlruntime.Must(metricsv1alpha2.AddToContainer(container))
urlruntime.Must(networkv1alpha2.AddToContainer(container, ""))
urlruntime.Must(alertingv2alpha1.AddToContainer(container, informerFactory, nil, nil, nil))
alertingOptions := &alerting.Options{}
alertingClient, _ := alerting.NewRuleClient(alertingOptions)
urlruntime.Must(alertingv2alpha1.AddToContainer(container, informerFactory, promfake.NewSimpleClientset(), alertingClient, alertingOptions))
config := restfulspec.Config{
WebServices: container.RegisteredWebServices(),
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册