You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
3.9 KiB
112 lines
3.9 KiB
package db
|
|
|
|
import (
|
|
"github.com/analogj/scrutiny/webapp/backend/pkg/metadata"
|
|
"github.com/jinzhu/gorm"
|
|
"strings"
|
|
)
|
|
|
|
const SmartAttributeStatusPassed = "passed"
|
|
const SmartAttributeStatusFailed = "failed"
|
|
const SmartAttributeStatusWarning = "warn"
|
|
|
|
type SmartAtaAttribute struct {
|
|
gorm.Model
|
|
|
|
SmartId int `json:"smart_id"`
|
|
Smart Device `json:"-" gorm:"foreignkey:SmartId"` // use SmartId as foreign key
|
|
|
|
AttributeId int `json:"attribute_id"`
|
|
Name string `json:"name"`
|
|
Value int `json:"value"`
|
|
Worst int `json:"worst"`
|
|
Threshold int `json:"thresh"`
|
|
RawValue int64 `json:"raw_value"`
|
|
RawString string `json:"raw_string"`
|
|
WhenFailed string `json:"when_failed"`
|
|
|
|
TransformedValue int64 `json:"transformed_value"`
|
|
Status string `gorm:"-" json:"status,omitempty"`
|
|
StatusReason string `gorm:"-" json:"status_reason,omitempty"`
|
|
FailureRate float64 `gorm:"-" json:"failure_rate,omitempty"`
|
|
History []SmartAtaAttribute `gorm:"-" json:"history,omitempty"`
|
|
}
|
|
|
|
//populate attribute status, using SMART Thresholds & Observed Metadata
|
|
func (sa *SmartAtaAttribute) PopulateAttributeStatus() {
|
|
if strings.ToUpper(sa.WhenFailed) == SmartWhenFailedFailingNow {
|
|
//this attribute has previously failed
|
|
sa.Status = SmartAttributeStatusFailed
|
|
sa.StatusReason = "Attribute is failing manufacturer SMART threshold"
|
|
|
|
} else if strings.ToUpper(sa.WhenFailed) == SmartWhenFailedInThePast {
|
|
sa.Status = SmartAttributeStatusWarning
|
|
sa.StatusReason = "Attribute has previously failed manufacturer SMART threshold"
|
|
}
|
|
|
|
if smartMetadata, ok := metadata.AtaMetadata[sa.AttributeId]; ok {
|
|
sa.MetadataObservedThresholdStatus(smartMetadata)
|
|
}
|
|
|
|
//check if status is blank, set to "passed"
|
|
if len(sa.Status) == 0 {
|
|
sa.Status = SmartAttributeStatusPassed
|
|
}
|
|
}
|
|
|
|
// compare the attribute (raw, normalized, transformed) value to observed thresholds, and update status if necessary
|
|
func (sa *SmartAtaAttribute) MetadataObservedThresholdStatus(smartMetadata metadata.AtaAttributeMetadata) {
|
|
//TODO: multiple rules
|
|
// try to predict the failure rates for observed thresholds that have 0 failure rate and error bars.
|
|
// - if the attribute is critical
|
|
// - the failure rate is over 10 - set to failed
|
|
// - the attribute does not match any threshold, set to warn
|
|
// - if the attribute is not critical
|
|
// - if failure rate is above 20 - set to failed
|
|
// - if failure rate is above 10 but below 20 - set to warn
|
|
|
|
//update the smart attribute status based on Observed thresholds.
|
|
var value int64
|
|
if smartMetadata.DisplayType == metadata.AtaSmartAttributeDisplayTypeNormalized {
|
|
value = int64(sa.Value)
|
|
} else if smartMetadata.DisplayType == metadata.AtaSmartAttributeDisplayTypeTransformed {
|
|
value = sa.TransformedValue
|
|
} else {
|
|
value = sa.RawValue
|
|
}
|
|
|
|
for _, obsThresh := range smartMetadata.ObservedThresholds {
|
|
|
|
//check if "value" is in this bucket
|
|
if ((obsThresh.Low == obsThresh.High) && value == obsThresh.Low) ||
|
|
(obsThresh.Low < value && value <= obsThresh.High) {
|
|
sa.FailureRate = obsThresh.AnnualFailureRate
|
|
|
|
if smartMetadata.Critical {
|
|
if obsThresh.AnnualFailureRate >= 0.10 {
|
|
sa.Status = SmartAttributeStatusFailed
|
|
sa.StatusReason = "Observed Failure Rate for Critical Attribute is greater than 10%"
|
|
}
|
|
} else {
|
|
if obsThresh.AnnualFailureRate >= 0.20 {
|
|
sa.Status = SmartAttributeStatusFailed
|
|
sa.StatusReason = "Observed Failure Rate for Attribute is greater than 20%"
|
|
} else if obsThresh.AnnualFailureRate >= 0.10 {
|
|
sa.Status = SmartAttributeStatusWarning
|
|
sa.StatusReason = "Observed Failure Rate for Attribute is greater than 10%"
|
|
}
|
|
}
|
|
|
|
//we've found the correct bucket, we can drop out of this loop
|
|
return
|
|
}
|
|
}
|
|
// no bucket found
|
|
if smartMetadata.Critical {
|
|
sa.Status = SmartAttributeStatusWarning
|
|
sa.StatusReason = "Could not determine Observed Failure Rate for Critical Attribute"
|
|
}
|
|
|
|
return
|
|
}
|