/
rules_sync.go
116 lines (107 loc) · 3.61 KB
/
rules_sync.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package alarms
import (
"context"
"fmt"
"github.com/google/go-cmp/cmp"
alertingv1 "github.com/rancher/opni/pkg/apis/alerting/v1"
corev1 "github.com/rancher/opni/pkg/apis/core/v1"
"github.com/rancher/opni/pkg/auth/cluster"
"github.com/rancher/opni/pkg/util"
"github.com/rancher/opni/plugins/alerting/pkg/apis/rules"
"github.com/samber/lo"
"go.uber.org/multierr"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/testing/protocmp"
"google.golang.org/protobuf/types/known/emptypb"
"google.golang.org/protobuf/types/known/timestamppb"
)
const (
metadataReadOnly = "readOnly"
)
func ignoreOpniConfigurations(conf *alertingv1.AlertCondition) {
conf.Metadata = nil
conf.Name = ""
conf.Description = ""
conf.Labels = nil
conf.Severity = 0
conf.AttachedEndpoints = nil
conf.Silence = nil
conf.LastUpdated = nil
conf.GoldenSignal = 0
conf.OverrideType = ""
}
func applyMutableReadOnlyFields(dest, src *alertingv1.AlertCondition) {
dest.Name = src.Name
dest.Description = src.Description
dest.Labels = src.Labels
dest.Severity = src.Severity
dest.AttachedEndpoints = src.AttachedEndpoints
dest.Silence = src.Silence
dest.LastUpdated = src.LastUpdated
dest.GoldenSignal = src.GoldenSignal
dest.OverrideType = src.OverrideType
}
func areRuleSpecsEqual(old, new *alertingv1.AlertCondition) bool {
oldIgnoreOpniConf := util.ProtoClone(old)
newIgnoreOpniConf := util.ProtoClone(new)
ignoreOpniConfigurations(oldIgnoreOpniConf)
ignoreOpniConfigurations(newIgnoreOpniConf)
return cmp.Equal(oldIgnoreOpniConf, newIgnoreOpniConf, protocmp.Transform())
}
func (a *AlarmServerComponent) SyncRules(ctx context.Context, rules *rules.RuleManifest) (*emptypb.Empty, error) {
clusterId := cluster.StreamAuthorizedID(ctx)
errors := []error{}
condStorage := a.conditionStorage.Get()
for _, rule := range rules.Rules {
incomingCond := &alertingv1.AlertCondition{
// immutable sync fields
Id: rule.RuleId.Id,
GroupId: rule.GroupId.Id,
AlertType: &alertingv1.AlertTypeDetails{
Type: &alertingv1.AlertTypeDetails_PrometheusQuery{
PrometheusQuery: &alertingv1.AlertConditionPrometheusQuery{
ClusterId: &corev1.Reference{Id: clusterId},
Query: rule.GetExpr(),
For: rule.GetDuration(),
},
},
},
Metadata: map[string]string{
metadataReadOnly: "true",
},
// these will be considered mutable
Name: rule.Name,
Description: fmt.Sprintf("Prometheus alerting rule '%s' synced ", rule.Name),
Labels: []string{},
Severity: 0,
AttachedEndpoints: &alertingv1.AttachedEndpoints{},
Silence: &alertingv1.SilenceInfo{},
LastUpdated: timestamppb.Now(),
GoldenSignal: 0,
OverrideType: "",
}
existing, err := condStorage.Group(rule.GetGroupId().Id).Get(ctx, rule.GetRuleId().Id)
if err == nil {
metadata := existing.GetMetadata()
if metadata == nil {
metadata = map[string]string{}
}
// keep opni managed metadata, unless overriden
retMetadata := lo.Assign(metadata, incomingCond.Metadata)
if !areRuleSpecsEqual(existing, incomingCond) {
applyMutableReadOnlyFields(incomingCond, existing)
incomingCond.Metadata = retMetadata
if err := condStorage.Group(rule.GroupId.Id).Put(ctx, rule.RuleId.Id, incomingCond); err != nil {
errors = append(errors, err)
}
}
}
if st, ok := status.FromError(err); ok && st.Code() == codes.NotFound {
if err := condStorage.Group(rule.GroupId.Id).Put(ctx, rule.RuleId.Id, incomingCond); err != nil {
errors = append(errors, err)
}
}
}
return &emptypb.Empty{}, multierr.Combine(errors...)
}