storj/satellite/contact/endpoint.go
Jess G 93788e5218
remove kademlia: create upsert query to update uptime (#2999)
* create upsert query for check-in method

* add tests

* fix lint err

* add benchmark test for db query

* fix lint and tests

* add a unit test, fix lint

* add address to tests

* replace print w/ b.Fatal

* refactor query per CR comments

* fix disqualified, only set if null

* fix query

* add version to updatecheckin query

* fix version

* fix tests

* change version for tests

* add version to tests

* add IP, add transport, mv unit test

* use node.address as arg

* add last ip

* fix lint
2019-09-19 11:37:31 -07:00

137 lines
3.9 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package contact
import (
"context"
"fmt"
"net"
"github.com/zeebo/errs"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/peer"
"google.golang.org/grpc/status"
"storj.io/storj/pkg/identity"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/storj"
"storj.io/storj/satellite/overlay"
)
// Endpoint implements the contact service Endpoints.
type Endpoint struct {
log *zap.Logger
service *Service
}
// NewEndpoint returns a new contact service endpoint.
func NewEndpoint(log *zap.Logger, service *Service) *Endpoint {
return &Endpoint{
log: log,
service: service,
}
}
// CheckIn is periodically called by storage nodes to keep the satellite informed of its existence,
// address, and operator information. In return, this satellite keeps the node informed of its
// reachability.
// When a node checks-in with the satellite, the satellite pings the node back to confirm they can
// successfully connect.
func (endpoint *Endpoint) CheckIn(ctx context.Context, req *pb.CheckInRequest) (_ *pb.CheckInResponse, err error) {
defer mon.Task()(&ctx)(&err)
peerID, err := peerIDFromContext(ctx)
if err != nil {
return nil, status.Error(codes.Internal, Error.Wrap(err).Error())
}
nodeID := peerID.ID
err = endpoint.service.peerIDs.Set(ctx, nodeID, peerID)
if err != nil {
return nil, status.Error(codes.Internal, Error.Wrap(err).Error())
}
lastIP, err := overlay.GetNetwork(ctx, req.Address)
if err != nil {
return nil, status.Error(codes.Internal, Error.Wrap(err).Error())
}
pingNodeSuccess, pingErrorMessage, err := endpoint.pingBack(ctx, req, nodeID)
if err != nil {
return nil, status.Error(codes.Internal, Error.Wrap(err).Error())
}
nodeInfo := overlay.NodeCheckInInfo{
NodeID: peerID.ID,
Address: &pb.NodeAddress{
Address: req.Address,
Transport: pb.NodeTransport_TCP_TLS_GRPC,
},
LastIP: lastIP,
IsUp: pingNodeSuccess,
Capacity: req.Capacity,
Operator: req.Operator,
Version: req.Version,
}
err = endpoint.service.overlay.UpdateCheckIn(ctx, nodeInfo)
if err != nil {
return nil, status.Error(codes.Internal, Error.Wrap(err).Error())
}
endpoint.log.Debug("checking in", zap.String("node addr", req.Address), zap.Bool("ping node succes", pingNodeSuccess))
return &pb.CheckInResponse{
PingNodeSuccess: pingNodeSuccess,
PingErrorMessage: pingErrorMessage,
}, nil
}
func (endpoint *Endpoint) pingBack(ctx context.Context, req *pb.CheckInRequest, peerID storj.NodeID) (bool, string, error) {
client, err := newClient(ctx,
endpoint.service.transport,
req.Address,
peerID,
)
if err != nil {
// if this is a network error, then return the error otherwise just report internal error
_, ok := err.(net.Error)
if ok {
return false, "", Error.New("failed to connect to %s: %v", req.Address, err)
}
endpoint.log.Info("pingBack internal error", zap.String("error", err.Error()))
return false, "", Error.New("couldn't connect to client at addr: %s due to internal error.", req.Address)
}
defer func() {
err = errs.Combine(err, client.close())
}()
pingNodeSuccess := true
var pingErrorMessage string
p := &peer.Peer{}
_, err = client.pingNode(ctx, &pb.ContactPingRequest{}, grpc.Peer(p))
if err != nil {
pingNodeSuccess = false
pingErrorMessage = "erroring while trying to pingNode due to internal error"
_, ok := err.(net.Error)
if ok {
pingErrorMessage = fmt.Sprintf("network erroring while trying to pingNode: %v\n", err)
}
}
return pingNodeSuccess, pingErrorMessage, err
}
func peerIDFromContext(ctx context.Context) (*identity.PeerIdentity, error) {
p, ok := peer.FromContext(ctx)
if !ok {
return nil, Error.New("unable to get grpc peer from context")
}
peerIdentity, err := identity.PeerIdentityFromPeer(p)
if err != nil {
return nil, err
}
return peerIdentity, nil
}