Skip to content

Commit

Permalink
Add script notification (#142)
Browse files Browse the repository at this point in the history
  • Loading branch information
crazy-max committed Nov 29, 2020
1 parent c7f628d commit d315593
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 6 deletions.
1 change: 1 addition & 0 deletions docs/config/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,5 @@ Can be transposed to:
* notif
* [mail](notif/mail.md)
* [slack](notif/slack.md)
* [script](notif/script.md)
* [webhook](notif/webhook.md)
50 changes: 50 additions & 0 deletions docs/config/notif/script.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Script notifications

You can call a script when a notification occured. Following environment variables will be passed:

```
FTPGRAB_VERSION=3.0.0
FTPGRAB_SERVER_IP=10.0.0.1
FTPGRAB_DEST_HOSTNAME=my-computer
FTPGRAB_JOURNAL_ENTRIES[0]_FILE=/test/test_changed/1GB.bin
FTPGRAB_JOURNAL_ENTRIES[0]_STATUS=Not included
FTPGRAB_JOURNAL_ENTRIES[0]_LEVEL=skip
FTPGRAB_JOURNAL_ENTRIES[0]_TEXT=
FTPGRAB_JOURNAL_ENTRIES[1]_FILE=/test/test_changed/56a42b12df8d27baa163536e7b10d3c7.png
FTPGRAB_JOURNAL_ENTRIES[1]_STATUS=Not included
FTPGRAB_JOURNAL_ENTRIES[1]_LEVEL=skip
FTPGRAB_JOURNAL_ENTRIES[1]_TEXT=
FTPGRAB_JOURNAL_ENTRIES[2]_FILE=/test/test_special_chars/1024.rnd
FTPGRAB_JOURNAL_ENTRIES[2]_STATUS=Never downloaded
FTPGRAB_JOURNAL_ENTRIES[2]_LEVEL=success
FTPGRAB_JOURNAL_ENTRIES[2]_TEXT=1.049MB successfully downloaded in 513 milliseconds
FTPGRAB_JOURNAL_COUNT_SUCCESS=1
FTPGRAB_JOURNAL_COUNT_SKIP=2
FTPGRAB_JOURNAL_COUNT_ERROR=0
FTPGRAB_JOURNAL_DURATION=12 seconds
```

## Configuration

!!! example "File"
```yaml
notif:
script:
cmd: "myprogram"
args:
- "--anarg"
- "another"
```

| Name | Default | Description |
|-----------------------|---------------|---------------|
| `cmd`[^1] | | Command or script to execute |
| `args` | | List of args to pass to `cmd` |
| `dir` | | Specifies the working directory of the command |

!!! abstract "Environment variables"
* `FTPGRAB_NOTIF_SCRIPT_CMD`
* `FTPGRAB_NOTIF_SCRIPT_ARGS`
* `FTPGRAB_NOTIF_SCRIPT_DIR`

[^1]: Value required
13 changes: 7 additions & 6 deletions docs/config/notif/webhook.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,19 @@ The JSON response will look like this:
"entries": [
{
"file": "/test/test_changed/1GB.bin",
"status_type": "skip",
"status_text": "Not included"
"status": "Not included",
"level": "skip"
},
{
"file": "/test/test_changed/56a42b12df8d27baa163536e7b10d3c7.png",
"status_type": "skip",
"status_text": "Not included"
"status": "Not included",
"level": "skip"
},
{
"file": "/test/test_special_chars/1024.rnd",
"status_type": "success",
"status_text": "1.049MB successfully downloaded in 513 milliseconds"
"status": "Never downloaded",
"level": "success",
"text": "1.049MB successfully downloaded in 513 milliseconds"
}
],
"count": {
Expand Down
6 changes: 6 additions & 0 deletions internal/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ func TestLoadFile(t *testing.T) {
Slack: &NotifSlack{
WebhookURL: "https://hooks.slack.com/services/ABCD12EFG/HIJK34LMN/01234567890abcdefghij",
},
Script: &NotifScript{
Cmd: "uname",
Args: []string{
"-a",
},
},
Webhook: &NotifWebhook{
Endpoint: "http://webhook.foo.com/sd54qad89azd5a",
Method: "GET",
Expand Down
4 changes: 4 additions & 0 deletions internal/config/fixtures/config.test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ notif:
to: [email protected]
slack:
webhookURL: https://hooks.slack.com/services/ABCD12EFG/HIJK34LMN/01234567890abcdefghij
script:
cmd: "uname"
args:
- "-a"
webhook:
endpoint: http://webhook.foo.com/sd54qad89azd5a
method: GET
Expand Down
1 change: 1 addition & 0 deletions internal/config/notif.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package config
type Notif struct {
Mail *NotifMail `yaml:"mail,omitempty" json:"mail,omitempty"`
Slack *NotifSlack `yaml:"slack,omitempty" json:"slack,omitempty"`
Script *NotifScript `yaml:"script,omitempty" json:"script,omitempty"`
Webhook *NotifWebhook `yaml:"webhook,omitempty" json:"webhook,omitempty"`
}

Expand Down
18 changes: 18 additions & 0 deletions internal/config/notif_script.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package config

// NotifScript holds script notification configuration details
type NotifScript struct {
Cmd string `yaml:"cmd,omitempty" json:"cmd,omitempty" validate:"required"`
Args []string `yaml:"args,omitempty" json:"args,omitempty" validate:"omitempty"`
Dir string `yaml:"dir,omitempty" json:"dir,omitempty" validate:"omitempty,dir"`
}

// GetDefaults gets the default values
func (s *NotifScript) GetDefaults() *NotifScript {
return nil
}

// SetDefaults sets the default values
func (s *NotifScript) SetDefaults() {
// noop
}
4 changes: 4 additions & 0 deletions internal/notif/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/crazy-max/ftpgrab/v7/internal/journal"
"github.com/crazy-max/ftpgrab/v7/internal/notif/mail"
"github.com/crazy-max/ftpgrab/v7/internal/notif/notifier"
"github.com/crazy-max/ftpgrab/v7/internal/notif/script"
"github.com/crazy-max/ftpgrab/v7/internal/notif/slack"
"github.com/crazy-max/ftpgrab/v7/internal/notif/webhook"
"github.com/rs/zerolog/log"
Expand Down Expand Up @@ -37,6 +38,9 @@ func New(cfg *config.Notif, meta config.Meta) (*Client, error) {
if cfg.Slack != nil {
c.notifiers = append(c.notifiers, slack.New(cfg.Slack, meta))
}
if cfg.Script != nil {
c.notifiers = append(c.notifiers, script.New(cfg.Script, meta))
}
if cfg.Webhook != nil {
c.notifiers = append(c.notifiers, webhook.New(cfg.Webhook, meta))
}
Expand Down
83 changes: 83 additions & 0 deletions internal/notif/script/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package script

import (
"bytes"
"fmt"
"os"
"os/exec"
"strings"

"github.com/crazy-max/ftpgrab/v7/internal/config"
"github.com/crazy-max/ftpgrab/v7/internal/journal"
"github.com/crazy-max/ftpgrab/v7/internal/notif/notifier"
"github.com/hako/durafmt"
"github.com/pkg/errors"
"github.com/rs/zerolog/log"
)

// Client represents an active script notification object
type Client struct {
*notifier.Notifier
cfg *config.NotifScript
meta config.Meta
}

// New creates a new script notification instance
func New(config *config.NotifScript, meta config.Meta) notifier.Notifier {
return notifier.Notifier{
Handler: &Client{
cfg: config,
meta: meta,
},
}
}

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

// Send creates and sends a slack notification with journal entries
func (c *Client) Send(jnl journal.Journal) error {
cmd := exec.Command(c.cfg.Cmd, c.cfg.Args...)
setSysProcAttr(cmd)

// Capture output
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr

// Set working dir
if c.cfg.Dir != "" {
cmd.Dir = c.cfg.Dir
}

// Set env vars
cmd.Env = append(os.Environ(), []string{
fmt.Sprintf("FTPGRAB_VERSION=%s", c.meta.Version),
fmt.Sprintf("FTPGRAB_SERVER_IP=%s", jnl.ServerHost),
fmt.Sprintf("FTPGRAB_DEST_HOSTNAME=%s", c.meta.Hostname),
}...)
for idx, entry := range jnl.Entries {
cmd.Env = append(cmd.Env, []string{
fmt.Sprintf("FTPGRAB_JOURNAL_ENTRIES[%d]_FILE=%s", idx, entry.File),
fmt.Sprintf("FTPGRAB_JOURNAL_ENTRIES[%d]_STATUS=%s", idx, string(entry.Status)),
fmt.Sprintf("FTPGRAB_JOURNAL_ENTRIES[%d]_LEVEL=%s", idx, string(entry.Level)),
fmt.Sprintf("FTPGRAB_JOURNAL_ENTRIES[%d]_TEXT=%s", idx, entry.Text),
}...)
}
cmd.Env = append(cmd.Env, []string{
fmt.Sprintf("FTPGRAB_JOURNAL_COUNT_SUCCESS=%d", jnl.Count.Success),
fmt.Sprintf("FTPGRAB_JOURNAL_COUNT_ERROR=%d", jnl.Count.Error),
fmt.Sprintf("FTPGRAB_JOURNAL_COUNT_SKIP=%d", jnl.Count.Skip),
fmt.Sprintf("FTPGRAB_JOURNAL_DURATION=%s", durafmt.ParseShort(jnl.Duration).String()),
}...)

// Run
if err := cmd.Run(); err != nil {
return errors.Wrap(err, strings.TrimSpace(stderr.String()))
}

log.Debug().Msgf(strings.TrimSpace(stdout.String()))
return nil
}
10 changes: 10 additions & 0 deletions internal/notif/script/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// +build !windows

package script

import (
"os/exec"
)

func setSysProcAttr(cmd *exec.Cmd) {
}
10 changes: 10 additions & 0 deletions internal/notif/script/cmd_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package script

import (
"os/exec"
"syscall"
)

func setSysProcAttr(cmd *exec.Cmd) {
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
}

0 comments on commit d315593

Please sign in to comment.