From 2a7901f15df6433fc9b22fc4dbb84e5ac5362e50 Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Tue, 17 Dec 2019 23:40:03 +0100 Subject: [PATCH] Add Slack notifier (#8) --- .res/notif-slack.png | Bin 0 -> 21142 bytes CHANGELOG.md | 4 ++ doc/configuration.md | 7 +++ doc/notifications.md | 7 +++ go.mod | 1 + go.sum | 4 ++ internal/config/config.go | 7 ++- internal/config/config.test.yml | 3 ++ internal/config/config_test.go | 8 ++- internal/model/mail.go | 16 ------ internal/model/notif.go | 43 +++++++++++++--- internal/model/webhook.go | 10 ---- internal/notif/client.go | 4 ++ internal/notif/mail/client.go | 6 +-- internal/notif/slack/slack.go | 85 +++++++++++++++++++++++++++++++ internal/notif/webhook/client.go | 4 +- 16 files changed, 168 insertions(+), 41 deletions(-) create mode 100644 .res/notif-slack.png delete mode 100644 internal/model/mail.go delete mode 100644 internal/model/webhook.go create mode 100644 internal/notif/slack/slack.go diff --git a/.res/notif-slack.png b/.res/notif-slack.png new file mode 100644 index 0000000000000000000000000000000000000000..c2f46295c8dbe8b04933c5bf10ea5fa08da61718 GIT binary patch literal 21142 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 U)r-_H;NSsMBMZYSeb4xR0ZAz<%m4rY literal 0 HcmV?d00001 diff --git a/CHANGELOG.md b/CHANGELOG.md index 13556217..87d15e32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/doc/configuration.md b/doc/configuration.md index e35557dc..9203f1ab 100644 --- a/doc/configuration.md +++ b/doc/configuration.md @@ -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 @@ -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** diff --git a/doc/notifications.md b/doc/notifications.md index 2216c1ae..16b58ad5 100644 --- a/doc/notifications.md +++ b/doc/notifications.md @@ -1,6 +1,7 @@ # Notifications * [Mail](#mail) +* [Slack](#slack) * [Webhook](#webhook) ## Mail @@ -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: diff --git a/go.mod b/go.mod index f3f9a2ac..100c4016 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index fec4897d..d4a30733 100644 --- a/go.sum +++ b/go.sum @@ -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= @@ -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= diff --git a/internal/config/config.go b/internal/config/config.go index 9ae4c203..db786386 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -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, diff --git a/internal/config/config.test.yml b/internal/config/config.test.yml index 227897c5..e05250ef 100644 --- a/internal/config/config.test.yml +++ b/internal/config/config.test.yml @@ -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 diff --git a/internal/config/config_test.go b/internal/config/config_test.go index f1416e29..7c31ae87 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -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", diff --git a/internal/model/mail.go b/internal/model/mail.go deleted file mode 100644 index 0b15d4d3..00000000 --- a/internal/model/mail.go +++ /dev/null @@ -1,16 +0,0 @@ -package model - -// Mail holds mail notification configuration details -type Mail 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"` -} diff --git a/internal/model/notif.go b/internal/model/notif.go index a3f80ba4..0d136755 100644 --- a/internal/model/notif.go +++ b/internal/model/notif.go @@ -5,12 +5,6 @@ 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"` @@ -18,3 +12,40 @@ type NotifEntry struct { 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"` +} diff --git a/internal/model/webhook.go b/internal/model/webhook.go deleted file mode 100644 index 301fbb0e..00000000 --- a/internal/model/webhook.go +++ /dev/null @@ -1,10 +0,0 @@ -package model - -// Webhook holds webhook notification configuration details -type Webhook 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"` -} diff --git a/internal/notif/client.go b/internal/notif/client.go index e381934d..a53ce0a1 100644 --- a/internal/notif/client.go +++ b/internal/notif/client.go @@ -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" ) @@ -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)) } diff --git a/internal/notif/mail/client.go b/internal/notif/mail/client.go index 6209ed2d..b5b6b2ce 100644 --- a/internal/notif/mail/client.go +++ b/internal/notif/mail/client.go @@ -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, @@ -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 {{ .Manifest.Created }} with digest {{ .Manifest.Digest }} for {{ .Manifest.Os }}/{{ .Manifest.Architecture }} platform. +This image has been {{ if (eq .Status "new") }}created{{ else }}updated{{ end }} at {{ .Manifest.Created.Format "Jan 02, 2006 15:04:05 UTC" }} with digest {{ .Manifest.Digest }} for {{ .Manifest.Os }}/{{ .Manifest.Architecture }} platform. Need help, or have questions? Go to https://github.com/crazy-max/diun and leave an issue. diff --git a/internal/notif/slack/slack.go b/internal/notif/slack/slack.go new file mode 100644 index 00000000..5327ac62 --- /dev/null +++ b/internal/notif/slack/slack.go @@ -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(" 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)), + }}, + }) +} diff --git a/internal/notif/webhook/client.go b/internal/notif/webhook/client.go index a3054986..8267f64f 100644 --- a/internal/notif/webhook/client.go +++ b/internal/notif/webhook/client.go @@ -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,