feat(notification_rule): create notification rule task

feat(notification_rule): generate base flux for notification rule

wip: saving state

fix(notification/endpoint): add comment about weird requirements

feat(notification_rule): create notification rule task
pull/14695/head
Michael Desa 2019-08-16 15:43:15 -04:00
parent 1f499d599a
commit 8e56c36737
No known key found for this signature in database
GPG Key ID: 87002651EC5DFFE6
22 changed files with 918 additions and 228 deletions

View File

@ -304,13 +304,13 @@ func TestService_handleGetChecks(t *testing.T) {
}
}
func mustDuration(d string) *check.Duration {
func mustDuration(d string) *notification.Duration {
dur, err := parser.ParseDuration(d)
if err != nil {
panic(err)
}
return (*check.Duration)(dur)
return (*notification.Duration)(dur)
}
func TestService_handleGetCheck(t *testing.T) {

View File

@ -161,6 +161,7 @@ type notificationRulesResponse struct {
}
func newNotificationRuleResponse(nr influxdb.NotificationRule, labels []*influxdb.Label) *notificationRuleResponse {
nr.ClearPrivateData()
res := &notificationRuleResponse{
NotificationRule: nr,
Links: notificationRuleLinks{

View File

@ -43,12 +43,12 @@ func Test_newNotificationRuleResponses(t *testing.T) {
ID: influxdb.ID(1),
OrgID: influxdb.ID(2),
OwnerID: influxdb.ID(3),
EndpointID: influxTesting.IDPtr(influxdb.ID(4)),
EndpointID: 4,
Name: "name1",
Description: "desc1",
Status: influxdb.Active,
Every: influxdb.Duration{Duration: time.Minute * 5},
Offset: influxdb.Duration{Duration: time.Second * 15},
Every: mustDuration("5m"),
Offset: mustDuration("15s"),
TagRules: []notification.TagRule{
{
Tag: notification.Tag{Key: "k1", Value: "v1"},
@ -79,7 +79,7 @@ func Test_newNotificationRuleResponses(t *testing.T) {
ID: influxdb.ID(11),
OrgID: influxdb.ID(2),
OwnerID: influxdb.ID(33),
EndpointID: influxTesting.IDPtr(influxdb.ID(44)),
EndpointID: 44,
Name: "name2",
Description: "desc2",
Status: influxdb.Inactive,
@ -98,7 +98,7 @@ func Test_newNotificationRuleResponses(t *testing.T) {
"createdAt": "0001-01-01T00:00:00Z",
"description": "desc1",
"endpointID": "0000000000000004",
"every": "5m0s",
"every": "5m",
"id": "0000000000000001",
"messageTemplate": "message 1{var1}",
"name": "name1",
@ -154,10 +154,8 @@ func Test_newNotificationRuleResponses(t *testing.T) {
"createdAt": "0001-01-01T00:00:00Z",
"description": "desc2",
"endpointID": "000000000000002c",
"every": "0s",
"id": "000000000000000b",
"name": "name2",
"offset": "0s",
"orgID": "0000000000000002",
"runbookLink": "",
"status": "inactive",
@ -208,12 +206,12 @@ func Test_newNotificationRuleResponse(t *testing.T) {
ID: influxdb.ID(1),
OrgID: influxdb.ID(2),
OwnerID: influxdb.ID(3),
EndpointID: influxTesting.IDPtr(influxdb.ID(4)),
EndpointID: 4,
Name: "name1",
Description: "desc1",
Status: influxdb.Active,
Every: influxdb.Duration{Duration: time.Minute * 5},
Offset: influxdb.Duration{Duration: time.Second * 15},
Every: mustDuration("5m"),
Offset: mustDuration("15s"),
TagRules: []notification.TagRule{
{
Tag: notification.Tag{Key: "k1", Value: "v1"},
@ -248,7 +246,7 @@ func Test_newNotificationRuleResponse(t *testing.T) {
"endpointID": "0000000000000004",
"name": "name1",
"description": "desc1",
"every": "5m0s",
"every": "5m",
"offset": "15s",
"type": "slack",
"runbookLink": "",

View File

@ -9030,6 +9030,7 @@ components:
- $ref: "#/components/schemas/SlackNotificationRule"
- $ref: "#/components/schemas/SMTPNotificationRule"
- $ref: "#/components/schemas/PagerDutyNotificationRule"
- $ref: "#/components/schemas/HTTPNotificationRule"
NotificationRules:
properties:
notificationRules:
@ -9138,10 +9139,19 @@ components:
operation:
type: string
enum: ["equal", "notequal"]
SlackNotificationRule:
HTTPNotificationRuleBase:
type: object
required: [type, url]
properties:
type:
type: string
enum: [http]
url:
type: string
HTTPNotificationRule:
allOf:
- $ref: "#/components/schemas/NotificationRuleBase"
- $ref: "#/components/schemas/SlackNotificationRuleBase"
- $ref: "#/components/schemas/HTTPNotificationRuleBase"
SlackNotificationRuleBase:
type: object
required: [type, messageTemplate]
@ -9153,6 +9163,10 @@ components:
type: string
messageTemplate:
type: string
SlackNotificationRule:
allOf:
- $ref: "#/components/schemas/NotificationRuleBase"
- $ref: "#/components/schemas/SlackNotificationRuleBase"
SMTPNotificationRule:
allOf:
- $ref: "#/components/schemas/NotificationRuleBase"

View File

@ -78,6 +78,14 @@ func (s *Service) createNotificationRule(ctx context.Context, tx Tx, nr influxdb
nr.SetOwnerID(userID)
nr.SetCreatedAt(now)
nr.SetUpdatedAt(now)
t, err := s.createNotificationTask(ctx, tx, nr)
if err != nil {
return err
}
nr.SetTaskID(t.ID)
if err := s.putNotificationRule(ctx, tx, nr); err != nil {
return err
}
@ -91,6 +99,34 @@ func (s *Service) createNotificationRule(ctx context.Context, tx Tx, nr influxdb
return s.createUserResourceMapping(ctx, tx, urm)
}
func (s *Service) createNotificationTask(ctx context.Context, tx Tx, r influxdb.NotificationRule) (*influxdb.Task, error) {
// TODO(desa): figure out what to do about this
//ep, _, _, err := s.findNotificationEndpointByID(ctx, tx, r.GetEndpointID())
//if err != nil {
// return nil, err
//}
// TODO(desa): pass in non nil notification endpoint.
script, err := r.GenerateFlux(nil)
if err != nil {
return nil, err
}
tc := influxdb.TaskCreate{
Type: r.Type(),
Flux: script,
OwnerID: r.GetOwnerID(),
OrganizationID: r.GetOrgID(),
}
t, err := s.createTask(ctx, tx, tc)
if err != nil {
return nil, err
}
return t, nil
}
// UpdateNotificationRule updates a single notification rule.
// Returns the new notification rule after update.
func (s *Service) UpdateNotificationRule(ctx context.Context, id influxdb.ID, nr influxdb.NotificationRule, userID influxdb.ID) (influxdb.NotificationRule, error) {
@ -103,6 +139,7 @@ func (s *Service) UpdateNotificationRule(ctx context.Context, id influxdb.ID, nr
}
func (s *Service) updateNotificationRule(ctx context.Context, tx Tx, id influxdb.ID, nr influxdb.NotificationRule, userID influxdb.ID) (influxdb.NotificationRule, error) {
current, err := s.findNotificationRuleByID(ctx, tx, id)
if err != nil {
return nil, err
@ -114,8 +151,24 @@ func (s *Service) updateNotificationRule(ctx context.Context, tx Tx, id influxdb
nr.SetOwnerID(current.GetOwnerID())
nr.SetCreatedAt(current.GetCRUDLog().CreatedAt)
nr.SetUpdatedAt(s.TimeGenerator.Now())
err = s.putNotificationRule(ctx, tx, nr)
return nr, err
nr.SetTaskID(current.GetTaskID())
if err := s.deleteTask(ctx, tx, nr.GetTaskID()); err != nil {
return nil, err
}
t, err := s.createNotificationTask(ctx, tx, nr)
if err != nil {
return nil, err
}
nr.SetTaskID(t.ID)
if err := s.putNotificationRule(ctx, tx, nr); err != nil {
return nil, err
}
return nr, nil
}
// PatchNotificationRule updates a single notification rule with changeset.
@ -353,6 +406,16 @@ func (s *Service) DeleteNotificationRule(ctx context.Context, id influxdb.ID) er
}
func (s *Service) deleteNotificationRule(ctx context.Context, tx Tx, id influxdb.ID) error {
r, err := s.findNotificationRuleByID(ctx, tx, id)
if err != nil {
return err
}
fmt.Println(r.GetTaskID())
if err := s.deleteTask(ctx, tx, r.GetTaskID()); err != nil {
return err
}
encodedID, err := id.Encode()
if err != nil {
return ErrInvalidNotificationRuleID

View File

@ -74,6 +74,12 @@ func initNotificationRuleStore(s kv.Store, f influxdbtesting.NotificationRuleFie
}
}
for _, c := range f.Tasks {
if _, err := svc.CreateTask(ctx, c); err != nil {
t.Fatalf("failed to populate task: %v", err)
}
}
return svc, func() {
for _, nr := range f.NotificationRules {
if err := svc.DeleteNotificationRule(ctx, nr.GetID()); err != nil {

View File

@ -37,8 +37,13 @@ type NotificationRule interface {
Updater
Getter
SetOwnerID(id ID)
ClearPrivateData()
GetOwnerID() ID
SetTaskID(id ID)
GetTaskID() ID
GetEndpointID() ID
GetLimit() *Limit
GenerateFlux(NotificationEndpoint) (string, error)
}
// Limit don't notify me more than <limit> times every <limitEvery> seconds.

View File

@ -1,13 +1,9 @@
package check
import (
"bytes"
"encoding/json"
"fmt"
"strconv"
"github.com/influxdata/flux/ast"
"github.com/influxdata/flux/parser"
"github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/notification"
)
@ -26,44 +22,16 @@ type Base struct {
// Care should be taken to prevent TaskID from being exposed publicly.
TaskID influxdb.ID `json:"taskID,omitempty"`
Cron string `json:"cron,omitempty"`
Every *Duration `json:"every,omitempty"`
Cron string `json:"cron,omitempty"`
Every *notification.Duration `json:"every,omitempty"`
// Offset represents a delay before execution.
// It gets marshalled from a string duration, i.e.: "10s" is 10 seconds
Offset *Duration `json:"offset,omitempty"`
Offset *notification.Duration `json:"offset,omitempty"`
Tags []notification.Tag `json:"tags"`
influxdb.CRUDLog
}
// Duration is a custom type used for generating flux compatible durations.
type Duration ast.DurationLiteral
// MarshalJSON turns a Duration into a JSON-ified string.
func (d Duration) MarshalJSON() ([]byte, error) {
var b bytes.Buffer
b.WriteByte('"')
for _, d := range d.Values {
b.WriteString(strconv.Itoa(int(d.Magnitude)))
b.WriteString(d.Unit)
}
b.WriteByte('"')
return b.Bytes(), nil
}
// UnmarshalJSON turns a flux duration literal into a Duration.
func (d *Duration) UnmarshalJSON(b []byte) error {
dur, err := parser.ParseDuration(string(b[1 : len(b)-1]))
if err != nil {
return err
}
*d = *(*Duration)(dur)
return nil
}
// Valid returns err if the check is invalid.
func (b Base) Valid() error {
if !b.ID.Valid() {

View File

@ -145,13 +145,13 @@ func TestValidCheck(t *testing.T) {
var timeGen1 = mock.TimeGenerator{FakeValue: time.Date(2006, time.July, 13, 4, 19, 10, 0, time.UTC)}
var timeGen2 = mock.TimeGenerator{FakeValue: time.Date(2006, time.July, 14, 5, 23, 53, 10, time.UTC)}
func mustDuration(d string) *check.Duration {
func mustDuration(d string) *notification.Duration {
dur, err := parser.ParseDuration(d)
if err != nil {
panic(err)
}
return (*check.Duration)(dur)
return (*notification.Duration)(dur)
}
func TestJSON(t *testing.T) {
@ -231,7 +231,7 @@ func TestJSON(t *testing.T) {
if err != nil {
t.Fatalf("%s unmarshal failed, err: %s", c.name, err.Error())
}
if diff := cmp.Diff(got, c.src, cmpopts.IgnoreFields(check.Duration{}, "BaseNode")); diff != "" {
if diff := cmp.Diff(got, c.src, cmpopts.IgnoreFields(notification.Duration{}, "BaseNode")); diff != "" {
t.Errorf("failed %s, Check are different -got/+want\ndiff %s", c.name, diff)
}
}

37
notification/duration.go Normal file
View File

@ -0,0 +1,37 @@
package notification
import (
"bytes"
"strconv"
"github.com/influxdata/flux/ast"
"github.com/influxdata/flux/parser"
)
// Duration is a custom type used for generating flux compatible durations.
type Duration ast.DurationLiteral
// MarshalJSON turns a Duration into a JSON-ified string.
func (d Duration) MarshalJSON() ([]byte, error) {
var b bytes.Buffer
b.WriteByte('"')
for _, d := range d.Values {
b.WriteString(strconv.Itoa(int(d.Magnitude)))
b.WriteString(d.Unit)
}
b.WriteByte('"')
return b.Bytes(), nil
}
// UnmarshalJSON turns a flux duration literal into a Duration.
func (d *Duration) UnmarshalJSON(b []byte) error {
dur, err := parser.ParseDuration(string(b[1 : len(b)-1]))
if err != nil {
return err
}
*d = *(*Duration)(dur)
return nil
}

View File

@ -55,6 +55,7 @@ func (s Slack) Valid() error {
Msg: fmt.Sprintf("slack endpoint URL is invalid: %s", err.Error()),
}
}
// TODO(desa): this requirement seems odd
if s.Token.Key != s.ID.String()+slackTokenSuffix {
return &influxdb.Error{
Code: influxdb.EInvalid,

View File

@ -29,6 +29,15 @@ func LessThan(lhs, rhs ast.Expression) *ast.BinaryExpression {
}
}
// Equal returns an equal to *ast.BinaryExpression.
func Equal(lhs, rhs ast.Expression) *ast.BinaryExpression {
return &ast.BinaryExpression{
Operator: ast.EqualOperator,
Left: lhs,
Right: rhs,
}
}
// Member returns an *ast.MemberExpression where the key is p and the values is c.
func Member(p, c string) *ast.MemberExpression {
return &ast.MemberExpression{

154
notification/rule/http.go Normal file
View File

@ -0,0 +1,154 @@
package rule
import (
"encoding/json"
"fmt"
"github.com/influxdata/flux/ast"
"github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/notification"
"github.com/influxdata/influxdb/notification/flux"
)
// HTTP is the notification rule config of http.
type HTTP struct {
Base
URL string
}
// GenerateFlux generates a flux script for the http notification rule.
func (s *HTTP) GenerateFlux(e influxdb.NotificationEndpoint) (string, error) {
// TODO(desa): still needs full implementation
return s.GenerateFluxReal(e)
}
// GenerateFluxReal generates a flux script for the http notification rule.
func (s *HTTP) GenerateFluxReal(e influxdb.NotificationEndpoint) (string, error) {
p, err := s.GenerateFluxAST()
if err != nil {
return "", err
}
return ast.Format(p), nil
}
// GenerateFluxAST generates a flux AST for the http notification rule.
func (s *HTTP) GenerateFluxAST() (*ast.Package, error) {
f := flux.File(
s.Name,
flux.Imports("influxdata/influxdb/alerts", "http"),
s.generateFluxASTBody(),
)
return &ast.Package{Package: "main", Files: []*ast.File{f}}, nil
}
func (s *HTTP) generateFluxASTBody() []ast.Statement {
var statements []ast.Statement
statements = append(statements, s.generateTaskOption())
statements = append(statements, s.generateFluxASTEndpoint())
statements = append(statements, s.generateFluxASTNotificationDefinition())
statements = append(statements, s.generateFluxASTStatusPipe())
statements = append(statements, s.generateFluxASTNotifyPipe())
return statements
}
func (s *HTTP) generateTaskOption() ast.Statement {
props := []*ast.Property{}
props = append(props, flux.Property("name", flux.String(s.Name)))
if s.Cron != "" {
props = append(props, flux.Property("cron", flux.String(s.Cron)))
}
if s.Every != nil {
props = append(props, flux.Property("every", (*ast.DurationLiteral)(s.Every)))
}
if s.Offset != nil {
props = append(props, flux.Property("offset", (*ast.DurationLiteral)(s.Offset)))
}
return flux.DefineTaskOption(flux.Object(props...))
}
func (s *HTTP) generateFluxASTNotificationDefinition() ast.Statement {
// TODO(desa): what else needs to be here?
id := flux.Property("notificationID", flux.String(s.ID.String()))
name := flux.Property("name", flux.String(s.Name))
return flux.DefineVariable("notification", flux.Object(id, name))
}
func (s *HTTP) generateFluxASTEndpoint() ast.Statement {
// TODO(desa): where does <some key> come from
call := flux.Call(flux.Member("http", "endpoint"), flux.Object(flux.Property("url", flux.String(s.URL))))
return flux.DefineVariable("http_endpoint", call)
}
func (s *HTTP) generateFluxASTStatusPipe() ast.Statement {
base := flux.Call(flux.Identifier("from"), flux.Object(flux.Property("bucket", flux.String("system_bucket"))))
calls := []*ast.CallExpression{}
// TODO(desa): make start negative of every
calls = append(calls, flux.Call(flux.Identifier("range"), flux.Object(flux.Property("start", (*ast.DurationLiteral)(s.Every)))))
for _, r := range s.TagRules {
switch r.Operator {
case notification.Equal:
fn := flux.Function(flux.FunctionParams("r"), flux.Equal(flux.Member("r", r.Key), flux.String(r.Value)))
calls = append(calls, flux.Call(flux.Identifier("filter"), flux.Object(flux.Property("fn", fn))))
default:
// TODO(desa): have this work for all operator types
panic(fmt.Sprintf("operator %v not currently supported", r.Operator))
}
}
return flux.DefineVariable("statuses", flux.Pipe(base, calls...))
}
func (s *HTTP) generateFluxASTNotifyPipe() ast.Statement {
endpointProps := []*ast.Property{}
endpointBody := flux.Call(flux.Member("json", "encode"), flux.Object(flux.Property("v", flux.Identifier("r"))))
endpointProps = append(endpointProps, flux.Property("data", endpointBody))
endpointFn := flux.Function(flux.FunctionParams("r"), flux.Object(endpointProps...))
props := []*ast.Property{}
props = append(props, flux.Property("name", flux.String(s.Name)))
props = append(props, flux.Property("notification", flux.Identifier("notification")))
props = append(props, flux.Property("endpoint",
flux.Call(flux.Identifier("http_endpoint"), flux.Object(flux.Property("mapFn", endpointFn)))))
call := flux.Call(flux.Member("alerts", "notify"), flux.Object(props...))
return flux.ExpressionStatement(flux.Pipe(flux.Identifier("statuses"), call))
}
type httpAlias HTTP
// MarshalJSON implement json.Marshaler interface.
func (c HTTP) MarshalJSON() ([]byte, error) {
return json.Marshal(
struct {
httpAlias
Type string `json:"type"`
}{
httpAlias: httpAlias(c),
Type: c.Type(),
})
}
// Valid returns where the config is valid.
func (c HTTP) Valid() error {
if err := c.Base.valid(); err != nil {
return err
}
return nil
}
// Type returns the type of the rule config.
func (c HTTP) Type() string {
return "http"
}

View File

@ -0,0 +1,64 @@
package rule_test
import (
"testing"
"github.com/influxdata/influxdb/notification"
"github.com/influxdata/influxdb/notification/rule"
)
func TestHTTP_GenerateFlux(t *testing.T) {
want := `package main
// foo
import "influxdata/influxdb/alerts"
import "http"
option task = {name: "foo", every: 1h}
http_endpoint = http.endpoint(url: "http://localhost:7777")
notification = {notificationID: "0000000000000001", name: "foo"}
statuses = from(bucket: "system_bucket")
|> range(start: 1h)
|> filter(fn: (r) =>
(r.foo == "bar"))
|> filter(fn: (r) =>
(r.baz == "bang"))
statuses
|> alerts.notify(name: "foo", notification: notification, endpoint: http_endpoint(mapFn: (r) =>
({data: json.encode(v: r)})))`
s := &rule.HTTP{
URL: "http://localhost:7777",
Base: rule.Base{
ID: 1,
Name: "foo",
Every: mustDuration("1h"),
TagRules: []notification.TagRule{
{
Tag: notification.Tag{
Key: "foo",
Value: "bar",
},
Operator: notification.Equal,
},
{
Tag: notification.Tag{
Key: "baz",
Value: "bang",
},
Operator: notification.Equal,
},
},
},
}
f, err := s.GenerateFluxReal(nil)
if err != nil {
panic(err)
}
if f != want {
t.Errorf("scripts did not match. want:\n%v\n\ngot:\n%v", want, f)
}
}

View File

@ -12,6 +12,16 @@ type PagerDuty struct {
MessageTemp string `json:"messageTemplate"`
}
// GenerateFlux Generates the flux pager duty notification.
func (d *PagerDuty) GenerateFlux(e influxdb.NotificationEndpoint) (string, error) {
// TODO(desa): needs implementation
return `package main
data = from(bucket: "telegraf")
|> range(start: -1m)
option task = {name: "name1", every: 1m}`, nil
}
type pagerDutyAlias PagerDuty
// MarshalJSON implement json.Marshaler interface.

View File

@ -12,6 +12,7 @@ import (
var typeToRule = map[string](func() influxdb.NotificationRule){
"slack": func() influxdb.NotificationRule { return &Slack{} },
"pagerduty": func() influxdb.NotificationRule { return &PagerDuty{} },
"http": func() influxdb.NotificationRule { return &HTTP{} },
}
type rawRuleJSON struct {
@ -42,17 +43,18 @@ type Base struct {
ID influxdb.ID `json:"id,omitempty"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
EndpointID *influxdb.ID `json:"endpointID,omitempty"`
EndpointID influxdb.ID `json:"endpointID,omitempty"`
OrgID influxdb.ID `json:"orgID,omitempty"`
OwnerID influxdb.ID `json:"ownerID,omitempty"`
TaskID influxdb.ID `json:"taskID,omitempty"`
Status influxdb.Status `json:"status"`
// SleepUntil is an optional sleeptime to start a task.
SleepUntil *time.Time `json:"sleepUntil,omitempty"`
Cron string `json:"cron,omitempty"`
Every influxdb.Duration `json:"every,omitempty"`
SleepUntil *time.Time `json:"sleepUntil,omitempty"`
Cron string `json:"cron,omitempty"`
Every *notification.Duration `json:"every,omitempty"`
// Offset represents a delay before execution.
// It gets marshalled from a string duration, i.e.: "10s" is 10 seconds
Offset influxdb.Duration `json:"offset,omitempty"`
Offset *notification.Duration `json:"offset,omitempty"`
RunbookLink string `json:"runbookLink"`
TagRules []notification.TagRule `json:"tagRules,omitempty"`
StatusRules []notification.StatusRule `json:"statusRules,omitempty"`
@ -85,7 +87,7 @@ func (b Base) valid() error {
Msg: "Notification Rule OrgID is invalid",
}
}
if b.EndpointID != nil && !b.EndpointID.Valid() {
if !b.EndpointID.Valid() {
return &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "Notification Rule EndpointID is invalid",
@ -119,11 +121,31 @@ func (b Base) GetID() influxdb.ID {
return b.ID
}
// GetEndpointID gets the endpointID for a base.
func (b Base) GetEndpointID() influxdb.ID {
return b.EndpointID
}
// GetOrgID implements influxdb.Getter interface.
func (b Base) GetOrgID() influxdb.ID {
return b.OrgID
}
// GetTaskID gets the task ID for a base.
func (b Base) GetTaskID() influxdb.ID {
return b.TaskID
}
// SetTaskID sets the task ID for a base.
func (b *Base) SetTaskID(id influxdb.ID) {
b.TaskID = id
}
// Clears the task ID from the base.
func (b *Base) ClearPrivateData() {
b.TaskID = 0
}
// GetOwnerID returns the owner id.
func (b Base) GetOwnerID() influxdb.ID {
return b.OwnerID

View File

@ -22,11 +22,12 @@ const (
)
var goodBase = rule.Base{
ID: influxTesting.MustIDBase16(id1),
Name: "name1",
OwnerID: influxTesting.MustIDBase16(id2),
OrgID: influxTesting.MustIDBase16(id3),
Status: influxdb.Inactive,
ID: influxTesting.MustIDBase16(id1),
Name: "name1",
OwnerID: influxTesting.MustIDBase16(id2),
OrgID: influxTesting.MustIDBase16(id3),
Status: influxdb.Inactive,
EndpointID: 1,
}
func TestValidRule(t *testing.T) {
@ -90,7 +91,7 @@ func TestValidRule(t *testing.T) {
Name: "name1",
OwnerID: influxTesting.MustIDBase16(id2),
OrgID: influxTesting.MustIDBase16(id3),
EndpointID: influxTesting.IDPtr(influxdb.InvalidID()),
EndpointID: 0,
},
},
err: &influxdb.Error{
@ -102,10 +103,11 @@ func TestValidRule(t *testing.T) {
name: "invalid status",
src: &rule.Slack{
Base: rule.Base{
ID: influxTesting.MustIDBase16(id1),
Name: "name1",
OwnerID: influxTesting.MustIDBase16(id2),
OrgID: influxTesting.MustIDBase16(id3),
ID: influxTesting.MustIDBase16(id1),
Name: "name1",
OwnerID: influxTesting.MustIDBase16(id2),
OrgID: influxTesting.MustIDBase16(id3),
EndpointID: 1,
},
},
err: &influxdb.Error{
@ -138,11 +140,12 @@ func TestValidRule(t *testing.T) {
name: "bad tag rule",
src: &rule.PagerDuty{
Base: rule.Base{
ID: influxTesting.MustIDBase16(id1),
OwnerID: influxTesting.MustIDBase16(id2),
Name: "name1",
OrgID: influxTesting.MustIDBase16(id3),
Status: influxdb.Active,
ID: influxTesting.MustIDBase16(id1),
OwnerID: influxTesting.MustIDBase16(id2),
Name: "name1",
OrgID: influxTesting.MustIDBase16(id3),
EndpointID: 1,
Status: influxdb.Active,
TagRules: []notification.TagRule{
{
Tag: notification.Tag{
@ -164,11 +167,12 @@ func TestValidRule(t *testing.T) {
name: "bad limit",
src: &rule.PagerDuty{
Base: rule.Base{
ID: influxTesting.MustIDBase16(id1),
OwnerID: influxTesting.MustIDBase16(id2),
OrgID: influxTesting.MustIDBase16(id3),
Name: "name1",
Status: influxdb.Active,
ID: influxTesting.MustIDBase16(id1),
OwnerID: influxTesting.MustIDBase16(id2),
OrgID: influxTesting.MustIDBase16(id3),
EndpointID: 1,
Name: "name1",
Status: influxdb.Active,
TagRules: []notification.TagRule{
{
Tag: notification.Tag{
@ -191,8 +195,10 @@ func TestValidRule(t *testing.T) {
},
}
for _, c := range cases {
got := c.src.Valid()
influxTesting.ErrorsEqual(t, got, c.err)
t.Run(c.name, func(t *testing.T) {
got := c.src.Valid()
influxTesting.ErrorsEqual(t, got, c.err)
})
}
}
@ -216,7 +222,7 @@ func TestJSON(t *testing.T) {
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
TagRules: []notification.TagRule{
{
Tag: notification.Tag{
@ -253,7 +259,7 @@ func TestJSON(t *testing.T) {
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
TagRules: []notification.TagRule{
{
Tag: notification.Tag{
@ -289,7 +295,7 @@ func TestJSON(t *testing.T) {
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
TagRules: []notification.TagRule{
{
Tag: notification.Tag{

View File

@ -2,8 +2,13 @@ package rule
import (
"encoding/json"
"fmt"
"github.com/influxdata/flux/ast"
"github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/notification"
"github.com/influxdata/influxdb/notification/flux"
)
// Slack is the notification rule config of slack.
@ -13,6 +18,129 @@ type Slack struct {
MessageTemplate string `json:"messageTemplate"`
}
// GenerateFlux generates a flux script for the slack notification rule.
func (s *Slack) GenerateFlux(e influxdb.NotificationEndpoint) (string, error) {
// TODO(desa): needs implementation
return `package main
data = from(bucket: "telegraf")
|> range(start: -1m)
option task = {name: "name1", every: 1m}`, nil
}
// GenerateFluxReal generates a flux script for the slack notification rule.
func (s *Slack) GenerateFluxReal(e influxdb.NotificationEndpoint) (string, error) {
p, err := s.GenerateFluxAST()
if err != nil {
return "", err
}
return ast.Format(p), nil
}
// GenerateFluxAST generates a flux AST for the slack notification rule.
func (s *Slack) GenerateFluxAST() (*ast.Package, error) {
f := flux.File(
s.Name,
flux.Imports("influxdata/influxdb/alerts", "slack", "secrets"),
s.generateFluxASTBody(),
)
return &ast.Package{Package: "main", Files: []*ast.File{f}}, nil
}
func (s *Slack) generateFluxASTBody() []ast.Statement {
var statements []ast.Statement
statements = append(statements, s.generateTaskOption())
statements = append(statements, s.generateFluxASTSecrets())
statements = append(statements, s.generateFluxASTEndpoint())
statements = append(statements, s.generateFluxASTNotificationDefinition())
statements = append(statements, s.generateFluxASTStatusPipe())
statements = append(statements, s.generateFluxASTNotifyPipe())
return statements
}
func (s *Slack) generateTaskOption() ast.Statement {
props := []*ast.Property{}
props = append(props, flux.Property("name", flux.String(s.Name)))
if s.Cron != "" {
props = append(props, flux.Property("cron", flux.String(s.Cron)))
}
if s.Every != nil {
props = append(props, flux.Property("every", (*ast.DurationLiteral)(s.Every)))
}
if s.Offset != nil {
props = append(props, flux.Property("offset", (*ast.DurationLiteral)(s.Offset)))
}
return flux.DefineTaskOption(flux.Object(props...))
}
func (s *Slack) generateFluxASTNotificationDefinition() ast.Statement {
// TODO(desa): what else needs to be here?
id := flux.Property("notificationID", flux.String(s.ID.String()))
name := flux.Property("name", flux.String(s.Name))
return flux.DefineVariable("notification", flux.Object(id, name))
}
func (s *Slack) generateFluxASTSecrets() ast.Statement {
// TODO(desa): where does <some key> come from
call := flux.Call(flux.Member("secrets", "get"), flux.Object(flux.Property("key", flux.String("<secrets key>"))))
return flux.DefineVariable("slack_secret", call)
}
func (s *Slack) generateFluxASTEndpoint() ast.Statement {
// TODO(desa): where does <some key> come from
call := flux.Call(flux.Member("slack", "endpoint"), flux.Object(flux.Property("token", flux.Identifier("slack_secret"))))
return flux.DefineVariable("slack_endpoint", call)
}
func (s *Slack) generateFluxASTStatusPipe() ast.Statement {
base := flux.Call(flux.Identifier("from"), flux.Object(flux.Property("bucket", flux.String("system_bucket"))))
calls := []*ast.CallExpression{}
// TODO(desa): make start negative of every
calls = append(calls, flux.Call(flux.Identifier("range"), flux.Object(flux.Property("start", (*ast.DurationLiteral)(s.Every)))))
for _, r := range s.TagRules {
switch r.Operator {
case notification.Equal:
fn := flux.Function(flux.FunctionParams("r"), flux.Equal(flux.Member("r", r.Key), flux.String(r.Value)))
calls = append(calls, flux.Call(flux.Identifier("filter"), flux.Object(flux.Property("fn", fn))))
default:
// TODO(desa): have this work for all operator types
panic(fmt.Sprintf("operator %v not currently supported", r.Operator))
}
}
return flux.DefineVariable("statuses", flux.Pipe(base, calls...))
}
func (s *Slack) generateFluxASTNotifyPipe() ast.Statement {
endpointProps := []*ast.Property{}
endpointProps = append(endpointProps, flux.Property("channel", flux.String(s.Channel)))
// TODO(desa): are these values correct?
endpointProps = append(endpointProps, flux.Property("text", flux.String(s.MessageTemplate)))
endpointFn := flux.Function(flux.FunctionParams("r"), flux.Object(endpointProps...))
props := []*ast.Property{}
props = append(props, flux.Property("name", flux.String(s.Name)))
props = append(props, flux.Property("notification", flux.Identifier("notification")))
props = append(props, flux.Property("endpoint",
flux.Call(flux.Identifier("slack_endpoint"), flux.Object(flux.Property("mapFn", endpointFn)))))
call := flux.Call(flux.Member("alerts", "notify"), flux.Object(props...))
return flux.ExpressionStatement(flux.Pipe(flux.Identifier("statuses"), call))
}
type slackAlias Slack
// MarshalJSON implement json.Marshaler interface.

View File

@ -0,0 +1,77 @@
package rule_test
import (
"testing"
"github.com/influxdata/flux/parser"
"github.com/influxdata/influxdb/notification"
"github.com/influxdata/influxdb/notification/rule"
)
func mustDuration(d string) *notification.Duration {
dur, err := parser.ParseDuration(d)
if err != nil {
panic(err)
}
return (*notification.Duration)(dur)
}
func TestSlack_GenerateFlux(t *testing.T) {
want := `package main
// foo
import "influxdata/influxdb/alerts"
import "slack"
import "secrets"
option task = {name: "foo", every: 1h}
slack_secret = secrets.get(key: "<secrets key>")
slack_endpoint = slack.endpoint(token: slack_secret)
notification = {notificationID: "0000000000000001", name: "foo"}
statuses = from(bucket: "system_bucket")
|> range(start: 1h)
|> filter(fn: (r) =>
(r.foo == "bar"))
|> filter(fn: (r) =>
(r.baz == "bang"))
statuses
|> alerts.notify(name: "foo", notification: notification, endpoint: slack_endpoint(mapFn: (r) =>
({channel: "bar", text: "blah"})))`
s := &rule.Slack{
Channel: "bar",
MessageTemplate: "blah",
Base: rule.Base{
ID: 1,
Name: "foo",
Every: mustDuration("1h"),
TagRules: []notification.TagRule{
{
Tag: notification.Tag{
Key: "foo",
Value: "bar",
},
Operator: notification.Equal,
},
{
Tag: notification.Tag{
Key: "baz",
Value: "bang",
},
Operator: notification.Equal,
},
},
},
}
f, err := s.GenerateFluxReal(nil)
if err != nil {
panic(err)
}
if f != want {
t.Errorf("scripts did not match. want:\n%v\n\ngot:\n%v", want, f)
}
}

View File

@ -17,13 +17,13 @@ import (
"github.com/influxdata/influxdb/notification/check"
)
func mustDuration(d string) *check.Duration {
func mustDuration(d string) *notification.Duration {
dur, err := parser.ParseDuration(d)
if err != nil {
panic(err)
}
return (*check.Duration)(dur)
return (*notification.Duration)(dur)
}
const (

View File

@ -4,9 +4,9 @@ import (
"context"
"sort"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/influxdata/influxdb"
"github.com/influxdata/influxdb/mock"
"github.com/influxdata/influxdb/notification"
@ -20,9 +20,11 @@ type NotificationRuleFields struct {
NotificationRules []influxdb.NotificationRule
Orgs []*influxdb.Organization
UserResourceMappings []*influxdb.UserResourceMapping
Tasks []influxdb.TaskCreate
}
var notificationRuleCmpOptions = cmp.Options{
cmpopts.IgnoreFields(rule.Base{}, "TaskID"),
cmp.Transformer("Sort", func(in []influxdb.NotificationRule) []influxdb.NotificationRule {
out := append([]influxdb.NotificationRule(nil), in...)
sort.Slice(out, func(i, j int) bool {
@ -99,6 +101,12 @@ func CreateNotificationRule(
fields: NotificationRuleFields{
IDGenerator: mock.NewIDGenerator(twoID, t),
TimeGenerator: fakeGenerator,
Orgs: []*influxdb.Organization{
{
Name: "org",
ID: MustIDBase16(fourID),
},
},
NotificationRules: []influxdb.NotificationRule{
&rule.Slack{
Base: rule.Base{
@ -107,9 +115,10 @@ func CreateNotificationRule(
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
Status: influxdb.Active,
EndpointID: 1,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
TagRules: []notification.TagRule{
{
Tag: notification.Tag{
@ -151,11 +160,11 @@ func CreateNotificationRule(
OwnerID: MustIDBase16(sixID),
Name: "name2",
OrgID: MustIDBase16(fourID),
EndpointID: IDPtr(MustIDBase16(fiveID)),
EndpointID: MustIDBase16(fiveID),
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
TagRules: []notification.TagRule{
{
Tag: notification.Tag{
@ -185,9 +194,10 @@ func CreateNotificationRule(
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
Status: influxdb.Active,
EndpointID: 1,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
TagRules: []notification.TagRule{
{
Tag: notification.Tag{
@ -218,11 +228,11 @@ func CreateNotificationRule(
Name: "name2",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: IDPtr(MustIDBase16(fiveID)),
EndpointID: MustIDBase16(fiveID),
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
TagRules: []notification.TagRule{
{
Tag: notification.Tag{
@ -354,10 +364,11 @@ func FindNotificationRuleByID(
Name: "name1",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -372,10 +383,11 @@ func FindNotificationRuleByID(
Name: "name2",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -419,10 +431,11 @@ func FindNotificationRuleByID(
Name: "name1",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -437,10 +450,11 @@ func FindNotificationRuleByID(
Name: "name2",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -484,10 +498,11 @@ func FindNotificationRuleByID(
Name: "name1",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -502,10 +517,11 @@ func FindNotificationRuleByID(
Name: "name2",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -525,10 +541,11 @@ func FindNotificationRuleByID(
Name: "name2",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -614,10 +631,11 @@ func FindNotificationRules(
Name: "name1",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -632,10 +650,11 @@ func FindNotificationRules(
Name: "name2",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -661,10 +680,11 @@ func FindNotificationRules(
Name: "name1",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -679,10 +699,11 @@ func FindNotificationRules(
Name: "name2",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -717,10 +738,11 @@ func FindNotificationRules(
Name: "name1",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -735,10 +757,11 @@ func FindNotificationRules(
Name: "name2",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -765,10 +788,11 @@ func FindNotificationRules(
Name: "name1",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -816,32 +840,35 @@ func FindNotificationRules(
NotificationRules: []influxdb.NotificationRule{
&rule.Slack{
Base: rule.Base{
ID: MustIDBase16(oneID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr1",
ID: MustIDBase16(oneID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr1",
},
Channel: "ch1",
MessageTemplate: "msg1",
},
&rule.PagerDuty{
Base: rule.Base{
ID: MustIDBase16(twoID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr2",
ID: MustIDBase16(twoID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr2",
},
MessageTemp: "body2",
},
&rule.PagerDuty{
Base: rule.Base{
ID: MustIDBase16(fourID),
OrgID: MustIDBase16(oneID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr3",
ID: MustIDBase16(fourID),
OrgID: MustIDBase16(oneID),
EndpointID: 1,
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr3",
},
MessageTemp: "msg",
},
@ -856,11 +883,12 @@ func FindNotificationRules(
notificationRules: []influxdb.NotificationRule{
&rule.PagerDuty{
Base: rule.Base{
ID: MustIDBase16(fourID),
OrgID: MustIDBase16(oneID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr3",
ID: MustIDBase16(fourID),
OrgID: MustIDBase16(oneID),
OwnerID: MustIDBase16(sixID),
EndpointID: 1,
Status: influxdb.Active,
Name: "nr3",
},
MessageTemp: "msg",
},
@ -903,32 +931,35 @@ func FindNotificationRules(
NotificationRules: []influxdb.NotificationRule{
&rule.Slack{
Base: rule.Base{
ID: MustIDBase16(oneID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr1",
ID: MustIDBase16(oneID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
EndpointID: 1,
Status: influxdb.Active,
Name: "nr1",
},
Channel: "ch1",
MessageTemplate: "msg1",
},
&rule.PagerDuty{
Base: rule.Base{
ID: MustIDBase16(twoID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr2",
ID: MustIDBase16(twoID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
EndpointID: 1,
Status: influxdb.Active,
Name: "nr2",
},
MessageTemp: "body2",
},
&rule.PagerDuty{
Base: rule.Base{
ID: MustIDBase16(fourID),
OrgID: MustIDBase16(oneID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr3",
ID: MustIDBase16(fourID),
OrgID: MustIDBase16(oneID),
OwnerID: MustIDBase16(sixID),
EndpointID: 1,
Status: influxdb.Active,
Name: "nr3",
},
MessageTemp: "msg",
},
@ -943,22 +974,24 @@ func FindNotificationRules(
notificationRules: []influxdb.NotificationRule{
&rule.Slack{
Base: rule.Base{
ID: MustIDBase16(oneID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr1",
ID: MustIDBase16(oneID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr1",
},
Channel: "ch1",
MessageTemplate: "msg1",
},
&rule.PagerDuty{
Base: rule.Base{
ID: MustIDBase16(twoID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr2",
ID: MustIDBase16(twoID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr2",
},
MessageTemp: "body2",
},
@ -1001,32 +1034,35 @@ func FindNotificationRules(
NotificationRules: []influxdb.NotificationRule{
&rule.Slack{
Base: rule.Base{
ID: MustIDBase16(oneID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr1",
ID: MustIDBase16(oneID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr1",
},
Channel: "ch1",
MessageTemplate: "msg1",
},
&rule.PagerDuty{
Base: rule.Base{
ID: MustIDBase16(twoID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr2",
ID: MustIDBase16(twoID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
EndpointID: 1,
Status: influxdb.Active,
Name: "nr2",
},
MessageTemp: "body2",
},
&rule.PagerDuty{
Base: rule.Base{
ID: MustIDBase16(fourID),
OrgID: MustIDBase16(oneID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr3",
ID: MustIDBase16(fourID),
OrgID: MustIDBase16(oneID),
OwnerID: MustIDBase16(sixID),
EndpointID: 1,
Status: influxdb.Active,
Name: "nr3",
},
MessageTemp: "msg",
},
@ -1046,11 +1082,12 @@ func FindNotificationRules(
notificationRules: []influxdb.NotificationRule{
&rule.PagerDuty{
Base: rule.Base{
ID: MustIDBase16(fourID),
OrgID: MustIDBase16(oneID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr3",
ID: MustIDBase16(fourID),
OrgID: MustIDBase16(oneID),
OwnerID: MustIDBase16(sixID),
EndpointID: 1,
Status: influxdb.Active,
Name: "nr3",
},
MessageTemp: "msg",
},
@ -1093,32 +1130,35 @@ func FindNotificationRules(
NotificationRules: []influxdb.NotificationRule{
&rule.Slack{
Base: rule.Base{
ID: MustIDBase16(oneID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr1",
ID: MustIDBase16(oneID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr1",
},
Channel: "ch1",
MessageTemplate: "msg1",
},
&rule.PagerDuty{
Base: rule.Base{
ID: MustIDBase16(twoID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr2",
ID: MustIDBase16(twoID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
EndpointID: 1,
Name: "nr2",
},
MessageTemp: "body2",
},
&rule.PagerDuty{
Base: rule.Base{
ID: MustIDBase16(fourID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr3",
ID: MustIDBase16(fourID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
EndpointID: 1,
Status: influxdb.Active,
Name: "nr3",
},
MessageTemp: "msg",
},
@ -1169,32 +1209,35 @@ func FindNotificationRules(
NotificationRules: []influxdb.NotificationRule{
&rule.Slack{
Base: rule.Base{
ID: MustIDBase16(oneID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr1",
ID: MustIDBase16(oneID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
EndpointID: 1,
Status: influxdb.Active,
Name: "nr1",
},
Channel: "ch1",
MessageTemplate: "msg1",
},
&rule.PagerDuty{
Base: rule.Base{
ID: MustIDBase16(twoID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr2",
ID: MustIDBase16(twoID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
EndpointID: 1,
Status: influxdb.Active,
Name: "nr2",
},
MessageTemp: "body2",
},
&rule.PagerDuty{
Base: rule.Base{
ID: MustIDBase16(fourID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
Name: "nr3",
ID: MustIDBase16(fourID),
OrgID: MustIDBase16(fourID),
OwnerID: MustIDBase16(sixID),
Status: influxdb.Active,
EndpointID: 1,
Name: "nr3",
},
MessageTemp: "msg",
},
@ -1277,10 +1320,11 @@ func UpdateNotificationRule(
Name: "name1",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1295,10 +1339,11 @@ func UpdateNotificationRule(
Name: "name2",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1317,10 +1362,11 @@ func UpdateNotificationRule(
Name: "name2",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Inactive,
RunbookLink: "runbooklink3",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour * 2},
Every: mustDuration("2h"),
},
MessageTemp: "msg2",
},
@ -1336,6 +1382,7 @@ func UpdateNotificationRule(
name: "regular update",
fields: NotificationRuleFields{
TimeGenerator: fakeGenerator,
IDGenerator: mock.NewIDGenerator(twoID, t),
UserResourceMappings: []*influxdb.UserResourceMapping{
{
ResourceID: MustIDBase16(oneID),
@ -1350,6 +1397,21 @@ func UpdateNotificationRule(
ResourceType: influxdb.NotificationRuleResourceType,
},
},
Tasks: []influxdb.TaskCreate{
{
OwnerID: MustIDBase16(sixID),
OrganizationID: MustIDBase16(fourID),
Flux: `from(bucket: "foo") |> range(start: -1m)
option task = {name: "bar", every: 1m}
`,
},
},
Orgs: []*influxdb.Organization{
{
ID: MustIDBase16(fourID),
Name: "foo",
},
},
NotificationRules: []influxdb.NotificationRule{
&rule.Slack{
Base: rule.Base{
@ -1357,10 +1419,12 @@ func UpdateNotificationRule(
Name: "name1",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
TaskID: MustIDBase16(twoID),
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1375,10 +1439,12 @@ func UpdateNotificationRule(
Name: "name2",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
TaskID: MustIDBase16(twoID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1396,10 +1462,11 @@ func UpdateNotificationRule(
OwnerID: MustIDBase16(sixID),
Name: "name3",
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Inactive,
RunbookLink: "runbooklink3",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour * 2},
Every: mustDuration("2h"),
},
MessageTemp: "msg2",
},
@ -1411,10 +1478,12 @@ func UpdateNotificationRule(
Name: "name3",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
TaskID: MustIDBase16(twoID),
EndpointID: 1,
Status: influxdb.Inactive,
RunbookLink: "runbooklink3",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour * 2},
Every: mustDuration("2h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: fakeDate,
@ -1492,9 +1561,10 @@ func PatchNotificationRule(
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
Status: influxdb.Active,
EndpointID: 1,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1509,10 +1579,11 @@ func PatchNotificationRule(
Name: "name2",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1562,9 +1633,10 @@ func PatchNotificationRule(
Status: influxdb.Active,
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1579,10 +1651,11 @@ func PatchNotificationRule(
Name: "name2",
Status: influxdb.Active,
OwnerID: MustIDBase16(sixID),
EndpointID: 1,
OrgID: MustIDBase16(fourID),
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1607,9 +1680,10 @@ func PatchNotificationRule(
Status: status3,
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: fakeDate,
@ -1681,9 +1755,10 @@ func DeleteNotificationRule(
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
Status: influxdb.Active,
EndpointID: 1,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1699,9 +1774,10 @@ func DeleteNotificationRule(
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
Status: influxdb.Active,
EndpointID: 1,
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1740,11 +1816,12 @@ func DeleteNotificationRule(
ID: MustIDBase16(oneID),
Name: "name1",
OwnerID: MustIDBase16(sixID),
EndpointID: 1,
OrgID: MustIDBase16(fourID),
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1759,10 +1836,11 @@ func DeleteNotificationRule(
Name: "name2",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1790,6 +1868,22 @@ func DeleteNotificationRule(
ResourceType: influxdb.NotificationRuleResourceType,
},
},
Tasks: []influxdb.TaskCreate{
{
OwnerID: MustIDBase16(sixID),
OrganizationID: MustIDBase16(fourID),
Flux: `from(bucket: "foo") |> range(start: -1m)
option task = {name: "bar", every: 1m}
`,
},
},
IDGenerator: mock.NewIDGenerator(twoID, t),
Orgs: []*influxdb.Organization{
{
ID: MustIDBase16(fourID),
Name: "foo",
},
},
NotificationRules: []influxdb.NotificationRule{
&rule.Slack{
Base: rule.Base{
@ -1798,9 +1892,10 @@ func DeleteNotificationRule(
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
Status: influxdb.Active,
EndpointID: 1,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1815,10 +1910,12 @@ func DeleteNotificationRule(
Name: "name2",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
TaskID: MustIDBase16(twoID),
Status: influxdb.Active,
EndpointID: 1,
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1858,10 +1955,11 @@ func DeleteNotificationRule(
Name: "name1",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1876,10 +1974,11 @@ func DeleteNotificationRule(
Name: "name2",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
EndpointID: 1,
Status: influxdb.Active,
RunbookLink: "runbooklink2",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1907,17 +2006,35 @@ func DeleteNotificationRule(
ResourceType: influxdb.NotificationRuleResourceType,
},
},
Tasks: []influxdb.TaskCreate{
{
OwnerID: MustIDBase16(sixID),
OrganizationID: MustIDBase16(fourID),
Flux: `from(bucket: "foo") |> range(start: -1m)
option task = {name: "bar", every: 1m}
`,
},
},
IDGenerator: mock.NewIDGenerator(twoID, t),
Orgs: []*influxdb.Organization{
{
ID: MustIDBase16(fourID),
Name: "foo",
},
},
NotificationRules: []influxdb.NotificationRule{
&rule.Slack{
Base: rule.Base{
ID: MustIDBase16(oneID),
Name: "name1",
OwnerID: MustIDBase16(sixID),
EndpointID: 1,
TaskID: MustIDBase16(twoID),
OrgID: MustIDBase16(fourID),
Status: influxdb.Active,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1931,11 +2048,13 @@ func DeleteNotificationRule(
ID: MustIDBase16(twoID),
Name: "name2",
OwnerID: MustIDBase16(sixID),
TaskID: MustIDBase16(twoID),
OrgID: MustIDBase16(fourID),
Status: influxdb.Active,
RunbookLink: "runbooklink2",
EndpointID: 1,
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
@ -1965,10 +2084,12 @@ func DeleteNotificationRule(
Name: "name1",
OwnerID: MustIDBase16(sixID),
OrgID: MustIDBase16(fourID),
TaskID: MustIDBase16(twoID),
Status: influxdb.Active,
EndpointID: 1,
RunbookLink: "runbooklink1",
SleepUntil: &time3,
Every: influxdb.Duration{Duration: time.Hour},
Every: mustDuration("1h"),
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),

View File

@ -5,6 +5,7 @@ import {
SlackNotificationRuleBase,
SMTPNotificationRuleBase,
PagerDutyNotificationRuleBase,
HTTPNotificationRuleBase,
NotificationRule,
} from 'src/client'
@ -33,11 +34,16 @@ export type NotificationRuleBaseDraft = Overwrite<
}
>
export type NotificationRuleDraft = SlackRule | SMTPRule | PagerDutyRule
export type NotificationRuleDraft =
| SlackRule
| SMTPRule
| PagerDutyRule
| HTTPRule
type SlackRule = NotificationRuleBaseDraft & SlackNotificationRuleBase
type SMTPRule = NotificationRuleBaseDraft & SMTPNotificationRuleBase
type PagerDutyRule = NotificationRuleBaseDraft & PagerDutyNotificationRuleBase
type HTTPRule = NotificationRuleBaseDraft & HTTPNotificationRuleBase
export {
Check,