diff --git a/README.md b/README.md index 4e09f87..770eacb 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,34 @@ We support a global YAML configuration file that must be located at /scrutiny/co Check the [example.scrutiny.yml](example.scrutiny.yaml) file for a fully commented version. +## Notifications + +Scrutiny supports sending SMART device failure notifications via the following services: +- Email +- Webhooks +- Discord +- Gotify +- Hangouts +- IFTTT +- Join +- Mattermost +- Pushbullet +- Pushover +- Slack +- Teams +- Telegram +- Tulip + +Check the `notify.urls` section of [example.scrutiny.yml](example.scrutiny.yaml) for more information and documentation for service specific setup. + +### Testing Notifications + +You can test that your notifications are configured correctly by posting an empty payload to the notifications health check API. + +``` +curl -X POST http://localhost:8080/api/health/notify +``` + # Contributing Please see the [CONTRIBUTING.md](CONTRIBUTING.md) for instructions for how to develop and contribute to the scrutiny codebase. diff --git a/example.scrutiny.yaml b/example.scrutiny.yaml index c2461eb..2846f46 100644 --- a/example.scrutiny.yaml +++ b/example.scrutiny.yaml @@ -33,6 +33,9 @@ log: level: INFO +# Notification "urls" look like the following. For more information about service specific configuration see +# Shoutrrr's documentation: https://containrrr.dev/shoutrrr/services/overview/ + #notify: # urls: # - "discord://token@channel" @@ -51,8 +54,12 @@ log: # - "script:///file/path/on/disk" # - "https://www.example.com/path" - +######################################################################################################################## +# FEATURES COMING SOON +# # The following commented out sections are a preview of additional configuration options that will be available soon. +# +######################################################################################################################## #disks: # include: diff --git a/webapp/backend/pkg/notify/notify.go b/webapp/backend/pkg/notify/notify.go index f2ccedc..e70334d 100644 --- a/webapp/backend/pkg/notify/notify.go +++ b/webapp/backend/pkg/notify/notify.go @@ -28,17 +28,21 @@ type Payload struct { Date string `json:"date"` //populated by Send function. FailureType string `json:"failure_type"` //EmailTest, SmartFail, ScrutinyFail DeviceType string `json:"device_type"` //ATA/SCSI/NVMe - DeviceName string `json:"device_string"` //dev/sda - DeviceSerial string `json:"device"` //WDDJ324KSO - Test bool `json:"-"` // false + DeviceName string `json:"device_name"` //dev/sda + DeviceSerial string `json:"device_serial"` //WDDJ324KSO + Test bool `json:"test"` // false + + //should not be populated + Subject string `json:"subject"` + Message string `json:"message"` } -func (p *Payload) GenerateMessage() string { +func (p *Payload) GenerateSubject() string { //generate a detailed failure message return fmt.Sprintf("Scrutiny SMART error (%s) detected on device: %s", p.FailureType, p.DeviceName) } -func (p *Payload) GenerateSubject() string { +func (p *Payload) GenerateMessage() string { //generate a detailed failure message message := fmt.Sprintf( `Scrutiny SMART error notification for device: %s @@ -66,6 +70,8 @@ func (n *Notify) Send() error { //validate that the Payload is populated sendDate := time.Now() n.Payload.Date = sendDate.Format(time.RFC3339) + n.Payload.Subject = n.Payload.GenerateSubject() + n.Payload.Message = n.Payload.GenerateMessage() //retrieve list of notification endpoints from config file configUrls := n.Config.GetStringSlice("notify.urls") @@ -155,13 +161,13 @@ func (n *Notify) SendScriptNotification(wg *sync.WaitGroup, scriptUrl string) { } copyEnv := os.Environ() - copyEnv = append(copyEnv, fmt.Sprintf("SCRUTINY_SUBJECT=%s", n.Payload.GenerateSubject())) + copyEnv = append(copyEnv, fmt.Sprintf("SCRUTINY_SUBJECT=%s", n.Payload.Subject)) copyEnv = append(copyEnv, fmt.Sprintf("SCRUTINY_DATE=%s", n.Payload.Date)) copyEnv = append(copyEnv, fmt.Sprintf("SCRUTINY_FAILURE_TYPE=%s", n.Payload.FailureType)) copyEnv = append(copyEnv, fmt.Sprintf("SCRUTINY_DEVICE_NAME=%s", n.Payload.DeviceName)) copyEnv = append(copyEnv, fmt.Sprintf("SCRUTINY_DEVICE_TYPE=%s", n.Payload.DeviceType)) copyEnv = append(copyEnv, fmt.Sprintf("SCRUTINY_DEVICE_SERIAL=%s", n.Payload.DeviceSerial)) - copyEnv = append(copyEnv, fmt.Sprintf("SCRUTINY_MESSAGE=%s", n.Payload.GenerateMessage())) + copyEnv = append(copyEnv, fmt.Sprintf("SCRUTINY_MESSAGE=%s", n.Payload.Message)) err := utils.CmdExec(scriptPath, []string{}, "", copyEnv, "") if err != nil { n.Logger.Errorf("An error occurred while executing script %s: %v", scriptPath, err) @@ -189,7 +195,7 @@ func (n *Notify) SendShoutrrrNotification(wg *sync.WaitGroup, shoutrrrUrl string n.Logger.Errorf("An error occurred occurred while generating notification payload for %s:\n %v", serviceName, shoutrrrUrl, err) } - errs := sender.Send(n.Payload.GenerateMessage(), params) + errs := sender.Send(n.Payload.Message, params) if len(errs) > 0 { n.Logger.Errorf("One or more errors occurred occurred while sending notifications for %s:\n %v", shoutrrrUrl, errs) for _, err := range errs { @@ -208,7 +214,7 @@ func (n *Notify) GenShoutrrrNotificationParams(shoutrrrUrl string) (string, *sho params := &shoutrrrTypes.Params{} logoUrl := "https://raw.githubusercontent.com/AnalogJ/scrutiny/master/webapp/frontend/src/ms-icon-144x144.png" - subject := n.Payload.GenerateSubject() + subject := n.Payload.Subject switch serviceName { // no params supported for these services case "discord", "hangouts", "ifttt", "mattermost", "teams":