ensure that all buckets are created during init. Remove all references to "name" field for attributes (shoudl come from metadata instead). Status is now an int64 (0 is passing).
This commit is contained in:
@@ -4,9 +4,9 @@ const DeviceProtocolAta = "ATA"
|
|||||||
const DeviceProtocolScsi = "SCSI"
|
const DeviceProtocolScsi = "SCSI"
|
||||||
const DeviceProtocolNvme = "NVMe"
|
const DeviceProtocolNvme = "NVMe"
|
||||||
|
|
||||||
const SmartAttributeStatusPassed = "passed"
|
const SmartAttributeStatusPassed = 0
|
||||||
const SmartAttributeStatusFailed = "failed"
|
const SmartAttributeStatusFailed = 1
|
||||||
const SmartAttributeStatusWarning = "warn"
|
const SmartAttributeStatusWarning = 2
|
||||||
|
|
||||||
const SmartWhenFailedFailingNow = "FAILING_NOW"
|
const SmartWhenFailedFailingNow = "FAILING_NOW"
|
||||||
const SmartWhenFailedInThePast = "IN_THE_PAST"
|
const SmartWhenFailedInThePast = "IN_THE_PAST"
|
||||||
|
|||||||
@@ -74,47 +74,20 @@ func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.Field
|
|||||||
// we will initialize with a predetermined username & password, that you should change.
|
// we will initialize with a predetermined username & password, that you should change.
|
||||||
|
|
||||||
// metrics bucket will have a retention period of 8 days (since it will be down-sampled once a week)
|
// metrics bucket will have a retention period of 8 days (since it will be down-sampled once a week)
|
||||||
// in hours (24hours * 8 days) = 192
|
// in seconds (60seconds * 60minutes * 24hours * 15 days) = 1_296_000 (see EnsureBucket() function)
|
||||||
onboardingResponse, err := client.Setup(
|
onboardingResponse, err := client.Setup(
|
||||||
backgroundContext,
|
backgroundContext,
|
||||||
appConfig.GetString("web.influxdb.init_username"),
|
appConfig.GetString("web.influxdb.init_username"),
|
||||||
appConfig.GetString("web.influxdb.init_password"),
|
appConfig.GetString("web.influxdb.init_password"),
|
||||||
appConfig.GetString("web.influxdb.org"),
|
appConfig.GetString("web.influxdb.org"),
|
||||||
appConfig.GetString("web.influxdb.bucket"),
|
appConfig.GetString("web.influxdb.bucket"),
|
||||||
192)
|
0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
appConfig.Set("web.influxdb.token", *onboardingResponse.Auth.Token)
|
appConfig.Set("web.influxdb.token", *onboardingResponse.Auth.Token)
|
||||||
//todo: determine if we should write the config file out here.
|
//todo: determine if we should write the config file out here.
|
||||||
|
|
||||||
orgId, err := client.OrganizationsAPI().FindOrganizationByID(backgroundContext, appConfig.GetString("web.influxdb.org"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
//create buckets (used for downsampling)
|
|
||||||
|
|
||||||
// metrics_weekly bucket will have a retention period of 8+1 weeks (since it will be down-sampled once a month)
|
|
||||||
// in seconds (60seconds * 60minutes * 24hours * 7 days * 9 weeks) = 5_443_200
|
|
||||||
_, err = client.BucketsAPI().CreateBucketWithName(backgroundContext, orgId, fmt.Sprintf("%s_weekly", appConfig.GetString("web.influxdb.bucket")), domain.RetentionRule{EverySeconds: 5_443_200})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// metrics_monthly bucket will have a retention period of 24+1 months (since it will be down-sampled once a year)
|
|
||||||
// in seconds (60seconds * 60minutes * 24hours * 7 days * (52 + 52 + 4)weeks) = 65_318_400
|
|
||||||
_, err = client.BucketsAPI().CreateBucketWithName(backgroundContext, orgId, fmt.Sprintf("%s_monthly", appConfig.GetString("web.influxdb.bucket")), domain.RetentionRule{EverySeconds: 65_318_400})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// metrics_yearly bucket will have an infinite retention period
|
|
||||||
_, err = client.BucketsAPI().CreateBucketWithName(backgroundContext, orgId, fmt.Sprintf("%s_yearly", appConfig.GetString("web.influxdb.bucket")))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use blocking write client for writes to desired bucket
|
// Use blocking write client for writes to desired bucket
|
||||||
@@ -139,8 +112,20 @@ func NewScrutinyRepository(appConfig config.Interface, globalLogger logrus.Field
|
|||||||
influxTaskApi: taskAPI,
|
influxTaskApi: taskAPI,
|
||||||
gormClient: database,
|
gormClient: database,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orgInfo, err := client.OrganizationsAPI().FindOrganizationByName(backgroundContext, appConfig.GetString("web.influxdb.org"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize Buckets (if necessary)
|
||||||
|
err = deviceRepo.EnsureBuckets(backgroundContext, orgInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize Background Tasks
|
// Initialize Background Tasks
|
||||||
err = deviceRepo.InitTasks(backgroundContext)
|
err = deviceRepo.EnsureTasks(backgroundContext, *orgInfo.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -164,32 +149,81 @@ func (sr *scrutinyRepository) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sr *scrutinyRepository) EnsureBuckets(ctx context.Context, org *domain.Organization) error {
|
||||||
|
|
||||||
|
mainBucket := sr.appConfig.GetString("web.influxdb.bucket")
|
||||||
|
if foundMainBucket, foundErr := sr.influxClient.BucketsAPI().FindBucketByName(ctx, mainBucket); foundErr != nil {
|
||||||
|
// metrics bucket will have a retention period of (14+1) 15 days (since it will be down-sampled once a week)
|
||||||
|
// in seconds (60seconds * 60minutes * 24hours * 15 days) = 1_296_000
|
||||||
|
_, err := sr.influxClient.BucketsAPI().CreateBucketWithName(ctx, org, mainBucket, domain.RetentionRule{EverySeconds: 1_296_000})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//correctly set the retention period for the main bucket (cant do it during creation)
|
||||||
|
foundMainBucket.RetentionRules = domain.RetentionRules{domain.RetentionRule{EverySeconds: 1_296_000}}
|
||||||
|
sr.influxClient.BucketsAPI().UpdateBucket(ctx, foundMainBucket)
|
||||||
|
}
|
||||||
|
|
||||||
|
//create buckets (used for downsampling)
|
||||||
|
weeklyBucket := fmt.Sprintf("%s_weekly", sr.appConfig.GetString("web.influxdb.bucket"))
|
||||||
|
if _, foundErr := sr.influxClient.BucketsAPI().FindBucketByName(ctx, weeklyBucket); foundErr != nil {
|
||||||
|
// metrics_weekly bucket will have a retention period of 8+1 weeks (since it will be down-sampled once a month)
|
||||||
|
// in seconds (60seconds * 60minutes * 24hours * 7 days * 9 weeks) = 5_443_200
|
||||||
|
_, err := sr.influxClient.BucketsAPI().CreateBucketWithName(ctx, org, weeklyBucket, domain.RetentionRule{EverySeconds: 5_443_200})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
monthlyBucket := fmt.Sprintf("%s_monthly", sr.appConfig.GetString("web.influxdb.bucket"))
|
||||||
|
if _, foundErr := sr.influxClient.BucketsAPI().FindBucketByName(ctx, monthlyBucket); foundErr != nil {
|
||||||
|
// metrics_monthly bucket will have a retention period of 24+1 months (since it will be down-sampled once a year)
|
||||||
|
// in seconds (60seconds * 60minutes * 24hours * 7 days * (52 + 52 + 4)weeks) = 65_318_400
|
||||||
|
_, err := sr.influxClient.BucketsAPI().CreateBucketWithName(ctx, org, monthlyBucket, domain.RetentionRule{EverySeconds: 65_318_400})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yearlyBucket := fmt.Sprintf("%s_yearly", sr.appConfig.GetString("web.influxdb.bucket"))
|
||||||
|
if _, foundErr := sr.influxClient.BucketsAPI().FindBucketByName(ctx, yearlyBucket); foundErr != nil {
|
||||||
|
// metrics_yearly bucket will have an infinite retention period
|
||||||
|
_, err := sr.influxClient.BucketsAPI().CreateBucketWithName(ctx, org, yearlyBucket)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Tasks
|
// Tasks
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
func (sr *scrutinyRepository) InitTasks(ctx context.Context) error {
|
func (sr *scrutinyRepository) EnsureTasks(ctx context.Context, orgID string) error {
|
||||||
weeklyTaskName := "tsk-weekly-aggr"
|
weeklyTaskName := "tsk-weekly-aggr"
|
||||||
if _, missingTask := sr.influxTaskApi.GetTaskByID(ctx, weeklyTaskName); missingTask != nil {
|
if found, findErr := sr.influxTaskApi.FindTasks(ctx, &api.TaskFilter{Name: weeklyTaskName}); findErr == nil && len(found) == 0 {
|
||||||
//weekly on Sunday at 1:00am
|
//weekly on Sunday at 1:00am
|
||||||
_, err := sr.influxTaskApi.CreateTaskWithCron(ctx, weeklyTaskName, sr.DownsampleScript("weekly"), "0 1 * * 0", sr.appConfig.GetString("web.influxdb.org"))
|
_, err := sr.influxTaskApi.CreateTaskWithCron(ctx, weeklyTaskName, sr.DownsampleScript("weekly"), "0 1 * * 0", orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
monthlyTaskName := "tsk-monthly-aggr"
|
monthlyTaskName := "tsk-monthly-aggr"
|
||||||
if _, missingTask := sr.influxTaskApi.GetTaskByID(ctx, monthlyTaskName); missingTask != nil {
|
if found, findErr := sr.influxTaskApi.FindTasks(ctx, &api.TaskFilter{Name: monthlyTaskName}); findErr == nil && len(found) == 0 {
|
||||||
//monthly on first day of the month at 1:30am
|
//monthly on first day of the month at 1:30am
|
||||||
_, err := sr.influxTaskApi.CreateTaskWithCron(ctx, monthlyTaskName, sr.DownsampleScript("monthly"), "30 1 1 * *", sr.appConfig.GetString("web.influxdb.org"))
|
_, err := sr.influxTaskApi.CreateTaskWithCron(ctx, monthlyTaskName, sr.DownsampleScript("monthly"), "30 1 1 * *", orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
yearlyTaskName := "tsk-monthly-aggr"
|
yearlyTaskName := "tsk-yearly-aggr"
|
||||||
if _, missingTask := sr.influxTaskApi.GetTaskByID(ctx, yearlyTaskName); missingTask != nil {
|
if found, findErr := sr.influxTaskApi.FindTasks(ctx, &api.TaskFilter{Name: yearlyTaskName}); findErr == nil && len(found) == 0 {
|
||||||
//yearly on the first day of the year at 2:00am
|
//yearly on the first day of the year at 2:00am
|
||||||
_, err := sr.influxTaskApi.CreateTaskWithCron(ctx, yearlyTaskName, sr.DownsampleScript("yearly"), "0 2 1 1 *", sr.appConfig.GetString("web.influxdb.org"))
|
_, err := sr.influxTaskApi.CreateTaskWithCron(ctx, yearlyTaskName, sr.DownsampleScript("yearly"), "0 2 1 1 *", orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -235,7 +269,7 @@ func (sr *scrutinyRepository) DownsampleScript(aggregationType string) string {
|
|||||||
smart_data = from(bucket: sourceBucket)
|
smart_data = from(bucket: sourceBucket)
|
||||||
|> range(start: rangeStart, stop: rangeEnd)
|
|> range(start: rangeStart, stop: rangeEnd)
|
||||||
|> filter(fn: (r) => r["_measurement"] == "smart" )
|
|> filter(fn: (r) => r["_measurement"] == "smart" )
|
||||||
|> filter(fn: (r) => r["_field"] !~ /(raw_string|_measurement|device_protocol|device_wwn|attribute_id|name|status|when_failed)/)
|
|> filter(fn: (r) => r["_field"] !~ /(raw_string|_measurement|device_protocol|device_wwn|attribute_id|when_failed)/)
|
||||||
|> last()
|
|> last()
|
||||||
|> yield(name: "last")
|
|> yield(name: "last")
|
||||||
|
|
||||||
|
|||||||
@@ -140,7 +140,6 @@ func (sm *Smart) ProcessAtaSmartInfo(info collector.SmartInfo) {
|
|||||||
for _, collectorAttr := range info.AtaSmartAttributes.Table {
|
for _, collectorAttr := range info.AtaSmartAttributes.Table {
|
||||||
attrModel := SmartAtaAttribute{
|
attrModel := SmartAtaAttribute{
|
||||||
AttributeId: collectorAttr.ID,
|
AttributeId: collectorAttr.ID,
|
||||||
Name: collectorAttr.Name,
|
|
||||||
Value: collectorAttr.Value,
|
Value: collectorAttr.Value,
|
||||||
Worst: collectorAttr.Worst,
|
Worst: collectorAttr.Worst,
|
||||||
Threshold: collectorAttr.Thresh,
|
Threshold: collectorAttr.Thresh,
|
||||||
@@ -151,7 +150,6 @@ func (sm *Smart) ProcessAtaSmartInfo(info collector.SmartInfo) {
|
|||||||
|
|
||||||
//now that we've parsed the data from the smartctl response, lets match it against our metadata rules and add additional Scrutiny specific data.
|
//now that we've parsed the data from the smartctl response, lets match it against our metadata rules and add additional Scrutiny specific data.
|
||||||
if smartMetadata, ok := thresholds.AtaMetadata[collectorAttr.ID]; ok {
|
if smartMetadata, ok := thresholds.AtaMetadata[collectorAttr.ID]; ok {
|
||||||
attrModel.Name = smartMetadata.DisplayName
|
|
||||||
if smartMetadata.Transform != nil {
|
if smartMetadata.Transform != nil {
|
||||||
attrModel.TransformedValue = smartMetadata.Transform(attrModel.Value, attrModel.RawValue, attrModel.RawString)
|
attrModel.TransformedValue = smartMetadata.Transform(attrModel.Value, attrModel.RawValue, attrModel.RawString)
|
||||||
}
|
}
|
||||||
@@ -168,22 +166,22 @@ func (sm *Smart) ProcessAtaSmartInfo(info collector.SmartInfo) {
|
|||||||
func (sm *Smart) ProcessNvmeSmartInfo(info collector.SmartInfo) {
|
func (sm *Smart) ProcessNvmeSmartInfo(info collector.SmartInfo) {
|
||||||
|
|
||||||
sm.Attributes = map[string]SmartAttribute{
|
sm.Attributes = map[string]SmartAttribute{
|
||||||
"critical_warning": (&SmartNvmeAttribute{AttributeId: "critical_warning", Name: "Critical Warning", Value: info.NvmeSmartHealthInformationLog.CriticalWarning, Threshold: 0}).PopulateAttributeStatus(),
|
"critical_warning": (&SmartNvmeAttribute{AttributeId: "critical_warning", Value: info.NvmeSmartHealthInformationLog.CriticalWarning, Threshold: 0}).PopulateAttributeStatus(),
|
||||||
"temperature": (&SmartNvmeAttribute{AttributeId: "temperature", Name: "Temperature", Value: info.NvmeSmartHealthInformationLog.Temperature, Threshold: -1}).PopulateAttributeStatus(),
|
"temperature": (&SmartNvmeAttribute{AttributeId: "temperature", Value: info.NvmeSmartHealthInformationLog.Temperature, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"available_spare": (&SmartNvmeAttribute{AttributeId: "available_spare", Name: "Available Spare", Value: info.NvmeSmartHealthInformationLog.AvailableSpare, Threshold: info.NvmeSmartHealthInformationLog.AvailableSpareThreshold}).PopulateAttributeStatus(),
|
"available_spare": (&SmartNvmeAttribute{AttributeId: "available_spare", Value: info.NvmeSmartHealthInformationLog.AvailableSpare, Threshold: info.NvmeSmartHealthInformationLog.AvailableSpareThreshold}).PopulateAttributeStatus(),
|
||||||
"percentage_used": (&SmartNvmeAttribute{AttributeId: "percentage_used", Name: "Percentage Used", Value: info.NvmeSmartHealthInformationLog.PercentageUsed, Threshold: 100}).PopulateAttributeStatus(),
|
"percentage_used": (&SmartNvmeAttribute{AttributeId: "percentage_used", Value: info.NvmeSmartHealthInformationLog.PercentageUsed, Threshold: 100}).PopulateAttributeStatus(),
|
||||||
"data_units_read": (&SmartNvmeAttribute{AttributeId: "data_units_read", Name: "Data Units Read", Value: info.NvmeSmartHealthInformationLog.DataUnitsRead, Threshold: -1}).PopulateAttributeStatus(),
|
"data_units_read": (&SmartNvmeAttribute{AttributeId: "data_units_read", Value: info.NvmeSmartHealthInformationLog.DataUnitsRead, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"data_units_written": (&SmartNvmeAttribute{AttributeId: "data_units_written", Name: "Data Units Written", Value: info.NvmeSmartHealthInformationLog.DataUnitsWritten, Threshold: -1}).PopulateAttributeStatus(),
|
"data_units_written": (&SmartNvmeAttribute{AttributeId: "data_units_written", Value: info.NvmeSmartHealthInformationLog.DataUnitsWritten, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"host_reads": (&SmartNvmeAttribute{AttributeId: "host_reads", Name: "Host Reads", Value: info.NvmeSmartHealthInformationLog.HostReads, Threshold: -1}).PopulateAttributeStatus(),
|
"host_reads": (&SmartNvmeAttribute{AttributeId: "host_reads", Value: info.NvmeSmartHealthInformationLog.HostReads, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"host_writes": (&SmartNvmeAttribute{AttributeId: "host_writes", Name: "Host Writes", Value: info.NvmeSmartHealthInformationLog.HostWrites, Threshold: -1}).PopulateAttributeStatus(),
|
"host_writes": (&SmartNvmeAttribute{AttributeId: "host_writes", Value: info.NvmeSmartHealthInformationLog.HostWrites, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"controller_busy_time": (&SmartNvmeAttribute{AttributeId: "controller_busy_time", Name: "Controller Busy Time", Value: info.NvmeSmartHealthInformationLog.ControllerBusyTime, Threshold: -1}).PopulateAttributeStatus(),
|
"controller_busy_time": (&SmartNvmeAttribute{AttributeId: "controller_busy_time", Value: info.NvmeSmartHealthInformationLog.ControllerBusyTime, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"power_cycles": (&SmartNvmeAttribute{AttributeId: "power_cycles", Name: "Power Cycles", Value: info.NvmeSmartHealthInformationLog.PowerCycles, Threshold: -1}).PopulateAttributeStatus(),
|
"power_cycles": (&SmartNvmeAttribute{AttributeId: "power_cycles", Value: info.NvmeSmartHealthInformationLog.PowerCycles, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"power_on_hours": (&SmartNvmeAttribute{AttributeId: "power_on_hours", Name: "Power on Hours", Value: info.NvmeSmartHealthInformationLog.PowerOnHours, Threshold: -1}).PopulateAttributeStatus(),
|
"power_on_hours": (&SmartNvmeAttribute{AttributeId: "power_on_hours", Value: info.NvmeSmartHealthInformationLog.PowerOnHours, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"unsafe_shutdowns": (&SmartNvmeAttribute{AttributeId: "unsafe_shutdowns", Name: "Unsafe Shutdowns", Value: info.NvmeSmartHealthInformationLog.UnsafeShutdowns, Threshold: -1}).PopulateAttributeStatus(),
|
"unsafe_shutdowns": (&SmartNvmeAttribute{AttributeId: "unsafe_shutdowns", Value: info.NvmeSmartHealthInformationLog.UnsafeShutdowns, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"media_errors": (&SmartNvmeAttribute{AttributeId: "media_errors", Name: "Media Errors", Value: info.NvmeSmartHealthInformationLog.MediaErrors, Threshold: 0}).PopulateAttributeStatus(),
|
"media_errors": (&SmartNvmeAttribute{AttributeId: "media_errors", Value: info.NvmeSmartHealthInformationLog.MediaErrors, Threshold: 0}).PopulateAttributeStatus(),
|
||||||
"num_err_log_entries": (&SmartNvmeAttribute{AttributeId: "num_err_log_entries", Name: "Numb Err Log Entries", Value: info.NvmeSmartHealthInformationLog.NumErrLogEntries, Threshold: 0}).PopulateAttributeStatus(),
|
"num_err_log_entries": (&SmartNvmeAttribute{AttributeId: "num_err_log_entries", Value: info.NvmeSmartHealthInformationLog.NumErrLogEntries, Threshold: 0}).PopulateAttributeStatus(),
|
||||||
"warning_temp_time": (&SmartNvmeAttribute{AttributeId: "warning_temp_time", Name: "Warning Temp Time", Value: info.NvmeSmartHealthInformationLog.WarningTempTime, Threshold: -1}).PopulateAttributeStatus(),
|
"warning_temp_time": (&SmartNvmeAttribute{AttributeId: "warning_temp_time", Value: info.NvmeSmartHealthInformationLog.WarningTempTime, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"critical_comp_time": (&SmartNvmeAttribute{AttributeId: "critical_comp_time", Name: "Critical CompTime", Value: info.NvmeSmartHealthInformationLog.CriticalCompTime, Threshold: -1}).PopulateAttributeStatus(),
|
"critical_comp_time": (&SmartNvmeAttribute{AttributeId: "critical_comp_time", Value: info.NvmeSmartHealthInformationLog.CriticalCompTime, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
}
|
}
|
||||||
|
|
||||||
//find analyzed attribute status
|
//find analyzed attribute status
|
||||||
@@ -197,19 +195,19 @@ func (sm *Smart) ProcessNvmeSmartInfo(info collector.SmartInfo) {
|
|||||||
//generate SmartScsiAttribute entries from Scrutiny Collector Smart data.
|
//generate SmartScsiAttribute entries from Scrutiny Collector Smart data.
|
||||||
func (sm *Smart) ProcessScsiSmartInfo(info collector.SmartInfo) {
|
func (sm *Smart) ProcessScsiSmartInfo(info collector.SmartInfo) {
|
||||||
sm.Attributes = map[string]SmartAttribute{
|
sm.Attributes = map[string]SmartAttribute{
|
||||||
"scsi_grown_defect_list": (&SmartScsiAttribute{AttributeId: "scsi_grown_defect_list", Name: "Grown Defect List", Value: info.ScsiGrownDefectList, Threshold: 0}).PopulateAttributeStatus(),
|
"scsi_grown_defect_list": (&SmartScsiAttribute{AttributeId: "scsi_grown_defect_list", Value: info.ScsiGrownDefectList, Threshold: 0}).PopulateAttributeStatus(),
|
||||||
"read_errors_corrected_by_eccfast": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccfast", Name: "Read Errors Corrected by ECC Fast", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccfast, Threshold: -1}).PopulateAttributeStatus(),
|
"read_errors_corrected_by_eccfast": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccfast", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccfast, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"read_errors_corrected_by_eccdelayed": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccdelayed", Name: "Read Errors Corrected by ECC Delayed", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccdelayed, Threshold: -1}).PopulateAttributeStatus(),
|
"read_errors_corrected_by_eccdelayed": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_eccdelayed", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByEccdelayed, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"read_errors_corrected_by_rereads_rewrites": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_rereads_rewrites", Name: "Read Errors Corrected by ReReads/ReWrites", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByRereadsRewrites, Threshold: 0}).PopulateAttributeStatus(),
|
"read_errors_corrected_by_rereads_rewrites": (&SmartScsiAttribute{AttributeId: "read_errors_corrected_by_rereads_rewrites", Value: info.ScsiErrorCounterLog.Read.ErrorsCorrectedByRereadsRewrites, Threshold: 0}).PopulateAttributeStatus(),
|
||||||
"read_total_errors_corrected": (&SmartScsiAttribute{AttributeId: "read_total_errors_corrected", Name: "Read Total Errors Corrected", Value: info.ScsiErrorCounterLog.Read.TotalErrorsCorrected, Threshold: -1}).PopulateAttributeStatus(),
|
"read_total_errors_corrected": (&SmartScsiAttribute{AttributeId: "read_total_errors_corrected", Value: info.ScsiErrorCounterLog.Read.TotalErrorsCorrected, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"read_correction_algorithm_invocations": (&SmartScsiAttribute{AttributeId: "read_correction_algorithm_invocations", Name: "Read Correction Algorithm Invocations", Value: info.ScsiErrorCounterLog.Read.CorrectionAlgorithmInvocations, Threshold: -1}).PopulateAttributeStatus(),
|
"read_correction_algorithm_invocations": (&SmartScsiAttribute{AttributeId: "read_correction_algorithm_invocations", Value: info.ScsiErrorCounterLog.Read.CorrectionAlgorithmInvocations, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"read_total_uncorrected_errors": (&SmartScsiAttribute{AttributeId: "read_total_uncorrected_errors", Name: "Read Total Uncorrected Errors", Value: info.ScsiErrorCounterLog.Read.TotalUncorrectedErrors, Threshold: 0}).PopulateAttributeStatus(),
|
"read_total_uncorrected_errors": (&SmartScsiAttribute{AttributeId: "read_total_uncorrected_errors", Value: info.ScsiErrorCounterLog.Read.TotalUncorrectedErrors, Threshold: 0}).PopulateAttributeStatus(),
|
||||||
"write_errors_corrected_by_eccfast": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccfast", Name: "Write Errors Corrected by ECC Fast", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccfast, Threshold: -1}).PopulateAttributeStatus(),
|
"write_errors_corrected_by_eccfast": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccfast", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccfast, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"write_errors_corrected_by_eccdelayed": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccdelayed", Name: "Write Errors Corrected by ECC Delayed", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccdelayed, Threshold: -1}).PopulateAttributeStatus(),
|
"write_errors_corrected_by_eccdelayed": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_eccdelayed", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByEccdelayed, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"write_errors_corrected_by_rereads_rewrites": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_rereads_rewrites", Name: "Write Errors Corrected by ReReads/ReWrites", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByRereadsRewrites, Threshold: 0}).PopulateAttributeStatus(),
|
"write_errors_corrected_by_rereads_rewrites": (&SmartScsiAttribute{AttributeId: "write_errors_corrected_by_rereads_rewrites", Value: info.ScsiErrorCounterLog.Write.ErrorsCorrectedByRereadsRewrites, Threshold: 0}).PopulateAttributeStatus(),
|
||||||
"write_total_errors_corrected": (&SmartScsiAttribute{AttributeId: "write_total_errors_corrected", Name: "Write Total Errors Corrected", Value: info.ScsiErrorCounterLog.Write.TotalErrorsCorrected, Threshold: -1}).PopulateAttributeStatus(),
|
"write_total_errors_corrected": (&SmartScsiAttribute{AttributeId: "write_total_errors_corrected", Value: info.ScsiErrorCounterLog.Write.TotalErrorsCorrected, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"write_correction_algorithm_invocations": (&SmartScsiAttribute{AttributeId: "write_correction_algorithm_invocations", Name: "Write Correction Algorithm Invocations", Value: info.ScsiErrorCounterLog.Write.CorrectionAlgorithmInvocations, Threshold: -1}).PopulateAttributeStatus(),
|
"write_correction_algorithm_invocations": (&SmartScsiAttribute{AttributeId: "write_correction_algorithm_invocations", Value: info.ScsiErrorCounterLog.Write.CorrectionAlgorithmInvocations, Threshold: -1}).PopulateAttributeStatus(),
|
||||||
"write_total_uncorrected_errors": (&SmartScsiAttribute{AttributeId: "write_total_uncorrected_errors", Name: "Write Total Uncorrected Errors", Value: info.ScsiErrorCounterLog.Write.TotalUncorrectedErrors, Threshold: 0}).PopulateAttributeStatus(),
|
"write_total_uncorrected_errors": (&SmartScsiAttribute{AttributeId: "write_total_uncorrected_errors", Value: info.ScsiErrorCounterLog.Write.TotalUncorrectedErrors, Threshold: 0}).PopulateAttributeStatus(),
|
||||||
}
|
}
|
||||||
|
|
||||||
//find analyzed attribute status
|
//find analyzed attribute status
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
|
|
||||||
type SmartAtaAttribute struct {
|
type SmartAtaAttribute struct {
|
||||||
AttributeId int `json:"attribute_id"`
|
AttributeId int `json:"attribute_id"`
|
||||||
Name string `json:"name"`
|
|
||||||
Value int64 `json:"value"`
|
Value int64 `json:"value"`
|
||||||
Threshold int64 `json:"thresh"`
|
Threshold int64 `json:"thresh"`
|
||||||
Worst int64 `json:"worst"`
|
Worst int64 `json:"worst"`
|
||||||
@@ -20,12 +19,12 @@ type SmartAtaAttribute struct {
|
|||||||
|
|
||||||
//Generated data
|
//Generated data
|
||||||
TransformedValue int64 `json:"transformed_value"`
|
TransformedValue int64 `json:"transformed_value"`
|
||||||
Status string `json:"status,omitempty"`
|
Status int64 `json:"status,omitempty"`
|
||||||
StatusReason string `json:"status_reason,omitempty"`
|
StatusReason string `json:"status_reason,omitempty"`
|
||||||
FailureRate float64 `json:"failure_rate,omitempty"`
|
FailureRate float64 `json:"failure_rate,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sa *SmartAtaAttribute) GetStatus() string {
|
func (sa *SmartAtaAttribute) GetStatus() int64 {
|
||||||
return sa.Status
|
return sa.Status
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,7 +34,6 @@ func (sa *SmartAtaAttribute) Flatten() map[string]interface{} {
|
|||||||
|
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
fmt.Sprintf("attr.%s.attribute_id", idString): idString,
|
fmt.Sprintf("attr.%s.attribute_id", idString): idString,
|
||||||
fmt.Sprintf("attr.%s.name", idString): sa.Name,
|
|
||||||
fmt.Sprintf("attr.%s.value", idString): sa.Value,
|
fmt.Sprintf("attr.%s.value", idString): sa.Value,
|
||||||
fmt.Sprintf("attr.%s.worst", idString): sa.Worst,
|
fmt.Sprintf("attr.%s.worst", idString): sa.Worst,
|
||||||
fmt.Sprintf("attr.%s.thresh", idString): sa.Threshold,
|
fmt.Sprintf("attr.%s.thresh", idString): sa.Threshold,
|
||||||
@@ -62,8 +60,6 @@ func (sa *SmartAtaAttribute) Inflate(key string, val interface{}) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
sa.AttributeId = attrId
|
sa.AttributeId = attrId
|
||||||
}
|
}
|
||||||
case "name":
|
|
||||||
sa.Name = val.(string)
|
|
||||||
case "value":
|
case "value":
|
||||||
sa.Value = val.(int64)
|
sa.Value = val.(int64)
|
||||||
case "worst":
|
case "worst":
|
||||||
@@ -81,7 +77,7 @@ func (sa *SmartAtaAttribute) Inflate(key string, val interface{}) {
|
|||||||
case "transformed_value":
|
case "transformed_value":
|
||||||
sa.TransformedValue = val.(int64)
|
sa.TransformedValue = val.(int64)
|
||||||
case "status":
|
case "status":
|
||||||
sa.Status = val.(string)
|
sa.Status = val.(int64)
|
||||||
case "status_reason":
|
case "status_reason":
|
||||||
sa.StatusReason = val.(string)
|
sa.StatusReason = val.(string)
|
||||||
case "failure_rate":
|
case "failure_rate":
|
||||||
@@ -107,10 +103,6 @@ func (sa *SmartAtaAttribute) PopulateAttributeStatus() *SmartAtaAttribute {
|
|||||||
sa.ValidateThreshold(smartMetadata)
|
sa.ValidateThreshold(smartMetadata)
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if status is blank, set to "passed"
|
|
||||||
if len(sa.Status) == 0 {
|
|
||||||
sa.Status = pkg.SmartAttributeStatusPassed
|
|
||||||
}
|
|
||||||
return sa
|
return sa
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ package measurements
|
|||||||
type SmartAttribute interface {
|
type SmartAttribute interface {
|
||||||
Flatten() (fields map[string]interface{})
|
Flatten() (fields map[string]interface{})
|
||||||
Inflate(key string, val interface{})
|
Inflate(key string, val interface{})
|
||||||
GetStatus() string
|
GetStatus() int64
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,24 +9,22 @@ import (
|
|||||||
|
|
||||||
type SmartNvmeAttribute struct {
|
type SmartNvmeAttribute struct {
|
||||||
AttributeId string `json:"attribute_id"` //json string from smartctl
|
AttributeId string `json:"attribute_id"` //json string from smartctl
|
||||||
Name string `json:"name"`
|
|
||||||
Value int64 `json:"value"`
|
Value int64 `json:"value"`
|
||||||
Threshold int64 `json:"thresh"`
|
Threshold int64 `json:"thresh"`
|
||||||
|
|
||||||
TransformedValue int64 `json:"transformed_value"`
|
TransformedValue int64 `json:"transformed_value"`
|
||||||
Status string `json:"status,omitempty"`
|
Status int64 `json:"status,omitempty"`
|
||||||
StatusReason string `json:"status_reason,omitempty"`
|
StatusReason string `json:"status_reason,omitempty"`
|
||||||
FailureRate float64 `json:"failure_rate,omitempty"`
|
FailureRate float64 `json:"failure_rate,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sa *SmartNvmeAttribute) GetStatus() string {
|
func (sa *SmartNvmeAttribute) GetStatus() int64 {
|
||||||
return sa.Status
|
return sa.Status
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sa *SmartNvmeAttribute) Flatten() map[string]interface{} {
|
func (sa *SmartNvmeAttribute) Flatten() map[string]interface{} {
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
fmt.Sprintf("attr.%s.attribute_id", sa.AttributeId): sa.AttributeId,
|
fmt.Sprintf("attr.%s.attribute_id", sa.AttributeId): sa.AttributeId,
|
||||||
fmt.Sprintf("attr.%s.name", sa.AttributeId): sa.Name,
|
|
||||||
fmt.Sprintf("attr.%s.value", sa.AttributeId): sa.Value,
|
fmt.Sprintf("attr.%s.value", sa.AttributeId): sa.Value,
|
||||||
fmt.Sprintf("attr.%s.thresh", sa.AttributeId): sa.Threshold,
|
fmt.Sprintf("attr.%s.thresh", sa.AttributeId): sa.Threshold,
|
||||||
|
|
||||||
@@ -47,8 +45,6 @@ func (sa *SmartNvmeAttribute) Inflate(key string, val interface{}) {
|
|||||||
switch keyParts[2] {
|
switch keyParts[2] {
|
||||||
case "attribute_id":
|
case "attribute_id":
|
||||||
sa.AttributeId = val.(string)
|
sa.AttributeId = val.(string)
|
||||||
case "name":
|
|
||||||
sa.Name = val.(string)
|
|
||||||
case "value":
|
case "value":
|
||||||
sa.Value = val.(int64)
|
sa.Value = val.(int64)
|
||||||
case "thresh":
|
case "thresh":
|
||||||
@@ -58,7 +54,7 @@ func (sa *SmartNvmeAttribute) Inflate(key string, val interface{}) {
|
|||||||
case "transformed_value":
|
case "transformed_value":
|
||||||
sa.TransformedValue = val.(int64)
|
sa.TransformedValue = val.(int64)
|
||||||
case "status":
|
case "status":
|
||||||
sa.Status = val.(string)
|
sa.Status = val.(int64)
|
||||||
case "status_reason":
|
case "status_reason":
|
||||||
sa.StatusReason = val.(string)
|
sa.StatusReason = val.(string)
|
||||||
case "failure_rate":
|
case "failure_rate":
|
||||||
@@ -83,9 +79,5 @@ func (sa *SmartNvmeAttribute) PopulateAttributeStatus() *SmartNvmeAttribute {
|
|||||||
}
|
}
|
||||||
//TODO: eventually figure out the critical_warning bits and determine correct error messages here.
|
//TODO: eventually figure out the critical_warning bits and determine correct error messages here.
|
||||||
|
|
||||||
//check if status is blank, set to "passed"
|
|
||||||
if len(sa.Status) == 0 {
|
|
||||||
sa.Status = pkg.SmartAttributeStatusPassed
|
|
||||||
}
|
|
||||||
return sa
|
return sa
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,24 +9,22 @@ import (
|
|||||||
|
|
||||||
type SmartScsiAttribute struct {
|
type SmartScsiAttribute struct {
|
||||||
AttributeId string `json:"attribute_id"` //json string from smartctl
|
AttributeId string `json:"attribute_id"` //json string from smartctl
|
||||||
Name string `json:"name"`
|
|
||||||
Value int64 `json:"value"`
|
Value int64 `json:"value"`
|
||||||
Threshold int64 `json:"thresh"`
|
Threshold int64 `json:"thresh"`
|
||||||
|
|
||||||
TransformedValue int64 `json:"transformed_value"`
|
TransformedValue int64 `json:"transformed_value"`
|
||||||
Status string `json:"status,omitempty"`
|
Status int64 `json:"status,omitempty"`
|
||||||
StatusReason string `json:"status_reason,omitempty"`
|
StatusReason string `json:"status_reason,omitempty"`
|
||||||
FailureRate float64 `json:"failure_rate,omitempty"`
|
FailureRate float64 `json:"failure_rate,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sa *SmartScsiAttribute) GetStatus() string {
|
func (sa *SmartScsiAttribute) GetStatus() int64 {
|
||||||
return sa.Status
|
return sa.Status
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sa *SmartScsiAttribute) Flatten() map[string]interface{} {
|
func (sa *SmartScsiAttribute) Flatten() map[string]interface{} {
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
fmt.Sprintf("attr.%s.attribute_id", sa.AttributeId): sa.AttributeId,
|
fmt.Sprintf("attr.%s.attribute_id", sa.AttributeId): sa.AttributeId,
|
||||||
fmt.Sprintf("attr.%s.name", sa.AttributeId): sa.Name,
|
|
||||||
fmt.Sprintf("attr.%s.value", sa.AttributeId): sa.Value,
|
fmt.Sprintf("attr.%s.value", sa.AttributeId): sa.Value,
|
||||||
fmt.Sprintf("attr.%s.thresh", sa.AttributeId): sa.Threshold,
|
fmt.Sprintf("attr.%s.thresh", sa.AttributeId): sa.Threshold,
|
||||||
|
|
||||||
@@ -47,8 +45,6 @@ func (sa *SmartScsiAttribute) Inflate(key string, val interface{}) {
|
|||||||
switch keyParts[2] {
|
switch keyParts[2] {
|
||||||
case "attribute_id":
|
case "attribute_id":
|
||||||
sa.AttributeId = val.(string)
|
sa.AttributeId = val.(string)
|
||||||
case "name":
|
|
||||||
sa.Name = val.(string)
|
|
||||||
case "value":
|
case "value":
|
||||||
sa.Value = val.(int64)
|
sa.Value = val.(int64)
|
||||||
case "thresh":
|
case "thresh":
|
||||||
@@ -58,7 +54,7 @@ func (sa *SmartScsiAttribute) Inflate(key string, val interface{}) {
|
|||||||
case "transformed_value":
|
case "transformed_value":
|
||||||
sa.TransformedValue = val.(int64)
|
sa.TransformedValue = val.(int64)
|
||||||
case "status":
|
case "status":
|
||||||
sa.Status = val.(string)
|
sa.Status = val.(int64)
|
||||||
case "status_reason":
|
case "status_reason":
|
||||||
sa.StatusReason = val.(string)
|
sa.StatusReason = val.(string)
|
||||||
case "failure_rate":
|
case "failure_rate":
|
||||||
@@ -83,9 +79,5 @@ func (sa *SmartScsiAttribute) PopulateAttributeStatus() *SmartScsiAttribute {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if status is blank, set to "passed"
|
|
||||||
if len(sa.Status) == 0 {
|
|
||||||
sa.Status = pkg.SmartAttributeStatusPassed
|
|
||||||
}
|
|
||||||
return sa
|
return sa
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const AtaSmartAttributeDisplayTypeTransformed = "transformed"
|
|||||||
|
|
||||||
type AtaAttributeMetadata struct {
|
type AtaAttributeMetadata struct {
|
||||||
ID int64 `json:"-"`
|
ID int64 `json:"-"`
|
||||||
DisplayName string `json:"-"`
|
DisplayName string `json:"display_name"`
|
||||||
Ideal string `json:"ideal"`
|
Ideal string `json:"ideal"`
|
||||||
Critical bool `json:"critical"`
|
Critical bool `json:"critical"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
|
|||||||
Reference in New Issue
Block a user