2019-01-24 20:15:10 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
2018-10-16 18:40:34 +01:00
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package audit
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
2018-12-04 18:47:58 +00:00
|
|
|
"storj.io/storj/pkg/statdb"
|
2018-11-29 18:39:27 +00:00
|
|
|
"storj.io/storj/pkg/storj"
|
2018-10-16 18:40:34 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
type reporter interface {
|
2018-12-19 18:44:03 +00:00
|
|
|
RecordAudits(ctx context.Context, req *RecordAuditsInfo) (failed *RecordAuditsInfo, err error)
|
2018-10-16 18:40:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Reporter records audit reports in statdb and implements the reporter interface
|
|
|
|
type Reporter struct {
|
2018-12-14 20:17:30 +00:00
|
|
|
statdb statdb.DB
|
2018-10-16 18:40:34 +01:00
|
|
|
maxRetries int
|
|
|
|
}
|
|
|
|
|
2018-12-19 18:44:03 +00:00
|
|
|
// RecordAuditsInfo is a struct containing arguments/return values for RecordAudits()
|
|
|
|
type RecordAuditsInfo struct {
|
|
|
|
SuccessNodeIDs storj.NodeIDList
|
|
|
|
FailNodeIDs storj.NodeIDList
|
|
|
|
OfflineNodeIDs storj.NodeIDList
|
|
|
|
}
|
|
|
|
|
2018-10-16 18:40:34 +01:00
|
|
|
// NewReporter instantiates a reporter
|
2019-01-23 19:58:44 +00:00
|
|
|
func NewReporter(sdb statdb.DB, maxRetries int) (reporter *Reporter, err error) {
|
|
|
|
return &Reporter{statdb: sdb, maxRetries: maxRetries}, nil
|
2018-10-16 18:40:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// RecordAudits saves failed audit details to statdb
|
2018-12-19 18:44:03 +00:00
|
|
|
func (reporter *Reporter) RecordAudits(ctx context.Context, req *RecordAuditsInfo) (failed *RecordAuditsInfo, err error) {
|
|
|
|
successNodeIDs := req.SuccessNodeIDs
|
|
|
|
failNodeIDs := req.FailNodeIDs
|
|
|
|
offlineNodeIDs := req.OfflineNodeIDs
|
|
|
|
|
|
|
|
var errNodeIDs storj.NodeIDList
|
|
|
|
|
2018-10-16 18:40:34 +01:00
|
|
|
retries := 0
|
2018-12-19 18:44:03 +00:00
|
|
|
for retries < reporter.maxRetries {
|
|
|
|
if len(successNodeIDs) == 0 && len(failNodeIDs) == 0 && len(offlineNodeIDs) == 0 {
|
|
|
|
return nil, nil
|
2018-10-16 18:40:34 +01:00
|
|
|
}
|
2018-12-19 18:44:03 +00:00
|
|
|
|
|
|
|
errNodeIDs = storj.NodeIDList{}
|
|
|
|
|
|
|
|
if len(successNodeIDs) > 0 {
|
|
|
|
successNodeIDs, err = reporter.recordAuditSuccessStatus(ctx, successNodeIDs)
|
|
|
|
if err != nil {
|
|
|
|
errNodeIDs = append(errNodeIDs, successNodeIDs...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(failNodeIDs) > 0 {
|
|
|
|
failNodeIDs, err = reporter.recordAuditFailStatus(ctx, failNodeIDs)
|
|
|
|
if err != nil {
|
|
|
|
errNodeIDs = append(errNodeIDs, failNodeIDs...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(offlineNodeIDs) > 0 {
|
|
|
|
offlineNodeIDs, err = reporter.recordOfflineStatus(ctx, offlineNodeIDs)
|
|
|
|
if err != nil {
|
|
|
|
errNodeIDs = append(errNodeIDs, offlineNodeIDs...)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-16 18:40:34 +01:00
|
|
|
retries++
|
|
|
|
}
|
2018-12-19 18:44:03 +00:00
|
|
|
if retries >= reporter.maxRetries && len(errNodeIDs) > 0 {
|
|
|
|
return &RecordAuditsInfo{
|
|
|
|
SuccessNodeIDs: successNodeIDs,
|
|
|
|
FailNodeIDs: failNodeIDs,
|
|
|
|
OfflineNodeIDs: offlineNodeIDs,
|
|
|
|
}, Error.New("some nodes failed to be updated in statdb")
|
2018-10-16 18:40:34 +01:00
|
|
|
}
|
2018-12-19 18:44:03 +00:00
|
|
|
return nil, nil
|
2018-10-16 18:40:34 +01:00
|
|
|
}
|
|
|
|
|
2018-12-19 18:44:03 +00:00
|
|
|
// recordAuditFailStatus updates nodeIDs in statdb with isup=true, auditsuccess=false
|
|
|
|
func (reporter *Reporter) recordAuditFailStatus(ctx context.Context, failedAuditNodeIDs storj.NodeIDList) (failed storj.NodeIDList, err error) {
|
|
|
|
failedIDs := storj.NodeIDList{}
|
|
|
|
|
|
|
|
for _, nodeID := range failedAuditNodeIDs {
|
|
|
|
_, err := reporter.statdb.Update(ctx, &statdb.UpdateRequest{
|
|
|
|
NodeID: nodeID,
|
|
|
|
IsUp: true,
|
|
|
|
AuditSuccess: false,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
failedIDs = append(failedIDs, nodeID)
|
2018-10-16 18:40:34 +01:00
|
|
|
}
|
|
|
|
}
|
2018-12-19 18:44:03 +00:00
|
|
|
if len(failedIDs) > 0 {
|
|
|
|
return failedIDs, Error.New("failed to record some audit fail statuses in statdb")
|
|
|
|
}
|
|
|
|
return nil, nil
|
2018-10-16 18:40:34 +01:00
|
|
|
}
|
|
|
|
|
2018-12-19 18:44:03 +00:00
|
|
|
// recordOfflineStatus updates nodeIDs in statdb with isup=false
|
2018-10-16 18:40:34 +01:00
|
|
|
// TODO: offline nodes should maybe be marked as failing the audit in the future
|
2018-12-19 18:44:03 +00:00
|
|
|
func (reporter *Reporter) recordOfflineStatus(ctx context.Context, offlineNodeIDs storj.NodeIDList) (failed storj.NodeIDList, err error) {
|
|
|
|
failedIDs := storj.NodeIDList{}
|
|
|
|
|
|
|
|
for _, nodeID := range offlineNodeIDs {
|
|
|
|
_, err := reporter.statdb.UpdateUptime(ctx, nodeID, false)
|
|
|
|
if err != nil {
|
|
|
|
failedIDs = append(failedIDs, nodeID)
|
2018-10-16 18:40:34 +01:00
|
|
|
}
|
|
|
|
}
|
2018-12-19 18:44:03 +00:00
|
|
|
if len(failedIDs) > 0 {
|
|
|
|
return failedIDs, Error.New("failed to record some audit offline statuses in statdb")
|
|
|
|
}
|
|
|
|
return nil, nil
|
2018-10-16 18:40:34 +01:00
|
|
|
}
|
|
|
|
|
2018-12-19 18:44:03 +00:00
|
|
|
// recordAuditSuccessStatus updates nodeIDs in statdb with isup=true, auditsuccess=true
|
|
|
|
func (reporter *Reporter) recordAuditSuccessStatus(ctx context.Context, successNodeIDs storj.NodeIDList) (failed storj.NodeIDList, err error) {
|
|
|
|
failedIDs := storj.NodeIDList{}
|
|
|
|
|
|
|
|
for _, nodeID := range successNodeIDs {
|
|
|
|
_, err := reporter.statdb.Update(ctx, &statdb.UpdateRequest{
|
|
|
|
NodeID: nodeID,
|
|
|
|
IsUp: true,
|
|
|
|
AuditSuccess: true,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
failedIDs = append(failedIDs, nodeID)
|
2018-10-16 18:40:34 +01:00
|
|
|
}
|
|
|
|
}
|
2018-12-19 18:44:03 +00:00
|
|
|
if len(failedIDs) > 0 {
|
|
|
|
return failedIDs, Error.New("failed to record some audit success statuses in statdb")
|
|
|
|
}
|
|
|
|
return nil, nil
|
2018-10-16 18:40:34 +01:00
|
|
|
}
|