diff --git a/cmd/neofs-node/control.go b/cmd/neofs-node/control.go index db1447a0..47f69e81 100644 --- a/cmd/neofs-node/control.go +++ b/cmd/neofs-node/control.go @@ -42,6 +42,7 @@ func initControlService(c *cfg) { controlSvc.WithKey(c.key), controlSvc.WithAuthorizedKeys(keys), controlSvc.WithHealthChecker(c), + controlSvc.WithNetMapSource(c.cfgNetmap.wrapper), ) var ( diff --git a/pkg/services/control/server/netmap_snapshot.go b/pkg/services/control/server/netmap_snapshot.go index 6643da14..25f2a8cc 100644 --- a/pkg/services/control/server/netmap_snapshot.go +++ b/pkg/services/control/server/netmap_snapshot.go @@ -3,10 +3,87 @@ package control import ( "context" + netmapAPI "github.com/nspcc-dev/neofs-api-go/pkg/netmap" "github.com/nspcc-dev/neofs-node/pkg/services/control" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) // NetmapSnapshot reads network map snapshot from Netmap storage. func (s *Server) NetmapSnapshot(ctx context.Context, req *control.NetmapSnapshotRequest) (*control.NetmapSnapshotResponse, error) { - panic("implement me") + // verify request + if err := s.isValidRequest(req); err != nil { + return nil, status.Error(codes.PermissionDenied, err.Error()) + } + + // get current epoch + epoch, err := s.netMapSrc.Epoch() + if err != nil { + return nil, status.Error(codes.NotFound, err.Error()) + } + + apiNetMap, err := s.netMapSrc.GetNetMapByEpoch(epoch) + if err != nil { + return nil, status.Error(codes.NotFound, err.Error()) + } + + nm := new(control.Netmap) + nm.SetEpoch(epoch) + nm.SetNodes(nodesFromAPI(apiNetMap.Nodes)) + + // create and fill response + resp := new(control.NetmapSnapshotResponse) + + body := new(control.NetmapSnapshotResponse_Body) + resp.SetBody(body) + + body.SetNetmap(nm) + + // sign the response + if err := SignMessage(s.key, resp); err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + + return resp, nil +} + +func nodesFromAPI(apiNodes netmapAPI.Nodes) []*control.NodeInfo { + nodes := make([]*control.NodeInfo, 0, len(apiNodes)) + + for _, apiNode := range apiNodes { + node := new(control.NodeInfo) + node.SetPublicKey(apiNode.PublicKey()) + node.SetAddress(apiNode.Address()) + node.SetAttributes(attributesFromAPI(apiNode.Attributes())) + node.SetState(stateFromAPI(apiNode.State())) + + nodes = append(nodes, node) + } + + return nodes +} + +func stateFromAPI(s netmapAPI.NodeState) control.HealthStatus { + switch s { + default: + return control.HealthStatus_STATUS_UNDEFINED + case netmapAPI.NodeStateOffline: + return control.HealthStatus_OFFLINE + case netmapAPI.NodeStateOnline: + return control.HealthStatus_ONLINE + } +} + +func attributesFromAPI(apiAttrs []*netmapAPI.NodeAttribute) []*control.NodeInfo_Attribute { + attrs := make([]*control.NodeInfo_Attribute, 0, len(apiAttrs)) + + for _, apiAttr := range apiAttrs { + a := new(control.NodeInfo_Attribute) + a.SetKey(apiAttr.Key()) + a.SetValue(apiAttr.Value()) + + attrs = append(attrs, a) + } + + return attrs } diff --git a/pkg/services/control/server/server.go b/pkg/services/control/server/server.go index 8d445383..6f88ffac 100644 --- a/pkg/services/control/server/server.go +++ b/pkg/services/control/server/server.go @@ -3,6 +3,7 @@ package control import ( "crypto/ecdsa" + "github.com/nspcc-dev/neofs-node/pkg/core/netmap" "github.com/nspcc-dev/neofs-node/pkg/services/control" ) @@ -31,6 +32,8 @@ type cfg struct { allowedKeys [][]byte healthChecker HealthChecker + + netMapSrc netmap.Source } func defaultCfg() *cfg { @@ -73,3 +76,10 @@ func WithHealthChecker(hc HealthChecker) Option { c.healthChecker = hc } } + +// WithNetMapSource returns option to set network map storage. +func WithNetMapSource(netMapSrc netmap.Source) Option { + return func(c *cfg) { + c.netMapSrc = netMapSrc + } +} diff --git a/pkg/services/control/service.go b/pkg/services/control/service.go index 4cde4be0..5f0adcd6 100644 --- a/pkg/services/control/service.go +++ b/pkg/services/control/service.go @@ -73,6 +73,18 @@ func (m *NetmapSnapshotRequest) SetSignature(body *Signature) { } } +// ReadSignedData marshals request body to buf. +func (m *NetmapSnapshotRequest) ReadSignedData(buf []byte) ([]byte, error) { + _, err := m.GetBody().MarshalTo(buf) + + return buf, err +} + +// SignedDataSize returns binary size of the request body. +func (m *NetmapSnapshotRequest) SignedDataSize() int { + return m.GetBody().Size() +} + // SetNetmap sets structure of the current network map. func (m *NetmapSnapshotResponse_Body) SetNetmap(v *Netmap) { if m != nil { @@ -93,3 +105,15 @@ func (m *NetmapSnapshotResponse) SetSignature(v *Signature) { m.Signature = v } } + +// ReadSignedData marshals request body to buf. +func (m *NetmapSnapshotResponse) ReadSignedData(buf []byte) ([]byte, error) { + _, err := m.GetBody().MarshalTo(buf) + + return buf, err +} + +// SignedDataSize returns binary size of the request body. +func (m *NetmapSnapshotResponse) SignedDataSize() int { + return m.GetBody().Size() +}