make sure that the device host id is provided in notifications (if available).

fixes #337
pull/352/head
Jason Kulatunga 2 years ago
parent 9a4a8de341
commit d41d535ab7

@ -21,5 +21,6 @@ SCRUTINY_DEVICE_NAME - eg. /dev/sda
SCRUTINY_DEVICE_TYPE - ATA/SCSI/NVMe
SCRUTINY_DEVICE_SERIAL - eg. WDDJ324KSO
SCRUTINY_MESSAGE - eg. "Scrutiny SMART error notification for device: %s\nFailure Type: %s\nDevice Name: %s\nDevice Serial: %s\nDevice Type: %s\nDate: %s"
SCRUTINY_HOST_ID - (optional) eg. "my-custom-host-id"
```

@ -101,12 +101,13 @@ func ShouldNotify(device models.Device, smartAttrs measurements.Smart, statusThr
}
}
// TODO: include host and/or user label for device.
// TODO: include user label for device.
type Payload struct {
DeviceType string `json:"device_type"` //ATA/SCSI/NVMe
DeviceName string `json:"device_name"` //dev/sda
DeviceSerial string `json:"device_serial"` //WDDJ324KSO
Test bool `json:"test"` // false
HostId string `json:"host_id,omitempty"` //host id (optional)
DeviceType string `json:"device_type"` //ATA/SCSI/NVMe
DeviceName string `json:"device_name"` //dev/sda
DeviceSerial string `json:"device_serial"` //WDDJ324KSO
Test bool `json:"test"` // false
//private, populated during init (marked as Public for JSON serialization)
Date string `json:"date"` //populated by Send function.
@ -115,8 +116,9 @@ type Payload struct {
Message string `json:"message"`
}
func NewPayload(device models.Device, test bool) Payload {
func NewPayload(device models.Device, test bool, currentTime ...time.Time) Payload {
payload := Payload{
HostId: strings.TrimSpace(device.HostId),
DeviceType: device.DeviceType,
DeviceName: device.DeviceName,
DeviceSerial: device.SerialNumber,
@ -124,7 +126,13 @@ func NewPayload(device models.Device, test bool) Payload {
}
//validate that the Payload is populated
sendDate := time.Now()
var sendDate time.Time
if currentTime != nil && len(currentTime) > 0 {
sendDate = currentTime[0]
} else {
sendDate = time.Now()
}
payload.Date = sendDate.Format(time.RFC3339)
payload.FailureType = payload.GenerateFailureType(device.DeviceStatus)
payload.Subject = payload.GenerateSubject()
@ -148,25 +156,39 @@ func (p *Payload) GenerateFailureType(deviceStatus pkg.DeviceStatus) 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)
var subject string
if len(p.HostId) > 0 {
subject = fmt.Sprintf("Scrutiny SMART error (%s) detected on [host]device: [%s]%s", p.FailureType, p.HostId, p.DeviceName)
} else {
subject = fmt.Sprintf("Scrutiny SMART error (%s) detected on device: %s", p.FailureType, p.DeviceName)
}
return subject
}
func (p *Payload) GenerateMessage() string {
//generate a detailed failure message
message := fmt.Sprintf(
`Scrutiny SMART error notification for device: %s
Failure Type: %s
Device Name: %s
Device Serial: %s
Device Type: %s
Date: %s`, p.DeviceName, p.FailureType, p.DeviceName, p.DeviceSerial, p.DeviceType, p.Date)
messageParts := []string{}
messageParts = append(messageParts, fmt.Sprintf("Scrutiny SMART error notification for device: %s", p.DeviceName))
if len(p.HostId) > 0 {
messageParts = append(messageParts, fmt.Sprintf("Host Id: %s", p.HostId))
}
messageParts = append(messageParts,
fmt.Sprintf("Failure Type: %s", p.FailureType),
fmt.Sprintf("Device Name: %s", p.DeviceName),
fmt.Sprintf("Device Serial: %s", p.DeviceSerial),
fmt.Sprintf("Device Type: %s", p.DeviceType),
"",
fmt.Sprintf("Date: %s", p.Date),
)
if p.Test {
message = "TEST NOTIFICATION:\n" + message
messageParts = append([]string{"TEST NOTIFICATION:"}, messageParts...)
}
return message
return strings.Join(messageParts, "\n")
}
func New(logger logrus.FieldLogger, appconfig config.Interface, device models.Device, test bool) Notify {
@ -287,6 +309,9 @@ func (n *Notify) SendScriptNotification(scriptUrl string) error {
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.Message))
if len(n.Payload.HostId) > 0 {
copyEnv = append(copyEnv, fmt.Sprintf("SCRUTINY_HOST_ID=%s", n.Payload.HostId))
}
err := utils.CmdExec(scriptPath, []string{}, "", copyEnv, "")
if err != nil {
n.Logger.Errorf("An error occurred while executing script %s: %v", scriptPath, err)

@ -1,11 +1,13 @@
package notify
import (
"fmt"
"github.com/analogj/scrutiny/webapp/backend/pkg"
"github.com/analogj/scrutiny/webapp/backend/pkg/models"
"github.com/analogj/scrutiny/webapp/backend/pkg/models/measurements"
"github.com/stretchr/testify/require"
"testing"
"time"
)
func TestShouldNotify_MustSkipPassingDevices(t *testing.T) {
@ -159,3 +161,84 @@ func TestShouldNotify_MetricsStatusFilterAttributesCritical_MetricsStatusThresho
//assert
require.False(t, ShouldNotify(device, smartAttrs, statusThreshold, notifyFilterAttributes))
}
func TestNewPayload(t *testing.T) {
t.Parallel()
//setup
device := models.Device{
SerialNumber: "FAKEWDDJ324KSO",
DeviceType: pkg.DeviceProtocolAta,
DeviceName: "/dev/sda",
DeviceStatus: pkg.DeviceStatusFailedScrutiny,
}
currentTime := time.Now()
//test
payload := NewPayload(device, false, currentTime)
//assert
require.Equal(t, "Scrutiny SMART error (ScrutinyFailure) detected on device: /dev/sda", payload.Subject)
require.Equal(t, fmt.Sprintf(`Scrutiny SMART error notification for device: /dev/sda
Failure Type: ScrutinyFailure
Device Name: /dev/sda
Device Serial: FAKEWDDJ324KSO
Device Type: ATA
Date: %s`, currentTime.Format(time.RFC3339)), payload.Message)
}
func TestNewPayload_TestMode(t *testing.T) {
t.Parallel()
//setup
device := models.Device{
SerialNumber: "FAKEWDDJ324KSO",
DeviceType: pkg.DeviceProtocolAta,
DeviceName: "/dev/sda",
DeviceStatus: pkg.DeviceStatusFailedScrutiny,
}
currentTime := time.Now()
//test
payload := NewPayload(device, true, currentTime)
//assert
require.Equal(t, "Scrutiny SMART error (EmailTest) detected on device: /dev/sda", payload.Subject)
require.Equal(t, fmt.Sprintf(`TEST NOTIFICATION:
Scrutiny SMART error notification for device: /dev/sda
Failure Type: EmailTest
Device Name: /dev/sda
Device Serial: FAKEWDDJ324KSO
Device Type: ATA
Date: %s`, currentTime.Format(time.RFC3339)), payload.Message)
}
func TestNewPayload_WithHostId(t *testing.T) {
t.Parallel()
//setup
device := models.Device{
SerialNumber: "FAKEWDDJ324KSO",
DeviceType: pkg.DeviceProtocolAta,
DeviceName: "/dev/sda",
DeviceStatus: pkg.DeviceStatusFailedScrutiny,
HostId: "custom-host",
}
currentTime := time.Now()
//test
payload := NewPayload(device, false, currentTime)
//assert
require.Equal(t, "Scrutiny SMART error (ScrutinyFailure) detected on [host]device: [custom-host]/dev/sda", payload.Subject)
require.Equal(t, fmt.Sprintf(`Scrutiny SMART error notification for device: /dev/sda
Host Id: custom-host
Failure Type: ScrutinyFailure
Device Name: /dev/sda
Device Serial: FAKEWDDJ324KSO
Device Type: ATA
Date: %s`, currentTime.Format(time.RFC3339)), payload.Message)
}

Loading…
Cancel
Save