initial commit, based on sensu-email-handler

This commit is contained in:
Paul 2019-03-31 17:00:38 +02:00
commit 6490448439
7 changed files with 642 additions and 0 deletions

11
CHANGELOG.md Normal file
View File

@ -0,0 +1,11 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic
Versioning](http://semver.org/spec/v2.0.0.html).
## [0.0.1] - 2019-03-31
### Added
- Initial release, based on sensu-email-handler

233
Gopkg.lock generated Normal file
View File

@ -0,0 +1,233 @@
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
[[projects]]
digest = "1:660af934d331e79d29317ffd5c76fceedaa1249167b1ee461d284c58d53291c6"
name = "github.com/coreos/etcd"
packages = [
"auth/authpb",
"etcdserver/etcdserverpb",
"mvcc/mvccpb",
]
pruneopts = "UT"
revision = "27fc7e2296f506182f58ce846e48f36b34fe6842"
version = "v3.3.10"
[[projects]]
digest = "1:76dc72490af7174349349838f2fe118996381b31ea83243812a97e5a0fd5ed55"
name = "github.com/dgrijalva/jwt-go"
packages = ["."]
pruneopts = "UT"
revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e"
version = "v3.2.0"
[[projects]]
digest = "1:9d5bd7c02a73959247ccbf524180e363631ece23c58e12b21d697f4741c7926f"
name = "github.com/echlebek/timeproxy"
packages = ["."]
pruneopts = "UT"
revision = "d7c2918981322d4d437f7a52f3a15c7ec5a4f488"
version = "v1.0.0"
[[projects]]
digest = "1:bfc758d5a03d57d97226fac6934551c01bd76612adb119c177395b057a0a46db"
name = "github.com/gogo/protobuf"
packages = [
"gogoproto",
"proto",
"protoc-gen-gogo/descriptor",
]
pruneopts = "UT"
revision = "636bf0302bc95575d69441b25a2603156ffdddf1"
version = "v1.1.1"
[[projects]]
digest = "1:4c0989ca0bcd10799064318923b9bc2db6b4d6338dd75f3f2d86c3511aaaf5cf"
name = "github.com/golang/protobuf"
packages = [
"proto",
"ptypes",
"ptypes/any",
"ptypes/duration",
"ptypes/timestamp",
]
pruneopts = "UT"
revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5"
version = "v1.2.0"
[[projects]]
digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be"
name = "github.com/inconshreveable/mousetrap"
packages = ["."]
pruneopts = "UT"
revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75"
version = "v1.0"
[[projects]]
digest = "1:1ed5ad32e321bd35d51e30dbbccab9d226ac290347838d03362b427459036a91"
name = "github.com/json-iterator/go"
packages = ["."]
pruneopts = "UT"
revision = "f7279a603edee96fe7764d3de9c6ff8cf9970994"
[[projects]]
branch = "master"
digest = "1:dbfe572cc258e5bcf54cb650a06d90edd0da04e42ca1ed909cc1d49f00011c63"
name = "github.com/robertkrimen/otto"
packages = [
".",
"ast",
"dbg",
"file",
"parser",
"registry",
"token",
]
pruneopts = "UT"
revision = "15f95af6e78dcd2030d8195a138bd88d4f403546"
[[projects]]
digest = "1:bffc9efe1d7783f54cb0003b57cb3c8fe49f56beb9859cf122be97504e854666"
name = "github.com/robfig/cron"
packages = ["."]
pruneopts = "UT"
revision = "2315d5715e36303a941d907f038da7f7c44c773b"
[[projects]]
digest = "1:b9cc662e15cbe325399cb8a8610962a4b8373512c2f3318d0b30e856ca081c64"
name = "github.com/sensu/sensu-go"
packages = [
"api/core/v2",
"js",
"types",
"util/strings",
]
pruneopts = "UT"
revision = "0150bbcb0a2b70f720fa20a9a47c7e91bacd72b1"
[[projects]]
digest = "1:645cabccbb4fa8aab25a956cbcbdf6a6845ca736b2c64e197ca7cbb9d210b939"
name = "github.com/spf13/cobra"
packages = ["."]
pruneopts = "UT"
revision = "ef82de70bb3f60c65fb8eebacbb2d122ef517385"
version = "v0.0.3"
[[projects]]
digest = "1:c1b1102241e7f645bc8e0c22ae352e8f0dc6484b6cb4d132fa9f24174e0119e2"
name = "github.com/spf13/pflag"
packages = ["."]
pruneopts = "UT"
revision = "298182f68c66c05229eb03ac171abe6e309ee79a"
version = "v1.0.3"
[[projects]]
branch = "master"
digest = "1:6ca51c5d8a610b3da56856df7a8f8f3e075eba8d5f7a4acbadd79b2d2a368054"
name = "golang.org/x/net"
packages = [
"context",
"http/httpguts",
"http2",
"http2/hpack",
"idna",
"internal/timeseries",
"trace",
]
pruneopts = "UT"
revision = "adae6a3d119ae4890b46832a2e88a95adc62b8e7"
[[projects]]
branch = "master"
digest = "1:a62e80faf19c93dcbd7954a26fdb51acbfcb4b7161966adf1de531e593c4834a"
name = "golang.org/x/sys"
packages = ["unix"]
pruneopts = "UT"
revision = "93218def8b18e66adbdab3eca8ec334700329f1f"
[[projects]]
digest = "1:a2ab62866c75542dd18d2b069fec854577a20211d7c0ea6ae746072a1dccdd18"
name = "golang.org/x/text"
packages = [
"collate",
"collate/build",
"internal/colltab",
"internal/gen",
"internal/tag",
"internal/triegen",
"internal/ucd",
"language",
"secure/bidirule",
"transform",
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable",
]
pruneopts = "UT"
revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0"
version = "v0.3.0"
[[projects]]
branch = "master"
digest = "1:56b0bca90b7e5d1facf5fbdacba23e4e0ce069d25381b8e2f70ef1e7ebfb9c1a"
name = "google.golang.org/genproto"
packages = ["googleapis/rpc/status"]
pruneopts = "UT"
revision = "b5d43981345bdb2c233eb4bf3277847b48c6fdc6"
[[projects]]
digest = "1:c3ad9841823db6da420a5625b367913b4ff54bbe60e8e3c98bd20e243e62e2d2"
name = "google.golang.org/grpc"
packages = [
".",
"balancer",
"balancer/base",
"balancer/roundrobin",
"codes",
"connectivity",
"credentials",
"encoding",
"encoding/proto",
"grpclog",
"internal",
"internal/backoff",
"internal/channelz",
"internal/envconfig",
"internal/grpcrand",
"internal/transport",
"keepalive",
"metadata",
"naming",
"peer",
"resolver",
"resolver/dns",
"resolver/passthrough",
"stats",
"status",
"tap",
]
pruneopts = "UT"
revision = "2e463a05d100327ca47ac218281906921038fd95"
version = "v1.16.0"
[[projects]]
digest = "1:9935525a8c49b8434a0b0a54e1980e94a6fae73aaff45c5d33ba8dff69de123e"
name = "gopkg.in/sourcemap.v1"
packages = [
".",
"base64vlq",
]
pruneopts = "UT"
revision = "6e83acea0053641eff084973fee085f0c193c61a"
version = "v1.0.5"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
input-imports = [
"github.com/sensu/sensu-go/types",
"github.com/spf13/cobra",
]
solver-name = "gps-cdcl"
solver-version = 1

38
Gopkg.toml Normal file
View File

@ -0,0 +1,38 @@
# Gopkg.toml example
#
# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html
# for detailed Gopkg.toml documentation.
#
# required = ["github.com/user/thing/cmd/thing"]
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
#
# [[constraint]]
# name = "github.com/user/project"
# version = "1.0.0"
#
# [[constraint]]
# name = "github.com/user/project2"
# branch = "dev"
# source = "github.com/myfork/project2"
#
# [[override]]
# name = "github.com/x/y"
# version = "2.4.0"
#
# [prune]
# non-go = false
# go-tests = true
# unused-packages = true
[prune]
go-tests = true
unused-packages = true
[[constraint]]
name = "github.com/spf13/cobra"
version = "0.0.3"
[[constraint]]
name = "github.com/sensu/sensu-go"
revision = "0150bbcb0a2b70f720fa20a9a47c7e91bacd72b1"

43
LICENSE Normal file
View File

@ -0,0 +1,43 @@
MIT License
Copyright (c) 2019 PaulBSD
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
MIT License
Copyright (c) 2019 Sensu Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

64
README.md Normal file
View File

@ -0,0 +1,64 @@
# Sensu Go Telegram Handler Plugin
The Sensu Go Telegram Handler is a [Sensu Event Handler][2] for sending
incident notification emails.
## Installation
Download the latest version of the sensu-telegram-handler from [releases][1],
or create an executable script from this source.
From the local path of the sensu-telegram-handler repository:
```
go build -o /usr/local/bin/sensu-telegram-handler main.go
```
## Configuration
Example Sensu Go definition:
```json
{
"api_version": "core/v2",
"type": "Handler",
"metadata": {
"namespace": "default",
"name": "telegram"
},
"spec": {
"type": "pipe",
"command": "sensu-telegram-handler -t 123456789:dahxaemuGoM8ekeed1pideeCoh3ahm-abcd -c 9876543210",
"timeout": 10,
"filters": [
"is_incident",
"not_silenced"
]
}
}
```
## Usage Examples
Help:
```
The Sensu Go Telegram handler for sending an email notification
Usage:
sensu-telegram-handler [flags]
Flags:
-T, --bodyTemplateFile string A template file to use for the body
-c, --channel int The channel (default -1)
-h, --help help for sensu-telegram-handler
-H, --hookout Include output from check hook(s)
-t, --token string the telegram bot token
```
## Contributing
See https://github.com/sensu/sensu-go/blob/master/CONTRIBUTING.md
[1]: https://github.com/sensu/sensu-email-handler/releases (code base)
[2]: https://docs.sensu.io/sensu-go/5.0/reference/handlers/#how-do-sensu-handlers-work

121
event.json Normal file
View File

@ -0,0 +1,121 @@
{
"entity": {
"entity_class": "agent",
"system": {
"hostname": "webserver01",
"os": "linux",
"platform": "centos",
"platform_family": "rhel",
"platform_version": "7.4.1708",
"network": {
"interfaces": [
{
"name": "lo",
"addresses": [
"127.0.0.1/8",
"::1/128"
]
},
{
"name": "enp0s3",
"mac": "08:00:27:11:ad:d2",
"addresses": [
"10.0.2.15/24",
"fe80::26a5:54ec:cf0d:9704/64"
]
},
{
"name": "enp0s8",
"mac": "08:00:27:bc:be:60",
"addresses": [
"172.28.128.3/24",
"fe80::a00:27ff:febc:be60/64"
]
}
]
},
"arch": "amd64"
},
"subscriptions": [
"testing",
"entity:webserver01"
],
"last_seen": 1542667635,
"deregister": false,
"deregistration": {},
"user": "agent",
"redact": [
"password",
"passwd",
"pass",
"api_key",
"api_token",
"access_key",
"secret_key",
"private_key",
"secret"
],
"metadata": {
"name": "webserver01",
"namespace": "default",
"labels": null,
"annotations": null
}
},
"check": {
"check_hooks": null,
"duration": 1.903135228,
"executed": 1522100915,
"high_flap_threshold": 0,
"history": [
{
"executed": 1522100315
},
{
"executed": 1522100915
}
],
"command": "http_check.sh http://localhost:80",
"handlers": [
"slack"
],
"high_flap_threshold": 0,
"interval": 20,
"low_flap_threshold": 0,
"publish": true,
"runtime_assets": [],
"subscriptions": [
"testing"
],
"proxy_entity_name": "",
"check_hooks": null,
"stdin": false,
"ttl": 0,
"timeout": 0,
"duration": 0.010849143,
"executed": 1542667666,
"history": [
{
"status": 1,
"executed": 1542667666
}
],
"issued": 1542667666,
"output": "example output",
"state": "failing",
"status": 1,
"total_state_change": 0,
"last_ok": 0,
"occurrences": 1,
"occurrences_watermark": 1,
"output_metric_format": "",
"output_metric_handlers": [],
"env_vars": null,
"metadata": {
"name": "check-nginx",
"namespace": "default",
"labels": null,
"annotations": null
}
}
}

132
main.go Normal file
View File

@ -0,0 +1,132 @@
package main
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"text/template"
"github.com/sensu/sensu-go/types"
"github.com/spf13/cobra"
"github.com/go-telegram-bot-api/telegram-bot-api"
)
var (
token string
channel int64
subject string
hookout bool
bodyTemplateFile string
stdin *os.File
emailSubjectTemplate = "Sensu Alert - {{.Entity.Name}}/{{.Check.Name}}: {{.Check.State}}"
emailBodyTemplate = "{{.Check.Output}}"
)
func main() {
cmd := &cobra.Command{
Use: "sensu-telegram-handler",
Short: "The Sensu Go Telegram handler for sending an email notification",
RunE: run,
}
cmd.Flags().StringVarP(&token, "token", "t", "", "the telegram bot token")
cmd.Flags().Int64VarP(&channel, "channel", "c", -1, "The channel")
cmd.Flags().BoolVarP(&hookout, "hookout", "H", false, "Include output from check hook(s)")
cmd.Flags().StringVarP(&bodyTemplateFile, "bodyTemplateFile", "T", "", "A template file to use for the body")
cmd.Execute()
}
func run(cmd *cobra.Command, args []string) error {
validationError := checkArgs()
if validationError != nil {
return validationError
}
if stdin == nil {
stdin = os.Stdin
}
eventJSON, err := ioutil.ReadAll(stdin)
if err != nil {
return fmt.Errorf("failed to read stdin: %s", err)
}
event := &types.Event{}
err = json.Unmarshal(eventJSON, event)
if err != nil {
return fmt.Errorf("failed to unmarshal stdin data: %s", err)
}
if err = event.Validate(); err != nil {
return fmt.Errorf("failed to validate event: %s", err)
}
if !event.HasCheck() {
return fmt.Errorf("event does not contain check")
}
sendMsg(event)
return nil
}
func checkArgs() error {
if hookout && len(bodyTemplateFile) > 0 {
return errors.New("--hookout (-H) and --bodyTemplateFile (-T) are mutually exclusive")
}
if hookout {
emailBodyTemplate = "{{.Check.Output}}\n{{range .Check.Hooks}}Hook Name: {{.Name}}\nHook Command: {{.Command}}\n\n{{.Output}}\n\n{{end}}"
} else if len(bodyTemplateFile) > 0 {
templateBytes, fileErr := ioutil.ReadFile(bodyTemplateFile)
if fileErr != nil {
return fmt.Errorf("failed to read specified template file %s", bodyTemplateFile)
}
emailBodyTemplate = string(templateBytes)
}
return nil
}
func sendMsg(event *types.Event) error {
var output string
bot, botErr := tgbotapi.NewBotAPI(token)
if botErr != nil {
return botErr
}
subject, subjectErr := resolveTemplate(emailSubjectTemplate, event)
if subjectErr != nil {
return subjectErr
}
body, bodyErr := resolveTemplate(emailBodyTemplate, event)
if bodyErr != nil {
return bodyErr
}
output = fmt.Sprintf("%s, %s",subject,body)
msg := tgbotapi.NewMessage(channel, output)
_, sendErr := bot.Send(msg)
return sendErr
}
func resolveTemplate(templateValue string, event *types.Event) (string, error) {
var resolved bytes.Buffer
tmpl, err := template.New("test").Parse(templateValue)
if err != nil {
panic(err)
}
err = tmpl.Execute(&resolved, *event)
if err != nil {
panic(err)
}
return resolved.String(), nil
}