Skip to content

Commit

Permalink
send mail (wip)
Browse files Browse the repository at this point in the history
  • Loading branch information
ydkn committed May 9, 2019
1 parent 17be2df commit 45d3c8b
Show file tree
Hide file tree
Showing 20 changed files with 583 additions and 9 deletions.
7 changes: 2 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
FROM golang:1.12-alpine

# Maintainer
MAINTAINER Florian Schwab <me@ydkn.de>
MAINTAINER Florian Schwab <florian.schwab@sic.software>

# Upgrade system
RUN apk --no-cache --no-progress --update upgrade

# Install dependencies
# Install os dependencies
RUN apk --no-cache --no-progress --update add bash build-base git ca-certificates

# Install dep
Expand All @@ -34,8 +34,5 @@ WORKDIR /go/src/sensu-sic-handler
# Copy in the application code
COPY ./ /go/src/sensu-sic-handler

# Install dependencies
RUN dep ensure

# Default command
CMD ["bash"]
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ BINARY_NAME=dist/sensu-sic-handler

all: test build
build:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 $(GOBUILD) -a -ldflags '-w -extldflags "-static"' -o $(BINARY_NAME)
$(GOBUILD) -a -o $(BINARY_NAME)
test:
$(GOTEST)
clean:
Expand Down
14 changes: 12 additions & 2 deletions cmd/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,18 @@ func init() {

eventCmd.PersistentFlags().StringVar(&annotationPrefix,
"annotation-prefix",
os.Getenv("EVENT_ANNOTATION_PREFIX"),
"The annotation prefix to use, defaults to value of EVENT_ANNOTATION_PREFIX env variable")
os.Getenv("ANNOTATION_PREFIX"),
"The annotation prefix to use, defaults to value of ANNOTATION_PREFIX env variable")

eventCmd.PersistentFlags().StringVar(&handlerConfig.SMTPAddress,
"smtp-address",
os.Getenv("SMTP_ADDRESS"),
"The address of the SMTP server to use, defaults to value of SMTP_ADDRESS env variable")

eventCmd.PersistentFlags().StringVar(&handlerConfig.MailFrom,
"mail-from",
os.Getenv("MAIL_FROM"),
"The sender address for emails, defaults to value of MAIL_FROM env variable")
}

func loadEvent() (*types.Event, error) {
Expand Down
2 changes: 2 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,11 @@ func initConfig() {
if redisHost == "" {
redisHost = "localhost"
}

if redisPort == -1 {
redisPort = intValueFromEnvWithDefault("REDIS_PORT", 6379)
}

if redisDB == -1 {
redisDB = intValueFromEnvWithDefault("REDIS_DB", 0)
}
Expand Down
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ services:
volumes:
- ./.data/redis:/data

build:
dev:
depends_on:
- redis
build:
Expand Down
26 changes: 26 additions & 0 deletions handler/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright © 2019 SIC! Software GmbH

package handler

import (
"bytes"
"text/template"

sensu "github.com/sensu/sensu-go/types"
)

func resolveTemplate(templateValue string, event *sensu.Event) (string, error) {
var resolved bytes.Buffer

tmpl, err := template.New("tmpl").Parse(templateValue)
if err != nil {
return "", err
}

err = tmpl.Execute(&resolved, *event)
if err != nil {
return "", err
}

return resolved.String(), nil
}
78 changes: 78 additions & 0 deletions handler/mail.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright © 2019 SIC! Software GmbH

package handler

import (
"bytes"
"errors"
"net/mail"
"net/smtp"

sensu "github.com/sensu/sensu-go/types"

"sensu-sic-handler/recipient"
)

var (
mailSubjectTemplate = "[Sensu] {{.Entity.Name}}/{{.Check.Name}}: {{.Check.State}}"
mailBodyTemplate = "{{.Check.Output}}"
)

// HandleMail handles mail recipients (recipient.HandlerTypeMail)
func HandleMail(recipient *recipient.Recipient, event *sensu.Event, config *Config) error {
if len(config.MailFrom) == 0 {
return errors.New("from email is empty")
}

fromAddress, err := mail.ParseAddress(config.MailFrom)
if err != nil {
return err
}

if len(recipient.Args["mail"]) == 0 {
return errors.New("to email is empty")
}

toAddress, err := mail.ParseAddress(recipient.Args["mail"])
if err != nil {
return err
}

subject, err := resolveTemplate(mailSubjectTemplate, event)
if err != nil {
return err
}

body, err := resolveTemplate(mailBodyTemplate, event)
if err != nil {
return err
}

msg := []byte("From: " + fromAddress.String() + "\r\n" +
"To: " + toAddress.String() + "\r\n" +
"Subject: " + subject + "\r\n" +
"\r\n" +
body + "\r\n")

conn, err := smtp.Dial(config.SMTPAddress)
if err != nil {
return err
}
defer conn.Close()

conn.Mail(fromAddress.Address)
conn.Rcpt(toAddress.Address)

data, err := conn.Data()
if err != nil {
return err
}
defer data.Close()

buffer := bytes.NewBuffer(msg)
if _, err := buffer.WriteTo(data); err != nil {
return err
}

return nil
}
44 changes: 44 additions & 0 deletions handler/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright © 2019 SIC! Software GmbH

package handler

import (
"fmt"
"os"

sensu "github.com/sensu/sensu-go/types"

"sensu-sic-handler/recipient"
)

// Handle handles recipients
func Handle(recipients []*recipient.Recipient, event *sensu.Event, config *Config) error {
recipientMap := make(map[string]bool)

for _, rcpt := range recipients {
if _, ok := recipientMap[rcpt.ID]; !ok {
var err error
err = nil

switch rcpt.Type {
case recipient.HandlerTypeNone:
case recipient.HandlerTypeMail:
err = HandleMail(rcpt, event, config)
case recipient.HandlerTypeXMPP:
err = HandleXMPP(rcpt, event, config)
case recipient.HandlerTypeSlack:
err = HandleSlack(rcpt, event, config)
default:
fmt.Fprintln(os.Stderr, fmt.Sprintf("unsupported handler: %s", rcpt))
}

if err != nil {
fmt.Fprintln(os.Stderr, fmt.Sprintf("failed to handle: %s", err.Error()))
}

recipientMap[rcpt.ID] = true
}
}

return nil
}
14 changes: 14 additions & 0 deletions handler/slack.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright © 2019 SIC! Software GmbH

package handler

import (
sensu "github.com/sensu/sensu-go/types"

"sensu-sic-handler/recipient"
)

// HandleSlack handles slack recipients (recipient.HandlerTypeSlack)
func HandleSlack(recipient *recipient.Recipient, event *sensu.Event, config *Config) error {
return nil
}
9 changes: 9 additions & 0 deletions handler/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright © 2019 SIC! Software GmbH

package handler

// Config configuration for handlers
type Config struct {
SMTPAddress string
MailFrom string
}
14 changes: 14 additions & 0 deletions handler/xmpp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright © 2019 SIC! Software GmbH

package handler

import (
sensu "github.com/sensu/sensu-go/types"

"sensu-sic-handler/recipient"
)

// HandleXMPP handles XMPP recipients (recipient.HandlerTypeXMPP)
func HandleXMPP(recipient *recipient.Recipient, event *sensu.Event, config *Config) error {
return nil
}
28 changes: 28 additions & 0 deletions recipient/mail.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Copyright © 2019 SIC! Software GmbH

package recipient

import (
"fmt"
"strings"

"github.com/go-redis/redis"
)

// ParseMail parse mail recipients (HandlerTypeMail)
func ParseMail(redisClient *redis.Client, value string) []*Recipient {
recipients := make([]*Recipient, 0)

args := strings.Split(value, ":")

switch len(args) {
case 1:
recipients = append(recipients, &Recipient{
Type: HandlerTypeMail,
ID: fmt.Sprintf("mail|%s", args[0]),
Args: map[string]string{"mail": args[0]},
})
}

return recipients
}
36 changes: 36 additions & 0 deletions recipient/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright © 2019 SIC! Software GmbH

package recipient

import (
"fmt"
"os"
"strings"

"github.com/go-redis/redis"
)

// Parse parses recipients from string
func Parse(redisClient *redis.Client, value string) []*Recipient {
recipientDefinitions := strings.Split(value, ",")
recipients := make([]*Recipient, 0)

for _, recipientDefinition := range recipientDefinitions {
val := strings.SplitN(recipientDefinition, ":", 2)

switch val[0] {
case "slack":
recipients = append(recipients, ParseSlack(redisClient, val[1])...)
case "xmpp":
recipients = append(recipients, ParseXMPP(redisClient, val[1])...)
case "mail":
recipients = append(recipients, ParseMail(redisClient, val[1])...)
case "project":
recipients = append(recipients, ParseProject(redisClient, val[1])...)
default:
fmt.Fprintln(os.Stderr, fmt.Sprintf("unsupported recipient: %s", recipientDefinition))
}
}

return recipients
}
57 changes: 57 additions & 0 deletions recipient/project.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Copyright © 2019 SIC! Software GmbH

package recipient

import (
"encoding/json"
"fmt"
"strconv"
"strings"

"github.com/go-redis/redis"

"sensu-sic-handler/redmine"
)

// ParseProject parse redmine project recipients
func ParseProject(redisClient *redis.Client, value string) []*Recipient {
recipients := make([]*Recipient, 0)

args := strings.Split(value, ":")

switch len(args) {
case 2:
mails := readProjectMailsFromRedis(redisClient, args[0], args[1])

for _, m := range mails {
recipients = append(recipients, &Recipient{
Type: HandlerTypeMail,
ID: fmt.Sprintf("mail|%s", m),
Args: map[string]string{"mail": m},
})
}
}

return recipients
}

func readProjectMailsFromRedis(client *redis.Client, projectIdentifier string, roleIDStr string) []string {
var mails []string

roleID, err := strconv.Atoi(roleIDStr)
if err != nil {
return mails
}

val, err := client.Get(redmine.RedisKey(projectIdentifier, roleID, "mail")).Result()
if err != nil {
return mails
}

err = json.Unmarshal([]byte(val), &mails)
if err != nil {
return mails
}

return mails
}
Loading

0 comments on commit 45d3c8b

Please sign in to comment.