2019-03-18 10:55:06 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package inspector
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/golang/protobuf/ptypes"
|
|
|
|
"github.com/zeebo/errs"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
monkit "gopkg.in/spacemonkeygo/monkit.v2"
|
|
|
|
|
|
|
|
"storj.io/storj/pkg/kademlia"
|
|
|
|
"storj.io/storj/pkg/pb"
|
|
|
|
"storj.io/storj/pkg/piecestore/psserver"
|
|
|
|
"storj.io/storj/pkg/piecestore/psserver/psdb"
|
|
|
|
"storj.io/storj/pkg/storj"
|
|
|
|
"storj.io/storj/storagenode/bandwidth"
|
|
|
|
"storj.io/storj/storagenode/pieces"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
mon = monkit.Package()
|
|
|
|
|
|
|
|
// Error is the default error class for piecestore monitor errors
|
|
|
|
Error = errs.Class("piecestore inspector")
|
|
|
|
)
|
|
|
|
|
|
|
|
// Endpoint does inspectory things
|
|
|
|
type Endpoint struct {
|
|
|
|
log *zap.Logger
|
|
|
|
pieceInfo pieces.DB
|
|
|
|
kademlia *kademlia.Kademlia
|
|
|
|
usageDB bandwidth.DB
|
|
|
|
psdbDB *psdb.DB // TODO remove after complete migration
|
|
|
|
|
|
|
|
startTime time.Time
|
|
|
|
config psserver.Config
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewEndpoint creates piecestore inspector instance
|
|
|
|
func NewEndpoint(log *zap.Logger, pieceInfo pieces.DB, kademlia *kademlia.Kademlia, usageDB bandwidth.DB, psdbDB *psdb.DB, config psserver.Config) *Endpoint {
|
|
|
|
return &Endpoint{
|
|
|
|
log: log,
|
|
|
|
pieceInfo: pieceInfo,
|
|
|
|
kademlia: kademlia,
|
|
|
|
usageDB: usageDB,
|
|
|
|
psdbDB: psdbDB,
|
|
|
|
config: config,
|
|
|
|
startTime: time.Now(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (inspector *Endpoint) retrieveStats(ctx context.Context) (*pb.StatSummaryResponse, error) {
|
|
|
|
totalUsedSpace, err := inspector.pieceInfo.SpaceUsed(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
usage, err := inspector.usageDB.Summary(ctx, getBeginningOfMonth(), time.Now())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-03-27 19:44:18 +00:00
|
|
|
ingress := usage.Put + usage.PutRepair
|
|
|
|
egress := usage.Get + usage.GetAudit + usage.GetRepair
|
|
|
|
|
2019-03-18 10:55:06 +00:00
|
|
|
totalUsedBandwidth := int64(0)
|
|
|
|
oldUsage, err := inspector.psdbDB.SumTTLSizes()
|
|
|
|
if err != nil {
|
|
|
|
inspector.log.Warn("unable to calculate old bandwidth usage")
|
|
|
|
} else {
|
|
|
|
totalUsedBandwidth = oldUsage
|
|
|
|
}
|
|
|
|
|
|
|
|
totalUsedBandwidth += usage.Total()
|
|
|
|
|
|
|
|
return &pb.StatSummaryResponse{
|
|
|
|
UsedSpace: totalUsedSpace,
|
|
|
|
AvailableSpace: (inspector.config.AllocatedDiskSpace.Int64() - totalUsedSpace),
|
2019-03-27 19:44:18 +00:00
|
|
|
UsedIngress: ingress,
|
|
|
|
UsedEgress: egress,
|
2019-03-18 10:55:06 +00:00
|
|
|
UsedBandwidth: totalUsedBandwidth,
|
|
|
|
AvailableBandwidth: (inspector.config.AllocatedBandwidth.Int64() - totalUsedBandwidth),
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stats returns current statistics about the storage node
|
|
|
|
func (inspector *Endpoint) Stats(ctx context.Context, in *pb.StatsRequest) (out *pb.StatSummaryResponse, err error) {
|
|
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
|
|
|
|
inspector.log.Debug("Getting Stats...")
|
|
|
|
|
|
|
|
statsSummary, err := inspector.retrieveStats(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
inspector.log.Info("Successfully retrieved Stats...")
|
|
|
|
|
|
|
|
return statsSummary, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (inspector *Endpoint) getDashboardData(ctx context.Context) (*pb.DashboardResponse, error) {
|
|
|
|
statsSummary, err := inspector.retrieveStats(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return &pb.DashboardResponse{}, Error.Wrap(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: querying all nodes is slow, find a more performant way to do this.
|
|
|
|
nodes, err := inspector.kademlia.FindNear(ctx, storj.NodeID{}, 10000000)
|
|
|
|
if err != nil {
|
|
|
|
return &pb.DashboardResponse{}, Error.Wrap(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
bootstrapNodes := inspector.kademlia.GetBootstrapNodes()
|
|
|
|
bsNodes := make([]string, len(bootstrapNodes))
|
|
|
|
for i, node := range bootstrapNodes {
|
|
|
|
bsNodes[i] = node.Address.Address
|
|
|
|
}
|
|
|
|
|
2019-03-22 13:27:59 +00:00
|
|
|
pinged, err := ptypes.TimestampProto(inspector.kademlia.LastPinged())
|
|
|
|
if err != nil {
|
|
|
|
inspector.log.Warn("last ping time bad", zap.Error(err))
|
|
|
|
pinged = nil
|
|
|
|
}
|
|
|
|
queried, err := ptypes.TimestampProto(inspector.kademlia.LastQueried())
|
|
|
|
if err != nil {
|
|
|
|
inspector.log.Warn("last query time bad", zap.Error(err))
|
|
|
|
queried = nil
|
|
|
|
}
|
|
|
|
|
2019-03-18 10:55:06 +00:00
|
|
|
return &pb.DashboardResponse{
|
|
|
|
NodeId: inspector.kademlia.Local().Id,
|
|
|
|
NodeConnections: int64(len(nodes)),
|
|
|
|
BootstrapAddress: strings.Join(bsNodes[:], ", "),
|
|
|
|
InternalAddress: "",
|
|
|
|
ExternalAddress: inspector.kademlia.Local().Address.Address,
|
2019-03-22 13:27:59 +00:00
|
|
|
LastPinged: pinged,
|
|
|
|
LastQueried: queried,
|
2019-03-18 10:55:06 +00:00
|
|
|
Uptime: ptypes.DurationProto(time.Since(inspector.startTime)),
|
|
|
|
Stats: statsSummary,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dashboard returns dashboard information
|
|
|
|
func (inspector *Endpoint) Dashboard(ctx context.Context, in *pb.DashboardRequest) (out *pb.DashboardResponse, err error) {
|
|
|
|
defer mon.Task()(&ctx)(&err)
|
|
|
|
|
|
|
|
data, err := inspector.getDashboardData(ctx)
|
|
|
|
if err != nil {
|
|
|
|
inspector.log.Warn("unable to get dashboard information")
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getBeginningOfMonth() time.Time {
|
|
|
|
t := time.Now()
|
|
|
|
y, m, _ := t.Date()
|
|
|
|
return time.Date(y, m, 1, 0, 0, 0, 0, time.Now().Location())
|
|
|
|
}
|