Skip to content

Commit

Permalink
Add Slack notifier (crazy-max#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
crazy-max committed Dec 17, 2019
1 parent ce81972 commit 2a7901f
Show file tree
Hide file tree
Showing 16 changed files with 168 additions and 41 deletions.
Binary file added .res/notif-slack.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 2.1.0 (2019/12/17)

* Add Slack notifier (#8)

## 2.0.0 (2019/12/14)

* Include provider in notifications
Expand Down
7 changes: 7 additions & 0 deletions doc/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ notif:
password:
from:
to:
slack:
enable: false
webhook_url: https://hooks.slack.com/services/ABCD12EFG/HIJK34LMN/01234567890abcdefghij
webhook:
enable: false
endpoint: http://webhook.foo.com/sd54qad89azd5a
Expand Down Expand Up @@ -107,6 +110,10 @@ providers:
* `from`: Sender email address. **required**
* `to`: Recipient email address. **required**

* `slack`
* `enable`: Enable slack notification (default: `false`).
* `webhook_url`: Slack [incoming webhook URL](https://api.slack.com/messaging/webhooks). **required**

* `webhook`
* `enable`: Enable webhook notification (default: `false`).
* `endpoint`: URL of the HTTP request. **required**
Expand Down
7 changes: 7 additions & 0 deletions doc/notifications.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Notifications

* [Mail](#mail)
* [Slack](#slack)
* [Webhook](#webhook)

## Mail
Expand All @@ -9,6 +10,12 @@ Here is an email sample if you add `mail` notification:

![](../.res/notif-mail.png)

## Slack

You can send notifications to your slack channel using an [incoming webhook URL](https://api.slack.com/messaging/webhooks):

![](../.res/notif-slack.png)

## Webhook

If you choose `webhook` notification, a HTTP request is sent with a JSON format response that looks like:
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ require (
github.com/imdario/mergo v0.3.8
github.com/matcornic/hermes/v2 v2.0.2
github.com/morikuni/aec v1.0.0 // indirect
github.com/nlopes/slack v0.6.0
github.com/opencontainers/go-digest v1.0.0-rc1
github.com/opencontainers/image-spec v1.0.1 // indirect
github.com/panjf2000/ants/v2 v2.2.2
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ=
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/hako/durafmt v0.0.0-20190612201238-650ed9f29a84 h1:RvcDqcKLua4b/jtXez7ZVe9s6Iq5N6ujVevqY4FBQmM=
github.com/hako/durafmt v0.0.0-20190612201238-650ed9f29a84/go.mod h1:5Scbynm8dF1XAPwIwkGPqzkM/shndPm79Jd1003hTjE=
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
Expand Down Expand Up @@ -136,6 +138,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nlopes/slack v0.6.0 h1:jt0jxVQGhssx1Ib7naAOZEZcGdtIhTzkP0nopK0AsRA=
github.com/nlopes/slack v0.6.0/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk=
github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88=
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
Expand Down
7 changes: 5 additions & 2 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,17 @@ func Load(flags model.Flags, version string) (*Config, error) {
Schedule: "0 * * * *",
},
Notif: model.Notif{
Mail: model.Mail{
Mail: model.NotifMail{
Enable: false,
Host: "localhost",
Port: 25,
SSL: false,
InsecureSkipVerify: false,
},
Webhook: model.Webhook{
Slack: model.NotifSlack{
Enable: false,
},
Webhook: model.NotifWebhook{
Enable: false,
Method: "GET",
Timeout: 10,
Expand Down
3 changes: 3 additions & 0 deletions internal/config/config.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ notif:
password_file:
from:
to:
slack:
enable: false
webhook_url: https://hooks.slack.com/services/ABCD12EFG/HIJK34LMN/01234567890abcdefghij
webhook:
enable: false
endpoint: http://webhook.foo.com/sd54qad89azd5a
Expand Down
8 changes: 6 additions & 2 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,18 @@ func TestLoad(t *testing.T) {
Schedule: "*/30 * * * *",
},
Notif: model.Notif{
Mail: model.Mail{
Mail: model.NotifMail{
Enable: false,
Host: "localhost",
Port: 25,
SSL: false,
InsecureSkipVerify: false,
},
Webhook: model.Webhook{
Slack: model.NotifSlack{
Enable: false,
WebhookURL: "https://hooks.slack.com/services/ABCD12EFG/HIJK34LMN/01234567890abcdefghij",
},
Webhook: model.NotifWebhook{
Enable: false,
Endpoint: "http://webhook.foo.com/sd54qad89azd5a",
Method: "GET",
Expand Down
16 changes: 0 additions & 16 deletions internal/model/mail.go

This file was deleted.

43 changes: 37 additions & 6 deletions internal/model/notif.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,47 @@ import (
"github.com/crazy-max/diun/pkg/docker/registry"
)

// Notif holds data necessary for notification configuration
type Notif struct {
Mail Mail `yaml:"mail,omitempty"`
Webhook Webhook `yaml:"webhook,omitempty"`
}

// NotifEntry represents a notification entry
type NotifEntry struct {
Status ImageStatus `json:"status,omitempty"`
Provider string `json:"provider,omitempty"`
Image registry.Image `json:"image,omitempty"`
Manifest docker.Manifest `json:"manifest,omitempty"`
}

// Notif holds data necessary for notification configuration
type Notif struct {
Mail NotifMail `yaml:"mail,omitempty"`
Slack NotifSlack `yaml:"slack,omitempty"`
Webhook NotifWebhook `yaml:"webhook,omitempty"`
}

// NotifMail holds mail notification configuration details
type NotifMail struct {
Enable bool `yaml:"enable,omitempty"`
Host string `yaml:"host,omitempty"`
Port int `yaml:"port,omitempty"`
SSL bool `yaml:"ssl,omitempty"`
InsecureSkipVerify bool `yaml:"insecure_skip_verify,omitempty"`
Username string `yaml:"username,omitempty"`
UsernameFile string `yaml:"username_file,omitempty"`
Password string `yaml:"password,omitempty"`
PasswordFile string `yaml:"password_file,omitempty"`
From string `yaml:"from,omitempty"`
To string `yaml:"to,omitempty"`
}

// NotifSlack holds slack notification configuration details
type NotifSlack struct {
Enable bool `yaml:"enable,omitempty"`
WebhookURL string `yaml:"webhook_url,omitempty"`
}

// NotifWebhook holds webhook notification configuration details
type NotifWebhook struct {
Enable bool `yaml:"enable,omitempty"`
Endpoint string `yaml:"endpoint,omitempty"`
Method string `yaml:"method,omitempty"`
Headers map[string]string `yaml:"headers,omitempty"`
Timeout int `yaml:"timeout,omitempty"`
}
10 changes: 0 additions & 10 deletions internal/model/webhook.go

This file was deleted.

4 changes: 4 additions & 0 deletions internal/notif/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/crazy-max/diun/internal/model"
"github.com/crazy-max/diun/internal/notif/mail"
"github.com/crazy-max/diun/internal/notif/notifier"
"github.com/crazy-max/diun/internal/notif/slack"
"github.com/crazy-max/diun/internal/notif/webhook"
"github.com/rs/zerolog/log"
)
Expand All @@ -27,6 +28,9 @@ func New(config model.Notif, app model.App) (*Client, error) {
if config.Mail.Enable {
c.notifiers = append(c.notifiers, mail.New(config.Mail, app))
}
if config.Slack.Enable {
c.notifiers = append(c.notifiers, slack.New(config.Slack, app))
}
if config.Webhook.Enable {
c.notifiers = append(c.notifiers, webhook.New(config.Webhook, app))
}
Expand Down
6 changes: 3 additions & 3 deletions internal/notif/mail/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ import (
// Client represents an active mail notification object
type Client struct {
*notifier.Notifier
cfg model.Mail
cfg model.NotifMail
app model.App
}

// New creates a new mail notification instance
func New(config model.Mail, app model.App) notifier.Notifier {
func New(config model.NotifMail, app model.App) notifier.Notifier {
return notifier.Notifier{
Handler: &Client{
cfg: config,
Expand Down Expand Up @@ -65,7 +65,7 @@ func (c *Client) Send(entry model.NotifEntry) error {
Docker 🐳 tag **{{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }}** which you subscribed to through **{{ .Provider }}** provider has been {{ if (eq .Status "new") }}newly added{{ else }}updated{{ end }}.
This image has been {{ if (eq .Status "new") }}created{{ else }}updated{{ end }} at <code>{{ .Manifest.Created }}</code> with digest <code>{{ .Manifest.Digest }}</code> for <code>{{ .Manifest.Os }}/{{ .Manifest.Architecture }}</code> platform.
This image has been {{ if (eq .Status "new") }}created{{ else }}updated{{ end }} at <code>{{ .Manifest.Created.Format "Jan 02, 2006 15:04:05 UTC" }}</code> with digest <code>{{ .Manifest.Digest }}</code> for <code>{{ .Manifest.Os }}/{{ .Manifest.Architecture }}</code> platform.
Need help, or have questions? Go to https://github.com/crazy-max/diun and leave an issue.
Expand Down
85 changes: 85 additions & 0 deletions internal/notif/slack/slack.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package slack

import (
"bytes"
"encoding/json"
"fmt"
"strconv"
"text/template"
"time"

"github.com/crazy-max/diun/internal/model"
"github.com/crazy-max/diun/internal/notif/notifier"
"github.com/nlopes/slack"
)

// Client represents an active slack notification object
type Client struct {
*notifier.Notifier
cfg model.NotifSlack
app model.App
}

// New creates a new slack notification instance
func New(config model.NotifSlack, app model.App) notifier.Notifier {
return notifier.Notifier{
Handler: &Client{
cfg: config,
app: app,
},
}
}

// Name returns notifier's name
func (c *Client) Name() string {
return "slack"
}

// Send creates and sends a webhook notification with an entry
func (c *Client) Send(entry model.NotifEntry) error {
var textBuf bytes.Buffer
textTpl := template.Must(template.New("text").Parse("<!channel> Docker tag `{{ .Image.Domain }}/{{ .Image.Path }}:{{ .Image.Tag }}` {{ if (eq .Status \"new\") }}newly added{{ else }}updated{{ end }}."))
if err := textTpl.Execute(&textBuf, entry); err != nil {
return err
}

color := "#4caf50"
if entry.Status == model.ImageStatusUpdate {
color = "#0054ca"
}

return slack.PostWebhook(c.cfg.WebhookURL, &slack.WebhookMessage{
Attachments: []slack.Attachment{slack.Attachment{
Color: color,
AuthorName: "Diun",
AuthorSubname: "github.com/crazy-max/diun",
AuthorLink: "https://github.com/crazy-max/diun",
AuthorIcon: "https://raw.githubusercontent.com/crazy-max/diun/master/.res/diun.png",
Text: textBuf.String(),
Footer: fmt.Sprintf("%s © %d %s %s", c.app.Author, time.Now().Year(), c.app.Name, c.app.Version),
Fields: []slack.AttachmentField{
{
Title: "Provider",
Value: entry.Provider,
Short: false,
},
{
Title: "Created",
Value: entry.Manifest.Created.Format("Jan 02, 2006 15:04:05 UTC"),
Short: false,
},
{
Title: "Digest",
Value: entry.Manifest.Digest.String(),
Short: false,
},
{
Title: "Platform",
Value: fmt.Sprintf("%s/%s", entry.Manifest.Os, entry.Manifest.Architecture),
Short: false,
},
},
Ts: json.Number(strconv.FormatInt(time.Now().Unix(), 10)),
}},
})
}
4 changes: 2 additions & 2 deletions internal/notif/webhook/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ import (
// Client represents an active webhook notification object
type Client struct {
*notifier.Notifier
cfg model.Webhook
cfg model.NotifWebhook
app model.App
}

// New creates a new webhook notification instance
func New(config model.Webhook, app model.App) notifier.Notifier {
func New(config model.NotifWebhook, app model.App) notifier.Notifier {
return notifier.Notifier{
Handler: &Client{
cfg: config,
Expand Down

0 comments on commit 2a7901f

Please sign in to comment.