2019-10-11 14:58:12 +01:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package gracefulexit
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/zeebo/errs"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
|
|
|
|
"storj.io/storj/pkg/pb"
|
2019-10-16 18:50:01 +01:00
|
|
|
"storj.io/storj/pkg/rpc/rpcstatus"
|
2019-10-11 14:58:12 +01:00
|
|
|
"storj.io/storj/storagenode/pieces"
|
|
|
|
"storj.io/storj/storagenode/satellites"
|
|
|
|
"storj.io/storj/storagenode/trust"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Error is the default error class for graceful exit package.
|
|
|
|
var Error = errs.Class("gracefulexit")
|
|
|
|
|
|
|
|
// Endpoint is
|
|
|
|
type Endpoint struct {
|
|
|
|
log *zap.Logger
|
|
|
|
usageCache *pieces.BlobsUsageCache
|
|
|
|
trust *trust.Pool
|
|
|
|
satellites satellites.DB
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewEndpoint creates a new graceful exit endpoint.
|
|
|
|
func NewEndpoint(log *zap.Logger, trust *trust.Pool, satellites satellites.DB, usageCache *pieces.BlobsUsageCache) *Endpoint {
|
|
|
|
return &Endpoint{
|
|
|
|
log: log,
|
|
|
|
usageCache: usageCache,
|
|
|
|
trust: trust,
|
|
|
|
satellites: satellites,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetNonExitingSatellites returns a list of satellites that the storagenode has not begun a graceful exit for.
|
|
|
|
func (e *Endpoint) GetNonExitingSatellites(ctx context.Context, req *pb.GetNonExitingSatellitesRequest) (*pb.GetNonExitingSatellitesResponse, error) {
|
|
|
|
e.log.Debug("initialize graceful exit: GetSatellitesList")
|
|
|
|
// get all trusted satellites
|
|
|
|
trustedSatellites := e.trust.GetSatellites(ctx)
|
|
|
|
|
|
|
|
availableSatellites := make([]*pb.NonExitingSatellite, 0, len(trustedSatellites))
|
|
|
|
|
|
|
|
// filter out satellites that are already exiting
|
|
|
|
exitingSatellites, err := e.satellites.ListGracefulExits(ctx)
|
|
|
|
if err != nil {
|
2019-10-16 18:50:01 +01:00
|
|
|
return nil, rpcstatus.Error(rpcstatus.Internal, err.Error())
|
2019-10-11 14:58:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, trusted := range trustedSatellites {
|
|
|
|
var isExiting bool
|
|
|
|
for _, exiting := range exitingSatellites {
|
|
|
|
if trusted == exiting.SatelliteID {
|
|
|
|
isExiting = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if isExiting {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// get domain name
|
|
|
|
domain, err := e.trust.GetAddress(ctx, trusted)
|
|
|
|
if err != nil {
|
2019-10-22 21:42:21 +01:00
|
|
|
e.log.Debug("graceful exit: get satellite domian name", zap.Stringer("satelliteID", trusted), zap.Error(err))
|
2019-10-11 14:58:12 +01:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
// get space usage by satellites
|
|
|
|
spaceUsed, err := e.usageCache.SpaceUsedBySatellite(ctx, trusted)
|
|
|
|
if err != nil {
|
2019-10-22 21:42:21 +01:00
|
|
|
e.log.Debug("graceful exit: get space used by satellite", zap.Stringer("satelliteID", trusted), zap.Error(err))
|
2019-10-11 14:58:12 +01:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
availableSatellites = append(availableSatellites, &pb.NonExitingSatellite{
|
|
|
|
DomainName: domain,
|
|
|
|
NodeId: trusted,
|
|
|
|
SpaceUsed: float64(spaceUsed),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
return &pb.GetNonExitingSatellitesResponse{
|
|
|
|
Satellites: availableSatellites,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2019-10-15 23:07:32 +01:00
|
|
|
// InitiateGracefulExit updates one or more satellites in the storagenode's database to be gracefully exiting.
|
|
|
|
func (e *Endpoint) InitiateGracefulExit(ctx context.Context, req *pb.InitiateGracefulExitRequest) (*pb.ExitProgress, error) {
|
2019-10-22 21:42:21 +01:00
|
|
|
e.log.Debug("initialize graceful exit: start", zap.Stringer("satellite ID", req.NodeId))
|
2019-10-15 23:07:32 +01:00
|
|
|
|
|
|
|
domain, err := e.trust.GetAddress(ctx, req.NodeId)
|
|
|
|
if err != nil {
|
|
|
|
e.log.Debug("initialize graceful exit: retrieve satellite address", zap.Error(err))
|
2019-10-16 18:50:01 +01:00
|
|
|
return nil, rpcstatus.Error(rpcstatus.Internal, err.Error())
|
2019-10-15 23:07:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// get space usage by satellites
|
|
|
|
spaceUsed, err := e.usageCache.SpaceUsedBySatellite(ctx, req.NodeId)
|
|
|
|
if err != nil {
|
2019-10-22 21:42:21 +01:00
|
|
|
e.log.Debug("initialize graceful exit: retrieve space used", zap.Stringer("Satellite ID", req.NodeId), zap.Error(err))
|
2019-10-16 18:50:01 +01:00
|
|
|
return nil, rpcstatus.Error(rpcstatus.Internal, err.Error())
|
2019-10-15 23:07:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
err = e.satellites.InitiateGracefulExit(ctx, req.NodeId, time.Now().UTC(), spaceUsed)
|
|
|
|
if err != nil {
|
2019-10-22 21:42:21 +01:00
|
|
|
e.log.Debug("initialize graceful exit: save info into satellites table", zap.Stringer("Satellite ID", req.NodeId), zap.Error(err))
|
2019-10-16 18:50:01 +01:00
|
|
|
return nil, rpcstatus.Error(rpcstatus.Internal, err.Error())
|
2019-10-15 23:07:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return &pb.ExitProgress{
|
|
|
|
DomainName: domain,
|
|
|
|
NodeId: req.NodeId,
|
|
|
|
PercentComplete: float32(0),
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetExitProgress returns graceful exit progress on each satellite that a storagde node has started exiting.
|
|
|
|
func (e *Endpoint) GetExitProgress(ctx context.Context, req *pb.GetExitProgressRequest) (*pb.GetExitProgressResponse, error) {
|
|
|
|
exitProgress, err := e.satellites.ListGracefulExits(ctx)
|
|
|
|
if err != nil {
|
2019-10-16 18:50:01 +01:00
|
|
|
return nil, rpcstatus.Error(rpcstatus.Internal, err.Error())
|
2019-10-15 23:07:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
resp := &pb.GetExitProgressResponse{
|
|
|
|
Progress: make([]*pb.ExitProgress, 0, len(exitProgress)),
|
|
|
|
}
|
|
|
|
for _, progress := range exitProgress {
|
|
|
|
domain, err := e.trust.GetAddress(ctx, progress.SatelliteID)
|
2019-10-11 14:58:12 +01:00
|
|
|
if err != nil {
|
2019-10-22 21:42:21 +01:00
|
|
|
e.log.Debug("graceful exit: get satellite domain name", zap.Stringer("satelliteID", progress.SatelliteID), zap.Error(err))
|
2019-10-11 14:58:12 +01:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2019-10-15 23:07:32 +01:00
|
|
|
var percentCompleted float32
|
|
|
|
var hasCompleted bool
|
|
|
|
|
|
|
|
if progress.StartingDiskUsage != 0 {
|
|
|
|
percentCompleted = (float32(progress.BytesDeleted) / float32(progress.StartingDiskUsage)) * 100
|
2019-10-11 14:58:12 +01:00
|
|
|
}
|
2019-10-15 23:07:32 +01:00
|
|
|
if progress.CompletionReceipt != nil {
|
|
|
|
hasCompleted = true
|
2019-10-11 14:58:12 +01:00
|
|
|
}
|
|
|
|
|
2019-10-15 23:07:32 +01:00
|
|
|
resp.Progress = append(resp.Progress,
|
|
|
|
&pb.ExitProgress{
|
|
|
|
DomainName: domain,
|
|
|
|
NodeId: progress.SatelliteID,
|
|
|
|
PercentComplete: percentCompleted,
|
|
|
|
Successful: hasCompleted,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
2019-10-11 14:58:12 +01:00
|
|
|
return resp, nil
|
|
|
|
}
|