2019-01-10 13:13:27 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package storagenode
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
|
|
|
|
"github.com/zeebo/errs"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
"golang.org/x/sync/errgroup"
|
|
|
|
|
2019-04-17 11:09:44 +01:00
|
|
|
"storj.io/storj/internal/errs2"
|
2019-04-03 20:13:39 +01:00
|
|
|
"storj.io/storj/internal/version"
|
2019-03-18 10:55:06 +00:00
|
|
|
"storj.io/storj/pkg/auth/signing"
|
2019-01-10 13:13:27 +00:00
|
|
|
"storj.io/storj/pkg/identity"
|
|
|
|
"storj.io/storj/pkg/kademlia"
|
2019-04-22 10:07:50 +01:00
|
|
|
"storj.io/storj/pkg/overlay"
|
2019-01-10 13:13:27 +00:00
|
|
|
"storj.io/storj/pkg/pb"
|
2019-02-11 11:17:32 +00:00
|
|
|
"storj.io/storj/pkg/peertls/tlsopts"
|
2019-01-10 13:13:27 +00:00
|
|
|
"storj.io/storj/pkg/server"
|
|
|
|
"storj.io/storj/pkg/storj"
|
2019-02-06 12:37:17 +00:00
|
|
|
"storj.io/storj/pkg/transport"
|
2019-01-10 13:13:27 +00:00
|
|
|
"storj.io/storj/storage"
|
2019-03-18 10:55:06 +00:00
|
|
|
"storj.io/storj/storagenode/bandwidth"
|
2019-05-08 12:11:59 +01:00
|
|
|
"storj.io/storj/storagenode/collector"
|
2019-03-18 10:55:06 +00:00
|
|
|
"storj.io/storj/storagenode/inspector"
|
|
|
|
"storj.io/storj/storagenode/monitor"
|
|
|
|
"storj.io/storj/storagenode/orders"
|
|
|
|
"storj.io/storj/storagenode/pieces"
|
|
|
|
"storj.io/storj/storagenode/piecestore"
|
|
|
|
"storj.io/storj/storagenode/trust"
|
2019-01-10 13:13:27 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// DB is the master database for Storage Node
|
|
|
|
type DB interface {
|
2019-01-24 20:28:06 +00:00
|
|
|
// CreateTables initializes the database
|
|
|
|
CreateTables() error
|
|
|
|
// Close closes the database
|
|
|
|
Close() error
|
|
|
|
|
2019-03-18 10:55:06 +00:00
|
|
|
Pieces() storage.Blobs
|
|
|
|
|
|
|
|
Orders() orders.DB
|
|
|
|
PieceInfo() pieces.DB
|
|
|
|
CertDB() trust.CertDB
|
|
|
|
Bandwidth() bandwidth.DB
|
|
|
|
UsedSerials() piecestore.UsedSerials
|
|
|
|
|
2019-01-10 13:13:27 +00:00
|
|
|
// TODO: use better interfaces
|
|
|
|
RoutingTable() (kdb, ndb storage.KeyValueStore)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Config is all the configuration parameters for a Storage Node
|
|
|
|
type Config struct {
|
2019-01-25 14:54:54 +00:00
|
|
|
Identity identity.Config
|
|
|
|
|
2019-01-23 10:39:03 +00:00
|
|
|
Server server.Config
|
|
|
|
Kademlia kademlia.Config
|
2019-03-18 10:55:06 +00:00
|
|
|
|
2019-05-08 12:11:59 +01:00
|
|
|
// TODO: flatten storage config and only keep the new one
|
|
|
|
Storage piecestore.OldConfig
|
|
|
|
Storage2 piecestore.Config
|
|
|
|
Collector collector.Config
|
2019-04-03 20:13:39 +01:00
|
|
|
|
|
|
|
Version version.Config
|
2019-01-10 13:13:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Verify verifies whether configuration is consistent and acceptable.
|
2019-01-23 10:39:03 +00:00
|
|
|
func (config *Config) Verify(log *zap.Logger) error {
|
|
|
|
return config.Kademlia.Verify(log)
|
2019-01-10 13:13:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Peer is the representation of a Storage Node.
|
|
|
|
type Peer struct {
|
|
|
|
// core dependencies
|
|
|
|
Log *zap.Logger
|
|
|
|
Identity *identity.FullIdentity
|
|
|
|
DB DB
|
|
|
|
|
2019-02-06 12:37:17 +00:00
|
|
|
Transport transport.Client
|
2019-01-23 10:39:03 +00:00
|
|
|
|
2019-03-07 18:19:37 +00:00
|
|
|
Server *server.Server
|
2019-01-10 13:13:27 +00:00
|
|
|
|
2019-04-03 20:13:39 +01:00
|
|
|
Version *version.Service
|
|
|
|
|
2019-01-10 13:13:27 +00:00
|
|
|
// services and endpoints
|
2019-01-23 10:39:03 +00:00
|
|
|
// TODO: similar grouping to satellite.Peer
|
2019-01-24 20:28:06 +00:00
|
|
|
Kademlia struct {
|
|
|
|
RoutingTable *kademlia.RoutingTable
|
|
|
|
Service *kademlia.Kademlia
|
2019-02-06 12:37:17 +00:00
|
|
|
Endpoint *kademlia.Endpoint
|
2019-01-24 20:28:06 +00:00
|
|
|
Inspector *kademlia.Inspector
|
|
|
|
}
|
2019-01-10 13:13:27 +00:00
|
|
|
|
2019-03-18 10:55:06 +00:00
|
|
|
Storage2 struct {
|
2019-05-08 12:11:59 +01:00
|
|
|
// TODO: lift things outside of it to organize better
|
2019-03-18 10:55:06 +00:00
|
|
|
Trust *trust.Pool
|
|
|
|
Store *pieces.Store
|
|
|
|
Endpoint *piecestore.Endpoint
|
|
|
|
Inspector *inspector.Endpoint
|
|
|
|
Monitor *monitor.Service
|
2019-03-27 10:24:35 +00:00
|
|
|
Sender *orders.Sender
|
2019-03-18 10:55:06 +00:00
|
|
|
}
|
2019-05-08 12:11:59 +01:00
|
|
|
|
|
|
|
Collector *collector.Service
|
2019-01-10 13:13:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// New creates a new Storage Node.
|
2019-04-03 20:13:39 +01:00
|
|
|
func New(log *zap.Logger, full *identity.FullIdentity, db DB, config Config, versionInfo version.Info) (*Peer, error) {
|
2019-01-10 13:13:27 +00:00
|
|
|
peer := &Peer{
|
2019-02-11 11:17:32 +00:00
|
|
|
Log: log,
|
|
|
|
Identity: full,
|
|
|
|
DB: db,
|
2019-01-10 13:13:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
2019-04-03 20:13:39 +01:00
|
|
|
{
|
|
|
|
test := version.Info{}
|
|
|
|
if test != versionInfo {
|
|
|
|
peer.Log.Sugar().Debugf("Binary Version: %s with CommitHash %s, built at %s as Release %v",
|
|
|
|
versionInfo.Version.String(), versionInfo.CommitHash, versionInfo.Timestamp.String(), versionInfo.Release)
|
|
|
|
}
|
2019-04-04 16:40:07 +01:00
|
|
|
peer.Version = version.NewService(config.Version, versionInfo, "Storagenode")
|
2019-04-03 20:13:39 +01:00
|
|
|
}
|
|
|
|
|
2019-01-10 13:13:27 +00:00
|
|
|
{ // setup listener and server
|
2019-03-07 18:19:37 +00:00
|
|
|
sc := config.Server
|
|
|
|
options, err := tlsopts.NewOptions(peer.Identity, sc.Config)
|
2019-01-10 13:13:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, errs.Combine(err, peer.Close())
|
|
|
|
}
|
|
|
|
|
2019-03-07 18:19:37 +00:00
|
|
|
peer.Transport = transport.NewClient(options)
|
2019-01-10 13:13:27 +00:00
|
|
|
|
2019-03-07 18:19:37 +00:00
|
|
|
peer.Server, err = server.New(options, sc.Address, sc.PrivateAddress, nil)
|
2019-01-10 13:13:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, errs.Combine(err, peer.Close())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{ // setup kademlia
|
|
|
|
config := config.Kademlia
|
|
|
|
// TODO: move this setup logic into kademlia package
|
|
|
|
if config.ExternalAddress == "" {
|
2019-03-07 18:19:37 +00:00
|
|
|
config.ExternalAddress = peer.Addr()
|
2019-01-10 13:13:27 +00:00
|
|
|
}
|
|
|
|
|
2019-04-10 07:04:24 +01:00
|
|
|
pbVersion, err := versionInfo.Proto()
|
|
|
|
if err != nil {
|
|
|
|
return nil, errs.Combine(err, peer.Close())
|
|
|
|
}
|
|
|
|
|
2019-04-22 10:07:50 +01:00
|
|
|
self := &overlay.NodeDossier{
|
|
|
|
Node: pb.Node{
|
|
|
|
Id: peer.ID(),
|
|
|
|
Address: &pb.NodeAddress{
|
|
|
|
Transport: pb.NodeTransport_TCP_TLS_GRPC,
|
|
|
|
Address: config.ExternalAddress,
|
|
|
|
},
|
2019-01-10 13:13:27 +00:00
|
|
|
},
|
2019-04-22 10:07:50 +01:00
|
|
|
Type: pb.NodeType_STORAGE,
|
|
|
|
Operator: pb.NodeOperator{
|
2019-01-10 13:13:27 +00:00
|
|
|
Wallet: config.Operator.Wallet,
|
|
|
|
},
|
2019-04-22 10:07:50 +01:00
|
|
|
Version: *pbVersion,
|
2019-01-10 13:13:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
kdb, ndb := peer.DB.RoutingTable()
|
2019-01-29 06:51:07 +00:00
|
|
|
peer.Kademlia.RoutingTable, err = kademlia.NewRoutingTable(peer.Log.Named("routing"), self, kdb, ndb, &config.RoutingTableConfig)
|
2019-01-10 13:13:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, errs.Combine(err, peer.Close())
|
|
|
|
}
|
|
|
|
|
2019-02-08 09:25:13 +00:00
|
|
|
peer.Transport = peer.Transport.WithObservers(peer.Kademlia.RoutingTable)
|
|
|
|
|
2019-04-22 10:07:50 +01:00
|
|
|
peer.Kademlia.Service, err = kademlia.NewService(peer.Log.Named("kademlia"), peer.Transport, peer.Kademlia.RoutingTable, config)
|
2019-01-10 13:13:27 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, errs.Combine(err, peer.Close())
|
|
|
|
}
|
|
|
|
|
2019-03-22 20:06:57 +00:00
|
|
|
peer.Kademlia.Endpoint = kademlia.NewEndpoint(peer.Log.Named("kademlia:endpoint"), peer.Kademlia.Service, peer.Kademlia.RoutingTable)
|
2019-03-07 18:19:37 +00:00
|
|
|
pb.RegisterNodesServer(peer.Server.GRPC(), peer.Kademlia.Endpoint)
|
2019-01-23 10:39:03 +00:00
|
|
|
|
2019-01-24 20:28:06 +00:00
|
|
|
peer.Kademlia.Inspector = kademlia.NewInspector(peer.Kademlia.Service, peer.Identity)
|
2019-03-07 18:19:37 +00:00
|
|
|
pb.RegisterKadInspectorServer(peer.Server.PrivateGRPC(), peer.Kademlia.Inspector)
|
2019-01-10 13:13:27 +00:00
|
|
|
}
|
|
|
|
|
2019-05-08 12:11:59 +01:00
|
|
|
{ // setup storage
|
2019-03-18 10:55:06 +00:00
|
|
|
trustAllSatellites := !config.Storage.SatelliteIDRestriction
|
|
|
|
peer.Storage2.Trust, err = trust.NewPool(peer.Kademlia.Service, trustAllSatellites, config.Storage.WhitelistedSatelliteIDs)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errs.Combine(err, peer.Close())
|
|
|
|
}
|
|
|
|
|
|
|
|
peer.Storage2.Store = pieces.NewStore(peer.Log.Named("pieces"), peer.DB.Pieces())
|
|
|
|
|
2019-04-15 11:12:22 +01:00
|
|
|
peer.Storage2.Monitor = monitor.NewService(
|
|
|
|
log.Named("piecestore:monitor"),
|
|
|
|
peer.Kademlia.RoutingTable,
|
|
|
|
peer.Storage2.Store,
|
|
|
|
peer.DB.PieceInfo(),
|
|
|
|
peer.DB.Bandwidth(),
|
|
|
|
config.Storage.AllocatedDiskSpace.Int64(),
|
|
|
|
config.Storage.AllocatedBandwidth.Int64(),
|
|
|
|
//TODO use config.Storage.Monitor.Interval, but for some reason is not set
|
|
|
|
config.Storage.KBucketRefreshInterval,
|
|
|
|
)
|
|
|
|
|
2019-03-18 10:55:06 +00:00
|
|
|
peer.Storage2.Endpoint, err = piecestore.NewEndpoint(
|
|
|
|
peer.Log.Named("piecestore"),
|
|
|
|
signing.SignerFromFullIdentity(peer.Identity),
|
|
|
|
peer.Storage2.Trust,
|
2019-04-15 11:12:22 +01:00
|
|
|
peer.Storage2.Monitor,
|
2019-03-18 10:55:06 +00:00
|
|
|
peer.Storage2.Store,
|
|
|
|
peer.DB.PieceInfo(),
|
|
|
|
peer.DB.Orders(),
|
|
|
|
peer.DB.Bandwidth(),
|
|
|
|
peer.DB.UsedSerials(),
|
|
|
|
config.Storage2,
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errs.Combine(err, peer.Close())
|
|
|
|
}
|
|
|
|
pb.RegisterPiecestoreServer(peer.Server.GRPC(), peer.Storage2.Endpoint)
|
|
|
|
|
|
|
|
peer.Storage2.Inspector = inspector.NewEndpoint(
|
|
|
|
peer.Log.Named("pieces:inspector"),
|
|
|
|
peer.DB.PieceInfo(),
|
|
|
|
peer.Kademlia.Service,
|
|
|
|
peer.DB.Bandwidth(),
|
|
|
|
config.Storage,
|
|
|
|
)
|
|
|
|
pb.RegisterPieceStoreInspectorServer(peer.Server.PrivateGRPC(), peer.Storage2.Inspector)
|
|
|
|
|
2019-03-27 10:24:35 +00:00
|
|
|
peer.Storage2.Sender = orders.NewSender(
|
|
|
|
log.Named("piecestore:orderssender"),
|
|
|
|
peer.Transport,
|
|
|
|
peer.Kademlia.Service,
|
|
|
|
peer.DB.Orders(),
|
|
|
|
config.Storage2.Sender,
|
|
|
|
)
|
2019-03-18 10:55:06 +00:00
|
|
|
}
|
|
|
|
|
2019-05-08 12:11:59 +01:00
|
|
|
peer.Collector = collector.NewService(peer.Log.Named("collector"), peer.Storage2.Store, peer.DB.PieceInfo(), config.Collector)
|
|
|
|
|
2019-01-10 13:13:27 +00:00
|
|
|
return peer, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Run runs storage node until it's either closed or it errors.
|
|
|
|
func (peer *Peer) Run(ctx context.Context) error {
|
2019-02-06 13:19:14 +00:00
|
|
|
group, ctx := errgroup.WithContext(ctx)
|
2019-01-10 13:13:27 +00:00
|
|
|
|
2019-04-03 20:13:39 +01:00
|
|
|
group.Go(func() error {
|
2019-04-17 11:09:44 +01:00
|
|
|
return errs2.IgnoreCanceled(peer.Version.Run(ctx))
|
2019-04-03 20:13:39 +01:00
|
|
|
})
|
2019-05-08 12:11:59 +01:00
|
|
|
|
2019-01-10 13:13:27 +00:00
|
|
|
group.Go(func() error {
|
2019-04-17 11:09:44 +01:00
|
|
|
return errs2.IgnoreCanceled(peer.Kademlia.Service.Bootstrap(ctx))
|
2019-01-10 13:13:27 +00:00
|
|
|
})
|
|
|
|
group.Go(func() error {
|
2019-04-17 11:09:44 +01:00
|
|
|
return errs2.IgnoreCanceled(peer.Kademlia.Service.Run(ctx))
|
2019-01-10 13:13:27 +00:00
|
|
|
})
|
2019-05-08 12:11:59 +01:00
|
|
|
|
|
|
|
group.Go(func() error {
|
|
|
|
return errs2.IgnoreCanceled(peer.Collector.Run(ctx))
|
|
|
|
})
|
2019-03-27 10:24:35 +00:00
|
|
|
group.Go(func() error {
|
2019-04-17 11:09:44 +01:00
|
|
|
return errs2.IgnoreCanceled(peer.Storage2.Sender.Run(ctx))
|
2019-03-27 10:24:35 +00:00
|
|
|
})
|
2019-01-23 10:39:03 +00:00
|
|
|
group.Go(func() error {
|
2019-04-17 11:09:44 +01:00
|
|
|
return errs2.IgnoreCanceled(peer.Storage2.Monitor.Run(ctx))
|
2019-01-29 15:41:01 +00:00
|
|
|
})
|
2019-05-08 12:11:59 +01:00
|
|
|
|
2019-01-23 10:39:03 +00:00
|
|
|
group.Go(func() error {
|
|
|
|
// TODO: move the message into Server instead
|
2019-03-07 18:19:37 +00:00
|
|
|
// Don't change the format of this comment, it is used to figure out the node id.
|
|
|
|
peer.Log.Sugar().Infof("Node %s started", peer.Identity.ID)
|
2019-03-18 17:02:37 +00:00
|
|
|
peer.Log.Sugar().Infof("Public server started on %s", peer.Addr())
|
|
|
|
peer.Log.Sugar().Infof("Private server started on %s", peer.PrivateAddr())
|
2019-04-17 11:09:44 +01:00
|
|
|
return errs2.IgnoreCanceled(peer.Server.Run(ctx))
|
2019-01-10 13:13:27 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
return group.Wait()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close closes all the resources.
|
|
|
|
func (peer *Peer) Close() error {
|
|
|
|
var errlist errs.Group
|
|
|
|
|
|
|
|
// TODO: ensure that Close can be called on nil-s that way this code won't need the checks.
|
|
|
|
|
2019-01-28 19:04:42 +00:00
|
|
|
// close servers, to avoid new connections to closing subsystems
|
2019-03-07 18:19:37 +00:00
|
|
|
if peer.Server != nil {
|
|
|
|
errlist.Add(peer.Server.Close())
|
2019-01-28 19:04:42 +00:00
|
|
|
}
|
|
|
|
|
2019-01-10 13:13:27 +00:00
|
|
|
// close services in reverse initialization order
|
2019-05-08 12:11:59 +01:00
|
|
|
|
|
|
|
if peer.Storage2.Monitor != nil {
|
|
|
|
errlist.Add(peer.Storage2.Monitor.Close())
|
|
|
|
}
|
|
|
|
if peer.Storage2.Sender != nil {
|
|
|
|
errlist.Add(peer.Storage2.Sender.Close())
|
|
|
|
}
|
|
|
|
if peer.Collector != nil {
|
|
|
|
errlist.Add(peer.Collector.Close())
|
|
|
|
}
|
|
|
|
|
2019-01-24 20:28:06 +00:00
|
|
|
if peer.Kademlia.Service != nil {
|
|
|
|
errlist.Add(peer.Kademlia.Service.Close())
|
2019-01-10 13:13:27 +00:00
|
|
|
}
|
2019-01-24 20:28:06 +00:00
|
|
|
if peer.Kademlia.RoutingTable != nil {
|
2019-01-29 06:51:07 +00:00
|
|
|
errlist.Add(peer.Kademlia.RoutingTable.Close())
|
2019-01-10 13:13:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return errlist.Err()
|
|
|
|
}
|
|
|
|
|
|
|
|
// ID returns the peer ID.
|
|
|
|
func (peer *Peer) ID() storj.NodeID { return peer.Identity.ID }
|
|
|
|
|
|
|
|
// Local returns the peer local node info.
|
2019-04-22 10:07:50 +01:00
|
|
|
func (peer *Peer) Local() overlay.NodeDossier { return peer.Kademlia.RoutingTable.Local() }
|
2019-01-10 13:13:27 +00:00
|
|
|
|
|
|
|
// Addr returns the public address.
|
2019-03-07 18:19:37 +00:00
|
|
|
func (peer *Peer) Addr() string { return peer.Server.Addr().String() }
|
|
|
|
|
|
|
|
// PrivateAddr returns the private address.
|
|
|
|
func (peer *Peer) PrivateAddr() string { return peer.Server.PrivateAddr().String() }
|