enhance globalrulegroups (#5134)

Signed-off-by: junot <junotxiang@kubesphere.io>

Signed-off-by: junot <junotxiang@kubesphere.io>
This commit is contained in:
junot
2022-08-12 20:30:33 +08:00
committed by GitHub
parent f741bc7943
commit b97a49b925
8 changed files with 555 additions and 21 deletions

View File

@@ -49,6 +49,23 @@ spec:
additionalProperties:
type: string
type: object
clusterSelector:
description: Only one of its members may be specified.
properties:
inValues:
items:
type: string
type: array
matcher:
properties:
type:
type: string
value:
type: string
required:
- type
type: object
type: object
disable:
type: boolean
expr:
@@ -56,6 +73,144 @@ spec:
- type: integer
- type: string
x-kubernetes-int-or-string: true
exprBuilder:
description: If ExprBuilder is not nil, the configured Expr
will be ignored
properties:
node:
properties:
comparator:
type: string
metricThreshold:
description: Only one of its members may be specified.
properties:
cpu:
description: Only one of its members may be specified.
properties:
load15m:
type: number
load1m:
type: number
load5m:
type: number
utilization:
type: number
type: object
disk:
description: Only one of its members may be specified.
properties:
inodeUtilization:
type: number
iopsRead:
description: The unit is io/s
type: number
iopsWrite:
description: The unit is io/s
type: number
spaceAvailable:
description: The unit is bytes
type: number
spaceUtilization:
type: number
throughputRead:
description: The unit is bytes/s
type: number
throughputWrite:
description: The unit is bytes/s
type: number
type: object
memory:
description: Only one of its members may be specified.
properties:
available:
description: The unit is bytes
type: number
utilization:
type: number
type: object
network:
description: Only one of its members may be specified.
properties:
receivedRate:
description: The unit is bit/s
type: number
transmittedRate:
description: The unit is bit/s
type: number
type: object
pod:
description: Only one of its members may be specified.
properties:
abnormalRatio:
type: number
utilization:
type: number
type: object
type: object
names:
items:
type: string
type: array
required:
- comparator
- metricThreshold
- names
type: object
workload:
properties:
comparator:
type: string
kind:
type: string
metricThreshold:
description: Only one of its members may be specified.
properties:
cpu:
description: Only one of its members may be specified.
properties:
usage:
description: The unit is core
type: number
type: object
memory:
description: Only one of its members may be specified.
properties:
usage:
description: The memory usage contains cache
The unit is bytes
type: number
usageWoCache:
description: The memory usage contains no cache
The unit is bytes
type: number
type: object
network:
description: Only one of its members may be specified.
properties:
receivedRate:
description: The unit is bit/s
type: number
transmittedRate:
description: The unit is bit/s
type: number
type: object
replica:
description: Only one of its members may be specified.
properties:
unavailableRatio:
type: number
type: object
type: object
names:
items:
type: string
type: array
required:
- comparator
- kind
- names
type: object
type: object
for:
description: 'Duration is a valid time unit Supported units:
y, w, d, h, m, s, ms Examples: `30s`, `1m`, `1h20m15s`'
@@ -65,6 +220,23 @@ spec:
additionalProperties:
type: string
type: object
namespaceSelector:
description: Only one of its members may be specified.
properties:
inValues:
items:
type: string
type: array
matcher:
properties:
type:
type: string
value:
type: string
required:
- type
type: object
type: object
severity:
type: string
required:

View File

@@ -25,11 +25,13 @@ import (
const (
// for rulegroup/alert
FieldState = "state"
FieldState = "state"
FieldBuiltin = "builtin"
// for rulegroup
FieldRuleGroupEvaluationTime = "evaluationTime"
FieldRuleGroupLastEvaluation = "lastEvalution"
// for alert
FieldAlertLabelFilters = "label_filters"
FieldAlertActiveAt = "activeAt"
@@ -69,6 +71,7 @@ type RuleGroupStatus struct {
}
type RuleStatus struct {
Expr string `json:"expr,omitempty" description:"expression evaluated, for global rules only"`
State string `json:"state,omitempty" description:"state of a rule, one of firing, pending or inactive depending on its alerts"`
Health string `json:"health,omitempty" description:"health state of a rule, one of ok, err, unknown depending on the last execution result"`
LastError string `json:"lastError,omitempty" description:"error of the last evaluation"`

View File

@@ -53,10 +53,13 @@ const (
SourceGroupResourceLabelValueEnableTrue = "true"
SourceGroupResourceLabelValueEnableFalse = "false"
// label keys in PrometheusRule.metadata.labels
// for PrometheusRule.metadata.labels
PrometheusRuleResourceLabelKeyOwnerNamespace = "alerting.kubesphere.io/owner_namespace"
PrometheusRuleResourceLabelKeyOwnerCluster = "alerting.kubesphere.io/owner_cluster"
PrometheusRuleResourceLabelKeyRuleLevel = "alerting.kubesphere.io/rule_level"
PrometheusRuleResourceLabelKeyBuiltin = "alerting.kubesphere.io/builtin"
PrometheusRuleResourceLabelValueBuiltinTrue = "true"
PrometheusRuleResourceLabelValueBuiltinFalse = "false"
// name prefix for PrometheusRule
PrometheusRulePrefix = "alertrules-"
@@ -73,23 +76,40 @@ var maxConfigMapDataSize = int(float64(corev1.MaxSecretSize) * 0.5)
type enforceRuleFunc func(rule *promresourcesv1.Rule) error
type EnforceExprFunc func(expr string) (string, error)
var emptyEnforceExprFunc = func(expr string) (string, error) {
return expr, nil
}
func CreateEnforceExprFunc(enforceRuleMatchers []*promlabels.Matcher) EnforceExprFunc {
if len(enforceRuleMatchers) > 0 {
enforcer := injectproxy.NewEnforcer(enforceRuleMatchers...)
return func(expr string) (string, error) {
parsedExpr, err := parser.ParseExpr(expr)
if err != nil {
return expr, err
}
if err := enforcer.EnforceNode(parsedExpr); err != nil {
return expr, err
}
return parsedExpr.String(), nil
}
}
return emptyEnforceExprFunc
}
func createEnforceRuleFuncs(enforceRuleMatchers []*promlabels.Matcher, enforceRuleLabels map[string]string) []enforceRuleFunc {
var enforceFuncs []enforceRuleFunc
// enforce func for rule.expr
if len(enforceRuleMatchers) > 0 {
enforcer := injectproxy.NewEnforcer(enforceRuleMatchers...)
enforceExprFunc := CreateEnforceExprFunc(enforceRuleMatchers)
enforceFuncs = append(enforceFuncs, func(rule *promresourcesv1.Rule) error {
if enforcer != nil {
expr := rule.Expr.String()
parsedExpr, err := parser.ParseExpr(expr)
if err != nil {
return err
}
if err = enforcer.EnforceNode(parsedExpr); err != nil {
return err
}
rule.Expr = intstr.FromString(parsedExpr.String())
expr, err := enforceExprFunc(rule.Expr.String())
if err != nil {
return err
}
rule.Expr = intstr.FromString(expr)
return nil
})
}
@@ -109,10 +129,10 @@ func createEnforceRuleFuncs(enforceRuleMatchers []*promlabels.Matcher, enforceRu
}
func makePrometheusRuleGroups(log logr.Logger, groupList client.ObjectList,
enforceFuncs ...enforceRuleFunc) ([]*promresourcesv1.RuleGroup, error) {
commonEnforceFuncs ...enforceRuleFunc) ([]*promresourcesv1.RuleGroup, error) {
var rulegroups []*promresourcesv1.RuleGroup
convertRule := func(rule *alertingv2beta1.Rule) (*promresourcesv1.Rule, error) {
convertRule := func(rule *alertingv2beta1.Rule, enforceFuncs ...enforceRuleFunc) (*promresourcesv1.Rule, error) {
if rule.Disable { // ignoring disabled rule
return nil, nil
}
@@ -135,6 +155,8 @@ func makePrometheusRuleGroups(log logr.Logger, groupList client.ObjectList,
Annotations: rule.Annotations,
}
enforceFuncs = append(enforceFuncs, commonEnforceFuncs...)
for _, f := range enforceFuncs {
if f == nil {
continue
@@ -193,7 +215,8 @@ func makePrometheusRuleGroups(log logr.Logger, groupList client.ObjectList,
for _, group := range list.Items {
var prules []promresourcesv1.Rule
for _, rule := range group.Spec.Rules {
prule, err := convertRule(&rule.Rule)
prule, err := convertRule(&rule.Rule, createEnforceRuleFuncs(ParseGlobalRuleEnforceMatchers(&rule), nil)...)
if err != nil {
log.WithValues("globalrulegroup", group.Name).Error(err, "failed to convert")
continue
@@ -214,6 +237,23 @@ func makePrometheusRuleGroups(log logr.Logger, groupList client.ObjectList,
return rulegroups, nil
}
func ParseGlobalRuleEnforceMatchers(rule *alertingv2beta1.GlobalRule) []*promlabels.Matcher {
var enforceRuleMatchers []*promlabels.Matcher
if rule.ClusterSelector != nil {
matcher := rule.ClusterSelector.ParseToMatcher(RuleLabelKeyCluster)
if matcher != nil {
enforceRuleMatchers = append(enforceRuleMatchers, matcher)
}
}
if rule.NamespaceSelector != nil {
matcher := rule.NamespaceSelector.ParseToMatcher(RuleLabelKeyNamespace)
if matcher != nil {
enforceRuleMatchers = append(enforceRuleMatchers, matcher)
}
}
return enforceRuleMatchers
}
func makePrometheusRuleResources(rulegroups []*promresourcesv1.RuleGroup, namespace, namePrefix string,
labels map[string]string, ownerReferences []metav1.OwnerReference) ([]*promresourcesv1.PrometheusRule, error) {

View File

@@ -108,6 +108,7 @@ func AddToContainer(container *restful.Container, ksclient kubesphere.Interface,
Param(ws.QueryParameter(query.ParameterAscending, "sort parameters, e.g. reverse=true").Required(false).DefaultValue("ascending=false")).
Param(ws.QueryParameter(query.ParameterOrderBy, "sort parameters, e.g. orderBy=createTime")).
Param(ws.QueryParameter(kapialertingv2beta1.FieldState, "state of a rulegroup, one of `firing`, `pending`, `inactive` depending on its rules")).
Param(ws.QueryParameter(kapialertingv2beta1.FieldBuiltin, "filter rule groups, `true` for built-in rule groups and `false` for custom rule groups")).
Returns(http.StatusOK, kapi.StatusOK, kapi.ListResult{}).
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))
@@ -126,6 +127,7 @@ func AddToContainer(container *restful.Container, ksclient kubesphere.Interface,
Param(ws.QueryParameter(query.ParameterOrderBy, "sort parameters, one of `activeAt`. e.g. orderBy=activeAt")).
Param(ws.QueryParameter(kapialertingv2beta1.FieldState, "state, one of `firing`, `pending`")).
Param(ws.QueryParameter(kapialertingv2beta1.FieldAlertLabelFilters, "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")).
Param(ws.QueryParameter(kapialertingv2beta1.FieldBuiltin, "filter alerts, `true` for alerts from built-in rule groups and `false` for alerts from custom rule groups")).
Returns(http.StatusOK, kapi.StatusOK, kapi.ListResult{}).
Metadata(restfulspec.KeyOpenAPITags, []string{constants.AlertingTag}))

View File

@@ -22,6 +22,7 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/selection"
"kubesphere.io/kubesphere/pkg/api"
kapialertingv2beta1 "kubesphere.io/kubesphere/pkg/api/alerting/v2beta1"
@@ -106,6 +107,14 @@ func (o *ruleGroupOperator) listRuleGroups(ctx context.Context, namespace string
statusg, ok := statusRuleGroupMap[g.Name]
if ok && len(statusg.Rules) == len(g.Spec.Rules) { // assure that they are the same rulegroups
copyRuleGroupStatus(statusg, &g.Status)
} else {
// for rules not loaded by rule reloader (eg.thanos) yet
for range g.Spec.Rules {
g.Status.RulesStatus = append(g.Status.RulesStatus, kapialertingv2beta1.RuleStatus{
State: stateInactiveString,
Health: string(promrules.HealthUnknown),
})
}
}
groups[i] = g
}
@@ -272,12 +281,23 @@ func (o *ruleGroupOperator) GetRuleGroup(ctx context.Context, namespace, name st
return nil, err
}
var setStatus bool
for _, g := range statusRuleGroups {
if g.Name == resourceRuleGroup.Name && len(g.Rules) == len(resourceRuleGroup.Spec.Rules) {
copyRuleGroupStatus(g, &ret.Status)
setStatus = true
break
}
}
if !setStatus {
// for rules not loaded by rule reloader (eg.thanos) yet
for range ret.Spec.Rules {
ret.Status.RulesStatus = append(ret.Status.RulesStatus, kapialertingv2beta1.RuleStatus{
State: stateInactiveString,
Health: string(promrules.HealthUnknown),
})
}
}
return ret, nil
}
@@ -324,6 +344,14 @@ func (o *ruleGroupOperator) listClusterRuleGroups(ctx context.Context, selector
statusg, ok := statusRuleGroupMap[g.Name]
if ok && len(statusg.Rules) == len(g.Spec.Rules) {
copyRuleGroupStatus(statusg, &g.Status)
} else {
// for rules not loaded by rule reloader (eg.thanos) yet
for range g.Spec.Rules {
g.Status.RulesStatus = append(g.Status.RulesStatus, kapialertingv2beta1.RuleStatus{
State: stateInactiveString,
Health: string(promrules.HealthUnknown),
})
}
}
groups[i] = g
}
@@ -410,12 +438,23 @@ func (o *ruleGroupOperator) GetClusterRuleGroup(ctx context.Context, name string
return nil, err
}
var setStatus bool
for _, g := range statusRuleGroups {
if g.Name == resourceRuleGroup.Name && len(g.Rules) == len(resourceRuleGroup.Spec.Rules) {
copyRuleGroupStatus(g, &ret.Status)
setStatus = true
break
}
}
if !setStatus {
// for rules not loaded by rule reloader (eg.thanos) yet
for range ret.Spec.Rules {
ret.Status.RulesStatus = append(ret.Status.RulesStatus, kapialertingv2beta1.RuleStatus{
State: stateInactiveString,
Health: string(promrules.HealthUnknown),
})
}
}
return ret, nil
}
@@ -463,6 +502,21 @@ func (o *ruleGroupOperator) listGlobalRuleGroups(ctx context.Context, selector l
statusg, ok := statusRuleGroupMap[g.Name]
if ok && len(statusg.Rules) == len(g.Spec.Rules) {
copyRuleGroupStatus(statusg, &g.Status)
} else {
// for rules not loaded by rule reloader (eg.thanos) yet
for _, rule := range g.Spec.Rules {
ruleStatus := kapialertingv2beta1.RuleStatus{
State: stateInactiveString,
Health: string(promrules.HealthUnknown),
}
enforceExprFunc := controller.CreateEnforceExprFunc(controller.ParseGlobalRuleEnforceMatchers(&rule))
expr, err := enforceExprFunc(rule.Expr.String())
if err != nil {
return nil, err
}
ruleStatus.Expr = expr
g.Status.RulesStatus = append(g.Status.RulesStatus, ruleStatus)
}
}
groups[i] = g
}
@@ -472,7 +526,22 @@ func (o *ruleGroupOperator) listGlobalRuleGroups(ctx context.Context, selector l
func (o *ruleGroupOperator) ListGlobalRuleGroups(ctx context.Context,
queryParam *query.Query) (*api.ListResult, error) {
groups, err := o.listGlobalRuleGroups(ctx, queryParam.Selector())
selector := queryParam.Selector()
if val, ok := queryParam.Filters[kapialertingv2beta1.FieldBuiltin]; ok {
// add match requirement to the selector to select only builtin or custom rulegroups
var operator selection.Operator
if val == controller.PrometheusRuleResourceLabelValueBuiltinTrue {
operator = selection.Equals
} else {
operator = selection.NotEquals
}
requirement, _ := labels.NewRequirement(
controller.PrometheusRuleResourceLabelKeyBuiltin,
operator,
[]string{controller.PrometheusRuleResourceLabelValueBuiltinTrue})
selector = selector.Add(*requirement)
}
groups, err := o.listGlobalRuleGroups(ctx, selector)
if err != nil {
return nil, err
}
@@ -486,6 +555,9 @@ func (o *ruleGroupOperator) ListGlobalRuleGroups(ctx context.Context,
return resources.DefaultObjectMetaCompare(
left.(*kapialertingv2beta1.GlobalRuleGroup).ObjectMeta, right.(*kapialertingv2beta1.GlobalRuleGroup).ObjectMeta, field)
}, func(obj runtime.Object, filter query.Filter) bool {
if filter.Field == kapialertingv2beta1.FieldBuiltin { // ignoring this filter because it is filtered at the front
return true
}
hit, selected := o.filterRuleGroupStatus(&obj.(*kapialertingv2beta1.GlobalRuleGroup).Status, filter)
if hit {
return selected
@@ -497,7 +569,22 @@ func (o *ruleGroupOperator) ListGlobalRuleGroups(ctx context.Context,
func (o *ruleGroupOperator) ListGlobalAlerts(ctx context.Context,
queryParam *query.Query) (*api.ListResult, error) {
groups, err := o.listGlobalRuleGroups(ctx, labels.Everything())
selector := labels.Everything()
if val, ok := queryParam.Filters[kapialertingv2beta1.FieldBuiltin]; ok {
// add match requirement to the selector to select only builtin or custom rulegroups
var operator selection.Operator
if val == controller.PrometheusRuleResourceLabelValueBuiltinTrue {
operator = selection.Equals
} else {
operator = selection.NotEquals
}
requirement, _ := labels.NewRequirement(
controller.PrometheusRuleResourceLabelKeyBuiltin,
operator,
[]string{controller.PrometheusRuleResourceLabelValueBuiltinTrue})
selector = selector.Add(*requirement)
}
groups, err := o.listGlobalRuleGroups(ctx, selector)
if err != nil {
return nil, err
}
@@ -549,12 +636,30 @@ func (o *ruleGroupOperator) GetGlobalRuleGroup(ctx context.Context, name string)
return nil, err
}
var setStatus bool
for _, g := range statusRuleGroups {
if g.Name == resourceRuleGroup.Name && len(g.Rules) == len(resourceRuleGroup.Spec.Rules) {
copyRuleGroupStatus(g, &ret.Status)
setStatus = true
break
}
}
if !setStatus {
// for rules not loaded by rule reloader (eg.thanos) yet
for _, rule := range ret.Spec.Rules {
ruleStatus := kapialertingv2beta1.RuleStatus{
State: stateInactiveString,
Health: string(promrules.HealthUnknown),
}
enforceExprFunc := controller.CreateEnforceExprFunc(controller.ParseGlobalRuleEnforceMatchers(&rule))
expr, err := enforceExprFunc(rule.Expr.String())
if err != nil {
return nil, err
}
ruleStatus.Expr = expr
ret.Status.RulesStatus = append(ret.Status.RulesStatus, ruleStatus)
}
}
return ret, nil
}
@@ -582,14 +687,21 @@ func copyRuleGroupStatus(source *alerting.RuleGroup, target *kapialertingv2beta1
Value: alert.Value,
})
}
target.RulesStatus = append(target.RulesStatus, kapialertingv2beta1.RuleStatus{
ruleStatus := kapialertingv2beta1.RuleStatus{
State: rule.State,
Health: rule.Health,
LastError: rule.LastError,
EvaluationTime: rule.EvaluationTime,
LastEvaluation: rule.LastEvaluation,
Alerts: alerts,
})
}
if len(rule.Labels) > 0 {
if level, ok := rule.Labels[controller.RuleLabelKeyRuleLevel]; ok &&
level == string(controller.RuleLevelGlobal) { // provided only for global rules
ruleStatus.Expr = rule.Query
}
}
target.RulesStatus = append(target.RulesStatus, ruleStatus)
}
target.State = groupState.String()
}

View File

@@ -20,6 +20,7 @@ import (
"fmt"
"strings"
"github.com/prometheus/prometheus/pkg/labels"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
@@ -33,6 +34,8 @@ type Comparator string
type Severity string
type MatchType string
const (
ComparatorLT Comparator = "<"
ComparatorLE Comparator = "<="
@@ -42,6 +45,11 @@ const (
SeverityWarning Severity = "warning"
SeverityError Severity = "error"
SeverityCritical Severity = "critical"
MatchEqual = "="
MatchNotEqual = "!="
MatchRegexp = "=~"
MatchNotRegexp = "!~"
)
type Rule struct {
@@ -71,7 +79,91 @@ type ClusterRule struct {
}
type GlobalRule struct {
Rule `json:",inline"`
ClusterSelector *MetricLabelSelector `json:"clusterSelector,omitempty"`
NamespaceSelector *MetricLabelSelector `json:"namespaceSelector,omitempty"`
Rule `json:",inline"`
// If ExprBuilder is not nil, the configured Expr will be ignored
ExprBuilder *GlobalRuleExprBuilder `json:"exprBuilder,omitempty"`
}
// Only one of its members may be specified.
type MetricLabelSelector struct {
InValues []string `json:"inValues,omitempty"`
Matcher *Matcher `json:"matcher,omitempty"`
}
func (s *MetricLabelSelector) ParseToMatcher(labelName string) *labels.Matcher {
if s == nil {
return nil
}
if len(s.InValues) == 1 {
return &labels.Matcher{
Type: labels.MatchEqual,
Name: labelName,
Value: s.InValues[0],
}
}
if len(s.InValues) > 1 {
return &labels.Matcher{
Type: labels.MatchRegexp,
Name: labelName,
Value: fmt.Sprintf("(%s)", strings.Join(s.InValues, "|")),
}
}
if s.Matcher != nil {
var mtype labels.MatchType
switch s.Matcher.Type {
case MatchEqual:
mtype = labels.MatchEqual
case MatchNotEqual:
mtype = labels.MatchNotEqual
case MatchRegexp:
mtype = labels.MatchRegexp
case MatchNotRegexp:
mtype = labels.MatchNotRegexp
default:
return nil
}
return &labels.Matcher{
Type: mtype,
Name: labelName,
Value: s.Matcher.Value,
}
}
return nil
}
func (s *MetricLabelSelector) Validate() error {
if s.Matcher != nil {
return s.Matcher.Validate()
}
return nil
}
type Matcher struct {
Type MatchType `json:"type"`
Value string `json:"value,omitempty"`
}
func (m *Matcher) Validate() error {
var mtype labels.MatchType
switch m.Type {
case MatchEqual:
mtype = labels.MatchEqual
case MatchNotEqual:
mtype = labels.MatchNotEqual
case MatchRegexp:
mtype = labels.MatchRegexp
case MatchNotRegexp:
mtype = labels.MatchNotRegexp
default:
return fmt.Errorf("unsupported match type [%s]", m.Type)
}
_, err := labels.NewMatcher(mtype, "name", m.Value)
if err != nil {
return fmt.Errorf("invalid matcher: %v", err)
}
return nil
}
type NamespaceRuleExprBuilder struct {
@@ -82,6 +174,12 @@ type ClusterRuleExprBuilder struct {
Node *NodeExprBuilder `json:"node,omitempty"`
}
// Only one of its members may be specified.
type GlobalRuleExprBuilder struct {
Workload *WorkloadExprBuilder `json:"workload,omitempty"`
Node *NodeExprBuilder `json:"node,omitempty"`
}
type WorkloadKind string
const (

View File

@@ -212,6 +212,20 @@ func (r *GlobalRuleGroup) SetupWebhookWithManager(mgr ctrl.Manager) error {
var _ webhook.Defaulter = &GlobalRuleGroup{}
func (r *GlobalRuleGroup) Default() {
log := globalrulegrouplog.WithValues("name", r.Name)
log.Info("default")
for i := range r.Spec.Rules {
rule := r.Spec.Rules[i]
if rule.ExprBuilder != nil {
if rule.ExprBuilder.Node != nil {
rule.Expr = intstr.FromString(rule.ExprBuilder.Node.Build())
} else if rule.ExprBuilder.Workload != nil {
rule.Expr = intstr.FromString(rule.ExprBuilder.Workload.Build())
}
}
r.Spec.Rules[i] = rule
}
}
var _ webhook.Validator = &GlobalRuleGroup{}
@@ -231,6 +245,16 @@ func (r *GlobalRuleGroup) Validate() error {
var rules []Rule
for _, r := range r.Spec.Rules {
if r.ClusterSelector != nil {
if err := r.ClusterSelector.Validate(); err != nil {
return err
}
}
if r.NamespaceSelector != nil {
if err := r.NamespaceSelector.Validate(); err != nil {
return err
}
}
rules = append(rules, r.Rule)
}
var err = validateRules(log, r.Name, r.Spec.Interval, rules)

View File

@@ -171,7 +171,22 @@ func (in *ClusterRuleGroupStatus) DeepCopy() *ClusterRuleGroupStatus {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GlobalRule) DeepCopyInto(out *GlobalRule) {
*out = *in
if in.ClusterSelector != nil {
in, out := &in.ClusterSelector, &out.ClusterSelector
*out = new(MetricLabelSelector)
(*in).DeepCopyInto(*out)
}
if in.NamespaceSelector != nil {
in, out := &in.NamespaceSelector, &out.NamespaceSelector
*out = new(MetricLabelSelector)
(*in).DeepCopyInto(*out)
}
in.Rule.DeepCopyInto(&out.Rule)
if in.ExprBuilder != nil {
in, out := &in.ExprBuilder, &out.ExprBuilder
*out = new(GlobalRuleExprBuilder)
(*in).DeepCopyInto(*out)
}
return
}
@@ -185,6 +200,32 @@ func (in *GlobalRule) DeepCopy() *GlobalRule {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GlobalRuleExprBuilder) DeepCopyInto(out *GlobalRuleExprBuilder) {
*out = *in
if in.Workload != nil {
in, out := &in.Workload, &out.Workload
*out = new(WorkloadExprBuilder)
(*in).DeepCopyInto(*out)
}
if in.Node != nil {
in, out := &in.Node, &out.Node
*out = new(NodeExprBuilder)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlobalRuleExprBuilder.
func (in *GlobalRuleExprBuilder) DeepCopy() *GlobalRuleExprBuilder {
if in == nil {
return nil
}
out := new(GlobalRuleExprBuilder)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GlobalRuleGroup) DeepCopyInto(out *GlobalRuleGroup) {
*out = *in
@@ -285,6 +326,48 @@ func (in *GlobalRuleGroupStatus) DeepCopy() *GlobalRuleGroupStatus {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Matcher) DeepCopyInto(out *Matcher) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Matcher.
func (in *Matcher) DeepCopy() *Matcher {
if in == nil {
return nil
}
out := new(Matcher)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *MetricLabelSelector) DeepCopyInto(out *MetricLabelSelector) {
*out = *in
if in.InValues != nil {
in, out := &in.InValues, &out.InValues
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Matcher != nil {
in, out := &in.Matcher, &out.Matcher
*out = new(Matcher)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricLabelSelector.
func (in *MetricLabelSelector) DeepCopy() *MetricLabelSelector {
if in == nil {
return nil
}
out := new(MetricLabelSelector)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *NamespaceRule) DeepCopyInto(out *NamespaceRule) {
*out = *in