feat(pkger): add export support for notification rules
parent
08f523ddc0
commit
af5b7fd7d3
|
@ -12,6 +12,7 @@
|
|||
1. [16297](https://github.com/influxdata/influxdb/pull/16297): Add support for notification rule to pkger parser
|
||||
1. [16298](https://github.com/influxdata/influxdb/pull/16298): Add support for notification rule pkger dry run functionality
|
||||
1. [16305](https://github.com/influxdata/influxdb/pull/16305): Add support for notification rule pkger apply functionality
|
||||
1. [16312](https://github.com/influxdata/influxdb/pull/16312): Add support for notification rule pkger export functionality
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ type cmdPkgBuilder struct {
|
|||
dashboards string
|
||||
endpoints string
|
||||
labels string
|
||||
rules string
|
||||
telegrafs string
|
||||
variables string
|
||||
}
|
||||
|
@ -229,6 +230,7 @@ func (b *cmdPkgBuilder) cmdPkgExport() *cobra.Command {
|
|||
cmd.Flags().StringVar(&b.exportOpts.dashboards, "dashboards", "", "List of dashboard ids comma separated")
|
||||
cmd.Flags().StringVar(&b.exportOpts.endpoints, "endpoints", "", "List of notification endpoint ids comma separated")
|
||||
cmd.Flags().StringVar(&b.exportOpts.labels, "labels", "", "List of label ids comma separated")
|
||||
cmd.Flags().StringVar(&b.exportOpts.rules, "rules", "", "List of notification rule ids comma separated")
|
||||
cmd.Flags().StringVar(&b.exportOpts.telegrafs, "telegraf-configs", "", "List of telegraf config ids comma separated")
|
||||
cmd.Flags().StringVar(&b.exportOpts.variables, "variables", "", "List of variable ids comma separated")
|
||||
|
||||
|
@ -253,8 +255,9 @@ func (b *cmdPkgBuilder) pkgExportRunEFn() func(*cobra.Command, []string) error {
|
|||
{kind: pkger.KindBucket, idStrs: strings.Split(b.exportOpts.buckets, ",")},
|
||||
{kind: pkger.KindCheck, idStrs: strings.Split(b.exportOpts.checks, ",")},
|
||||
{kind: pkger.KindDashboard, idStrs: strings.Split(b.exportOpts.dashboards, ",")},
|
||||
{kind: pkger.KindNotificationEndpoint, idStrs: strings.Split(b.exportOpts.endpoints, ",")},
|
||||
{kind: pkger.KindLabel, idStrs: strings.Split(b.exportOpts.labels, ",")},
|
||||
{kind: pkger.KindNotificationEndpoint, idStrs: strings.Split(b.exportOpts.endpoints, ",")},
|
||||
{kind: pkger.KindNotificationRule, idStrs: strings.Split(b.exportOpts.rules, ",")},
|
||||
{kind: pkger.KindTelegraf, idStrs: strings.Split(b.exportOpts.telegrafs, ",")},
|
||||
{kind: pkger.KindVariable, idStrs: strings.Split(b.exportOpts.variables, ",")},
|
||||
}
|
||||
|
|
|
@ -400,6 +400,11 @@ spec:
|
|||
}
|
||||
|
||||
resWithNewName := []pkger.ResourceToClone{
|
||||
{
|
||||
Kind: pkger.KindNotificationRule,
|
||||
Name: "new rule name",
|
||||
ID: influxdb.ID(rule.ID),
|
||||
},
|
||||
{
|
||||
Kind: pkger.KindVariable,
|
||||
Name: "new name",
|
||||
|
@ -457,6 +462,13 @@ spec:
|
|||
assert.Equal(t, endpoints[0].NotificationEndpoint.GetDescription(), newEndpoints[0].NotificationEndpoint.GetDescription())
|
||||
hasLabelAssociations(t, newEndpoints[0].LabelAssociations, 1, "label_1")
|
||||
|
||||
require.Len(t, newSum.NotificationRules, 1)
|
||||
newRule := newSum.NotificationRules[0]
|
||||
assert.Equal(t, "new rule name", newRule.Name)
|
||||
assert.Zero(t, newRule.EndpointID)
|
||||
assert.Equal(t, rule.EndpointName, newRule.EndpointName)
|
||||
hasLabelAssociations(t, newRule.LabelAssociations, 1, "label_1")
|
||||
|
||||
require.Len(t, newSum.TelegrafConfigs, 1)
|
||||
assert.Equal(t, teles[0].TelegrafConfig.Name, newSum.TelegrafConfigs[0].TelegrafConfig.Name)
|
||||
assert.Equal(t, teles[0].TelegrafConfig.Description, newSum.TelegrafConfigs[0].TelegrafConfig.Description)
|
||||
|
@ -636,6 +648,16 @@ spec:
|
|||
level: INfO
|
||||
min: 30.0
|
||||
max: 45.0
|
||||
- type: outside_range
|
||||
level: WARN
|
||||
min: 60.0
|
||||
max: 70.0
|
||||
- type: greater
|
||||
level: CRIT
|
||||
val: 80
|
||||
- type: lesser
|
||||
level: OK
|
||||
val: 30
|
||||
associations:
|
||||
- kind: Label
|
||||
name: label_1
|
||||
|
|
|
@ -7156,6 +7156,7 @@ components:
|
|||
- dashboard
|
||||
- label
|
||||
- notification_endpoint
|
||||
- notification_rule
|
||||
- telegraf
|
||||
- variable
|
||||
name:
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/influxdata/influxdb/notification"
|
||||
icheck "github.com/influxdata/influxdb/notification/check"
|
||||
"github.com/influxdata/influxdb/notification/endpoint"
|
||||
"github.com/influxdata/influxdb/notification/rule"
|
||||
)
|
||||
|
||||
// ResourceToClone is a resource that will be cloned.
|
||||
|
@ -79,18 +80,14 @@ func checkToResource(ch influxdb.Check, name string) Resource {
|
|||
}
|
||||
assignNonZeroStrings(r, map[string]string{fieldDescription: ch.GetDescription()})
|
||||
|
||||
assignFluxDur := func(field string, dur *notification.Duration) {
|
||||
if dur == nil {
|
||||
return
|
||||
}
|
||||
r[field] = dur.TimeDuration().String()
|
||||
}
|
||||
|
||||
assignBase := func(base icheck.Base) {
|
||||
r[fieldQuery] = base.Query.Text
|
||||
r[fieldCheckStatusMessageTemplate] = base.StatusMessageTemplate
|
||||
assignFluxDur(fieldEvery, base.Every)
|
||||
assignFluxDur(fieldOffset, base.Offset)
|
||||
assignNonZeroFluxDurs(r, map[string]*notification.Duration{
|
||||
fieldEvery: base.Every,
|
||||
fieldOffset: base.Offset,
|
||||
})
|
||||
|
||||
var tags []Resource
|
||||
for _, t := range base.Tags {
|
||||
if t.Valid() != nil {
|
||||
|
@ -110,8 +107,10 @@ func checkToResource(ch influxdb.Check, name string) Resource {
|
|||
case *icheck.Deadman:
|
||||
r[fieldKind] = KindCheckDeadman.title()
|
||||
assignBase(cT.Base)
|
||||
assignFluxDur(fieldCheckTimeSince, cT.TimeSince)
|
||||
assignFluxDur(fieldCheckStaleTime, cT.StaleTime)
|
||||
assignNonZeroFluxDurs(r, map[string]*notification.Duration{
|
||||
fieldCheckTimeSince: cT.TimeSince,
|
||||
fieldCheckStaleTime: cT.StaleTime,
|
||||
})
|
||||
r[fieldLevel] = cT.Level.String()
|
||||
assignNonZeroBools(r, map[string]bool{fieldCheckReportZero: cT.ReportZero})
|
||||
case *icheck.Threshold:
|
||||
|
@ -129,15 +128,21 @@ func checkToResource(ch influxdb.Check, name string) Resource {
|
|||
func convertThreshold(th icheck.ThresholdConfig) Resource {
|
||||
r := Resource{fieldLevel: th.GetLevel().String()}
|
||||
|
||||
assignLesser := func(threshType thresholdType, allValues bool, val float64) {
|
||||
r[fieldType] = string(threshType)
|
||||
assignNonZeroBools(r, map[string]bool{fieldCheckAllValues: allValues})
|
||||
r[fieldValue] = val
|
||||
}
|
||||
|
||||
switch realType := th.(type) {
|
||||
case icheck.Lesser:
|
||||
r[fieldType] = string(thresholdTypeLesser)
|
||||
assignNonZeroBools(r, map[string]bool{fieldCheckAllValues: realType.AllValues})
|
||||
r[fieldValue] = realType.Value
|
||||
assignLesser(thresholdTypeLesser, realType.AllValues, realType.Value)
|
||||
case *icheck.Lesser:
|
||||
assignLesser(thresholdTypeLesser, realType.AllValues, realType.Value)
|
||||
case icheck.Greater:
|
||||
r[fieldType] = string(thresholdTypeGreater)
|
||||
assignNonZeroBools(r, map[string]bool{fieldCheckAllValues: realType.AllValues})
|
||||
r[fieldValue] = realType.Value
|
||||
assignLesser(thresholdTypeGreater, realType.AllValues, realType.Value)
|
||||
case *icheck.Greater:
|
||||
assignLesser(thresholdTypeGreater, realType.AllValues, realType.Value)
|
||||
case icheck.Range:
|
||||
assignRangeThreshold(r, realType)
|
||||
case *icheck.Range:
|
||||
|
@ -433,6 +438,67 @@ func endpointToResource(e influxdb.NotificationEndpoint, name string) Resource {
|
|||
return r
|
||||
}
|
||||
|
||||
func ruleToResource(iRule influxdb.NotificationRule, endpointName, name string) Resource {
|
||||
if name == "" {
|
||||
name = iRule.GetName()
|
||||
}
|
||||
r := Resource{
|
||||
fieldKind: KindNotificationRule.title(),
|
||||
fieldName: name,
|
||||
fieldNotificationRuleEndpointName: endpointName,
|
||||
}
|
||||
assignNonZeroStrings(r, map[string]string{
|
||||
fieldDescription: iRule.GetDescription(),
|
||||
})
|
||||
|
||||
assignBase := func(base rule.Base) {
|
||||
assignNonZeroFluxDurs(r, map[string]*notification.Duration{
|
||||
fieldEvery: base.Every,
|
||||
fieldOffset: base.Offset,
|
||||
})
|
||||
|
||||
var tagRes []Resource
|
||||
for _, tRule := range base.TagRules {
|
||||
tagRes = append(tagRes, Resource{
|
||||
fieldKey: tRule.Key,
|
||||
fieldValue: tRule.Value,
|
||||
fieldOperator: tRule.Operator.String(),
|
||||
})
|
||||
}
|
||||
if len(tagRes) > 0 {
|
||||
r[fieldNotificationRuleTagRules] = tagRes
|
||||
}
|
||||
|
||||
var statusRuleRes []Resource
|
||||
for _, sRule := range base.StatusRules {
|
||||
sRes := Resource{
|
||||
fieldNotificationRuleCurrentLevel: sRule.CurrentLevel.String(),
|
||||
}
|
||||
if sRule.PreviousLevel != nil {
|
||||
sRes[fieldNotificationRulePreviousLevel] = sRule.PreviousLevel.String()
|
||||
}
|
||||
statusRuleRes = append(statusRuleRes, sRes)
|
||||
}
|
||||
if len(statusRuleRes) > 0 {
|
||||
r[fieldNotificationRuleStatusRules] = statusRuleRes
|
||||
}
|
||||
}
|
||||
|
||||
switch t := iRule.(type) {
|
||||
case *rule.HTTP:
|
||||
assignBase(t.Base)
|
||||
case *rule.PagerDuty:
|
||||
assignBase(t.Base)
|
||||
r[fieldNotificationRuleMessageTemplate] = t.MessageTemplate
|
||||
case *rule.Slack:
|
||||
assignBase(t.Base)
|
||||
r[fieldNotificationRuleMessageTemplate] = t.MessageTemplate
|
||||
assignNonZeroStrings(r, map[string]string{fieldNotificationRuleChannel: t.Channel})
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func telegrafToResource(t influxdb.TelegrafConfig, name string) Resource {
|
||||
if name == "" {
|
||||
name = t.Name
|
||||
|
@ -487,6 +553,18 @@ func variableToResource(v influxdb.Variable, name string) Resource {
|
|||
return r
|
||||
}
|
||||
|
||||
func assignNonZeroFluxDurs(r Resource, m map[string]*notification.Duration) {
|
||||
for field, dur := range m {
|
||||
if dur == nil {
|
||||
continue
|
||||
}
|
||||
if dur.TimeDuration() == 0 {
|
||||
continue
|
||||
}
|
||||
r[field] = dur.TimeDuration().String()
|
||||
}
|
||||
}
|
||||
|
||||
func assignNonZeroBools(r Resource, m map[string]bool) {
|
||||
for k, v := range m {
|
||||
if v {
|
||||
|
|
|
@ -54,6 +54,19 @@ var kinds = map[Kind]bool{
|
|||
KindVariable: true,
|
||||
}
|
||||
|
||||
var kindsUniqByName = map[Kind]bool{
|
||||
KindBucket: true,
|
||||
KindCheck: true,
|
||||
KindCheckDeadman: true,
|
||||
KindCheckThreshold: true,
|
||||
KindLabel: true,
|
||||
KindNotificationEndpoint: true,
|
||||
KindNotificationEndpointHTTP: true,
|
||||
KindNotificationEndpointPagerDuty: true,
|
||||
KindNotificationEndpointSlack: true,
|
||||
KindVariable: true,
|
||||
}
|
||||
|
||||
// Kind is a resource kind.
|
||||
type Kind string
|
||||
|
||||
|
|
|
@ -1274,7 +1274,13 @@ func uniqResources(resources []Resource) []Resource {
|
|||
kind Kind
|
||||
name string
|
||||
}
|
||||
|
||||
// these 2 maps are used to eliminate duplicates that come
|
||||
// from dependencies while keeping the Resource that has any
|
||||
// associations. If there are no associations, then the resources
|
||||
// are no different from one another.
|
||||
m := make(map[key]bool)
|
||||
res := make(map[key]Resource)
|
||||
|
||||
out := make([]Resource, 0, len(resources))
|
||||
for _, r := range resources {
|
||||
|
@ -1285,18 +1291,22 @@ func uniqResources(resources []Resource) []Resource {
|
|||
if err := k.OK(); err != nil {
|
||||
continue
|
||||
}
|
||||
switch k {
|
||||
// these 3 kinds are unique, have existing state identifiable by name
|
||||
case KindBucket, KindLabel, KindVariable:
|
||||
|
||||
if kindsUniqByName[k] {
|
||||
rKey := key{kind: k, name: r.Name()}
|
||||
if m[rKey] {
|
||||
if hasAssociations, ok := m[rKey]; ok && hasAssociations {
|
||||
continue
|
||||
}
|
||||
m[rKey] = true
|
||||
fallthrough
|
||||
default:
|
||||
out = append(out, r)
|
||||
_, hasAssociations := r[fieldAssociations]
|
||||
m[rKey] = hasAssociations
|
||||
res[rKey] = r
|
||||
continue
|
||||
}
|
||||
out = append(out, r)
|
||||
}
|
||||
|
||||
for _, r := range res {
|
||||
out = append(out, r)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
|
|
@ -257,10 +257,17 @@ func (s *Service) CreatePkg(ctx context.Context, setters ...CreatePkgSetFn) (*Pk
|
|||
}
|
||||
|
||||
var kindPriorities = map[Kind]int{
|
||||
KindLabel: 1,
|
||||
KindBucket: 2,
|
||||
KindVariable: 3,
|
||||
KindDashboard: 4,
|
||||
KindLabel: 1,
|
||||
KindBucket: 2,
|
||||
KindCheckDeadman: 3,
|
||||
KindCheckThreshold: 4,
|
||||
KindNotificationEndpointHTTP: 5,
|
||||
KindNotificationEndpointPagerDuty: 6,
|
||||
KindNotificationEndpointSlack: 7,
|
||||
KindNotificationRule: 8,
|
||||
KindVariable: 9,
|
||||
KindTelegraf: 10,
|
||||
KindDashboard: 11,
|
||||
}
|
||||
|
||||
sort.Slice(pkg.Spec.Resources, func(i, j int) bool {
|
||||
|
@ -302,6 +309,10 @@ func (s *Service) cloneOrgResources(ctx context.Context, orgID influxdb.ID) ([]R
|
|||
resType: KindNotificationEndpoint.ResourceType(),
|
||||
cloneFn: s.cloneOrgNotificationEndpoints,
|
||||
},
|
||||
{
|
||||
resType: KindNotificationRule.ResourceType(),
|
||||
cloneFn: s.cloneOrgNotificationRules,
|
||||
},
|
||||
{
|
||||
resType: KindTelegraf.ResourceType(),
|
||||
cloneFn: s.cloneOrgTelegrafs,
|
||||
|
@ -417,6 +428,24 @@ func (s *Service) cloneOrgNotificationEndpoints(ctx context.Context, orgID influ
|
|||
return resources, nil
|
||||
}
|
||||
|
||||
func (s *Service) cloneOrgNotificationRules(ctx context.Context, orgID influxdb.ID) ([]ResourceToClone, error) {
|
||||
rules, _, err := s.ruleSVC.FindNotificationRules(ctx, influxdb.NotificationRuleFilter{
|
||||
OrgID: &orgID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resources := make([]ResourceToClone, 0, len(rules))
|
||||
for _, r := range rules {
|
||||
resources = append(resources, ResourceToClone{
|
||||
Kind: KindNotificationRule,
|
||||
ID: r.GetID(),
|
||||
})
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
func (s *Service) cloneOrgTelegrafs(ctx context.Context, orgID influxdb.ID) ([]ResourceToClone, error) {
|
||||
teles, _, err := s.teleSVC.FindTelegrafConfigs(ctx, influxdb.TelegrafConfigFilter{OrgID: &orgID})
|
||||
if err != nil {
|
||||
|
@ -458,7 +487,11 @@ func (s *Service) resourceCloneToResource(ctx context.Context, r ResourceToClone
|
|||
e = ierrors.Wrap(e, "cloning resource")
|
||||
}
|
||||
}()
|
||||
var newResource Resource
|
||||
|
||||
var (
|
||||
newResource Resource
|
||||
sidecarResources []Resource
|
||||
)
|
||||
switch {
|
||||
case r.Kind.is(KindBucket):
|
||||
bkt, err := s.bucketSVC.FindBucketByID(ctx, r.ID)
|
||||
|
@ -495,6 +528,12 @@ func (s *Service) resourceCloneToResource(ctx context.Context, r ResourceToClone
|
|||
return nil, err
|
||||
}
|
||||
newResource = endpointToResource(e, r.Name)
|
||||
case r.Kind.is(KindNotificationRule):
|
||||
ruleRes, endpointRes, err := s.exportNotificationRule(ctx, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newResource, sidecarResources = ruleRes, append(sidecarResources, endpointRes)
|
||||
case r.Kind.is(KindTelegraf):
|
||||
t, err := s.teleSVC.FindTelegrafConfigByID(ctx, r.ID)
|
||||
if err != nil {
|
||||
|
@ -519,7 +558,21 @@ func (s *Service) resourceCloneToResource(ctx context.Context, r ResourceToClone
|
|||
newResource[fieldAssociations] = ass.associations
|
||||
}
|
||||
|
||||
return append([]Resource{newResource}, ass.newLableResources...), nil
|
||||
return append(ass.newLableResources, append(sidecarResources, newResource)...), nil
|
||||
}
|
||||
|
||||
func (s *Service) exportNotificationRule(ctx context.Context, r ResourceToClone) (Resource, Resource, error) {
|
||||
rule, err := s.ruleSVC.FindNotificationRuleByID(ctx, r.ID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ruleEndpoint, err := s.endpointSVC.FindNotificationEndpointByID(ctx, rule.GetEndpointID())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return ruleToResource(rule, ruleEndpoint.GetName(), r.Name), endpointToResource(ruleEndpoint, ""), nil
|
||||
}
|
||||
|
||||
type (
|
||||
|
@ -1043,10 +1096,8 @@ func (s *Service) Apply(ctx context.Context, orgID, userID influxdb.ID, pkg *Pkg
|
|||
}
|
||||
}
|
||||
|
||||
// this is required after first primary run and before secondary run, b/c this has dependencies
|
||||
// on the notification endpoints being live in the source of truth (store). Hence we break
|
||||
// it up after the 1st group and before the 2nd. The 2nd group needs these done first so the
|
||||
// label mappings are accurate.
|
||||
// this has to be run after the above primary resources, because it relies on
|
||||
// notification endpoints already being applied.
|
||||
app, err := s.applyNotificationRulesGenerator(ctx, orgID, pkg.notificationRules())
|
||||
if err != nil {
|
||||
return Summary{}, err
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/influxdata/influxdb/notification"
|
||||
icheck "github.com/influxdata/influxdb/notification/check"
|
||||
"github.com/influxdata/influxdb/notification/endpoint"
|
||||
"github.com/influxdata/influxdb/notification/rule"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap/zaptest"
|
||||
|
@ -1966,6 +1967,171 @@ func TestService(t *testing.T) {
|
|||
}
|
||||
})
|
||||
|
||||
t.Run("notification rules", func(t *testing.T) {
|
||||
newRuleBase := func(id int) rule.Base {
|
||||
return rule.Base{
|
||||
ID: 9000,
|
||||
Name: "old_name",
|
||||
Description: "desc",
|
||||
EndpointID: influxdb.ID(id),
|
||||
Every: mustDuration(t, time.Hour),
|
||||
Offset: mustDuration(t, time.Minute),
|
||||
TagRules: []notification.TagRule{
|
||||
{Tag: influxdb.Tag{Key: "k1", Value: "v1"}},
|
||||
},
|
||||
StatusRules: []notification.StatusRule{
|
||||
{CurrentLevel: notification.Ok, PreviousLevel: levelPtr(notification.Warn)},
|
||||
{CurrentLevel: notification.Critical},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
newName string
|
||||
endpoint influxdb.NotificationEndpoint
|
||||
rule influxdb.NotificationRule
|
||||
}{
|
||||
{
|
||||
name: "pager duty",
|
||||
newName: "pager_duty_name",
|
||||
endpoint: &endpoint.PagerDuty{
|
||||
Base: endpoint.Base{
|
||||
ID: newTestIDPtr(13),
|
||||
Name: "endpoint_0",
|
||||
Description: "desc",
|
||||
Status: influxdb.TaskStatusActive,
|
||||
},
|
||||
ClientURL: "http://example.com",
|
||||
RoutingKey: influxdb.SecretField{Key: "-routing-key"},
|
||||
},
|
||||
rule: &rule.PagerDuty{
|
||||
Base: newRuleBase(13),
|
||||
MessageTemplate: "Template",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "slack",
|
||||
endpoint: &endpoint.Slack{
|
||||
Base: endpoint.Base{
|
||||
ID: newTestIDPtr(13),
|
||||
Name: "endpoint_0",
|
||||
Description: "desc",
|
||||
Status: influxdb.TaskStatusInactive,
|
||||
},
|
||||
URL: "http://example.com",
|
||||
Token: influxdb.SecretField{Key: "tokne"},
|
||||
},
|
||||
rule: &rule.Slack{
|
||||
Base: newRuleBase(13),
|
||||
Channel: "abc",
|
||||
MessageTemplate: "SLACK TEMPlate",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "http none",
|
||||
endpoint: &endpoint.HTTP{
|
||||
Base: endpoint.Base{
|
||||
ID: newTestIDPtr(13),
|
||||
Name: "endpoint_0",
|
||||
Description: "desc",
|
||||
Status: influxdb.TaskStatusInactive,
|
||||
},
|
||||
AuthMethod: "none",
|
||||
Method: "GET",
|
||||
URL: "http://example.com",
|
||||
},
|
||||
rule: &rule.HTTP{
|
||||
Base: newRuleBase(13),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
fn := func(t *testing.T) {
|
||||
endpointSVC := mock.NewNotificationEndpointService()
|
||||
endpointSVC.FindNotificationEndpointByIDF = func(ctx context.Context, id influxdb.ID) (influxdb.NotificationEndpoint, error) {
|
||||
if id != tt.endpoint.GetID() {
|
||||
return nil, errors.New("uh ohhh, wrong id here: " + id.String())
|
||||
}
|
||||
return tt.endpoint, nil
|
||||
}
|
||||
ruleSVC := mock.NewNotificationRuleStore()
|
||||
ruleSVC.FindNotificationRuleByIDF = func(ctx context.Context, id influxdb.ID) (influxdb.NotificationRule, error) {
|
||||
return tt.rule, nil
|
||||
}
|
||||
|
||||
svc := newTestService(
|
||||
WithNotificationEndpointSVC(endpointSVC),
|
||||
WithNotificationRuleSVC(ruleSVC),
|
||||
)
|
||||
|
||||
resToClone := ResourceToClone{
|
||||
Kind: KindNotificationRule,
|
||||
ID: tt.rule.GetID(),
|
||||
Name: tt.newName,
|
||||
}
|
||||
pkg, err := svc.CreatePkg(context.TODO(), CreateWithExistingResources(resToClone))
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, pkg.Summary().NotificationRules, 1)
|
||||
|
||||
actualRule := pkg.Summary().NotificationRules[0]
|
||||
assert.Zero(t, actualRule.ID)
|
||||
assert.Zero(t, actualRule.EndpointID)
|
||||
assert.Zero(t, actualRule.EndpointType)
|
||||
assert.Equal(t, "endpoint_0", actualRule.EndpointName)
|
||||
|
||||
baseEqual := func(t *testing.T, base rule.Base) {
|
||||
t.Helper()
|
||||
expectedName := base.Name
|
||||
if tt.newName != "" {
|
||||
expectedName = tt.newName
|
||||
}
|
||||
assert.Equal(t, expectedName, actualRule.Name)
|
||||
assert.Equal(t, base.Description, actualRule.Description)
|
||||
assert.Equal(t, base.Every.TimeDuration().String(), actualRule.Every)
|
||||
assert.Equal(t, base.Offset.TimeDuration().String(), actualRule.Offset)
|
||||
|
||||
for _, sRule := range base.StatusRules {
|
||||
expected := SummaryStatusRule{CurrentLevel: sRule.CurrentLevel.String()}
|
||||
if sRule.PreviousLevel != nil {
|
||||
expected.PreviousLevel = sRule.PreviousLevel.String()
|
||||
}
|
||||
assert.Contains(t, actualRule.StatusRules, expected)
|
||||
}
|
||||
for _, tRule := range base.TagRules {
|
||||
expected := SummaryTagRule{
|
||||
Key: tRule.Key,
|
||||
Value: tRule.Value,
|
||||
Operator: tRule.Operator.String(),
|
||||
}
|
||||
assert.Contains(t, actualRule.TagRules, expected)
|
||||
}
|
||||
}
|
||||
|
||||
switch p := tt.rule.(type) {
|
||||
case *rule.HTTP:
|
||||
baseEqual(t, p.Base)
|
||||
case *rule.PagerDuty:
|
||||
baseEqual(t, p.Base)
|
||||
assert.Equal(t, p.MessageTemplate, actualRule.MessageTemplate)
|
||||
case *rule.Slack:
|
||||
baseEqual(t, p.Base)
|
||||
assert.Equal(t, p.MessageTemplate, actualRule.MessageTemplate)
|
||||
}
|
||||
|
||||
require.Len(t, pkg.Summary().NotificationEndpoints, 1)
|
||||
|
||||
actualEndpoint := pkg.Summary().NotificationEndpoints[0].NotificationEndpoint
|
||||
assert.Equal(t, tt.endpoint.GetName(), actualEndpoint.GetName())
|
||||
assert.Equal(t, tt.endpoint.GetDescription(), actualEndpoint.GetDescription())
|
||||
assert.Equal(t, tt.endpoint.GetStatus(), actualEndpoint.GetStatus())
|
||||
}
|
||||
t.Run(tt.name, fn)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("variable", func(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
|
@ -2242,7 +2408,17 @@ func TestService(t *testing.T) {
|
|||
endpointSVC.FindNotificationEndpointsF = func(ctx context.Context, f influxdb.NotificationEndpointFilter, _ ...influxdb.FindOptions) ([]influxdb.NotificationEndpoint, int, error) {
|
||||
id := influxdb.ID(2)
|
||||
endpoints := []influxdb.NotificationEndpoint{
|
||||
&endpoint.HTTP{Base: endpoint.Base{ID: &id}},
|
||||
&endpoint.HTTP{
|
||||
Base: endpoint.Base{
|
||||
ID: &id,
|
||||
Name: "http",
|
||||
},
|
||||
URL: "http://example.com",
|
||||
Username: influxdb.SecretField{Key: id.String() + "-username"},
|
||||
Password: influxdb.SecretField{Key: id.String() + "-password"},
|
||||
AuthMethod: "basic",
|
||||
Method: "POST",
|
||||
},
|
||||
}
|
||||
return endpoints, len(endpoints), nil
|
||||
}
|
||||
|
@ -2260,6 +2436,23 @@ func TestService(t *testing.T) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
ruleSVC := mock.NewNotificationRuleStore()
|
||||
ruleSVC.FindNotificationRulesF = func(ctx context.Context, f influxdb.NotificationRuleFilter, _ ...influxdb.FindOptions) ([]influxdb.NotificationRule, int, error) {
|
||||
out := []influxdb.NotificationRule{&rule.HTTP{Base: rule.Base{ID: 91}}}
|
||||
return out, len(out), nil
|
||||
}
|
||||
ruleSVC.FindNotificationRuleByIDF = func(ctx context.Context, id influxdb.ID) (influxdb.NotificationRule, error) {
|
||||
return &rule.HTTP{
|
||||
Base: rule.Base{
|
||||
ID: id,
|
||||
Name: "rule_0",
|
||||
EndpointID: 2,
|
||||
Every: mustDuration(t, time.Minute),
|
||||
StatusRules: []notification.StatusRule{{CurrentLevel: notification.Critical}},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
labelSVC := mock.NewLabelService()
|
||||
labelSVC.FindLabelsFn = func(_ context.Context, f influxdb.LabelFilter) ([]*influxdb.Label, error) {
|
||||
if f.OrgID == nil || *f.OrgID != orgID {
|
||||
|
@ -2294,6 +2487,7 @@ func TestService(t *testing.T) {
|
|||
WithDashboardSVC(dashSVC),
|
||||
WithLabelSVC(labelSVC),
|
||||
WithNotificationEndpointSVC(endpointSVC),
|
||||
WithNotificationRuleSVC(ruleSVC),
|
||||
WithVariableSVC(varSVC),
|
||||
)
|
||||
|
||||
|
@ -2321,9 +2515,23 @@ func TestService(t *testing.T) {
|
|||
require.Len(t, endpoints, 1)
|
||||
assert.Equal(t, "http", endpoints[0].NotificationEndpoint.GetName())
|
||||
|
||||
rules := summary.NotificationRules
|
||||
require.Len(t, rules, 1)
|
||||
assert.Equal(t, "rule_0", rules[0].Name)
|
||||
assert.Equal(t, "http", rules[0].EndpointName)
|
||||
|
||||
vars := summary.Variables
|
||||
require.Len(t, vars, 1)
|
||||
assert.Equal(t, "variable", vars[0].Name)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func newTestIDPtr(i int) *influxdb.ID {
|
||||
id := influxdb.ID(i)
|
||||
return &id
|
||||
}
|
||||
|
||||
func levelPtr(l notification.CheckLevel) *notification.CheckLevel {
|
||||
return &l
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue