2018-04-23 16:54:22 +01:00
|
|
|
// Copyright (C) 2018 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
2018-04-12 14:50:22 +01:00
|
|
|
package overlay
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2018-08-03 14:15:52 +01:00
|
|
|
"fmt"
|
2018-09-18 05:39:06 +01:00
|
|
|
|
|
|
|
"github.com/gogo/protobuf/proto"
|
2018-09-11 05:52:14 +01:00
|
|
|
"github.com/zeebo/errs"
|
2018-06-05 22:06:37 +01:00
|
|
|
"go.uber.org/zap"
|
2018-08-03 14:15:52 +01:00
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
"google.golang.org/grpc/status"
|
2018-06-13 19:22:32 +01:00
|
|
|
"gopkg.in/spacemonkeygo/monkit.v2"
|
2018-06-22 14:33:57 +01:00
|
|
|
|
2018-10-16 12:43:44 +01:00
|
|
|
"storj.io/storj/pkg/dht"
|
2018-09-18 05:39:06 +01:00
|
|
|
"storj.io/storj/pkg/pb"
|
2018-06-22 14:33:57 +01:00
|
|
|
"storj.io/storj/storage"
|
|
|
|
)
|
|
|
|
|
2018-09-11 05:52:14 +01:00
|
|
|
// ServerError creates class of errors for stack traces
|
|
|
|
var ServerError = errs.Class("Server Error")
|
|
|
|
|
2018-06-19 15:00:15 +01:00
|
|
|
// Server implements our overlay RPC service
|
|
|
|
type Server struct {
|
2018-11-19 20:39:25 +00:00
|
|
|
logger *zap.Logger
|
2018-06-22 14:33:57 +01:00
|
|
|
dht dht.DHT
|
2018-06-13 19:22:32 +01:00
|
|
|
cache *Cache
|
2018-06-05 22:06:37 +01:00
|
|
|
metrics *monkit.Registry
|
|
|
|
}
|
2018-04-12 14:50:22 +01:00
|
|
|
|
2018-11-19 20:39:25 +00:00
|
|
|
// NewServer creates a new Overlay Server
|
|
|
|
func NewServer(log *zap.Logger, cache *Cache, dht dht.DHT) *Server {
|
|
|
|
return &Server{
|
|
|
|
dht: dht,
|
|
|
|
cache: cache,
|
|
|
|
logger: log,
|
|
|
|
metrics: monkit.Default,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-12 14:50:22 +01:00
|
|
|
// Lookup finds the address of a node in our overlay network
|
2018-09-18 05:39:06 +01:00
|
|
|
func (o *Server) Lookup(ctx context.Context, req *pb.LookupRequest) (*pb.LookupResponse, error) {
|
2018-06-13 19:22:32 +01:00
|
|
|
na, err := o.cache.Get(ctx, req.NodeID)
|
2018-06-19 15:00:15 +01:00
|
|
|
|
2018-06-05 22:06:37 +01:00
|
|
|
if err != nil {
|
|
|
|
o.logger.Error("Error looking up node", zap.Error(err), zap.String("nodeID", req.NodeID))
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2018-09-18 05:39:06 +01:00
|
|
|
return &pb.LookupResponse{
|
2018-08-01 15:15:38 +01:00
|
|
|
Node: na,
|
2018-06-05 22:06:37 +01:00
|
|
|
}, nil
|
2018-04-12 14:50:22 +01:00
|
|
|
}
|
|
|
|
|
2018-09-11 05:52:14 +01:00
|
|
|
//BulkLookup finds the addresses of nodes in our overlay network
|
2018-09-18 05:39:06 +01:00
|
|
|
func (o *Server) BulkLookup(ctx context.Context, reqs *pb.LookupRequests) (*pb.LookupResponses, error) {
|
2018-09-11 05:52:14 +01:00
|
|
|
ns, err := o.cache.GetAll(ctx, lookupRequestsToNodeIDs(reqs))
|
|
|
|
if err != nil {
|
|
|
|
return nil, ServerError.New("could not get nodes requested %s\n", err)
|
|
|
|
}
|
|
|
|
return nodesToLookupResponses(ns), nil
|
|
|
|
}
|
|
|
|
|
2018-04-12 14:50:22 +01:00
|
|
|
// FindStorageNodes searches the overlay network for nodes that meet the provided requirements
|
2018-09-18 05:39:06 +01:00
|
|
|
func (o *Server) FindStorageNodes(ctx context.Context, req *pb.FindStorageNodesRequest) (resp *pb.FindStorageNodesResponse, err error) {
|
2018-08-01 15:15:38 +01:00
|
|
|
opts := req.GetOpts()
|
2018-11-02 18:50:28 +00:00
|
|
|
maxNodes := req.GetMaxNodes()
|
|
|
|
if maxNodes <= 0 {
|
|
|
|
maxNodes = opts.GetAmount()
|
|
|
|
}
|
|
|
|
|
2018-10-15 18:42:36 +01:00
|
|
|
excluded := opts.GetExcludedNodes()
|
2018-08-01 15:15:38 +01:00
|
|
|
restrictions := opts.GetRestrictions()
|
|
|
|
restrictedBandwidth := restrictions.GetFreeBandwidth()
|
|
|
|
restrictedSpace := restrictions.GetFreeDisk()
|
|
|
|
|
|
|
|
var start storage.Key
|
2018-09-18 05:39:06 +01:00
|
|
|
result := []*pb.Node{}
|
2018-08-01 15:15:38 +01:00
|
|
|
for {
|
2018-09-18 05:39:06 +01:00
|
|
|
var nodes []*pb.Node
|
2018-11-02 18:50:28 +00:00
|
|
|
nodes, start, err = o.populate(ctx, req.GetStart(), maxNodes, restrictedBandwidth, restrictedSpace, excluded)
|
2018-08-01 15:15:38 +01:00
|
|
|
if err != nil {
|
2018-08-03 14:15:52 +01:00
|
|
|
return nil, Error.Wrap(err)
|
2018-08-01 15:15:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(nodes) <= 0 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
result = append(result, nodes...)
|
|
|
|
|
|
|
|
if len(result) >= int(maxNodes) || start == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-08-03 14:15:52 +01:00
|
|
|
if len(result) < int(maxNodes) {
|
|
|
|
return nil, status.Errorf(codes.ResourceExhausted, fmt.Sprintf("requested %d nodes, only %d nodes matched the criteria requested", maxNodes, len(result)))
|
|
|
|
}
|
|
|
|
|
2018-08-01 15:15:38 +01:00
|
|
|
if len(result) > int(maxNodes) {
|
|
|
|
result = result[:maxNodes]
|
|
|
|
}
|
|
|
|
|
2018-09-18 05:39:06 +01:00
|
|
|
return &pb.FindStorageNodesResponse{
|
2018-08-01 15:15:38 +01:00
|
|
|
Nodes: result,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2018-09-18 05:39:06 +01:00
|
|
|
func (o *Server) getNodes(ctx context.Context, keys storage.Keys) ([]*pb.Node, error) {
|
2018-08-01 15:15:38 +01:00
|
|
|
values, err := o.cache.DB.GetAll(keys)
|
2018-06-05 22:06:37 +01:00
|
|
|
if err != nil {
|
2018-08-03 14:15:52 +01:00
|
|
|
return nil, Error.Wrap(err)
|
2018-06-05 22:06:37 +01:00
|
|
|
}
|
|
|
|
|
2018-09-18 05:39:06 +01:00
|
|
|
nodes := []*pb.Node{}
|
2018-08-01 15:15:38 +01:00
|
|
|
for _, v := range values {
|
2018-09-18 05:39:06 +01:00
|
|
|
n := &pb.Node{}
|
|
|
|
if err := proto.Unmarshal(v, n); err != nil {
|
2018-08-03 14:15:52 +01:00
|
|
|
return nil, Error.Wrap(err)
|
2018-08-01 15:15:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
nodes = append(nodes, n)
|
2018-06-22 14:33:57 +01:00
|
|
|
}
|
|
|
|
|
2018-08-01 15:15:38 +01:00
|
|
|
return nodes, nil
|
2018-06-22 14:33:57 +01:00
|
|
|
|
2018-04-12 14:50:22 +01:00
|
|
|
}
|
2018-06-22 14:33:57 +01:00
|
|
|
|
2018-10-15 18:42:36 +01:00
|
|
|
func (o *Server) populate(ctx context.Context, starting storage.Key, maxNodes, restrictedBandwidth, restrictedSpace int64, excluded []string) ([]*pb.Node, storage.Key, error) {
|
2018-09-07 15:20:15 +01:00
|
|
|
limit := int(maxNodes * 2)
|
2018-08-03 14:15:52 +01:00
|
|
|
keys, err := o.cache.DB.List(starting, limit)
|
2018-08-01 15:15:38 +01:00
|
|
|
if err != nil {
|
|
|
|
o.logger.Error("Error listing nodes", zap.Error(err))
|
2018-08-03 14:15:52 +01:00
|
|
|
return nil, nil, Error.Wrap(err)
|
2018-08-01 15:15:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(keys) <= 0 {
|
|
|
|
o.logger.Info("No Keys returned from List operation")
|
2018-09-18 05:39:06 +01:00
|
|
|
return []*pb.Node{}, starting, nil
|
2018-08-01 15:15:38 +01:00
|
|
|
}
|
2018-06-22 14:33:57 +01:00
|
|
|
|
2018-09-18 05:39:06 +01:00
|
|
|
result := []*pb.Node{}
|
2018-08-01 15:15:38 +01:00
|
|
|
nodes, err := o.getNodes(ctx, keys)
|
|
|
|
if err != nil {
|
2018-08-03 14:15:52 +01:00
|
|
|
o.logger.Error("Error getting nodes", zap.Error(err))
|
|
|
|
return nil, nil, Error.Wrap(err)
|
2018-08-01 15:15:38 +01:00
|
|
|
}
|
2018-06-22 14:33:57 +01:00
|
|
|
|
2018-08-01 15:15:38 +01:00
|
|
|
for _, v := range nodes {
|
|
|
|
rest := v.GetRestrictions()
|
2018-10-15 18:42:36 +01:00
|
|
|
|
|
|
|
if rest.GetFreeBandwidth() < restrictedBandwidth ||
|
|
|
|
rest.GetFreeDisk() < restrictedSpace ||
|
|
|
|
contains(excluded, v.Id) {
|
2018-08-01 15:15:38 +01:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
result = append(result, v)
|
2018-06-22 14:33:57 +01:00
|
|
|
}
|
|
|
|
|
2018-08-01 15:15:38 +01:00
|
|
|
nextStart := keys[len(keys)-1]
|
2018-09-07 15:20:15 +01:00
|
|
|
if len(keys) < limit {
|
2018-08-01 15:15:38 +01:00
|
|
|
nextStart = nil
|
2018-06-22 14:33:57 +01:00
|
|
|
}
|
|
|
|
|
2018-08-01 15:15:38 +01:00
|
|
|
return result, nextStart, nil
|
2018-06-22 14:33:57 +01:00
|
|
|
}
|
2018-09-11 05:52:14 +01:00
|
|
|
|
2018-10-15 18:42:36 +01:00
|
|
|
// contains checks if item exists in list
|
|
|
|
func contains(list []string, item string) bool {
|
|
|
|
for _, listItem := range list {
|
|
|
|
if listItem == item {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
//lookupRequestsToNodeIDs returns the nodeIDs from the LookupRequests
|
2018-09-18 05:39:06 +01:00
|
|
|
func lookupRequestsToNodeIDs(reqs *pb.LookupRequests) []string {
|
2018-09-11 05:52:14 +01:00
|
|
|
var ids []string
|
|
|
|
for _, v := range reqs.Lookuprequest {
|
|
|
|
ids = append(ids, v.NodeID)
|
|
|
|
}
|
|
|
|
return ids
|
|
|
|
}
|
|
|
|
|
2018-10-09 17:09:33 +01:00
|
|
|
// nodesToLookupResponses returns LookupResponses from the nodes
|
2018-09-18 05:39:06 +01:00
|
|
|
func nodesToLookupResponses(nodes []*pb.Node) *pb.LookupResponses {
|
|
|
|
var rs []*pb.LookupResponse
|
2018-09-11 05:52:14 +01:00
|
|
|
for _, v := range nodes {
|
2018-09-18 05:39:06 +01:00
|
|
|
r := &pb.LookupResponse{Node: v}
|
2018-09-11 05:52:14 +01:00
|
|
|
rs = append(rs, r)
|
|
|
|
}
|
2018-09-18 05:39:06 +01:00
|
|
|
return &pb.LookupResponses{Lookupresponse: rs}
|
2018-09-11 05:52:14 +01:00
|
|
|
}
|