Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(notification/telegram): add telegram notification #19135

Merged
merged 5 commits into from
Aug 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
1. [19223](https://github.com/influxdata/influxdb/pull/19223): Add dashboards command to influx CLI
1. [19225](https://github.com/influxdata/influxdb/pull/19225): Allow user onboarding to optionally set passwords
1. [18841](https://github.com/influxdata/influxdb/pull/18841): Limit query response sizes for queries built in QueryBuilder by requiring an aggregate window
1. [19135](https://github.com/influxdata/influxdb/pull/19135): Add telegram notification.

### Bug Fixes

Expand Down
44 changes: 43 additions & 1 deletion http/swagger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11169,13 +11169,15 @@ components:
- $ref: "#/components/schemas/SMTPNotificationRule"
- $ref: "#/components/schemas/PagerDutyNotificationRule"
- $ref: "#/components/schemas/HTTPNotificationRule"
- $ref: "#/components/schemas/TelegramNotificationRule"
discriminator:
propertyName: type
mapping:
slack: "#/components/schemas/SlackNotificationRule"
smtp: "#/components/schemas/SMTPNotificationRule"
pagerduty: "#/components/schemas/PagerDutyNotificationRule"
http: "#/components/schemas/HTTPNotificationRule"
telegram: "#/components/schemas/TelegramNotificationRule"
NotificationRule:
allOf:
- $ref: "#/components/schemas/NotificationRuleDiscriminator"
Expand Down Expand Up @@ -11377,6 +11379,31 @@ components:
enum: [pagerduty]
messageTemplate:
type: string
TelegramNotificationRule:
allOf:
- $ref: "#/components/schemas/NotificationRuleBase"
- $ref: "#/components/schemas/TelegramNotificationRuleBase"
TelegramNotificationRuleBase:
type: object
required: [type, messageTemplate, channel]
properties:
type:
description: The discriminator between other types of notification rules is "telegram".
type: string
enum: [telegram]
messageTemplate:
description: The message template as a flux interpolated string.
type: string
parseMode:
description: Parse mode of the message text per https://core.telegram.org/bots/api#formatting-options . Defaults to "MarkdownV2" .
type: string
enum:
- MarkdownV2
- HTML
- Markdown
disableWebPagePreview:
description: Disables preview of web links in the sent messages when "true". Defaults to "false" .
type: boolean
NotificationEndpointUpdate:
type: object

Expand All @@ -11395,12 +11422,14 @@ components:
- $ref: "#/components/schemas/SlackNotificationEndpoint"
- $ref: "#/components/schemas/PagerDutyNotificationEndpoint"
- $ref: "#/components/schemas/HTTPNotificationEndpoint"
- $ref: "#/components/schemas/TelegramNotificationEndpoint"
discriminator:
propertyName: type
mapping:
slack: "#/components/schemas/SlackNotificationEndpoint"
pagerduty: "#/components/schemas/PagerDutyNotificationEndpoint"
http: "#/components/schemas/HTTPNotificationEndpoint"
telegram: "#/components/schemas/TelegramNotificationEndpoint"
NotificationEndpoint:
allOf:
- $ref: "#/components/schemas/NotificationEndpointDiscrimator"
Expand Down Expand Up @@ -11519,9 +11548,22 @@ components:
description: Customized headers.
additionalProperties:
type: string
TelegramNotificationEndpoint:
type: object
allOf:
- $ref: "#/components/schemas/NotificationEndpointBase"
- type: object
required: [token, channel]
properties:
token:
description: Specifies the Telegram bot token. See https://core.telegram.org/bots#creating-a-new-bot .
type: string
channel:
description: ID of the telegram channel, a chat_id in https://core.telegram.org/bots/api#sendmessage .
type: string
NotificationEndpointType:
type: string
enum: ["slack", "pagerduty", "http"]
enum: ["slack", "pagerduty", "http", "telegram"]
DBRP:
required:
- orgID
Expand Down
2 changes: 2 additions & 0 deletions notification/endpoint/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ const (
SlackType = "slack"
PagerDutyType = "pagerduty"
HTTPType = "http"
TelegramType = "telegram"
)

var typeToEndpoint = map[string]func() influxdb.NotificationEndpoint{
SlackType: func() influxdb.NotificationEndpoint { return &Slack{} },
PagerDutyType: func() influxdb.NotificationEndpoint { return &PagerDuty{} },
HTTPType: func() influxdb.NotificationEndpoint { return &HTTP{} },
TelegramType: func() influxdb.NotificationEndpoint { return &Telegram{} },
}

// UnmarshalJSON will convert the bytes to notification endpoint.
Expand Down
225 changes: 224 additions & 1 deletion notification/endpoint/endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func TestValidEndpoint(t *testing.T) {
},
},
{
name: "empty name",
name: "empty name PagerDuty",
src: &endpoint.PagerDuty{
Base: endpoint.Base{
ID: influxTesting.MustIDBase16Ptr(id1),
Expand All @@ -70,6 +70,22 @@ func TestValidEndpoint(t *testing.T) {
Msg: "Notification Endpoint Name can't be empty",
},
},
{
name: "empty name Telegram",
src: &endpoint.Telegram{
Base: endpoint.Base{
ID: influxTesting.MustIDBase16Ptr(id1),
OrgID: influxTesting.MustIDBase16Ptr(id3),
Status: influxdb.Active,
},
Token: influxdb.SecretField{Key: id1 + "-token"},
Channel: "-1001406363649",
},
err: &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "Notification Endpoint Name can't be empty",
},
},
{
name: "empty slack url",
src: &endpoint.Slack{
Expand Down Expand Up @@ -136,6 +152,36 @@ func TestValidEndpoint(t *testing.T) {
Msg: "invalid http username/password for basic auth",
},
},
{
name: "empty telegram token",
src: &endpoint.Telegram{
Base: goodBase,
},
err: &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "empty telegram bot token",
},
},
{
name: "empty telegram channel",
src: &endpoint.Telegram{
Base: goodBase,
Token: influxdb.SecretField{Key: id1 + "-token"},
},
err: &influxdb.Error{
Code: influxdb.EInvalid,
Msg: "empty telegram channel",
},
},
{
name: "valid telegram token",
src: &endpoint.Telegram{
Base: goodBase,
Token: influxdb.SecretField{Key: id1 + "-token"},
Channel: "-1001406363649",
},
err: nil,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
Expand Down Expand Up @@ -226,6 +272,22 @@ func TestJSON(t *testing.T) {
Password: influxdb.SecretField{Key: "password-key"},
},
},
{
name: "simple Telegram",
src: &endpoint.Telegram{
Base: endpoint.Base{
ID: influxTesting.MustIDBase16Ptr(id1),
Name: "nameTelegram",
OrgID: influxTesting.MustIDBase16Ptr(id3),
Status: influxdb.Active,
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
},
},
Token: influxdb.SecretField{Key: "token-key-1"},
},
},
}
for _, c := range cases {
b, err := json.Marshal(c.src)
Expand Down Expand Up @@ -365,6 +427,40 @@ func TestBackFill(t *testing.T) {
},
},
},
{
name: "simple Telegram",
src: &endpoint.Telegram{
Base: endpoint.Base{
ID: influxTesting.MustIDBase16Ptr(id1),
Name: "name1",
OrgID: influxTesting.MustIDBase16Ptr(id3),
Status: influxdb.Active,
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
},
},
Token: influxdb.SecretField{
Value: strPtr("token-value"),
},
},
target: &endpoint.Telegram{
Base: endpoint.Base{
ID: influxTesting.MustIDBase16Ptr(id1),
Name: "name1",
OrgID: influxTesting.MustIDBase16Ptr(id3),
Status: influxdb.Active,
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
},
},
Token: influxdb.SecretField{
Key: id1 + "-token",
Value: strPtr("token-value"),
},
},
},
}
for _, c := range cases {
c.src.BackfillSecretKeys()
Expand All @@ -374,6 +470,133 @@ func TestBackFill(t *testing.T) {
}
}

func TestSecretFields(t *testing.T) {
cases := []struct {
name string
src influxdb.NotificationEndpoint
secrets []influxdb.SecretField
}{
{
name: "simple Slack",
src: &endpoint.Slack{
Base: endpoint.Base{
ID: influxTesting.MustIDBase16Ptr(id1),
Name: "name1",
OrgID: influxTesting.MustIDBase16Ptr(id3),
Status: influxdb.Active,
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
},
},
URL: "https://slack.com/api/chat.postMessage",
Token: influxdb.SecretField{
Key: id1 + "-token",
Value: strPtr("token-value"),
},
},
secrets: []influxdb.SecretField{
{
Key: id1 + "-token",
Value: strPtr("token-value"),
},
},
},
{
name: "simple pagerduty",
src: &endpoint.PagerDuty{
Base: endpoint.Base{
ID: influxTesting.MustIDBase16Ptr(id1),
Name: "name1",
OrgID: influxTesting.MustIDBase16Ptr(id3),
Status: influxdb.Active,
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
},
},
ClientURL: "https://events.pagerduty.com/v2/enqueue",
RoutingKey: influxdb.SecretField{
Key: id1 + "-routing-key",
Value: strPtr("routing-key-value"),
},
},
secrets: []influxdb.SecretField{
{
Key: id1 + "-routing-key",
Value: strPtr("routing-key-value"),
},
},
},
{
name: "http with user and password",
src: &endpoint.HTTP{
Base: endpoint.Base{
ID: influxTesting.MustIDBase16Ptr(id1),
Name: "name1",
OrgID: influxTesting.MustIDBase16Ptr(id3),
Status: influxdb.Active,
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
},
},
AuthMethod: "basic",
URL: "http://example.com",
Username: influxdb.SecretField{
Key: id1 + "-username",
Value: strPtr("user1"),
},
Password: influxdb.SecretField{
Key: id1 + "-password",
Value: strPtr("password1"),
},
},
secrets: []influxdb.SecretField{
{
Key: id1 + "-username",
Value: strPtr("user1"),
},
{
Key: id1 + "-password",
Value: strPtr("password1"),
},
},
},
{
name: "simple Telegram",
src: &endpoint.Telegram{
Base: endpoint.Base{
ID: influxTesting.MustIDBase16Ptr(id1),
Name: "name1",
OrgID: influxTesting.MustIDBase16Ptr(id3),
Status: influxdb.Active,
CRUDLog: influxdb.CRUDLog{
CreatedAt: timeGen1.Now(),
UpdatedAt: timeGen2.Now(),
},
},
Token: influxdb.SecretField{
Key: id1 + "-token",
Value: strPtr("token-value"),
},
},
secrets: []influxdb.SecretField{
{
Key: id1 + "-token",
Value: strPtr("token-value"),
},
},
},
}
for _, c := range cases {
secretFields := c.src.SecretFields()
if diff := cmp.Diff(c.secrets, secretFields); diff != "" {
t.Errorf("failed %s, NotificationEndpoint are different -got/+want\ndiff %s", c.name, diff)
}
}
}

func strPtr(s string) *string {
ss := new(string)
*ss = s
Expand Down
Loading