2019-01-24 20:15:10 +00:00
// Copyright (C) 2019 Storj Labs, Inc.
2018-04-18 17:55:28 +01:00
// See LICENSE for copying information.
2018-06-13 19:22:32 +01:00
package overlay
2018-04-18 16:34:15 +01:00
import (
2018-05-16 19:47:59 +01:00
"context"
2019-01-15 16:08:45 +00:00
"errors"
2019-05-30 18:35:04 +01:00
"net"
2019-04-04 17:34:36 +01:00
"time"
2018-04-18 16:34:15 +01:00
2018-06-13 19:22:32 +01:00
"github.com/zeebo/errs"
2018-12-22 04:51:42 +00:00
"go.uber.org/zap"
2018-11-16 16:31:14 +00:00
2019-12-27 11:48:47 +00:00
"storj.io/common/pb"
"storj.io/common/storj"
2018-06-13 19:22:32 +01:00
"storj.io/storj/storage"
2018-04-18 16:34:15 +01:00
)
2018-12-17 18:47:26 +00:00
// ErrEmptyNode is returned when the nodeID is empty
var ErrEmptyNode = errs . New ( "empty node ID" )
// ErrNodeNotFound is returned if a node does not exist in database
2019-03-29 08:53:43 +00:00
var ErrNodeNotFound = errs . Class ( "node not found" )
2018-11-21 17:31:27 +00:00
2019-05-27 12:13:47 +01:00
// ErrNodeOffline is returned if a nodes is offline
var ErrNodeOffline = errs . Class ( "node is offline" )
2019-06-24 15:46:10 +01:00
// ErrNodeDisqualified is returned if a nodes is disqualified
var ErrNodeDisqualified = errs . Class ( "node is disqualified" )
2019-01-31 18:49:00 +00:00
// ErrNotEnoughNodes is when selecting nodes failed with the given parameters
var ErrNotEnoughNodes = errs . Class ( "not enough nodes" )
2019-08-06 17:35:59 +01:00
// DB implements the database for overlay.Service
2019-09-10 14:24:16 +01:00
//
// architecture: Database
2019-01-15 16:08:45 +00:00
type DB interface {
2019-02-11 19:24:51 +00:00
// SelectStorageNodes looks up nodes based on criteria
2020-03-28 14:56:05 +00:00
SelectStorageNodes ( ctx context . Context , count int , criteria * NodeCriteria ) ( [ ] * SelectedNode , error )
2019-02-11 19:24:51 +00:00
// SelectNewStorageNodes looks up nodes based on new node criteria
2020-03-28 14:56:05 +00:00
SelectNewStorageNodes ( ctx context . Context , count int , criteria * NodeCriteria ) ( [ ] * SelectedNode , error )
2019-01-31 18:49:00 +00:00
2019-01-15 16:08:45 +00:00
// Get looks up the node by nodeID
2019-04-04 17:34:36 +01:00
Get ( ctx context . Context , nodeID storj . NodeID ) ( * NodeDossier , error )
2020-03-13 18:01:48 +00:00
// GetNodes returns a map of nodes for the supplied nodeIDs
GetNodes ( ctx context . Context , nodeIDs [ ] storj . NodeID ) ( map [ storj . NodeID ] * NodeDossier , error )
2019-06-18 23:22:14 +01:00
// KnownOffline filters a set of nodes to offline nodes
KnownOffline ( context . Context , * NodeCriteria , storj . NodeIDList ) ( storj . NodeIDList , error )
2019-05-01 14:45:52 +01:00
// KnownUnreliableOrOffline filters a set of nodes to unhealth or offlines node, independent of new
KnownUnreliableOrOffline ( context . Context , * NodeCriteria , storj . NodeIDList ) ( storj . NodeIDList , error )
2019-12-16 13:45:13 +00:00
// KnownReliable filters a set of nodes to reliable (online and qualified) nodes.
KnownReliable ( ctx context . Context , onlineWindow time . Duration , nodeIDs storj . NodeIDList ) ( [ ] * pb . Node , error )
2019-07-08 23:04:35 +01:00
// Reliable returns all nodes that are reliable
Reliable ( context . Context , * NodeCriteria ) ( storj . NodeIDList , error )
2019-04-22 10:07:50 +01:00
// Update updates node address
2020-03-06 22:04:23 +00:00
UpdateAddress ( ctx context . Context , value * NodeDossier , defaults NodeSelectionConfig ) error
2019-07-31 18:21:06 +01:00
// BatchUpdateStats updates multiple storagenode's stats in one transaction
BatchUpdateStats ( ctx context . Context , updateRequests [ ] * UpdateRequest , batchSize int ) ( failed storj . NodeIDList , err error )
2019-03-25 22:25:09 +00:00
// UpdateStats all parts of single storagenode's stats.
UpdateStats ( ctx context . Context , request * UpdateRequest ) ( stats * NodeStats , err error )
2019-04-10 07:04:24 +01:00
// UpdateNodeInfo updates node dossier with info requested from the node itself like node type, email, wallet, capacity, and version.
UpdateNodeInfo ( ctx context . Context , node storj . NodeID , nodeInfo * pb . InfoResponse ) ( stats * NodeDossier , err error )
2019-03-25 22:25:09 +00:00
// UpdateUptime updates a single storagenode's uptime stats.
2020-01-03 00:00:18 +00:00
UpdateUptime ( ctx context . Context , nodeID storj . NodeID , isUp bool ) ( stats * NodeStats , err error )
2019-09-19 19:37:31 +01:00
// UpdateCheckIn updates a single storagenode's check-in stats.
2019-11-15 22:43:06 +00:00
UpdateCheckIn ( ctx context . Context , node NodeCheckInInfo , timestamp time . Time , config NodeSelectionConfig ) ( err error )
2019-08-27 13:37:42 +01:00
// AllPieceCounts returns a map of node IDs to piece counts from the db.
AllPieceCounts ( ctx context . Context ) ( pieceCounts map [ storj . NodeID ] int , err error )
// UpdatePieceCounts sets the piece count field for the given node IDs.
UpdatePieceCounts ( ctx context . Context , pieceCounts map [ storj . NodeID ] int ) ( err error )
2019-10-01 23:18:21 +01:00
// UpdateExitStatus is used to update a node's graceful exit status.
2019-10-29 20:22:20 +00:00
UpdateExitStatus ( ctx context . Context , request * ExitStatusRequest ) ( _ * NodeDossier , err error )
2019-10-01 23:18:21 +01:00
// GetExitingNodes returns nodes who have initiated a graceful exit, but have not completed it.
2019-10-24 17:24:42 +01:00
GetExitingNodes ( ctx context . Context ) ( exitingNodes [ ] * ExitStatus , err error )
2019-10-23 02:06:01 +01:00
// GetGracefulExitCompletedByTimeFrame returns nodes who have completed graceful exit within a time window (time window is around graceful exit completion).
GetGracefulExitCompletedByTimeFrame ( ctx context . Context , begin , end time . Time ) ( exitedNodes storj . NodeIDList , err error )
// GetGracefulExitIncompleteByTimeFrame returns nodes who have initiated, but not completed graceful exit within a time window (time window is around graceful exit initiation).
GetGracefulExitIncompleteByTimeFrame ( ctx context . Context , begin , end time . Time ) ( exitingNodes storj . NodeIDList , err error )
// GetExitStatus returns a node's graceful exit status.
2019-10-11 22:18:05 +01:00
GetExitStatus ( ctx context . Context , nodeID storj . NodeID ) ( exitStatus * ExitStatus , err error )
2019-11-06 21:38:52 +00:00
2020-03-06 22:04:23 +00:00
// GetNodesNetwork returns the /24 subnet for each storage node, order is not guaranteed.
GetNodesNetwork ( ctx context . Context , nodeIDs [ ] storj . NodeID ) ( nodeNets [ ] string , err error )
2019-12-30 17:10:24 +00:00
2020-01-02 20:41:18 +00:00
// GetSuccesfulNodesNotCheckedInSince returns all nodes that last check-in was successful, but haven't checked-in within a given duration.
GetSuccesfulNodesNotCheckedInSince ( ctx context . Context , duration time . Duration ) ( nodeAddresses [ ] NodeLastContact , err error )
2019-12-30 17:10:24 +00:00
// GetOfflineNodesLimited returns a list of the first N offline nodes ordered by least recently contacted.
2020-01-06 20:06:05 +00:00
GetOfflineNodesLimited ( ctx context . Context , limit int ) ( [ ] NodeLastContact , error )
2020-01-03 19:11:47 +00:00
// DisqualifyNode disqualifies a storage node.
DisqualifyNode ( ctx context . Context , nodeID storj . NodeID ) ( err error )
2020-03-09 15:35:54 +00:00
// SuspendNode suspends a storage node.
SuspendNode ( ctx context . Context , nodeID storj . NodeID , suspendedAt time . Time ) ( err error )
// UnsuspendNode unsuspends a storage node.
UnsuspendNode ( ctx context . Context , nodeID storj . NodeID ) ( err error )
2019-01-15 16:08:45 +00:00
}
2019-09-19 19:37:31 +01:00
// NodeCheckInInfo contains all the info that will be updated when a node checkins
type NodeCheckInInfo struct {
2020-03-06 22:04:23 +00:00
NodeID storj . NodeID
Address * pb . NodeAddress
LastNet string
LastIPPort string
IsUp bool
Operator * pb . NodeOperator
Capacity * pb . NodeCapacity
Version * pb . NodeVersion
2019-09-19 19:37:31 +01:00
}
2019-03-23 08:06:11 +00:00
// FindStorageNodesRequest defines easy request parameters.
type FindStorageNodesRequest struct {
MinimumRequiredNodes int
RequestedCount int
2020-03-12 18:37:57 +00:00
ExcludedIDs [ ] storj . NodeID
2019-04-26 13:15:06 +01:00
MinimumVersion string // semver or empty
2019-03-23 08:06:11 +00:00
}
// NodeCriteria are the requirements for selecting nodes
type NodeCriteria struct {
2020-03-12 18:37:57 +00:00
FreeDisk int64
AuditCount int64
UptimeCount int64
ExcludedIDs [ ] storj . NodeID
ExcludedNetworks [ ] string // the /24 subnet IPv4 or /64 subnet IPv6 for nodes
MinimumVersion string // semver or empty
OnlineWindow time . Duration
DistinctIP bool
2019-03-23 08:06:11 +00:00
}
2020-03-09 15:35:54 +00:00
// AuditType is an enum representing the outcome of a particular audit reported to the overlay.
type AuditType int
const (
// AuditSuccess represents a successful audit.
AuditSuccess AuditType = iota
// AuditFailure represents a failed audit.
AuditFailure
// AuditUnknown represents an audit that resulted in an unknown error from the node.
AuditUnknown
)
2019-03-25 22:25:09 +00:00
// UpdateRequest is used to update a node status.
type UpdateRequest struct {
NodeID storj . NodeID
2020-03-09 15:35:54 +00:00
AuditOutcome AuditType
2019-03-25 22:25:09 +00:00
IsUp bool
2019-06-20 14:56:04 +01:00
// n.b. these are set values from the satellite.
// They are part of the UpdateRequest struct in order to be
// more easily accessible in satellite/satellitedb/overlaycache.go.
2020-01-03 00:00:18 +00:00
AuditLambda float64
AuditWeight float64
AuditDQ float64
2019-03-25 22:25:09 +00:00
}
2019-10-11 22:18:05 +01:00
// ExitStatus is used for reading graceful exit status.
type ExitStatus struct {
NodeID storj . NodeID
ExitInitiatedAt * time . Time
ExitLoopCompletedAt * time . Time
ExitFinishedAt * time . Time
2019-10-17 16:01:39 +01:00
ExitSuccess bool
2019-10-11 22:18:05 +01:00
}
2019-10-01 23:18:21 +01:00
// ExitStatusRequest is used to update a node's graceful exit status.
type ExitStatusRequest struct {
NodeID storj . NodeID
ExitInitiatedAt time . Time
ExitLoopCompletedAt time . Time
ExitFinishedAt time . Time
2019-10-17 16:01:39 +01:00
ExitSuccess bool
2019-10-01 23:18:21 +01:00
}
2019-04-04 17:34:36 +01:00
// NodeDossier is the complete info that the satellite tracks for a storage node
type NodeDossier struct {
pb . Node
2019-05-30 22:38:23 +01:00
Type pb . NodeType
Operator pb . NodeOperator
Capacity pb . NodeCapacity
Reputation NodeStats
Version pb . NodeVersion
Contained bool
2019-06-18 10:14:31 +01:00
Disqualified * time . Time
2020-03-09 15:35:54 +00:00
Suspended * time . Time
2019-08-19 11:58:13 +01:00
PieceCount int64
2019-10-11 22:18:05 +01:00
ExitStatus ExitStatus
2019-10-23 02:06:01 +01:00
CreatedAt time . Time
2020-03-06 22:04:23 +00:00
LastNet string
LastIPPort string
2019-04-04 17:34:36 +01:00
}
2019-03-29 08:53:43 +00:00
// NodeStats contains statistics about a node.
2019-03-25 22:25:09 +00:00
type NodeStats struct {
2020-03-09 15:35:54 +00:00
Latency90 int64
AuditSuccessCount int64
AuditCount int64
UptimeSuccessCount int64
UptimeCount int64
LastContactSuccess time . Time
LastContactFailure time . Time
AuditReputationAlpha float64
AuditReputationBeta float64
Disqualified * time . Time
UnknownAuditReputationAlpha float64
UnknownAuditReputationBeta float64
Suspended * time . Time
2019-03-25 22:25:09 +00:00
}
2020-01-02 20:41:18 +00:00
// NodeLastContact contains the ID, address, and timestamp
type NodeLastContact struct {
ID storj . NodeID
Address string
2020-03-06 22:04:23 +00:00
LastIPPort string
2020-01-02 20:41:18 +00:00
LastContactSuccess time . Time
LastContactFailure time . Time
}
2020-03-28 14:56:05 +00:00
// SelectedNode is used as a result for creating orders limits.
type SelectedNode struct {
ID storj . NodeID
Address * pb . NodeAddress
LastNet string
LastIPPort string
}
2019-08-06 17:35:59 +01:00
// Service is used to store and handle node information
2019-09-10 14:24:16 +01:00
//
// architecture: Service
2019-08-06 17:35:59 +01:00
type Service struct {
2019-07-31 18:21:06 +01:00
log * zap . Logger
db DB
config Config
2018-04-18 16:34:15 +01:00
}
2019-08-06 17:35:59 +01:00
// NewService returns a new Service
func NewService ( log * zap . Logger , db DB , config Config ) * Service {
return & Service {
2019-07-31 18:21:06 +01:00
log : log ,
db : db ,
config : config ,
2019-03-23 08:06:11 +00:00
}
2018-12-20 13:57:54 +00:00
}
2019-01-18 13:54:08 +00:00
// Close closes resources
2019-08-06 17:35:59 +01:00
func ( service * Service ) Close ( ) error { return nil }
2019-01-18 13:54:08 +00:00
2018-12-20 13:57:54 +00:00
// Inspect lists limited number of items in the cache
2019-08-06 17:35:59 +01:00
func ( service * Service ) Inspect ( ctx context . Context ) ( _ storage . Keys , err error ) {
2019-06-04 12:36:27 +01:00
defer mon . Task ( ) ( & ctx ) ( & err )
2019-01-15 16:08:45 +00:00
// TODO: implement inspection tools
return nil , errors . New ( "not implemented" )
2018-06-13 19:22:32 +01:00
}
2019-08-06 17:35:59 +01:00
// Get looks up the provided nodeID from the overlay.
func ( service * Service ) Get ( ctx context . Context , nodeID storj . NodeID ) ( _ * NodeDossier , err error ) {
2019-03-23 08:06:11 +00:00
defer mon . Task ( ) ( & ctx ) ( & err )
2018-12-17 18:47:26 +00:00
if nodeID . IsZero ( ) {
return nil , ErrEmptyNode
}
2019-08-06 17:35:59 +01:00
return service . db . Get ( ctx , nodeID )
2018-04-18 16:34:15 +01:00
}
2020-03-13 18:01:48 +00:00
// GetNodes returns a map of nodes for the supplied nodeIDs.
func ( service * Service ) GetNodes ( ctx context . Context , nodeIDs [ ] storj . NodeID ) ( _ map [ storj . NodeID ] * NodeDossier , err error ) {
defer mon . Task ( ) ( & ctx ) ( & err )
return service . db . GetNodes ( ctx , nodeIDs )
}
2019-04-23 23:45:50 +01:00
// IsOnline checks if a node is 'online' based on the collected statistics.
2019-08-06 17:35:59 +01:00
func ( service * Service ) IsOnline ( node * NodeDossier ) bool {
2019-11-15 22:43:06 +00:00
return time . Since ( node . Reputation . LastContactSuccess ) < service . config . Node . OnlineWindow
2019-04-23 23:45:50 +01:00
}
2019-03-23 08:06:11 +00:00
// FindStorageNodes searches the overlay network for nodes that meet the provided requirements
2020-03-28 14:56:05 +00:00
func ( service * Service ) FindStorageNodes ( ctx context . Context , req FindStorageNodesRequest ) ( _ [ ] * SelectedNode , err error ) {
2019-06-04 12:36:27 +01:00
defer mon . Task ( ) ( & ctx ) ( & err )
2019-08-06 17:35:59 +01:00
return service . FindStorageNodesWithPreferences ( ctx , req , & service . config . Node )
2019-03-23 08:06:11 +00:00
}
// FindStorageNodesWithPreferences searches the overlay network for nodes that meet the provided criteria
2020-03-28 14:56:05 +00:00
func ( service * Service ) FindStorageNodesWithPreferences ( ctx context . Context , req FindStorageNodesRequest , preferences * NodeSelectionConfig ) ( nodes [ ] * SelectedNode , err error ) {
2019-03-23 08:06:11 +00:00
defer mon . Task ( ) ( & ctx ) ( & err )
2019-01-31 18:49:00 +00:00
// TODO: add sanity limits to requested node count
// TODO: add sanity limits to excluded nodes
2019-03-23 08:06:11 +00:00
reputableNodeCount := req . MinimumRequiredNodes
2019-01-31 18:49:00 +00:00
if reputableNodeCount <= 0 {
2019-03-23 08:06:11 +00:00
reputableNodeCount = req . RequestedCount
2019-01-31 18:49:00 +00:00
}
2020-03-12 18:37:57 +00:00
excludedIDs := req . ExcludedIDs
// if distinctIP is enabled, keep track of the network
// to make sure we only select nodes from different networks
var excludedNetworks [ ] string
if preferences . DistinctIP && len ( excludedIDs ) > 0 {
excludedNetworks , err = service . db . GetNodesNetwork ( ctx , excludedIDs )
2019-11-06 21:38:52 +00:00
if err != nil {
return nil , Error . Wrap ( err )
}
}
2019-04-23 16:23:51 +01:00
newNodeCount := 0
2020-03-18 21:16:13 +00:00
if preferences . NewNodeFraction > 0 {
newNodeCount = int ( float64 ( reputableNodeCount ) * preferences . NewNodeFraction )
2019-04-23 16:23:51 +01:00
}
2020-03-28 14:56:05 +00:00
var newNodes [ ] * SelectedNode
2019-04-23 16:23:51 +01:00
if newNodeCount > 0 {
2019-08-06 17:35:59 +01:00
newNodes , err = service . db . SelectNewStorageNodes ( ctx , newNodeCount , & NodeCriteria {
2020-03-12 18:37:57 +00:00
FreeDisk : preferences . MinimumDiskSpace . Int64 ( ) ,
AuditCount : preferences . AuditCount ,
ExcludedIDs : excludedIDs ,
MinimumVersion : preferences . MinimumVersion ,
OnlineWindow : preferences . OnlineWindow ,
DistinctIP : preferences . DistinctIP ,
ExcludedNetworks : excludedNetworks ,
2019-04-23 16:23:51 +01:00
} )
if err != nil {
2019-08-06 17:35:59 +01:00
return nil , Error . Wrap ( err )
2019-04-23 16:23:51 +01:00
}
}
2020-03-12 18:37:57 +00:00
// add selected new nodes ID and network to the excluded lists for reputable node selection
2019-04-23 16:23:51 +01:00
for _ , newNode := range newNodes {
2020-03-28 14:56:05 +00:00
excludedIDs = append ( excludedIDs , newNode . ID )
2019-05-22 21:06:27 +01:00
if preferences . DistinctIP {
2020-03-12 18:37:57 +00:00
excludedNetworks = append ( excludedNetworks , newNode . LastNet )
2019-05-22 21:06:27 +01:00
}
2019-04-23 16:23:51 +01:00
}
2019-05-07 15:44:47 +01:00
criteria := NodeCriteria {
2020-03-12 18:37:57 +00:00
FreeDisk : preferences . MinimumDiskSpace . Int64 ( ) ,
AuditCount : preferences . AuditCount ,
UptimeCount : preferences . UptimeCount ,
ExcludedIDs : excludedIDs ,
ExcludedNetworks : excludedNetworks ,
MinimumVersion : preferences . MinimumVersion ,
OnlineWindow : preferences . OnlineWindow ,
DistinctIP : preferences . DistinctIP ,
2019-05-07 15:44:47 +01:00
}
2019-08-06 17:35:59 +01:00
reputableNodes , err := service . db . SelectStorageNodes ( ctx , reputableNodeCount - len ( newNodes ) , & criteria )
2019-01-31 18:49:00 +00:00
if err != nil {
2019-08-06 17:35:59 +01:00
return nil , Error . Wrap ( err )
2019-01-31 18:49:00 +00:00
}
nodes = append ( nodes , newNodes ... )
nodes = append ( nodes , reputableNodes ... )
2019-04-23 16:23:51 +01:00
if len ( nodes ) < reputableNodeCount {
2019-05-07 15:44:47 +01:00
return nodes , ErrNotEnoughNodes . New ( "requested %d found %d; %+v " , reputableNodeCount , len ( nodes ) , criteria )
2019-01-31 18:49:00 +00:00
}
return nodes , nil
}
2019-06-18 23:22:14 +01:00
// KnownOffline filters a set of nodes to offline nodes
2019-08-06 17:35:59 +01:00
func ( service * Service ) KnownOffline ( ctx context . Context , nodeIds storj . NodeIDList ) ( offlineNodes storj . NodeIDList , err error ) {
2019-06-18 23:22:14 +01:00
defer mon . Task ( ) ( & ctx ) ( & err )
criteria := & NodeCriteria {
2019-08-06 17:35:59 +01:00
OnlineWindow : service . config . Node . OnlineWindow ,
2019-06-18 23:22:14 +01:00
}
2019-08-06 17:35:59 +01:00
return service . db . KnownOffline ( ctx , criteria , nodeIds )
2019-06-18 23:22:14 +01:00
}
2019-05-10 20:05:42 +01:00
// KnownUnreliableOrOffline filters a set of nodes to unhealth or offlines node, independent of new.
2019-08-06 17:35:59 +01:00
func ( service * Service ) KnownUnreliableOrOffline ( ctx context . Context , nodeIds storj . NodeIDList ) ( badNodes storj . NodeIDList , err error ) {
2019-03-23 08:06:11 +00:00
defer mon . Task ( ) ( & ctx ) ( & err )
2019-05-01 14:45:52 +01:00
criteria := & NodeCriteria {
2019-08-06 17:35:59 +01:00
OnlineWindow : service . config . Node . OnlineWindow ,
2018-09-11 05:52:14 +01:00
}
2019-08-06 17:35:59 +01:00
return service . db . KnownUnreliableOrOffline ( ctx , criteria , nodeIds )
2018-09-11 05:52:14 +01:00
}
2019-12-16 13:45:13 +00:00
// KnownReliable filters a set of nodes to reliable (online and qualified) nodes.
func ( service * Service ) KnownReliable ( ctx context . Context , nodeIDs storj . NodeIDList ) ( nodes [ ] * pb . Node , err error ) {
defer mon . Task ( ) ( & ctx ) ( & err )
return service . db . KnownReliable ( ctx , service . config . Node . OnlineWindow , nodeIDs )
}
2019-07-08 23:04:35 +01:00
// Reliable filters a set of nodes that are reliable, independent of new.
2019-08-06 17:35:59 +01:00
func ( service * Service ) Reliable ( ctx context . Context ) ( nodes storj . NodeIDList , err error ) {
2019-07-08 23:04:35 +01:00
defer mon . Task ( ) ( & ctx ) ( & err )
criteria := & NodeCriteria {
2019-08-06 17:35:59 +01:00
OnlineWindow : service . config . Node . OnlineWindow ,
2019-07-08 23:04:35 +01:00
}
2019-08-06 17:35:59 +01:00
return service . db . Reliable ( ctx , criteria )
2019-07-08 23:04:35 +01:00
}
2019-08-06 17:35:59 +01:00
// Put adds a node id and proto definition into the overlay.
func ( service * Service ) Put ( ctx context . Context , nodeID storj . NodeID , value pb . Node ) ( err error ) {
2019-03-23 08:06:11 +00:00
defer mon . Task ( ) ( & ctx ) ( & err )
2019-10-04 21:48:41 +01:00
// If we get a Node without an ID
// we don't want to add to the database
2018-12-17 18:47:26 +00:00
if nodeID . IsZero ( ) {
2018-11-20 16:54:52 +00:00
return nil
}
2019-01-15 16:08:45 +00:00
if nodeID != value . Id {
return errors . New ( "invalid request" )
}
2019-05-30 18:35:04 +01:00
if value . Address == nil {
return errors . New ( "node has no address" )
}
2019-08-06 23:56:12 +01:00
2020-03-06 22:04:23 +00:00
// Resolve the IP and the subnet from the address that is sent
2020-03-12 18:37:57 +00:00
resolvedIPPort , resolvedNetwork , err := ResolveIPAndNetwork ( ctx , value . Address . Address )
2019-05-30 18:35:04 +01:00
if err != nil {
2019-08-06 17:35:59 +01:00
return Error . Wrap ( err )
2019-05-30 18:35:04 +01:00
}
2020-03-06 22:04:23 +00:00
n := NodeDossier {
Node : value ,
LastNet : resolvedNetwork ,
LastIPPort : resolvedIPPort ,
}
return service . db . UpdateAddress ( ctx , & n , service . config . Node )
2019-03-25 22:25:09 +00:00
}
2019-07-31 18:21:06 +01:00
// BatchUpdateStats updates multiple storagenode's stats in one transaction
2019-08-06 17:35:59 +01:00
func ( service * Service ) BatchUpdateStats ( ctx context . Context , requests [ ] * UpdateRequest ) ( failed storj . NodeIDList , err error ) {
2019-07-31 18:21:06 +01:00
defer mon . Task ( ) ( & ctx ) ( & err )
for _ , request := range requests {
2019-08-06 17:35:59 +01:00
request . AuditLambda = service . config . Node . AuditReputationLambda
request . AuditWeight = service . config . Node . AuditReputationWeight
request . AuditDQ = service . config . Node . AuditReputationDQ
2019-07-31 18:21:06 +01:00
}
2019-08-06 17:35:59 +01:00
return service . db . BatchUpdateStats ( ctx , requests , service . config . UpdateStatsBatchSize )
2019-07-31 18:21:06 +01:00
}
2019-03-25 22:25:09 +00:00
// UpdateStats all parts of single storagenode's stats.
2019-08-06 17:35:59 +01:00
func ( service * Service ) UpdateStats ( ctx context . Context , request * UpdateRequest ) ( stats * NodeStats , err error ) {
2019-03-25 22:25:09 +00:00
defer mon . Task ( ) ( & ctx ) ( & err )
2019-06-20 14:56:04 +01:00
2019-08-06 17:35:59 +01:00
request . AuditLambda = service . config . Node . AuditReputationLambda
request . AuditWeight = service . config . Node . AuditReputationWeight
request . AuditDQ = service . config . Node . AuditReputationDQ
2019-06-20 14:56:04 +01:00
2019-08-06 17:35:59 +01:00
return service . db . UpdateStats ( ctx , request )
2019-03-25 22:25:09 +00:00
}
2019-04-10 07:04:24 +01:00
// UpdateNodeInfo updates node dossier with info requested from the node itself like node type, email, wallet, capacity, and version.
2019-08-06 17:35:59 +01:00
func ( service * Service ) UpdateNodeInfo ( ctx context . Context , node storj . NodeID , nodeInfo * pb . InfoResponse ) ( stats * NodeDossier , err error ) {
2019-03-25 22:25:09 +00:00
defer mon . Task ( ) ( & ctx ) ( & err )
2019-08-06 17:35:59 +01:00
return service . db . UpdateNodeInfo ( ctx , node , nodeInfo )
2019-03-25 22:25:09 +00:00
}
// UpdateUptime updates a single storagenode's uptime stats.
2019-08-06 17:35:59 +01:00
func ( service * Service ) UpdateUptime ( ctx context . Context , nodeID storj . NodeID , isUp bool ) ( stats * NodeStats , err error ) {
2019-03-25 22:25:09 +00:00
defer mon . Task ( ) ( & ctx ) ( & err )
2020-01-03 00:00:18 +00:00
return service . db . UpdateUptime ( ctx , nodeID , isUp )
2019-03-25 22:25:09 +00:00
}
2019-09-19 19:37:31 +01:00
// UpdateCheckIn updates a single storagenode's check-in info.
2019-11-15 22:43:06 +00:00
func ( service * Service ) UpdateCheckIn ( ctx context . Context , node NodeCheckInInfo , timestamp time . Time ) ( err error ) {
2019-09-19 19:37:31 +01:00
defer mon . Task ( ) ( & ctx ) ( & err )
2019-11-15 22:43:06 +00:00
return service . db . UpdateCheckIn ( ctx , node , timestamp , service . config . Node )
2019-09-19 19:37:31 +01:00
}
2020-01-02 20:41:18 +00:00
// GetSuccesfulNodesNotCheckedInSince returns all nodes that last check-in was successful, but haven't checked-in within a given duration.
func ( service * Service ) GetSuccesfulNodesNotCheckedInSince ( ctx context . Context , duration time . Duration ) ( nodeLastContacts [ ] NodeLastContact , err error ) {
defer mon . Task ( ) ( & ctx ) ( & err )
return service . db . GetSuccesfulNodesNotCheckedInSince ( ctx , duration )
}
2019-05-16 14:49:10 +01:00
// GetMissingPieces returns the list of offline nodes
2019-08-06 17:35:59 +01:00
func ( service * Service ) GetMissingPieces ( ctx context . Context , pieces [ ] * pb . RemotePiece ) ( missingPieces [ ] int32 , err error ) {
2019-06-04 12:36:27 +01:00
defer mon . Task ( ) ( & ctx ) ( & err )
2019-05-16 14:49:10 +01:00
var nodeIDs storj . NodeIDList
for _ , p := range pieces {
nodeIDs = append ( nodeIDs , p . NodeId )
}
2019-08-06 17:35:59 +01:00
badNodeIDs , err := service . KnownUnreliableOrOffline ( ctx , nodeIDs )
2019-05-16 14:49:10 +01:00
if err != nil {
return nil , Error . New ( "error getting nodes %s" , err )
}
for _ , p := range pieces {
for _ , nodeID := range badNodeIDs {
if nodeID == p . NodeId {
missingPieces = append ( missingPieces , p . GetPieceNum ( ) )
}
}
}
return missingPieces , nil
}
2019-05-30 18:35:04 +01:00
2020-01-03 19:11:47 +00:00
// DisqualifyNode disqualifies a storage node.
func ( service * Service ) DisqualifyNode ( ctx context . Context , nodeID storj . NodeID ) ( err error ) {
defer mon . Task ( ) ( & ctx ) ( & err )
return service . db . DisqualifyNode ( ctx , nodeID )
}
2020-01-07 21:34:48 +00:00
// GetOfflineNodesLimited returns a list of the first N offline nodes ordered by least recently contacted.
func ( service * Service ) GetOfflineNodesLimited ( ctx context . Context , limit int ) ( offlineNodes [ ] NodeLastContact , err error ) {
defer mon . Task ( ) ( & ctx ) ( & err )
return service . db . GetOfflineNodesLimited ( ctx , limit )
}
2020-03-12 18:37:57 +00:00
// ResolveIPAndNetwork resolves the target address and determines its IP and /24 subnet IPv4 or /64 subnet IPv6
func ResolveIPAndNetwork ( ctx context . Context , target string ) ( ipPort , network string , err error ) {
2019-06-24 16:33:18 +01:00
defer mon . Task ( ) ( & ctx ) ( & err )
2020-03-06 22:04:23 +00:00
host , port , err := net . SplitHostPort ( target )
if err != nil {
return "" , "" , err
}
ipAddr , err := net . ResolveIPAddr ( "ip" , host )
2019-05-30 18:35:04 +01:00
if err != nil {
2020-03-06 22:04:23 +00:00
return "" , "" , err
2019-05-30 18:35:04 +01:00
}
2019-06-24 16:33:18 +01:00
// If addr can be converted to 4byte notation, it is an IPv4 address, else its an IPv6 address
2020-03-06 22:04:23 +00:00
if ipv4 := ipAddr . IP . To4 ( ) ; ipv4 != nil {
2019-06-24 16:33:18 +01:00
//Filter all IPv4 Addresses into /24 Subnet's
mask := net . CIDRMask ( 24 , 32 )
2020-03-06 22:04:23 +00:00
return net . JoinHostPort ( ipAddr . String ( ) , port ) , ipv4 . Mask ( mask ) . String ( ) , nil
2019-06-24 16:33:18 +01:00
}
2020-03-06 22:04:23 +00:00
if ipv6 := ipAddr . IP . To16 ( ) ; ipv6 != nil {
2019-06-24 16:33:18 +01:00
//Filter all IPv6 Addresses into /64 Subnet's
mask := net . CIDRMask ( 64 , 128 )
2020-03-06 22:04:23 +00:00
return net . JoinHostPort ( ipAddr . String ( ) , port ) , ipv6 . Mask ( mask ) . String ( ) , nil
2019-06-24 16:33:18 +01:00
}
2020-03-06 22:04:23 +00:00
return "" , "" , errors . New ( "unable to get network for address " + ipAddr . String ( ) )
2019-05-30 18:35:04 +01:00
}